This is a single-file OpenGL “hello world” boilerplate implementation. It assumes that SDL and GLEW are already installed.
#include <GL/glew.h>
#include <SDL2/SDL.h>
#include <stdio.h>
#include <string>
const std::string vs =
"#version 330\n"
"layout(location = 0) in vec4 position;\n"
"layout(location = 1) in vec4 color;\n"
"smooth out vec4 vertex_color;\n"
"void main() {\n"
" gl_Position = position;\n"
" vertex_color = color;\n"
"}\n"
""
;
const std::string fs =
"#version 330\n"
"smooth in vec4 vertex_color;\n"
"out vec4 out_color;\n"
"void main() {\n"
" out_color = vertex_color;\n"
"}\n"
""
;
bool create_shader(GLenum shader_kind, const char* shader_src, GLuint* out_shader) {
GLuint shader = glCreateShader(shader_kind);
glShaderSource(shader, 1, &shader_src, NULL);
glCompileShader(shader);
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE) {
GLint log_len;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_len);
GLchar log[4096];
glGetShaderInfoLog(shader, log_len, NULL, log);
const char* kind;
switch (shader_kind) {
case GL_VERTEX_SHADER: kind = "vertex"; break;
case GL_FRAGMENT_SHADER: kind = "fragment"; break;
default: kind = "unknown"; break;
}
fprintf(stderr, "Compile failure in %s shader: %s\n", kind, log);
return false;
}
*out_shader = shader;
return true;
}
bool build_shader_program(const char* vs, const char* fs, GLuint* out_program) {
GLuint vshader;
GLuint fshader;
if (!create_shader(GL_VERTEX_SHADER, vs, &vshader)) return false;
if (!create_shader(GL_FRAGMENT_SHADER, fs, &fshader)) return false;
GLuint program = glCreateProgram();
glAttachShader(program, vshader);
glAttachShader(program, fshader);
glLinkProgram(program);
GLint status;
glGetProgramiv(program, GL_LINK_STATUS, &status);
if (status == GL_FALSE) {
GLint log_len;
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &log_len);
GLchar log[4096];
glGetProgramInfoLog(program, log_len, NULL, log);
fprintf(stderr, "Shader linker failure: %s\n", log);
return false;
}
glDetachShader(program, vshader);
glDetachShader(program, fshader);
*out_program = program;
return true;
}
int main() {
if (SDL_Init(SDL_INIT_VIDEO) < 0) return 1;
SDL_Window *window = SDL_CreateWindow("SDL",
SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED,
640, 480,
SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL
);
SDL_GLContext gl_context = SDL_GL_CreateContext(window);
if (gl_context == NULL) {
fprintf(stderr, "Error in creating the OpenGL context\n");
return 1;
}
const unsigned char *version = glGetString(GL_VERSION);
if (version == NULL) {
fprintf(stderr, "Error in getting the OpenGL version\n");
return 1;
}
SDL_GL_MakeCurrent(window, gl_context);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
// MUST make a context AND make it current BEFORE glewInit()!
glewExperimental = GL_TRUE;
GLenum glew_status = glewInit();
if (glew_status != 0) {
fprintf(stderr, "GLEW init error: %s\n", glewGetErrorString(glew_status));
return 1;
}
const float triangle_vertices[] = {
// position
0.0f, 0.5f, 0.0f, 1.0f,
0.5f, -0.366f, 0.0f, 1.0f,
-0.5f, -0.366f, 0.0f, 1.0f,
// color
1.0f, 0.0f, 0.0f, 1.0f,
0.0f, 1.0f, 0.0f, 1.0f,
0.0f, 0.0f, 1.0f, 1.0f
};
GLuint shader_program;
if (!build_shader_program(vs.c_str(), fs.c_str(), &shader_program)) {
SDL_Quit();
return 0;
}
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
GLuint triangle_vbo;
glGenBuffers(1, &triangle_vbo);
glBindBuffer(GL_ARRAY_BUFFER, triangle_vbo);
glBufferData(
GL_ARRAY_BUFFER,
sizeof(triangle_vertices),
triangle_vertices,
GL_STATIC_DRAW
);
glBindBuffer(GL_ARRAY_BUFFER, 0);
bool running = true;
while (running) {
SDL_Event e;
while (SDL_PollEvent(&e)) {
if (e.type == SDL_QUIT ||
(e.type == SDL_KEYUP && e.key.keysym.sym == SDLK_ESCAPE)) {
running = false;
}
}
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shader_program);
glBindBuffer(GL_ARRAY_BUFFER, triangle_vbo);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void*)48);
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisableVertexAttribArray(0);
glDisableVertexAttribArray(1);
glUseProgram(0);
SDL_GL_SwapWindow(window);
SDL_Delay(20);
}
SDL_GL_DeleteContext(gl_context);
SDL_Quit();
return 0;
}
sdl2-opengl.cpp
Compile with:
g++ sdl2-opengl.cpp -Wall -lSDL2 -lGL -lGLEW