In the world of gaming, SDL provides the entire necessary infrastructure. This would have become clear from the past parts of the series. But infrastructure is to a game what skeleton is to a human body. But without muscles, no locomotion is possible. So working with the analogy of body, SDL provides the skeletal structure to build up the game whereas the flesh, blood and skin are provided by 2D and 3D graphics libraries. In the current plethora of 3D libraries, OpenGL stands out on various accounts. The most significant of them is its compatibility with almost all the platforms and graphics cards. This even reflects in the architecture of SDL as SDL can create and use OpenGL contexts on several platforms. Such architecture helps the game programmer to use all the sub-systems of SDL seamlessly in conjunction with OpenGL to provide most effective games and gaming environments. In this article I will discuss how to use SDL and OpenGL together where gaming infrastructure is provided by SDL and animation as well as rendering is being handled by OpenGL. The first section would discuss the steps required to integrate OpenGL with SDL. The second section would utilize the pointers provided in the first section to create an application having animation(basic) using OpenGL. That is the agenda for the current discussion.
Initialization- Bringing OpenGL into Picture:
In SDL all the sub-systems are initialized via SDL_Init(). OpenGL, being a part of graphics subsystem, is not directly initialized in this manner. For initializing OpenGL following are the steps:
1. Set OpenGL Attributes
2. Specify use of Double Buffering
3. Set the Video Mode
Of these second one is optional as it is used only when double buffering is a requirement. Lets have a detailed look at all of them.
1. Setting the OpenGL Attributes:
Before initializing the video, it is better to set up the OpenGL. These attributes are passed to the OpenGL via SDL calling the SDL_GL_SetAttribute() function. The parameters are the OpenGL attribute and their values. The most common attributes passed to this function are:
i. SDL_GL_RED_SIZE:
It sets the size of the red component of the frame buffer. The value is in bits. The commonly used value is 5. Similar parameters exist for blue and green components which are SDL_GL_BLUE_SIZE and SDL_GL_GREEN_SIZE respectively. To set green component to a bit value of 4 the code would be:
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 4 );
ii. SDL_GL_BUFFER_SIZE:
To set the size of the frame buffer this attribute is passed with the required Buffer size in bits. It is greater than or equal to the combined value i.e. sum of the red, green, blue and alpha components. If the requirement is 24 bit color depth and alpha channel of 32-bits then each color component must be given the size value as 8 and frame buffer must be given size as 32. In code it would be:
SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE,8 );
SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32 );
iii. SDL_GL_DEPTH_SIZE:
This attribute controls the size of depth buffer or Z buffers. Normally the graphics cards provide 16-bit or 24-bit depth. If the value is set more than what is available, the operation will fail. To make it more clear following is the code:
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE,16);
iv. SDL_GL_ACCUM_RED_SIZE:
To set the size of red component of accumulation buffer, this attribute is used.
The value is specified in bits. SDL_GL_ACCUM_BLUE_SIZE, SDL_GL_ACCUM_GREEN_SIZE controls the size of blue and green component of accumulation buffer. In code it would be:
SDL_GL_SetAttribute(SDL_GL_ACCUM_RED_SIZE,5);
The question that would be arising in your mind would be that whether these attributes could be set after initializing the video mode. The answer is no. The reason is that these settings have to be initialized before invoking and configuring video mode. Next we have to setup the video mode.
2. Setting up double buffering:
This aspect has also to be covered before setting up the video mode as this attribute goes as a flag parameter to the SDL_GL_SetAttribute. The attribute is SDL_GL_DOUBLEBUFFER and the value is either 1 or 0. The point to be kept in mind is that when working in conjunction with OpenGL, the flag specifying double buffer must be passed as an attribute to the SDL_GL_SetAttribute function and not to the SDL_Set_VideoMode(). In code this would be:
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1);
would set the double buffering to one state.
3. Setting the Video Mode:
Once the OpenGL attributes are set, setting the video mode is similar to the setting of video mode as described in last tutorials. For more details have a look at Part-II of the tutorial. The only difference comes in flags being sent to the SDL_Set_VideoMode(). Apart from other required flags the SDL_OPENGL would also be set i.e.
int flags=0;
flags= SDL_OPENGL | SDL_FULLSCREEN;
setting the SDL_OPENGL flag is a must.
That’s all there about the required steps. Now let the OpenGL play.
OpenGL in Action:
The theory is over. Its now time to see some real action. The example application would render a rotating triangle. The includes will contain one more header file.
#include <SDL/SDL.h>
#include <gl/gl.h>
gl.h contains function declarations necessary to work with OpenGL.
Next comes the main() and OpenGL attributes.
int main(int argc, char *argv[])
{
SDL_Event event;
float theta = 0.0f;
SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE,8 );
SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32 );
:
:
}
Next initialize the video and video mode
int main(int argc, char *argv[])
{
SDL_Event event;
float theta = 0.0f;
SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE,8 );
SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32 );
SDL_Init(SDL_INIT_VIDEO);
SDL_SetVideoMode(600, 300, 0, SDL_OPENGL | SDL_HWSURFACE |
SDL_NOFRAME);
:
:
}
The video is initialized to 600×300 resolutions. And the hardware rendering mode is being used. This is done by SDL_HWSURFACE flag. Hence OpenGL would write on the graphic card’s memory instead of mapping it to software memory. After this step, the territory of OpenGL starts.
int main(int argc, char *argv[])
{
SDL_Event event;
float theta = 0.0f;
SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE,8 );
SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32 );
SDL_Init(SDL_INIT_VIDEO);
SDL_SetVideoMode(600, 300, 0, SDL_OPENGL | SDL_HWSURFACE |
SDL_NOFRAME);
glViewport(0, 0, 600, 300);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0);
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glMatrixMode(GL_PROJECTION);
glMatrixMode(GL_MODELVIEW);
:
:
}
to start working with OpenGL, the view port is initialized. Then the screen is cleared or rendered with the specified background color. Since the triangle would be rotating in 3D space hence the depth has to be set and depth testing has to be enabled. If smooth shading is not used, then the edges would seem jagged. Hence smooth shading model is used. This completes the setting up of OpenGL parameters after SDL video initialization. Drawing and rotation is taken care by the following code in bold:
int main(int argc, char *argv[])
{
SDL_Event event;
float theta = 0.0f;
SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE,8 );
SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32 );
SDL_Init(SDL_INIT_VIDEO);
SDL_SetVideoMode(600, 300, 0, SDL_OPENGL | SDL_HWSURFACE |
SDL_NOFRAME);
glViewport(0, 0, 600, 300);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0);
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glMatrixMode(GL_PROJECTION);
glMatrixMode(GL_MODELVIEW);
int done;
for(done = 0; !done;)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0.0f,0.0f,0.0f);
glRotatef(theta, 0.0f, 0.0f, 1.0f);
:
:
}
}
The focus is brought to the point of origin by translating it. Then rotation function is provided the theta value through which the triangle has to be rotated.
int main(int argc, char *argv[])
{
SDL_Event event;
float theta = 0.0f;
SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE,8 );
SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32 );
SDL_Init(SDL_INIT_VIDEO);
SDL_SetVideoMode(600, 300, 0, SDL_OPENGL | SDL_HWSURFACE |
SDL_NOFRAME);
glViewport(0, 0, 600, 300);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0);
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glMatrixMode(GL_PROJECTION);
glMatrixMode(GL_MODELVIEW);
int done;
for(done = 0; !done;)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0.0f,0.0f,0.0f);
glRotatef(theta, 0.0f, 0.0f, 1.0f);
glBegin(GL_TRIANGLES);
glColor3f(1.0f, 0.0f, 0.0f);
glVertex2f(0.0f, 1.0f);
glColor3f(0.0f, 1.0f, 0.0f);
glVertex2f(0.87f, -0.5f);
glColor3f(0.0f, 0.0f, 1.0f);
glVertex2f(-0.87f, -0.5f);
glEnd();
theta += .5f;
SDL_GL_SwapBuffers();
:
:
}
}
The triangle is drawn by specifying the vertices. Then the theta value is increased. Next event handling part cometh.
int main(int argc, char *argv[])
{
SDL_Event event;
float theta = 0.0f;
SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE,8 );
SDL_GL_SetAttribute(SDL_GL_BUFFER_SIZE, 32 );
SDL_Init(SDL_INIT_VIDEO);
SDL_SetVideoMode(600, 300, 0, SDL_OPENGL | SDL_HWSURFACE |
SDL_NOFRAME);
glViewport(0, 0, 600, 300);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0);
glDepthFunc(GL_LESS);
glEnable(GL_DEPTH_TEST);
glShadeModel(GL_SMOOTH);
glMatrixMode(GL_PROJECTION);
glMatrixMode(GL_MODELVIEW);
int done;
for(done = 0; !done;)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glTranslatef(0.0f,0.0f,0.0f);
glRotatef(theta, 0.0f, 0.0f, 1.0f);
glBegin(GL_TRIANGLES);
glColor3f(1.0f, 0.0f, 0.0f);
glVertex2f(0.0f, 1.0f);
glColor3f(0.0f, 1.0f, 0.0f);
glVertex2f(0.87f, -0.5f);
glColor3f(0.0f, 0.0f, 1.0f);
glVertex2f(-0.87f, -0.5f);
glEnd();
theta += .5f;
SDL_GL_SwapBuffers();
SDL_PollEvent(&event);
if(event.key.keysym.sym == SDLK_ESCAPE)
done = 1;
}
}
That’s it. This is how SDL and OpenGL work together. The only piece missing in this puzzle is sound. It will be tackled in the next part which incidentally is the last part of this series. So till next time.
