SDL + OpenGL Tutorial Basics

Beginning OpenGL

In this new tutorial series, we will be looking at using SDL along with OpenGL. SDL as it stands is nice for basic 2D graphics/composition, but when it comes to more intensive gaming applications or 3D graphics, we need to leverage the use of other libraries. SDL works so well with OpenGL because we can use OpenGL to manage only graphical rendering, and leave SDL for everything else (Events, Window management, etc).

So, lets get started. We'll be basing our code off of the "SDL Tutorial Basics" tutorial - so head on over there first if you haven't had a chance to look at it. Primarily what we'll be doing here is making any necessary changes to the code for use with OpenGL. What's nice about SDL is that it provides an easy way to setup OpenGL. On the technical side of things, whenever a window is created on an operating system, an OpenGL context must also be created (with certain properties) and linked to that window. SDL makes this rather easy for us.

Before we get started with modifying our code, open up your project file (the one from SDL Tutorial Basics). Because we are using another library now, we are going to need to link to it. So, open up your Project Properties, and add "opengl32", "glu32" to your linker settings (this is the same area that has mingw32, SDLmain, SDL). If you are another operating system besides Windows, your library names will most likely be "opengl", "glu." Most people already have the OpenGL library installed (as it usually comes with CodeBlocks). If you don't, make sure you downloaded the CodeBlocks with mingw. If you are on some Linux flavor, try installing Mesa. Also, as a last note, put the new libraries after the SDL libraries.

That's it for project settings, lets move on to modifying our code. Open up CApp.h and include our OpenGL header file.

If you are wondering what the difference between gl and glu, gl contains the primary functions from the OpenGL specification, and glu contains several helper/utility functions for creating complex shapes, moving the camera, etc. So now that we have that, lets actually get OpenGL up and running. Open up CApp_OnInit.cpp. Right now this is what we have:

The first thing we need to do is tell SDL that we are going to be using OpenGL. Thankfully, SDL provides an easy way to do this. Add the flag SDL_OPENGL just after SDL_DOUBLEBUF, and change SDL_DOUBLEBUF to SDL_GL_DOUBLEBUFFER:

These are all basic memory sizes for how much data OpenGL will store (except SDL_GL_MULTISAMPLEBUFFERS/SDL_GL_MULTISAMPLESAMPLES, those are for something else). By increasing these, you will effectively increase how much memory OpenGL will use for color information, and the buffer. As I mentioned before, the default on all of these is usually just fine. If you wish to set these, the values I have up above are pretty good. Be sure to call SDL_GL_SetAttribute before calling SDL_SetVideoMode. One thing I want to mention is on SDL_GL_MULTISAMPLEBUFFERS. This is basically your anti-aliasing flag. By turning this on, you are turning on anti-aliasing. SDL_GL_MULTISAMPLESAMPLES is how much to anti-alias. A value of 2 is pretty standard if turned on, 4 is also commonly used. Just keep in mind that this can be resource intensive for some systems. Also, not every computer is able to perform anti-aliasing. And one last note! Make sure your SDL_GL_DEPTH_SIZE is a power of two (16, 32 works), otherwise anti-aliasing may not work for you.

Moving on. Now we basically have OpenGL setup with our window, but the problem is that OpenGL requires additional information about the rendering area. What I mean by this is that because OpenGL is a 3D rendering library, it needs to know some basic things like where the camera is, what our 3D world looks like, what color is our rendering area, etc.

Okay, this is where we actually get to start using OpenGL. First, note that OpenGL is a C library (like SDL), and that all function calls begin with gl* (much like all SDL function calls begin with SDL_*). So what are we doing here exactly? The first function call, glClearColor, tells OpenGL what color to render the view when the color buffer is cleared. The color buffer is the buffer OpenGL uses to render pixels to the screen. glClearDepth does something similar. It tells OpenGL what value to reset the depth buffer when it is cleared. The depth buffer is used to determine the z-axis of a pixel. There are other buffers as well, but only worry about these two for now. The 4 arguments are basically Red, Green, Blue, Alpha. With 1.0f being full color, and 0.0f being no color. If you want to define values as regular RGB 255 values, do this:

