Skip to content

Instantly share code, notes, and snippets.

@isc30
Forked from vittorioromeo/hello_triangle.cpp
Last active January 13, 2023 23:03
Show Gist options
  • Save isc30/d379e40cbe4f0f34a3ee9ddeda2666db to your computer and use it in GitHub Desktop.
Save isc30/d379e40cbe4f0f34a3ee9ddeda2666db to your computer and use it in GitHub Desktop.
SDL2 + WebGL 2.0 = Triangle
#include <iostream>
#include <exception>
#include <functional>
#include <vector>
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif
#ifndef __EMSCRIPTEN__
#include <glad/glad.h> // OpenGL ES 3.0
#endif
#define GL_GLEXT_PROTOTYPES 1
#include <SDL_opengles2.h>
#include <SDL.h>
void loadOpenGL()
{
#ifndef __EMSCRIPTEN__
gladLoadGLES2Loader(SDL_GL_GetProcAddress);
#endif
}
// Shader sources
const GLchar* vertexSource =
"#version 300 es\n"
"in vec4 position; \n"
"void main() \n"
"{ \n"
" gl_Position = vec4(position.xyz, 1.0); \n"
"} \n";
const GLchar* fragmentSource =
"#version 300 es\n"
"precision mediump float;\n"
"out vec4 color;\n"
"void main() \n"
"{ \n"
" color = vec4 (0.4, 0.8, 0.2, 1.0 );\n"
"} \n";
std::function<bool()> loop;
void main_loop() { loop(); }
void printContext()
{
std::cout << "[OpenGL] " << glGetString(GL_VERSION) << std::endl;
std::cout << "[Vendor] " << glGetString(GL_VENDOR) << std::endl;
std::cout << "[Renderer] " << glGetString(GL_RENDERER) << std::endl;
std::cout << "[GLSL] " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
//std::cout << " [Extensions] " << glGetString(GL_EXTENSIONS) << std::endl;
}
void preRender()
{
// Create Vertex Array Object (WebGL disallows)
GLuint vao;
glGenVertexArraysOES(1, &vao);
glBindVertexArrayOES(vao);
// Create a Vertex Buffer Object and copy the vertex data to it
GLuint vbo;
glGenBuffers(1, &vbo);
GLfloat vertices[] = { 0.0f, 0.5f, 0.5f, -0.5f, -0.5f, -0.5f };
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// Create and compile the vertex shader
GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexSource, NULL);
glCompileShader(vertexShader);
GLint Result = GL_FALSE;
int InfoLogLength;
// Check Vertex Shader
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &Result);
glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength > 1) {
std::vector<char> VertexShaderErrorMessage(InfoLogLength + 1);
glGetShaderInfoLog(vertexShader, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
printf("vertex: %s\n", &VertexShaderErrorMessage[0]);
}
// Create and compile the fragment shader
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentSource, NULL);
glCompileShader(fragmentShader);
// Check Fragment Shader
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &Result);
glGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength > 1) {
std::vector<char> FragmentShaderErrorMessage(InfoLogLength + 1);
glGetShaderInfoLog(fragmentShader, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
printf("fragment: %s\n", &FragmentShaderErrorMessage[0]);
}
// Link the vertex and fragment shader into a shader program
GLuint shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
// glBindFragDataLocation(shaderProgram, 0, "outColor");
glLinkProgram(shaderProgram);
// Check the program
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &Result);
glGetProgramiv(shaderProgram, GL_INFO_LOG_LENGTH, &InfoLogLength);
if (InfoLogLength > 1) {
std::vector<char> ProgramErrorMessage(InfoLogLength + 1);
glGetProgramInfoLog(shaderProgram, InfoLogLength, NULL, &ProgramErrorMessage[0]);
printf("program: %s\n", &ProgramErrorMessage[0]);
}
glUseProgram(shaderProgram);
// Specify the layout of the vertex data
GLint posAttrib = glGetAttribLocation(shaderProgram, "position");
glEnableVertexAttribArray(posAttrib);
glVertexAttribPointer(posAttrib, 2, GL_FLOAT, GL_FALSE, 0, 0);
}
int main(int argc, char** argv)
{
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480
auto* window =
SDL_CreateWindow("test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);
#ifndef __EMSCRIPTEN__
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
#endif
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_CreateContext(window);
loadOpenGL();
printContext();
glViewport(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
SDL_GL_SetSwapInterval(0);
preRender();
loop = [&]
{
SDL_Event e;
while (SDL_PollEvent(&e))
{
switch (e.type)
{
case SDL_QUIT:
{
return false;
}
case SDL_MOUSEMOTION:
{
int x, y; SDL_GetMouseState(&x, &y);
std::cout << x << ", " << y << std::endl;
break;
}
default: break;
}
}
/*screenSurface = SDL_GetWindowSurface(window);
SDL_FillRect(screenSurface, NULL, SDL_MapRGB(screenSurface->format, 0xFF, 0x00, 0x00));
SDL_UpdateWindowSurface(window);*/
// Clear the screen
glClearColor(0.f, 0x33 / 255.f, 0x66 / 255.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Draw a triangle from the 3 vertices
glDrawArrays(GL_TRIANGLES, 0, 3);
SDL_GL_SwapWindow(window);
return true;
};
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop(main_loop, 0, true);
#else
while(true) main_loop();
#endif
std::cout << "end";
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment