Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
SDL2 + OpenGL ES 2.0 - "Hello triangle" example that works both on X11 and Emscripten
#include <exception>
#include <functional>
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#include <SDL.h>
#include <SDL_image.h>
#include <SDL_ttf.h>
#define GL_GLEXT_PROTOTYPES 1
#include <SDL_opengles2.h>
#else
#include <SDL2/SDL.h>
#define GL_GLEXT_PROTOTYPES 1
#include <SDL2/SDL_opengles2.h>
#endif
// Shader sources
const GLchar* vertexSource =
"attribute vec4 position; \n"
"void main() \n"
"{ \n"
" gl_Position = vec4(position.xyz, 1.0); \n"
"} \n";
const GLchar* fragmentSource =
"precision mediump float;\n"
"void main() \n"
"{ \n"
" gl_FragColor = vec4 (1.0, 1.0, 1.0, 1.0 );\n"
"} \n";
std::function<void()> loop;
void main_loop() { loop(); }
int main(int argc, char** argv)
{
// SDL_Init(SDL_INIT_VIDEO);
auto wnd(
SDL_CreateWindow("test", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
640, 480, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN));
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
SDL_GL_SetSwapInterval(0);
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
auto glc = SDL_GL_CreateContext(wnd);
auto rdr = SDL_CreateRenderer(
wnd, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
// Create Vertex Array Object
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);
// Create and compile the fragment shader
GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentSource, NULL);
glCompileShader(fragmentShader);
// 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);
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);
loop = [&]
{
SDL_Event e;
while(SDL_PollEvent(&e))
{
if(e.type == SDL_QUIT) std::terminate();
}
// Clear the screen to black
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Draw a triangle from the 3 vertices
glDrawArrays(GL_TRIANGLES, 0, 3);
SDL_GL_SwapWindow(wnd);
};
#ifdef __EMSCRIPTEN__
emscripten_set_main_loop(main_loop, 0, true);
#else
while(true) main_loop();
#endif
return 0;
}
@hikari-no-yume

This comment has been minimized.

Copy link

commented Jan 22, 2017

Thank you, this has helped me get off the ground with my GLES emscripten app.

@hikari-no-yume

This comment has been minimized.

Copy link

commented Jan 24, 2017

Heads-up: SDL_GL_SetSwapInterval(0); should come after creating the GL context. It's a noöp otherwise, at least on macOS.

@ROWEND36

This comment has been minimized.

Copy link

commented Nov 1, 2017

Whenever you feel like it, come over to my place for a treat. You've really helped me out. I had to comment out the vertex ary objects though since my vendor doesnt support that.But still, thanks a lot.

@makoConstruct

This comment has been minimized.

Copy link

commented Jul 24, 2018

Any idea why I'd be getting this compilation error?

» clang++ --std=c++14 -Wreturn-type -g -O0 -D_GLIBCXX_DEBUG -DCXXPOOL_ENABLE_THREAD_AFFINITIES `sdl2-config  --cflags --libs` -lGLESv2 -lEGL ./hello_triangle.cpp -lpthread -lstdc++fs -o hello_triangle
/tmp/hello_triangle-263b5f.o: In function `main':
/home/mako/programming/toying/./hello_triangle.cpp:62: undefined reference to `glGenVertexArraysOES'
/home/mako/programming/toying/./hello_triangle.cpp:63: undefined reference to `glBindVertexArrayOES'
@makoConstruct

This comment has been minimized.

Copy link

commented Jul 28, 2018

I found out. At least in sdl2.0.8 Those functions will only be defined if _MSC_VER is defined, which means it only works on windows.

@Grumbel

This comment has been minimized.

Copy link

commented Sep 5, 2018

To get this to work I had to remove:

"precision mediump float;\n"

and

GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
@raulfpl

This comment has been minimized.

Copy link

commented Oct 5, 2018

SDL_GL_SetAttribute calls should come before SDL_CreateWindow.
SDL2 documentation for SDL_GL_SetAttribute says:

Use this function to set an OpenGL window attribute before window creation.

One problem I noticed is that if you call SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); before SDL_CreateWindow on Android it will make you lose OpenGL ES context when your window loses focus. Then, when you get back to the app, nothing will be drawn on the screen as all opengl calls will fail because you have no valid context. (At least that was what happened on my device until I moved those calls to before SDL_CreateWindow or removed the line SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.