Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Blame | Last modification | View Log | RSS feed

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