| <HTML |
| ><HEAD |
| ><TITLE |
| >Using OpenGL With SDL</TITLE |
| ><META |
| NAME="GENERATOR" |
| CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+ |
| "><LINK |
| REL="HOME" |
| TITLE="SDL Library Documentation" |
| HREF="index.html"><LINK |
| REL="UP" |
| TITLE="Graphics and Video" |
| HREF="guidevideo.html"><LINK |
| REL="PREVIOUS" |
| TITLE="Graphics and Video" |
| HREF="guidevideo.html"><LINK |
| REL="NEXT" |
| TITLE="Input handling" |
| HREF="guideinput.html"></HEAD |
| ><BODY |
| CLASS="SECT1" |
| BGCOLOR="#FFF8DC" |
| TEXT="#000000" |
| LINK="#0000ee" |
| VLINK="#551a8b" |
| ALINK="#ff0000" |
| ><DIV |
| CLASS="NAVHEADER" |
| ><TABLE |
| SUMMARY="Header navigation table" |
| WIDTH="100%" |
| BORDER="0" |
| CELLPADDING="0" |
| CELLSPACING="0" |
| ><TR |
| ><TH |
| COLSPAN="3" |
| ALIGN="center" |
| >SDL Library Documentation</TH |
| ></TR |
| ><TR |
| ><TD |
| WIDTH="10%" |
| ALIGN="left" |
| VALIGN="bottom" |
| ><A |
| HREF="guidevideo.html" |
| ACCESSKEY="P" |
| >Prev</A |
| ></TD |
| ><TD |
| WIDTH="80%" |
| ALIGN="center" |
| VALIGN="bottom" |
| >Chapter 2. Graphics and Video</TD |
| ><TD |
| WIDTH="10%" |
| ALIGN="right" |
| VALIGN="bottom" |
| ><A |
| HREF="guideinput.html" |
| ACCESSKEY="N" |
| >Next</A |
| ></TD |
| ></TR |
| ></TABLE |
| ><HR |
| ALIGN="LEFT" |
| WIDTH="100%"></DIV |
| ><DIV |
| CLASS="SECT1" |
| ><H1 |
| CLASS="SECT1" |
| ><A |
| NAME="GUIDEVIDEOOPENGL" |
| ></A |
| >Using OpenGL With SDL</H1 |
| ><P |
| >SDL has the ability to create and use OpenGL contexts on several platforms(Linux/X11, Win32, BeOS, MacOS Classic/Toolbox, Mac OS X, FreeBSD/X11 and Solaris/X11). This allows you to use SDL's audio, event handling, threads and times in your OpenGL applications (a function often performed by GLUT).</P |
| ><DIV |
| CLASS="SECT2" |
| ><H2 |
| CLASS="SECT2" |
| ><A |
| NAME="AEN103" |
| ></A |
| >Initialisation</H2 |
| ><P |
| >Initialising SDL to use OpenGL is not very different to initialising SDL normally. There are three differences; you must pass <TT |
| CLASS="LITERAL" |
| >SDL_OPENGL</TT |
| > to <A |
| HREF="sdlsetvideomode.html" |
| ><TT |
| CLASS="FUNCTION" |
| >SDL_SetVideoMode</TT |
| ></A |
| >, you must specify several GL attributes (depth buffer size, framebuffer sizes) using <A |
| HREF="sdlglsetattribute.html" |
| ><TT |
| CLASS="FUNCTION" |
| >SDL_GL_SetAttribute</TT |
| ></A |
| > and finally, if you wish to use double buffering you must specify it as a GL attribute, <SPAN |
| CLASS="emphasis" |
| ><I |
| CLASS="EMPHASIS" |
| >not</I |
| ></SPAN |
| > by passing the <TT |
| CLASS="LITERAL" |
| >SDL_DOUBLEBUF</TT |
| > flag to <TT |
| CLASS="FUNCTION" |
| >SDL_SetVideoMode</TT |
| >.</P |
| ><DIV |
| CLASS="EXAMPLE" |
| ><A |
| NAME="AEN114" |
| ></A |
| ><P |
| ><B |
| >Example 2-7. Initializing SDL with OpenGL</B |
| ></P |
| ><PRE |
| CLASS="PROGRAMLISTING" |
| > /* Information about the current video settings. */ |
| const SDL_VideoInfo* info = NULL; |
| /* Dimensions of our window. */ |
| int width = 0; |
| int height = 0; |
| /* Color depth in bits of our window. */ |
| int bpp = 0; |
| /* Flags we will pass into SDL_SetVideoMode. */ |
| int flags = 0; |
| |
| /* First, initialize SDL's video subsystem. */ |
| if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) { |
| /* Failed, exit. */ |
| fprintf( stderr, "Video initialization failed: %s\n", |
| SDL_GetError( ) ); |
| quit_tutorial( 1 ); |
| } |
| |
| /* Let's get some video information. */ |
| info = SDL_GetVideoInfo( ); |
| |
| if( !info ) { |
| /* This should probably never happen. */ |
| fprintf( stderr, "Video query failed: %s\n", |
| SDL_GetError( ) ); |
| quit_tutorial( 1 ); |
| } |
| |
| /* |
| * Set our width/height to 640/480 (you would |
| * of course let the user decide this in a normal |
| * app). We get the bpp we will request from |
| * the display. On X11, VidMode can't change |
| * resolution, so this is probably being overly |
| * safe. Under Win32, ChangeDisplaySettings |
| * can change the bpp. |
| */ |
| width = 640; |
| height = 480; |
| bpp = info->vfmt->BitsPerPixel; |
| |
| /* |
| * Now, we want to setup our requested |
| * window attributes for our OpenGL window. |
| * We want *at least* 5 bits of red, green |
| * and blue. We also want at least a 16-bit |
| * depth buffer. |
| * |
| * The last thing we do is request a double |
| * buffered window. '1' turns on double |
| * buffering, '0' turns it off. |
| * |
| * Note that we do not use SDL_DOUBLEBUF in |
| * the flags to SDL_SetVideoMode. That does |
| * not affect the GL attribute state, only |
| * the standard 2D blitting setup. |
| */ |
| SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 ); |
| SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 ); |
| SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 ); |
| SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 ); |
| SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); |
| |
| /* |
| * We want to request that SDL provide us |
| * with an OpenGL window, in a fullscreen |
| * video mode. |
| * |
| * EXERCISE: |
| * Make starting windowed an option, and |
| * handle the resize events properly with |
| * glViewport. |
| */ |
| flags = SDL_OPENGL | SDL_FULLSCREEN; |
| |
| /* |
| * Set the video mode |
| */ |
| if( SDL_SetVideoMode( width, height, bpp, flags ) == 0 ) { |
| /* |
| * This could happen for a variety of reasons, |
| * including DISPLAY not being set, the specified |
| * resolution not being available, etc. |
| */ |
| fprintf( stderr, "Video mode set failed: %s\n", |
| SDL_GetError( ) ); |
| quit_tutorial( 1 ); |
| }</PRE |
| ></DIV |
| ></DIV |
| ><DIV |
| CLASS="SECT2" |
| ><H2 |
| CLASS="SECT2" |
| ><A |
| NAME="AEN117" |
| ></A |
| >Drawing</H2 |
| ><P |
| >Apart from initialisation, using OpenGL within SDL is the same as using OpenGL |
| with any other API, e.g. GLUT. You still use all the same function calls and |
| data types. However if you are using a double-buffered display, then you must |
| use |
| <A |
| HREF="sdlglswapbuffers.html" |
| ><TT |
| CLASS="FUNCTION" |
| >SDL_GL_SwapBuffers()</TT |
| ></A |
| > |
| to swap the buffers and update the display. To request double-buffering |
| with OpenGL, use |
| <A |
| HREF="sdlglsetattribute.html" |
| ><TT |
| CLASS="FUNCTION" |
| >SDL_GL_SetAttribute</TT |
| ></A |
| > |
| with <TT |
| CLASS="LITERAL" |
| >SDL_GL_DOUBLEBUFFER</TT |
| >, and use |
| <A |
| HREF="sdlglgetattribute.html" |
| ><TT |
| CLASS="FUNCTION" |
| >SDL_GL_GetAttribute</TT |
| ></A |
| > |
| to see if you actually got it.</P |
| ><P |
| >A full example code listing is now presented below.</P |
| ><DIV |
| CLASS="EXAMPLE" |
| ><A |
| NAME="AEN128" |
| ></A |
| ><P |
| ><B |
| >Example 2-8. SDL and OpenGL</B |
| ></P |
| ><PRE |
| CLASS="PROGRAMLISTING" |
| >/* |
| * SDL OpenGL Tutorial. |
| * (c) Michael Vance, 2000 |
| * briareos@lokigames.com |
| * |
| * Distributed under terms of the LGPL. |
| */ |
| |
| #include <SDL/SDL.h> |
| #include <GL/gl.h> |
| #include <GL/glu.h> |
| |
| #include <stdio.h> |
| #include <stdlib.h> |
| |
| static GLboolean should_rotate = GL_TRUE; |
| |
| static void quit_tutorial( int code ) |
| { |
| /* |
| * Quit SDL so we can release the fullscreen |
| * mode and restore the previous video settings, |
| * etc. |
| */ |
| SDL_Quit( ); |
| |
| /* Exit program. */ |
| exit( code ); |
| } |
| |
| static void handle_key_down( SDL_keysym* keysym ) |
| { |
| |
| /* |
| * We're only interested if 'Esc' has |
| * been presssed. |
| * |
| * EXERCISE: |
| * Handle the arrow keys and have that change the |
| * viewing position/angle. |
| */ |
| switch( keysym->sym ) { |
| case SDLK_ESCAPE: |
| quit_tutorial( 0 ); |
| break; |
| case SDLK_SPACE: |
| should_rotate = !should_rotate; |
| break; |
| default: |
| break; |
| } |
| |
| } |
| |
| static void process_events( void ) |
| { |
| /* Our SDL event placeholder. */ |
| SDL_Event event; |
| |
| /* Grab all the events off the queue. */ |
| while( SDL_PollEvent( &event ) ) { |
| |
| switch( event.type ) { |
| case SDL_KEYDOWN: |
| /* Handle key presses. */ |
| handle_key_down( &event.key.keysym ); |
| break; |
| case SDL_QUIT: |
| /* Handle quit requests (like Ctrl-c). */ |
| quit_tutorial( 0 ); |
| break; |
| } |
| |
| } |
| |
| } |
| |
| static void draw_screen( void ) |
| { |
| /* Our angle of rotation. */ |
| static float angle = 0.0f; |
| |
| /* |
| * EXERCISE: |
| * Replace this awful mess with vertex |
| * arrays and a call to glDrawElements. |
| * |
| * EXERCISE: |
| * After completing the above, change |
| * it to use compiled vertex arrays. |
| * |
| * EXERCISE: |
| * Verify my windings are correct here ;). |
| */ |
| static GLfloat v0[] = { -1.0f, -1.0f, 1.0f }; |
| static GLfloat v1[] = { 1.0f, -1.0f, 1.0f }; |
| static GLfloat v2[] = { 1.0f, 1.0f, 1.0f }; |
| static GLfloat v3[] = { -1.0f, 1.0f, 1.0f }; |
| static GLfloat v4[] = { -1.0f, -1.0f, -1.0f }; |
| static GLfloat v5[] = { 1.0f, -1.0f, -1.0f }; |
| static GLfloat v6[] = { 1.0f, 1.0f, -1.0f }; |
| static GLfloat v7[] = { -1.0f, 1.0f, -1.0f }; |
| static GLubyte red[] = { 255, 0, 0, 255 }; |
| static GLubyte green[] = { 0, 255, 0, 255 }; |
| static GLubyte blue[] = { 0, 0, 255, 255 }; |
| static GLubyte white[] = { 255, 255, 255, 255 }; |
| static GLubyte yellow[] = { 0, 255, 255, 255 }; |
| static GLubyte black[] = { 0, 0, 0, 255 }; |
| static GLubyte orange[] = { 255, 255, 0, 255 }; |
| static GLubyte purple[] = { 255, 0, 255, 0 }; |
| |
| /* Clear the color and depth buffers. */ |
| glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); |
| |
| /* We don't want to modify the projection matrix. */ |
| glMatrixMode( GL_MODELVIEW ); |
| glLoadIdentity( ); |
| |
| /* Move down the z-axis. */ |
| glTranslatef( 0.0, 0.0, -5.0 ); |
| |
| /* Rotate. */ |
| glRotatef( angle, 0.0, 1.0, 0.0 ); |
| |
| if( should_rotate ) { |
| |
| if( ++angle > 360.0f ) { |
| angle = 0.0f; |
| } |
| |
| } |
| |
| /* Send our triangle data to the pipeline. */ |
| glBegin( GL_TRIANGLES ); |
| |
| glColor4ubv( red ); |
| glVertex3fv( v0 ); |
| glColor4ubv( green ); |
| glVertex3fv( v1 ); |
| glColor4ubv( blue ); |
| glVertex3fv( v2 ); |
| |
| glColor4ubv( red ); |
| glVertex3fv( v0 ); |
| glColor4ubv( blue ); |
| glVertex3fv( v2 ); |
| glColor4ubv( white ); |
| glVertex3fv( v3 ); |
| |
| glColor4ubv( green ); |
| glVertex3fv( v1 ); |
| glColor4ubv( black ); |
| glVertex3fv( v5 ); |
| glColor4ubv( orange ); |
| glVertex3fv( v6 ); |
| |
| glColor4ubv( green ); |
| glVertex3fv( v1 ); |
| glColor4ubv( orange ); |
| glVertex3fv( v6 ); |
| glColor4ubv( blue ); |
| glVertex3fv( v2 ); |
| |
| glColor4ubv( black ); |
| glVertex3fv( v5 ); |
| glColor4ubv( yellow ); |
| glVertex3fv( v4 ); |
| glColor4ubv( purple ); |
| glVertex3fv( v7 ); |
| |
| glColor4ubv( black ); |
| glVertex3fv( v5 ); |
| glColor4ubv( purple ); |
| glVertex3fv( v7 ); |
| glColor4ubv( orange ); |
| glVertex3fv( v6 ); |
| |
| glColor4ubv( yellow ); |
| glVertex3fv( v4 ); |
| glColor4ubv( red ); |
| glVertex3fv( v0 ); |
| glColor4ubv( white ); |
| glVertex3fv( v3 ); |
| |
| glColor4ubv( yellow ); |
| glVertex3fv( v4 ); |
| glColor4ubv( white ); |
| glVertex3fv( v3 ); |
| glColor4ubv( purple ); |
| glVertex3fv( v7 ); |
| |
| glColor4ubv( white ); |
| glVertex3fv( v3 ); |
| glColor4ubv( blue ); |
| glVertex3fv( v2 ); |
| glColor4ubv( orange ); |
| glVertex3fv( v6 ); |
| |
| glColor4ubv( white ); |
| glVertex3fv( v3 ); |
| glColor4ubv( orange ); |
| glVertex3fv( v6 ); |
| glColor4ubv( purple ); |
| glVertex3fv( v7 ); |
| |
| glColor4ubv( green ); |
| glVertex3fv( v1 ); |
| glColor4ubv( red ); |
| glVertex3fv( v0 ); |
| glColor4ubv( yellow ); |
| glVertex3fv( v4 ); |
| |
| glColor4ubv( green ); |
| glVertex3fv( v1 ); |
| glColor4ubv( yellow ); |
| glVertex3fv( v4 ); |
| glColor4ubv( black ); |
| glVertex3fv( v5 ); |
| |
| glEnd( ); |
| |
| /* |
| * EXERCISE: |
| * Draw text telling the user that 'Spc' |
| * pauses the rotation and 'Esc' quits. |
| * Do it using vetors and textured quads. |
| */ |
| |
| /* |
| * Swap the buffers. This this tells the driver to |
| * render the next frame from the contents of the |
| * back-buffer, and to set all rendering operations |
| * to occur on what was the front-buffer. |
| * |
| * Double buffering prevents nasty visual tearing |
| * from the application drawing on areas of the |
| * screen that are being updated at the same time. |
| */ |
| SDL_GL_SwapBuffers( ); |
| } |
| |
| static void setup_opengl( int width, int height ) |
| { |
| float ratio = (float) width / (float) height; |
| |
| /* Our shading model--Gouraud (smooth). */ |
| glShadeModel( GL_SMOOTH ); |
| |
| /* Culling. */ |
| glCullFace( GL_BACK ); |
| glFrontFace( GL_CCW ); |
| glEnable( GL_CULL_FACE ); |
| |
| /* Set the clear color. */ |
| glClearColor( 0, 0, 0, 0 ); |
| |
| /* Setup our viewport. */ |
| glViewport( 0, 0, width, height ); |
| |
| /* |
| * Change to the projection matrix and set |
| * our viewing volume. |
| */ |
| glMatrixMode( GL_PROJECTION ); |
| glLoadIdentity( ); |
| /* |
| * EXERCISE: |
| * Replace this with a call to glFrustum. |
| */ |
| gluPerspective( 60.0, ratio, 1.0, 1024.0 ); |
| } |
| |
| int main( int argc, char* argv[] ) |
| { |
| /* Information about the current video settings. */ |
| const SDL_VideoInfo* info = NULL; |
| /* Dimensions of our window. */ |
| int width = 0; |
| int height = 0; |
| /* Color depth in bits of our window. */ |
| int bpp = 0; |
| /* Flags we will pass into SDL_SetVideoMode. */ |
| int flags = 0; |
| |
| /* First, initialize SDL's video subsystem. */ |
| if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) { |
| /* Failed, exit. */ |
| fprintf( stderr, "Video initialization failed: %s\n", |
| SDL_GetError( ) ); |
| quit_tutorial( 1 ); |
| } |
| |
| /* Let's get some video information. */ |
| info = SDL_GetVideoInfo( ); |
| |
| if( !info ) { |
| /* This should probably never happen. */ |
| fprintf( stderr, "Video query failed: %s\n", |
| SDL_GetError( ) ); |
| quit_tutorial( 1 ); |
| } |
| |
| /* |
| * Set our width/height to 640/480 (you would |
| * of course let the user decide this in a normal |
| * app). We get the bpp we will request from |
| * the display. On X11, VidMode can't change |
| * resolution, so this is probably being overly |
| * safe. Under Win32, ChangeDisplaySettings |
| * can change the bpp. |
| */ |
| width = 640; |
| height = 480; |
| bpp = info->vfmt->BitsPerPixel; |
| |
| /* |
| * Now, we want to setup our requested |
| * window attributes for our OpenGL window. |
| * We want *at least* 5 bits of red, green |
| * and blue. We also want at least a 16-bit |
| * depth buffer. |
| * |
| * The last thing we do is request a double |
| * buffered window. '1' turns on double |
| * buffering, '0' turns it off. |
| * |
| * Note that we do not use SDL_DOUBLEBUF in |
| * the flags to SDL_SetVideoMode. That does |
| * not affect the GL attribute state, only |
| * the standard 2D blitting setup. |
| */ |
| SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 ); |
| SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 ); |
| SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 ); |
| SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 ); |
| SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); |
| |
| /* |
| * We want to request that SDL provide us |
| * with an OpenGL window, in a fullscreen |
| * video mode. |
| * |
| * EXERCISE: |
| * Make starting windowed an option, and |
| * handle the resize events properly with |
| * glViewport. |
| */ |
| flags = SDL_OPENGL | SDL_FULLSCREEN; |
| |
| /* |
| * Set the video mode |
| */ |
| if( SDL_SetVideoMode( width, height, bpp, flags ) == 0 ) { |
| /* |
| * This could happen for a variety of reasons, |
| * including DISPLAY not being set, the specified |
| * resolution not being available, etc. |
| */ |
| fprintf( stderr, "Video mode set failed: %s\n", |
| SDL_GetError( ) ); |
| quit_tutorial( 1 ); |
| } |
| |
| /* |
| * At this point, we should have a properly setup |
| * double-buffered window for use with OpenGL. |
| */ |
| setup_opengl( width, height ); |
| |
| /* |
| * Now we want to begin our normal app process-- |
| * an event loop with a lot of redrawing. |
| */ |
| while( 1 ) { |
| /* Process incoming events. */ |
| process_events( ); |
| /* Draw the screen. */ |
| draw_screen( ); |
| } |
| |
| /* |
| * EXERCISE: |
| * Record timings using SDL_GetTicks() and |
| * and print out frames per second at program |
| * end. |
| */ |
| |
| /* Never reached. */ |
| return 0; |
| }</PRE |
| ></DIV |
| ></DIV |
| ></DIV |
| ><DIV |
| CLASS="NAVFOOTER" |
| ><HR |
| ALIGN="LEFT" |
| WIDTH="100%"><TABLE |
| SUMMARY="Footer navigation table" |
| WIDTH="100%" |
| BORDER="0" |
| CELLPADDING="0" |
| CELLSPACING="0" |
| ><TR |
| ><TD |
| WIDTH="33%" |
| ALIGN="left" |
| VALIGN="top" |
| ><A |
| HREF="guidevideo.html" |
| ACCESSKEY="P" |
| >Prev</A |
| ></TD |
| ><TD |
| WIDTH="34%" |
| ALIGN="center" |
| VALIGN="top" |
| ><A |
| HREF="index.html" |
| ACCESSKEY="H" |
| >Home</A |
| ></TD |
| ><TD |
| WIDTH="33%" |
| ALIGN="right" |
| VALIGN="top" |
| ><A |
| HREF="guideinput.html" |
| ACCESSKEY="N" |
| >Next</A |
| ></TD |
| ></TR |
| ><TR |
| ><TD |
| WIDTH="33%" |
| ALIGN="left" |
| VALIGN="top" |
| >Graphics and Video</TD |
| ><TD |
| WIDTH="34%" |
| ALIGN="center" |
| VALIGN="top" |
| ><A |
| HREF="guidevideo.html" |
| ACCESSKEY="U" |
| >Up</A |
| ></TD |
| ><TD |
| WIDTH="33%" |
| ALIGN="right" |
| VALIGN="top" |
| >Input handling</TD |
| ></TR |
| ></TABLE |
| ></DIV |
| ></BODY |
| ></HTML |
| > |