SDL & OpenGL Game with C++ – Part II
Parts in the Series
Rendering a Quad with OpenGL and SDL
Ok, so if we are going to program a video game then we need to draw something with OpenGL.
That being said, last time we left off with a basic framework for creating a game with SDL. If you haven’t read it then you should check out part 1 here because we’ll be building off of that. This time around the goal is simply to get something rendering on the screen with OpenGL. So with that in mind here is the road map for what I wanted to accomplish:
- Render a single quad
- Render a textured quad
As you can see I am going to keep it simple for now. I’ll throw in the ability to swap textures at runtime as well just to keep it interesting.
The game so far will look a little something like this:
![]()
Drawing a Square With SDL
First on the list is to render a single quad. But, before you do anything make sure you add the OpenGL libraries to your project. You can accomplish that by going into the linker section of the project settings and adding opengl32.lib and glu32.lib to the additional dependencies section, just as we did for the SDL libraries in Part I.
I am just going to start out showing you the new main function and then we will go through it step by step. So here ya go!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 | int main( int argc, char **argv) { // graphics properties const int width = 640; // width of the game window const int height = 480; // height of the game window const float fov = 45.0f; // field of view (degrees) const float nearClip = 1.0f; // near clip plane (don't set to zero) const float farClip = 100.0f; // far clip plane // initialize SDL if( SDL_Init( SDL_INIT_VIDEO ) == -1 ) { fprintf(stderr, "Failed to initialize SDL. [%s]\n", SDL_GetError()); exit(1); } // set desired OpenGL attributes prior to selecting a video mode SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 ); // use 16 bits for depth buffer SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); // enable double buffering // create an OpenGL surface/window SDL_Surface *screen = SDL_SetVideoMode(width, height, 32, SDL_OPENGL); if( screen == NULL ) { fprintf(stderr, "Failed to set video mode. [%s]\n", SDL_GetError()); exit(1); } // initialize OpenGL if( SetupOpenGL( width, height, fov, nearClip, farClip) == -1 ) { fprintf( stderr, "Failed to setup OpenGL.\n" ); exit(1); } // main game loop bool done = false; while( !done ) { RenderScene(); if( ProcessInput() ) done = true; } SDL_Quit(); return 0; } |
The variable declarations on lines 4-8 just control the graphical properties of the application. They’re pretty self-explanatory. You can change the width or height and so on.
Next up you’ll see that the code to initialize the video mode (lines 17-27) has been changed. SDL gives us certain attributes that can modify the behavior of OpenGL, but these changes only take place after a call to SDL_SetVideoMode. In this case we’re telling SDL that we would like OpenGL to use a 16-bit depth buffer and to use double buffering when rendering (actively draws to an off screen surface, not the screen). Note that technically we should check the value of these attributes after the SDL_SetVideoMode call to ensure that they were set successfully. You could (and technically should) do this with the correct calls to SDL_GL_GetAttribute. You’ll also notice that the flags parameter for SDL_SetVideoMode now uses SDL_OPENGL instead of SDL_SWSURFACE since we are specifying that we want to use OpenGL for drawing.
Following the setting of the video mode I make a call to SetupOpenGL which is going to configure OpenGL for the application. I’ll detail this function shortly. The last major change to the code is the addition of RenderScene in the main loop. This is the function that will actually draw the game on the screen. Everthing should seem pretty straight forward.
Configuring OpenGL
So now I am going to show you SetupOpenGL. The entire purpose of this function is simply to setup things with respect to OpenGL that we won’t be changing again or that need a known initial state. It’s pretty simple stuff.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | int SetupOpenGL( int width, int height, float fov, float nearClip, float farClip ) { glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); float ar = (GLfloat)width / height; // display aspect ratio // setup projection matrix glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(fov, ar, nearClip, farClip); // setup model view matrix glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // setup depth buffer glClearDepth(1.0f); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); // misc. GL settings glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); glShadeModel(GL_SMOOTH); glViewport( 0, 0, width, height ); return 0; } |
Here I do some basic setup work:
- Setup the projection matrix with gluPerspective
- Set the view matrix to identity
- Setup the depth buffer
- Setup some various GL settings such as the shade model
- And finally setup the viewport
If that looks like gably gook to you then you should check out the the OpenGL Red Book. The 3D transformation pipeline, matrix math, etc is a vast subject and beyond the scope of this post.
Render Scene
Next let’s look at the render scene function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | void RenderScene( void ) { // render everything for the current frame glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); // move off center so the quad is visible glTranslatef(-1.0f, 0.0f, -5.0f); // draw quad as red glColor3f( 1.0f, 0.0, 0.0 ); // render the quad glBegin(GL_QUADS); glVertex3f(-1.0f, 1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 0.0f); glVertex3f( 1.0f,-1.0f, 0.0f); glVertex3f(-1.0f,-1.0f, 0.0f); glEnd(); // update display SDL_GL_SwapBuffers(); } |
So this function will be called every frame to draw the entire screen or “scene”. In this example, it’s simply drawing a red quad on the screen. What’s happening should be clear. First the framebuffer is cleared to get rid of the last scene. Then the identity matrix is loaded into the view matrix so that we are in the center of our world. After that the “camera” is positioned slightly to the left and back a little so the quad is nice and visible. Also, remember OpenGL uses a right handed system so to move the camera back we move along the negative z-axis. Moving on, the active color is then set to red and the quad is drawn vertex by vertex inside the glBegin/glEnd calls. Note that we are not culling back faces so we don’t worry about vertex winding order. Finally a call to SDL_GL_SwapBuffers is made so that the output can be seen. You should see a nice pretty red square.
ProcessInput
The ProcessInput function is responsible for reacting to input events like key presses. Basically it’s the same code from the last example moved into its own little function. It returns true to indicate that the user has indicated he would like to exit the game. Here is the code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | bool ProcessInput( void ) { // runs the input processing loop // returns true if any input has requested the application to exit SDL_Event evt; bool exitFlag = false; // check for events generated from SDL while( SDL_PollEvent( &evt ) ) { switch( evt.type ) { case SDL_QUIT: exitFlag = true; break; case SDL_KEYUP: if( evt.key.keysym.sym == SDLK_ESCAPE ) exitFlag = true; break; default: break; } } return exitFlag; } |
Complete Code Listing
Ok, that was great fun. Now, behold the entire code listing!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 | #include <windows.h> #include <gl\gl.h> #include <gl\glu.h> #include <sdl.h> #include <sdl_opengl.h> // function prototypes int SetupOpenGL( int width, int height, float fov, float nearClip, float farClip ); void RenderScene( void ); bool ProcessInput( void ); int main( int argc, char **argv) { // graphics properties const int width = 640; // width of the game window const int height = 480; // height of the game window const float fov = 45.0f; // field of view (degrees) const float nearClip = 1.0f; // near clip plane (don't set to zero) const float farClip = 100.0f; // far clip plane // initialize SDL if( SDL_Init( SDL_INIT_VIDEO ) == -1 ) { fprintf(stderr, "Failed to initialize SDL. [%s]\n", SDL_GetError()); exit(1); } // set desired OpenGL attributes prior to selecting a video mode SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 ); // use 16 bits for depth buffer SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); // enable double buffering // create an OpenGL surface/window SDL_Surface *screen = SDL_SetVideoMode(width, height, 32, SDL_OPENGL); if( screen == NULL ) { fprintf(stderr, "Failed to set video mode. [%s]\n", SDL_GetError()); exit(1); } // initialize OpenGL if( SetupOpenGL( width, height, fov, nearClip, farClip) == -1 ) { fprintf( stderr, "Failed to setup OpenGL.\n" ); exit(1); } // main game loop bool done = false; while( !done ) { RenderScene(); if( ProcessInput() ) done = true; } SDL_Quit(); return 0; } int SetupOpenGL( int width, int height, float fov, float nearClip, float farClip ) { glClearColor( 0.0f, 0.0f, 0.0f, 0.0f ); float ar = (GLfloat)width / height; // display aspect ratio // setup projection matrix glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(fov, ar, nearClip, farClip); // setup model view matrix glMatrixMode(GL_MODELVIEW); glLoadIdentity(); // setup depth buffer glClearDepth(1.0f); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); // misc. GL settings glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); glShadeModel(GL_SMOOTH); glViewport( 0, 0, width, height ); return 0; } void RenderScene( void ) { // render everything for the current frame glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); // move off center so the quad is visible glTranslatef(-1.0f, 0.0f, -5.0f); // draw quad as red glColor3f( 1.0f, 0.0, 0.0 ); // render the quad glBegin(GL_QUADS); glVertex3f(-1.0f, 1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 0.0f); glVertex3f( 1.0f,-1.0f, 0.0f); glVertex3f(-1.0f,-1.0f, 0.0f); glEnd(); // update display SDL_GL_SwapBuffers(); } bool ProcessInput( void ) { // runs the input processing loop // returns true if any input has requested the application to exit SDL_Event evt; bool exitFlag = false; // check for events generated from SDL while( SDL_PollEvent( &evt ) ) { switch( evt.type ) { case SDL_QUIT: exitFlag = true; break; case SDL_KEYUP: if( evt.key.keysym.sym == SDLK_ESCAPE ) exitFlag = true; break; default: break; } } return exitFlag; } |
Wrap Up
Well, now we can at least draw something on the screen. I wanted to do textures on this post but it is already getting pretty lengthy. So, next time we will texture map the quad and work another step closer to having some kind of game programmed.
Have fun!
December 8, 2009
Posted in: C/C++, Game Programming, Programming

4 Responses
Crows Programming » SDL & OpenGL Game with C++ – Part I - December 8, 2009
[...] Part II – Drawing a Quad [...]
Костя - May 29, 2010
СПС.…
Я тут…
Ольга - May 30, 2010
СПС.…
Я тут…
Light - June 7, 2010
http://rel” rel=”nofollow”>Даже не знаю…
Ссылки как то странно отображаются…
Leave a Reply