glClearColor((128.0f / 255.0f), 1.0f, 1.0f, 1.0f); //Cyan color

Next, we setup the viewport for opengl. This, in essence, is the window area OpenGL will use. If you set it smaller to the SDL window size you'll have black borders, and if you set it larger then the SDL window, you'll have your view clipped. Usually, this will always be the same as the regular window size, but there are certain cases you would want it smaller (you can actually create multiple viewports, and have them all display different camera angles of a single scene). Arguments are X, Y, Width, Height.

After that, we tell OpenGL to change to GL_PROJECTION mode. OpenGL contains certain matrix modes that affect certain things. I don't want to confuse you with technical details, but you'll only ever want to use GL_PROJECTION when you are setting up the "projection" of the scene (which is what the glOrtho call does). Other possible projection functions are glLoadIdentity / gluPerspective / glFrustum / gluOrtho2D. Otherwise, you'll almost always want to be in GL_MODELVIEW mode.

So, after we are in projection mode, we call glLoadIdentity (which is basically a "reset matrix" call). Then, we call glOrtho. Now, to take a quick aside for a moment, we have been working in 2D thus far in all the tutorials on this website. This tutorial is no different, so we are going to use glOrtho to setup a "2D Perspective." An ortho, or orthogonal, perspective is one that flattens a 3D environment into a 2D one. This more or less elmiminates any 3D look, and makes it render like a regular 2D game. Please note though, you can still using the z-axis for layering. On the flip side, if you wanted a 3D environment, you would use gluPerspective or similar to setup a "3D Perspective." So, in simple basic terms, for 2D us glOrtho, and for 3D use gluPerspective. Regarding the arguments of the function, they are Left, Right, Bottom, Top, Near, Far. So, by setting Left to 0, and Right to 640, I am defining the perspective area. If you set these values to something different than the window size, it'd basically stretch / shrink everything.

Moving on, we switch to GL_MODELVIEW mode, reset it, and also enable GL_TEXTURE_2D (By default, textures are not enabled). What is a texture? A texture is very much like an SDL_Surface. It's an image stored in memory that can be rendered to the display, but unlike SDL_Surface's, Textures cannot be rendered to the screen on their own. They must be attached to some sort of primitive. Meaning, if you want to render a basic texture like an SDL_Surface, you have to "Bind" the texture (make it active), render a square, and then attach the texture to the four corners of that square. It sounds more complex then it really is, and we'll take a look at doing that in future tutorials.

We should be able to get through this fairly quickly. The first line clears our color and depth buffer. For all simplistic purposes, this does a type of reset, and makes our screen blank again. This is similar to calling SDL_FillRect on SDL's primary display surface. Keep in mind though it does more than that. Then, we reset our GL_MODELVIEW matrix. Why? Whenever you move around in the 2D / 3D world in OpenGL to render things you are modifying the model view matrix. This matrix is what OpenGL uses to determine where and how to render something to the screen. So, if you are moving around rendering things, you need to reset it on every loop.

Next is where the magic starts to happen. glBegin is used to signal the start of the rendering of a primitive. The parameter is used to simply define what primitive you are going to render. In this case, we are going to render a Rectangle (called a Quad - 4 sides). glEnd is used to signal the end you rendering that primitive.

Now, when we go to render our primitive what we have to do is define each corner of that primitive. So, we start with the first corner (or vertex), specify the coordinates, and then move to the next, and so on. At the same time, I am defining the colors of each corner (each corner will have a different color). What OpenGL will do for us is color the entire primitive blending those four corner's colors together. It ends up looking like this:

Lastly, we call SDL_GL_SwapBuffers which basically takes the buffer and moves it to the primary display - much like SDL_Flip.

