//compile with this command on my Ubuntu 12.04 machine: //gcc sdl2-opengl-sample.c -o sdl2-opengl-sample -Wall -std=c99 -I/usr/local/include/SDL2 -lSDL2 -I/usr/include/GL -lGL -lGLEW -Wall #define GLEW_STATIC #include #include #include #include #include #include #include #include #include GLuint BuildShaderProgram(const char *vsPath, const char *fsPath); GLuint CreateShader(GLenum eShaderType, const char *strShaderFile); enum VertexBuffer : int { VERT_POSITION = 0, VERT_COLOR = 1 }; void Init(); void Printf( const char *format... ); void InitHint(); struct Vertex { float xyz[4]; //float st[2]; GLfloat c[4]; }; void GLCheckError() { GLenum err; char str[64]; for( int i = 0; i < 15; i++ ) { if( ( err = glGetError() ) != GL_NO_ERROR ) { switch( err ) { case GL_INVALID_ENUM: strcpy( str, "GL_INVALID_ENUM" ); break; case GL_INVALID_VALUE: strcpy( str, "GL_INVALID_VALUE" ); break; case GL_INVALID_OPERATION: strcpy( str, "GL_INVALID_OPERATION" ); break; case GL_STACK_OVERFLOW: strcpy( str, "GL_STACK_OVERFLOW" ); break; case GL_STACK_UNDERFLOW: strcpy( str, "GL_STACK_UNDERFLOW" ); break; case GL_OUT_OF_MEMORY: strcpy( str, "GL_OUT_OF_MEMORY" ); break; case GL_INVALID_FRAMEBUFFER_OPERATION: strcpy( str, "GL_INVALID_FRAMEBUFFER_OPERATION" ); break; default: break; } printf( "GL error %s %#x\n", str, err ); } } } #define MAX_VERTS 3 Vertex immediate[ MAX_VERTS ]; #undef main int main() { Init(); if( SDL_Init(SDL_INIT_VIDEO) < 0 ) { printf( "Error SDL init\n" ); return 1; } SDL_Window *window = SDL_CreateWindow("My Game Window", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 800, 600, SDL_WINDOW_SHOWN | SDL_WINDOW_OPENGL ); if( !window ) { printf( "Window error init\n"); return 1; } SDL_GLContext glContext = SDL_GL_CreateContext(window); if( !glContext ) { printf("There was an error creating the OpenGL context!\n"); return 1; } InitHint(); const unsigned char *version = glGetString(GL_VERSION); if( !version ) { printf("There was an error creating the OpenGL context!\n"); return 1; } SDL_GL_MakeCurrent( window, glContext ); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_ACCUM_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_ACCUM_GREEN_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_ACCUM_BLUE_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_ACCUM_ALPHA_SIZE, 8); SDL_GL_SetSwapInterval( 1 ); if( !SDL_SetHint( SDL_HINT_RENDER_VSYNC, "1" ) ) { printf( "Application:Init: Warning: Vsync not enabled!\n" ); } glewExperimental = GL_TRUE; GLenum glew_status = glewInit(); if( glew_status != 0 ) { printf( "Error: %s\n", glewGetErrorString(glew_status) ); return 1; } const float triangleVertices[] = { 0.0f, 0.5f, 0.0f, 1.0f, 0.5f, -0.366f, 0.0f, 1.0f, -0.5f, -0.366f, 0.0f, 1.0f, //next part contains vertex colors 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f }; //we love you vertices! GLuint theShaderProgram; theShaderProgram = BuildShaderProgram( "base\\vs1.glsl", "base\\fs1.glsl" ); if( theShaderProgram == 0 ) { SDL_Quit(); return 0; } immediate[0].xyz[0] = 1.0f; immediate[0].xyz[1] = 0.5f; immediate[0].xyz[2] = 0.0f; immediate[0].xyz[3] = 1.0f; immediate[0].c[0] = 1.0f; immediate[0].c[1] = 0.0f; immediate[0].c[2] = 0.0f; immediate[0].c[3] = 1.0f; immediate[1].xyz[0] = 0.5f; immediate[1].xyz[1] = -0.366f; immediate[1].xyz[2] = 0.0f; immediate[1].xyz[3] = 1.0f; immediate[1].c[0] = 0.0f; immediate[1].c[1] = 1.0f; immediate[1].c[2] = 0.0f; immediate[1].c[3] = 1.0f; immediate[2].xyz[0] = -0.5f; immediate[2].xyz[1] = -0.366f; immediate[2].xyz[2] = 0.0f; immediate[2].xyz[3] = 1.0f; immediate[2].c[0] = 0.0f; immediate[2].c[1] = 0.0f; immediate[2].c[2] = 1.0f; immediate[2].c[3] = 1.0f; GLuint vao; glGenVertexArrays(1, &vao); glBindVertexArray(vao); /*GLuint triangleBufferObject; glGenBuffers(1, &triangleBufferObject); glBindBuffer(GL_ARRAY_BUFFER, triangleBufferObject); glBufferData(GL_ARRAY_BUFFER, sizeof(triangleVertices), triangleVertices, GL_STATIC_DRAW); glEnableVertexAttribArray( VertexBuffer::VERT_POSITION ); glEnableVertexAttribArray( VertexBuffer::VERT_COLOR ); glVertexAttribPointer( VertexBuffer::VERT_POSITION, 4, GL_FLOAT, GL_FALSE, 0, 0); glVertexAttribPointer( VertexBuffer::VERT_COLOR, 4, GL_FLOAT, GL_FALSE, 0, (void*)48);*/ GLuint triangleBufferObject; glGenBuffers(1, &triangleBufferObject); glBindBuffer( GL_ARRAY_BUFFER, triangleBufferObject ); glBufferData( GL_ARRAY_BUFFER, sizeof(Vertex)*MAX_VERTS, NULL, GL_STATIC_DRAW ); glBufferSubData( GL_ARRAY_BUFFER, 0, sizeof(Vertex)*MAX_VERTS, immediate ); glEnableVertexAttribArray( VertexBuffer::VERT_POSITION ); glEnableVertexAttribArray( VertexBuffer::VERT_COLOR ); glVertexAttribPointer( VertexBuffer::VERT_POSITION, 4, GL_FLOAT, GL_FALSE, sizeof( Vertex ), (const void*)offsetof( Vertex, xyz ) ); glVertexAttribPointer( VertexBuffer::VERT_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof( Vertex ), (const void*)offsetof( Vertex, c ) ); glBindBuffer( GL_ARRAY_BUFFER, 0 ); glBindVertexArray( 0 ); GLCheckError(); SDL_Event e; bool bGameLoopRunning = true; while( bGameLoopRunning ) { if ( SDL_PollEvent(&e) ) { if( e.type == SDL_QUIT ) { bGameLoopRunning = false; } if( e.type == SDL_KEYUP && e.key.keysym.sym == SDLK_ESCAPE ) { bGameLoopRunning = false; } if( e.type == SDL_KEYUP && e.key.keysym.sym == SDLK_F1 ) { /*immediate[0].xyz[0] = 0.0f; glBindBuffer( GL_ARRAY_BUFFER, triangleBufferObject ); glBufferSubData( GL_ARRAY_BUFFER, 0, sizeof(Vertex)*MAX_VERTS, immediate ); glBindBuffer( GL_ARRAY_BUFFER, 0 );*/ glBindBuffer( GL_ARRAY_BUFFER, triangleBufferObject ); float *v = (float*)glMapBuffer( GL_ARRAY_BUFFER, GL_WRITE_ONLY ); v[0] = 0.0f; glBindBuffer( GL_ARRAY_BUFFER, triangleBufferObject ); glUnmapBuffer( GL_ARRAY_BUFFER ); GLCheckError(); } } glClearColor( 0.3f, 0.4f, 0.4f, 1.0f ); glClear(GL_COLOR_BUFFER_BIT); glUseProgram(theShaderProgram); glBindVertexArray( vao ); glDrawArraysInstanced( GL_TRIANGLES, 0, 3, 1 ); glBindVertexArray( 0 ); glUseProgram(0); SDL_GL_SwapWindow(window); GLCheckError(); } SDL_GL_DeleteContext(glContext); SDL_Quit(); return 0; } GLuint BuildShaderProgram(const char *vsPath, const char *fsPath) { GLuint vertexShader; GLuint fragmentShader; vertexShader = CreateShader( GL_VERTEX_SHADER, vsPath ); fragmentShader = CreateShader( GL_FRAGMENT_SHADER, fsPath ); GLuint tempProgram; tempProgram = glCreateProgram(); glAttachShader( tempProgram, vertexShader ); glAttachShader( tempProgram, fragmentShader ); glLinkProgram( tempProgram ); GLint status; glGetProgramiv( tempProgram, GL_LINK_STATUS, &status ); if( status == GL_FALSE ) { GLint infoLogLength; glGetProgramiv( tempProgram, GL_INFO_LOG_LENGTH, &infoLogLength ); GLchar strInfoLog[4096]; glGetProgramInfoLog( tempProgram, infoLogLength, NULL, strInfoLog ); printf("Shader linker failure: %s\n", strInfoLog); return -1; } else { printf("Shader linked sucessfully!\n"); } glDetachShader( tempProgram, vertexShader ); glDetachShader( tempProgram, fragmentShader ); return tempProgram; } GLuint CreateShader(GLenum eShaderType, const char *strShaderFile) { char shaderSource[4096]; char inChar; FILE *shaderFile; int i = 0; shaderFile = fopen(strShaderFile, "r"); while(fscanf(shaderFile,"%c",&inChar) > 0) { shaderSource[i++] = inChar; } shaderSource[i - 1] = '\0'; fclose(shaderFile); //printf( "%s\n\n", shaderSource ); GLuint shader = glCreateShader(eShaderType); const char *ss = shaderSource; glShaderSource(shader, 1, &ss, NULL); glCompileShader(shader); GLint status; glGetShaderiv(shader, GL_COMPILE_STATUS, &status); if (status == GL_FALSE) { GLint infoLogLength; glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLogLength); GLchar strInfoLog[4096]; glGetShaderInfoLog(shader, infoLogLength, NULL, strInfoLog); char strShaderType[16]; switch( eShaderType ) { case GL_VERTEX_SHADER: sprintf(strShaderType, "vertex"); break; case GL_GEOMETRY_SHADER: sprintf(strShaderType, "geometry"); break; case GL_FRAGMENT_SHADER: sprintf(strShaderType, "fragment"); break; } printf( "Compile failure in %s shader:\n%s\n", strShaderType, strInfoLog); return -1; } else { printf( "Shader compiled sucessfully!\n" ); } return shader; } void Init() { FILE *file; file = fopen( "log", "w" ); if( !file ) { fprintf( stderr, "%s", "Cannot open file\n" ); return; } fclose( file ); } void Printf( const char *format, ... ) { va_list list; FILE *file; file = fopen( "log", "a" ); if( !file ) { fprintf( stderr, "%s", "Cannot open file\n" ); return; } va_start( list, format ); vfprintf( file, format, list ); va_end( list ); fclose( file ); } void InitHint() { if( !SDL_SetHint( SDL_HINT_RENDER_SCALE_QUALITY, "1" ) ) { Printf( "Warning: Linear texture filtering not enabled!\n" ); } if( !SDL_SetHint( SDL_HINT_RENDER_VSYNC, "1" ) ) { Printf( "Warning: Vsync not enabled!\n" ); } }