1 <HTML 2 ><HEAD 3 ><TITLE 4 >Using OpenGL With SDL</TITLE 5 ><META 6 NAME="GENERATOR" 7 CONTENT="Modular DocBook HTML Stylesheet Version 1.76b+ 8 "><LINK 9 REL="HOME" 10 TITLE="SDL Library Documentation" 11 HREF="index.html"><LINK 12 REL="UP" 13 TITLE="Graphics and Video" 14 HREF="guidevideo.html"><LINK 15 REL="PREVIOUS" 16 TITLE="Graphics and Video" 17 HREF="guidevideo.html"><LINK 18 REL="NEXT" 19 TITLE="Input handling" 20 HREF="guideinput.html"></HEAD 21 ><BODY 22 CLASS="SECT1" 23 BGCOLOR="#FFF8DC" 24 TEXT="#000000" 25 LINK="#0000ee" 26 VLINK="#551a8b" 27 ALINK="#ff0000" 28 ><DIV 29 CLASS="NAVHEADER" 30 ><TABLE 31 SUMMARY="Header navigation table" 32 WIDTH="100%" 33 BORDER="0" 34 CELLPADDING="0" 35 CELLSPACING="0" 36 ><TR 37 ><TH 38 COLSPAN="3" 39 ALIGN="center" 40 >SDL Library Documentation</TH 41 ></TR 42 ><TR 43 ><TD 44 WIDTH="10%" 45 ALIGN="left" 46 VALIGN="bottom" 47 ><A 48 HREF="guidevideo.html" 49 ACCESSKEY="P" 50 >Prev</A 51 ></TD 52 ><TD 53 WIDTH="80%" 54 ALIGN="center" 55 VALIGN="bottom" 56 >Chapter 2. Graphics and Video</TD 57 ><TD 58 WIDTH="10%" 59 ALIGN="right" 60 VALIGN="bottom" 61 ><A 62 HREF="guideinput.html" 63 ACCESSKEY="N" 64 >Next</A 65 ></TD 66 ></TR 67 ></TABLE 68 ><HR 69 ALIGN="LEFT" 70 WIDTH="100%"></DIV 71 ><DIV 72 CLASS="SECT1" 73 ><H1 74 CLASS="SECT1" 75 ><A 76 NAME="GUIDEVIDEOOPENGL" 77 ></A 78 >Using OpenGL With SDL</H1 79 ><P 80 >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 81 ><DIV 82 CLASS="SECT2" 83 ><H2 84 CLASS="SECT2" 85 ><A 86 NAME="AEN103" 87 ></A 88 >Initialisation</H2 89 ><P 90 >Initialising SDL to use OpenGL is not very different to initialising SDL normally. There are three differences; you must pass <TT 91 CLASS="LITERAL" 92 >SDL_OPENGL</TT 93 > to <A 94 HREF="sdlsetvideomode.html" 95 ><TT 96 CLASS="FUNCTION" 97 >SDL_SetVideoMode</TT 98 ></A 99 >, you must specify several GL attributes (depth buffer size, framebuffer sizes) using <A 100 HREF="sdlglsetattribute.html" 101 ><TT 102 CLASS="FUNCTION" 103 >SDL_GL_SetAttribute</TT 104 ></A 105 > and finally, if you wish to use double buffering you must specify it as a GL attribute, <SPAN 106 CLASS="emphasis" 107 ><I 108 CLASS="EMPHASIS" 109 >not</I 110 ></SPAN 111 > by passing the <TT 112 CLASS="LITERAL" 113 >SDL_DOUBLEBUF</TT 114 > flag to <TT 115 CLASS="FUNCTION" 116 >SDL_SetVideoMode</TT 117 >.</P 118 ><DIV 119 CLASS="EXAMPLE" 120 ><A 121 NAME="AEN114" 122 ></A 123 ><P 124 ><B 125 >Example 2-7. Initializing SDL with OpenGL</B 126 ></P 127 ><PRE 128 CLASS="PROGRAMLISTING" 129 > /* Information about the current video settings. */ 130 const SDL_VideoInfo* info = NULL; 131 /* Dimensions of our window. */ 132 int width = 0; 133 int height = 0; 134 /* Color depth in bits of our window. */ 135 int bpp = 0; 136 /* Flags we will pass into SDL_SetVideoMode. */ 137 int flags = 0; 138 139 /* First, initialize SDL's video subsystem. */ 140 if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) { 141 /* Failed, exit. */ 142 fprintf( stderr, "Video initialization failed: %s\n", 143 SDL_GetError( ) ); 144 quit_tutorial( 1 ); 145 } 146 147 /* Let's get some video information. */ 148 info = SDL_GetVideoInfo( ); 149 150 if( !info ) { 151 /* This should probably never happen. */ 152 fprintf( stderr, "Video query failed: %s\n", 153 SDL_GetError( ) ); 154 quit_tutorial( 1 ); 155 } 156 157 /* 158 * Set our width/height to 640/480 (you would 159 * of course let the user decide this in a normal 160 * app). We get the bpp we will request from 161 * the display. On X11, VidMode can't change 162 * resolution, so this is probably being overly 163 * safe. Under Win32, ChangeDisplaySettings 164 * can change the bpp. 165 */ 166 width = 640; 167 height = 480; 168 bpp = info->vfmt->BitsPerPixel; 169 170 /* 171 * Now, we want to setup our requested 172 * window attributes for our OpenGL window. 173 * We want *at least* 5 bits of red, green 174 * and blue. We also want at least a 16-bit 175 * depth buffer. 176 * 177 * The last thing we do is request a double 178 * buffered window. '1' turns on double 179 * buffering, '0' turns it off. 180 * 181 * Note that we do not use SDL_DOUBLEBUF in 182 * the flags to SDL_SetVideoMode. That does 183 * not affect the GL attribute state, only 184 * the standard 2D blitting setup. 185 */ 186 SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 ); 187 SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 ); 188 SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 ); 189 SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 ); 190 SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); 191 192 /* 193 * We want to request that SDL provide us 194 * with an OpenGL window, in a fullscreen 195 * video mode. 196 * 197 * EXERCISE: 198 * Make starting windowed an option, and 199 * handle the resize events properly with 200 * glViewport. 201 */ 202 flags = SDL_OPENGL | SDL_FULLSCREEN; 203 204 /* 205 * Set the video mode 206 */ 207 if( SDL_SetVideoMode( width, height, bpp, flags ) == 0 ) { 208 /* 209 * This could happen for a variety of reasons, 210 * including DISPLAY not being set, the specified 211 * resolution not being available, etc. 212 */ 213 fprintf( stderr, "Video mode set failed: %s\n", 214 SDL_GetError( ) ); 215 quit_tutorial( 1 ); 216 }</PRE 217 ></DIV 218 ></DIV 219 ><DIV 220 CLASS="SECT2" 221 ><H2 222 CLASS="SECT2" 223 ><A 224 NAME="AEN117" 225 ></A 226 >Drawing</H2 227 ><P 228 >Apart from initialisation, using OpenGL within SDL is the same as using OpenGL 229 with any other API, e.g. GLUT. You still use all the same function calls and 230 data types. However if you are using a double-buffered display, then you must 231 use 232 <A 233 HREF="sdlglswapbuffers.html" 234 ><TT 235 CLASS="FUNCTION" 236 >SDL_GL_SwapBuffers()</TT 237 ></A 238 > 239 to swap the buffers and update the display. To request double-buffering 240 with OpenGL, use 241 <A 242 HREF="sdlglsetattribute.html" 243 ><TT 244 CLASS="FUNCTION" 245 >SDL_GL_SetAttribute</TT 246 ></A 247 > 248 with <TT 249 CLASS="LITERAL" 250 >SDL_GL_DOUBLEBUFFER</TT 251 >, and use 252 <A 253 HREF="sdlglgetattribute.html" 254 ><TT 255 CLASS="FUNCTION" 256 >SDL_GL_GetAttribute</TT 257 ></A 258 > 259 to see if you actually got it.</P 260 ><P 261 >A full example code listing is now presented below.</P 262 ><DIV 263 CLASS="EXAMPLE" 264 ><A 265 NAME="AEN128" 266 ></A 267 ><P 268 ><B 269 >Example 2-8. SDL and OpenGL</B 270 ></P 271 ><PRE 272 CLASS="PROGRAMLISTING" 273 >/* 274 * SDL OpenGL Tutorial. 275 * (c) Michael Vance, 2000 276 * briareos (a] lokigames.com 277 * 278 * Distributed under terms of the LGPL. 279 */ 280 281 #include <SDL/SDL.h> 282 #include <GL/gl.h> 283 #include <GL/glu.h> 284 285 #include <stdio.h> 286 #include <stdlib.h> 287 288 static GLboolean should_rotate = GL_TRUE; 289 290 static void quit_tutorial( int code ) 291 { 292 /* 293 * Quit SDL so we can release the fullscreen 294 * mode and restore the previous video settings, 295 * etc. 296 */ 297 SDL_Quit( ); 298 299 /* Exit program. */ 300 exit( code ); 301 } 302 303 static void handle_key_down( SDL_keysym* keysym ) 304 { 305 306 /* 307 * We're only interested if 'Esc' has 308 * been presssed. 309 * 310 * EXERCISE: 311 * Handle the arrow keys and have that change the 312 * viewing position/angle. 313 */ 314 switch( keysym->sym ) { 315 case SDLK_ESCAPE: 316 quit_tutorial( 0 ); 317 break; 318 case SDLK_SPACE: 319 should_rotate = !should_rotate; 320 break; 321 default: 322 break; 323 } 324 325 } 326 327 static void process_events( void ) 328 { 329 /* Our SDL event placeholder. */ 330 SDL_Event event; 331 332 /* Grab all the events off the queue. */ 333 while( SDL_PollEvent( &event ) ) { 334 335 switch( event.type ) { 336 case SDL_KEYDOWN: 337 /* Handle key presses. */ 338 handle_key_down( &event.key.keysym ); 339 break; 340 case SDL_QUIT: 341 /* Handle quit requests (like Ctrl-c). */ 342 quit_tutorial( 0 ); 343 break; 344 } 345 346 } 347 348 } 349 350 static void draw_screen( void ) 351 { 352 /* Our angle of rotation. */ 353 static float angle = 0.0f; 354 355 /* 356 * EXERCISE: 357 * Replace this awful mess with vertex 358 * arrays and a call to glDrawElements. 359 * 360 * EXERCISE: 361 * After completing the above, change 362 * it to use compiled vertex arrays. 363 * 364 * EXERCISE: 365 * Verify my windings are correct here ;). 366 */ 367 static GLfloat v0[] = { -1.0f, -1.0f, 1.0f }; 368 static GLfloat v1[] = { 1.0f, -1.0f, 1.0f }; 369 static GLfloat v2[] = { 1.0f, 1.0f, 1.0f }; 370 static GLfloat v3[] = { -1.0f, 1.0f, 1.0f }; 371 static GLfloat v4[] = { -1.0f, -1.0f, -1.0f }; 372 static GLfloat v5[] = { 1.0f, -1.0f, -1.0f }; 373 static GLfloat v6[] = { 1.0f, 1.0f, -1.0f }; 374 static GLfloat v7[] = { -1.0f, 1.0f, -1.0f }; 375 static GLubyte red[] = { 255, 0, 0, 255 }; 376 static GLubyte green[] = { 0, 255, 0, 255 }; 377 static GLubyte blue[] = { 0, 0, 255, 255 }; 378 static GLubyte white[] = { 255, 255, 255, 255 }; 379 static GLubyte yellow[] = { 0, 255, 255, 255 }; 380 static GLubyte black[] = { 0, 0, 0, 255 }; 381 static GLubyte orange[] = { 255, 255, 0, 255 }; 382 static GLubyte purple[] = { 255, 0, 255, 0 }; 383 384 /* Clear the color and depth buffers. */ 385 glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); 386 387 /* We don't want to modify the projection matrix. */ 388 glMatrixMode( GL_MODELVIEW ); 389 glLoadIdentity( ); 390 391 /* Move down the z-axis. */ 392 glTranslatef( 0.0, 0.0, -5.0 ); 393 394 /* Rotate. */ 395 glRotatef( angle, 0.0, 1.0, 0.0 ); 396 397 if( should_rotate ) { 398 399 if( ++angle > 360.0f ) { 400 angle = 0.0f; 401 } 402 403 } 404 405 /* Send our triangle data to the pipeline. */ 406 glBegin( GL_TRIANGLES ); 407 408 glColor4ubv( red ); 409 glVertex3fv( v0 ); 410 glColor4ubv( green ); 411 glVertex3fv( v1 ); 412 glColor4ubv( blue ); 413 glVertex3fv( v2 ); 414 415 glColor4ubv( red ); 416 glVertex3fv( v0 ); 417 glColor4ubv( blue ); 418 glVertex3fv( v2 ); 419 glColor4ubv( white ); 420 glVertex3fv( v3 ); 421 422 glColor4ubv( green ); 423 glVertex3fv( v1 ); 424 glColor4ubv( black ); 425 glVertex3fv( v5 ); 426 glColor4ubv( orange ); 427 glVertex3fv( v6 ); 428 429 glColor4ubv( green ); 430 glVertex3fv( v1 ); 431 glColor4ubv( orange ); 432 glVertex3fv( v6 ); 433 glColor4ubv( blue ); 434 glVertex3fv( v2 ); 435 436 glColor4ubv( black ); 437 glVertex3fv( v5 ); 438 glColor4ubv( yellow ); 439 glVertex3fv( v4 ); 440 glColor4ubv( purple ); 441 glVertex3fv( v7 ); 442 443 glColor4ubv( black ); 444 glVertex3fv( v5 ); 445 glColor4ubv( purple ); 446 glVertex3fv( v7 ); 447 glColor4ubv( orange ); 448 glVertex3fv( v6 ); 449 450 glColor4ubv( yellow ); 451 glVertex3fv( v4 ); 452 glColor4ubv( red ); 453 glVertex3fv( v0 ); 454 glColor4ubv( white ); 455 glVertex3fv( v3 ); 456 457 glColor4ubv( yellow ); 458 glVertex3fv( v4 ); 459 glColor4ubv( white ); 460 glVertex3fv( v3 ); 461 glColor4ubv( purple ); 462 glVertex3fv( v7 ); 463 464 glColor4ubv( white ); 465 glVertex3fv( v3 ); 466 glColor4ubv( blue ); 467 glVertex3fv( v2 ); 468 glColor4ubv( orange ); 469 glVertex3fv( v6 ); 470 471 glColor4ubv( white ); 472 glVertex3fv( v3 ); 473 glColor4ubv( orange ); 474 glVertex3fv( v6 ); 475 glColor4ubv( purple ); 476 glVertex3fv( v7 ); 477 478 glColor4ubv( green ); 479 glVertex3fv( v1 ); 480 glColor4ubv( red ); 481 glVertex3fv( v0 ); 482 glColor4ubv( yellow ); 483 glVertex3fv( v4 ); 484 485 glColor4ubv( green ); 486 glVertex3fv( v1 ); 487 glColor4ubv( yellow ); 488 glVertex3fv( v4 ); 489 glColor4ubv( black ); 490 glVertex3fv( v5 ); 491 492 glEnd( ); 493 494 /* 495 * EXERCISE: 496 * Draw text telling the user that 'Spc' 497 * pauses the rotation and 'Esc' quits. 498 * Do it using vetors and textured quads. 499 */ 500 501 /* 502 * Swap the buffers. This this tells the driver to 503 * render the next frame from the contents of the 504 * back-buffer, and to set all rendering operations 505 * to occur on what was the front-buffer. 506 * 507 * Double buffering prevents nasty visual tearing 508 * from the application drawing on areas of the 509 * screen that are being updated at the same time. 510 */ 511 SDL_GL_SwapBuffers( ); 512 } 513 514 static void setup_opengl( int width, int height ) 515 { 516 float ratio = (float) width / (float) height; 517 518 /* Our shading model--Gouraud (smooth). */ 519 glShadeModel( GL_SMOOTH ); 520 521 /* Culling. */ 522 glCullFace( GL_BACK ); 523 glFrontFace( GL_CCW ); 524 glEnable( GL_CULL_FACE ); 525 526 /* Set the clear color. */ 527 glClearColor( 0, 0, 0, 0 ); 528 529 /* Setup our viewport. */ 530 glViewport( 0, 0, width, height ); 531 532 /* 533 * Change to the projection matrix and set 534 * our viewing volume. 535 */ 536 glMatrixMode( GL_PROJECTION ); 537 glLoadIdentity( ); 538 /* 539 * EXERCISE: 540 * Replace this with a call to glFrustum. 541 */ 542 gluPerspective( 60.0, ratio, 1.0, 1024.0 ); 543 } 544 545 int main( int argc, char* argv[] ) 546 { 547 /* Information about the current video settings. */ 548 const SDL_VideoInfo* info = NULL; 549 /* Dimensions of our window. */ 550 int width = 0; 551 int height = 0; 552 /* Color depth in bits of our window. */ 553 int bpp = 0; 554 /* Flags we will pass into SDL_SetVideoMode. */ 555 int flags = 0; 556 557 /* First, initialize SDL's video subsystem. */ 558 if( SDL_Init( SDL_INIT_VIDEO ) < 0 ) { 559 /* Failed, exit. */ 560 fprintf( stderr, "Video initialization failed: %s\n", 561 SDL_GetError( ) ); 562 quit_tutorial( 1 ); 563 } 564 565 /* Let's get some video information. */ 566 info = SDL_GetVideoInfo( ); 567 568 if( !info ) { 569 /* This should probably never happen. */ 570 fprintf( stderr, "Video query failed: %s\n", 571 SDL_GetError( ) ); 572 quit_tutorial( 1 ); 573 } 574 575 /* 576 * Set our width/height to 640/480 (you would 577 * of course let the user decide this in a normal 578 * app). We get the bpp we will request from 579 * the display. On X11, VidMode can't change 580 * resolution, so this is probably being overly 581 * safe. Under Win32, ChangeDisplaySettings 582 * can change the bpp. 583 */ 584 width = 640; 585 height = 480; 586 bpp = info->vfmt->BitsPerPixel; 587 588 /* 589 * Now, we want to setup our requested 590 * window attributes for our OpenGL window. 591 * We want *at least* 5 bits of red, green 592 * and blue. We also want at least a 16-bit 593 * depth buffer. 594 * 595 * The last thing we do is request a double 596 * buffered window. '1' turns on double 597 * buffering, '0' turns it off. 598 * 599 * Note that we do not use SDL_DOUBLEBUF in 600 * the flags to SDL_SetVideoMode. That does 601 * not affect the GL attribute state, only 602 * the standard 2D blitting setup. 603 */ 604 SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 5 ); 605 SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 5 ); 606 SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 5 ); 607 SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16 ); 608 SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); 609 610 /* 611 * We want to request that SDL provide us 612 * with an OpenGL window, in a fullscreen 613 * video mode. 614 * 615 * EXERCISE: 616 * Make starting windowed an option, and 617 * handle the resize events properly with 618 * glViewport. 619 */ 620 flags = SDL_OPENGL | SDL_FULLSCREEN; 621 622 /* 623 * Set the video mode 624 */ 625 if( SDL_SetVideoMode( width, height, bpp, flags ) == 0 ) { 626 /* 627 * This could happen for a variety of reasons, 628 * including DISPLAY not being set, the specified 629 * resolution not being available, etc. 630 */ 631 fprintf( stderr, "Video mode set failed: %s\n", 632 SDL_GetError( ) ); 633 quit_tutorial( 1 ); 634 } 635 636 /* 637 * At this point, we should have a properly setup 638 * double-buffered window for use with OpenGL. 639 */ 640 setup_opengl( width, height ); 641 642 /* 643 * Now we want to begin our normal app process-- 644 * an event loop with a lot of redrawing. 645 */ 646 while( 1 ) { 647 /* Process incoming events. */ 648 process_events( ); 649 /* Draw the screen. */ 650 draw_screen( ); 651 } 652 653 /* 654 * EXERCISE: 655 * Record timings using SDL_GetTicks() and 656 * and print out frames per second at program 657 * end. 658 */ 659 660 /* Never reached. */ 661 return 0; 662 }</PRE 663 ></DIV 664 ></DIV 665 ></DIV 666 ><DIV 667 CLASS="NAVFOOTER" 668 ><HR 669 ALIGN="LEFT" 670 WIDTH="100%"><TABLE 671 SUMMARY="Footer navigation table" 672 WIDTH="100%" 673 BORDER="0" 674 CELLPADDING="0" 675 CELLSPACING="0" 676 ><TR 677 ><TD 678 WIDTH="33%" 679 ALIGN="left" 680 VALIGN="top" 681 ><A 682 HREF="guidevideo.html" 683 ACCESSKEY="P" 684 >Prev</A 685 ></TD 686 ><TD 687 WIDTH="34%" 688 ALIGN="center" 689 VALIGN="top" 690 ><A 691 HREF="index.html" 692 ACCESSKEY="H" 693 >Home</A 694 ></TD 695 ><TD 696 WIDTH="33%" 697 ALIGN="right" 698 VALIGN="top" 699 ><A 700 HREF="guideinput.html" 701 ACCESSKEY="N" 702 >Next</A 703 ></TD 704 ></TR 705 ><TR 706 ><TD 707 WIDTH="33%" 708 ALIGN="left" 709 VALIGN="top" 710 >Graphics and Video</TD 711 ><TD 712 WIDTH="34%" 713 ALIGN="center" 714 VALIGN="top" 715 ><A 716 HREF="guidevideo.html" 717 ACCESSKEY="U" 718 >Up</A 719 ></TD 720 ><TD 721 WIDTH="33%" 722 ALIGN="right" 723 VALIGN="top" 724 >Input handling</TD 725 ></TR 726 ></TABLE 727 ></DIV 728 ></BODY 729 ></HTML 730 >