And that's it! I hope you see how easy it is to setup OpenGL. There's quiet a bit to memorize at first, but once you have it down, it's not that bad at all.

I have tried get this code running, it works except one problem: If i use the SDL_GL_DOUBLEBUFFER Flag, i get an enlarged view of my editor for some seconds, and then my screen turns black. If I leave the Flag out, i get the result as shown in this tutorial... Do you have an idea?

(Hide)

Reply to Comment

Name (required):

Email (required, not published):

Website:

Escain

March 28th, 2014

This tutorial is for SDL 1.2 and use deprecated functions.

(Hide)

Reply to Comment

Name (required):

Email (required, not published):

Website:

Yanthir

November 20th, 2013

I can't make my textures accept alpha channels, any ideas? I'm using your code from the SDL_Surf to GLTexture tip you created.

(Hide)

Reply to Comment

Name (required):

Email (required, not published):

Website:

Yanthir

November 20th, 2013

I fixed it! Yay!
For anyone haveing this problem, add those lines in the Init():

Thanks for the simple overview - very helpful. I have a couple of comments that may help others:

1) Another poster suggested SDL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1) - that should be SDL_GL_SetAttribute.

2) The coordinates in your example are wrong. They need to be floating point. So they should be glVertex3f (1.0, 1.0, 0); for example - or, since this is 2D, use glVertex2f (1.0, 1.0);

(Hide)

Reply to Comment

Name (required):

Email (required, not published):

Website:

Richard JB

May 23rd, 2012

Wow!
It's taken less than 10 minutes to build this demo using eclipse, ubuntu, and gcc.
I had to install the development packages for a few things, and tweak some paths.. SDL.h -> SDL/SDL.h, gl/gl.h -> GL/gl.h etc..
Libraries.. to GL, GLU, SDL, SDLmain

Let the hacking begin!

(Hide)

Reply to Comment

Name (required):

Email (required, not published):

Website:

Dan Ford

January 24th, 2012

I've been looking to take my C++ out of console land for along time.
Finding information can be very frustrating. Your no nonsense approach
is a breath of fresh air thanks so much for the tut's !

(Hide)

Reply to Comment

Name (required):

Email (required, not published):

Website:

Blaah Blaah

November 20th, 2011

These tutorials are great, they're a really good basis and introduction for a serious project.

I'm struggling to get anti-aliasing to work. If I run the lines SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, 2) or SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, 1) then my program finishes without displaying anything. All of the other SetAttribute lines work fine. Any idea what's happening?

(Hide)

Reply to Comment

Name (required):

Email (required, not published):

Website:

dcward

November 27th, 2011

Your video card is probably not up to par for the anti-aliasing to work.

(Hide)

Reply to Comment

Name (required):

Email (required, not published):

Website:

BGwra

November 9th, 2011

nice tut. Add some more tut on sdl+opengl when you get some free time :).

Regards.

(Hide)

Reply to Comment

Name (required):

Email (required, not published):

Website:

Zeh

September 17th, 2011

Hi.
I had to replace the <gl/gl.h> and <gl/glu.h> with <SDL_opengl.h> for this to work.
If I only used the gl headers I would get lots of errors.
Including <Windows.h> before the gl headers also worked.

Did I miss something from the tutorial?

(Hide)

Reply to Comment

Name (required):

Email (required, not published):

Website:

Diego

September 25th, 2011

I'm also getting errors (undefined reference to 'gl*') but I can't get around it even with your suggestions.

(Hide)

Reply to Comment

Name (required):

Email (required, not published):

Website:

Diego

September 25th, 2011

Nah.. my mistake was just a typo

(Hide)

Reply to Comment

Name (required):

Email (required, not published):

Website:

Dredlockz

July 6th, 2011

Useful stuff, love the no-fluff level of detail in your tutorials, really spot-on to get a basic sense of how OpenGL operates.