Want more features on Pastebin? Sign Up, it's FREE!
Guest

3rd Person Shooter Programming Tutorial (OpenGL)

By: a guest on Jan 16th, 2012  |  syntax: C  |  size: 30.04 KB  |  views: 55  |  expires: Never
download  |  raw  |  embed  |  report abuse  |  print
Text below is selected. Please press Ctrl+C to copy to your clipboard. (⌘+C on Mac)
  1. //-----------------------------------------------------------------------------
  2. // Shogun3D's OpenGL Utility Toolkit framework.
  3. //
  4. // Disclamer:  Use this code as you see fit, for both personal and/or commercial
  5. //                         usages.  You don't exactly have to give me credit for using this
  6. //                         code in your own projects (although I would appreciate it if you
  7. //                         did), but you could at let me know that this has benefited you
  8. //                         in one way or another, because I didn't write this code just for
  9. //                         myself you know ^^
  10. //
  11. // File:        main.c
  12. // Desc:        This code will hopefully show you how easy it is to create a 3rd
  13. //                      person game :)
  14. // Date:        August 20, 2010
  15. //-----------------------------------------------------------------------------
  16.  
  17. // Include files
  18.  
  19. #ifdef WIN32 // For windows builds
  20. #include <windows.h>
  21. #endif
  22.  
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <math.h>
  26.  
  27. #include <gl\glut.h>
  28. #include <gl\glext.h>
  29.  
  30.  
  31. //-----------------------------------------------------------------------------
  32. // 3D vector
  33. //-----------------------------------------------------------------------------
  34. struct Vector3
  35. {
  36.         float x, y, z;
  37. };
  38.  
  39. //-----------------------------------------------------------------------------
  40. // Third Person Camera structure
  41. //-----------------------------------------------------------------------------
  42. struct ThirdPersonCamera_t
  43. {
  44.         struct Vector3 vecPos;
  45.         struct Vector3 vecRot;
  46.         float fRadius;                  // Distance between the camera and the object.
  47.         float fLastX;
  48.         float fLastY;
  49. };
  50.  
  51. //-----------------------------------------------------------------------------
  52. // Sphere structure
  53. //-----------------------------------------------------------------------------
  54. struct Sphere_t
  55. {
  56.         struct Vector3 position;        // Position in 3D space
  57.         int selected;                           // Did OpenGL select this one?
  58.         int dead;                                       // Is this sphere dead?
  59.         unsigned int death_time;        // How long has this sphere been dead?
  60.                                                                 // Respawn after X milliseconds
  61.         float distance;                         // Distance between you and the sphere.
  62.         float size;                                     // The size of the sphere. Decreases during
  63.                                                                 // death phase.
  64. };
  65.  
  66. //-----------------------------------------------------------------------------
  67. // Global variables
  68. //-----------------------------------------------------------------------------
  69. #define sphere_count 20                 // Number of spheres in the game
  70. #define respawn_time 5000               // After a sphere is shot dead, respawn after this
  71.                                                                 // amount of time.
  72.  
  73. struct  ThirdPersonCamera_t             camera;
  74. struct  Sphere_t                                spheres[sphere_count];
  75. GLuint                                                  floor_tex = 0;
  76. GLuint                                                  select_buffer[sphere_count*4] = {0};
  77. GLint                                                   hits = 0;
  78. float                                                   jump_height = 0.0f;
  79. GLboolean                                               sniper_mode = GL_FALSE;
  80. GLint                                                   kills = 0;
  81.  
  82.  
  83.  
  84.  
  85. //-----------------------------------------------------------------------------
  86. // Name: glEnable2D
  87. // Desc: Enabled 2D primitive rendering by setting up the appropriate orthographic
  88. //               perspectives and matrices.
  89. //-----------------------------------------------------------------------------
  90. void glEnable2D( void )
  91. {
  92.         GLint iViewport[4];
  93.  
  94.         // Get a copy of the viewport
  95.         glGetIntegerv( GL_VIEWPORT, iViewport );
  96.  
  97.         // Save a copy of the projection matrix so that we can restore it
  98.         // when it's time to do 3D rendering again.
  99.         glMatrixMode( GL_PROJECTION );
  100.         glPushMatrix();
  101.         glLoadIdentity();
  102.  
  103.         // Set up the orthographic projection
  104.         glOrtho( iViewport[0], iViewport[0]+iViewport[2],
  105.                          iViewport[1]+iViewport[3], iViewport[1], -1, 1 );
  106.         glMatrixMode( GL_MODELVIEW );
  107.         glPushMatrix();
  108.         glLoadIdentity();
  109.  
  110.         // Make sure depth testing and lighting are disabled for 2D rendering until
  111.         // we are finished rendering in 2D
  112.         glPushAttrib( GL_DEPTH_BUFFER_BIT | GL_LIGHTING_BIT );
  113.         glDisable( GL_DEPTH_TEST );
  114.         glDisable( GL_LIGHTING );
  115. }
  116.  
  117.  
  118. //-----------------------------------------------------------------------------
  119. // Name: glDisable2D
  120. // Desc: Disables 2D rendering and restores the previous matrix and render states
  121. //               before they were modified.
  122. //-----------------------------------------------------------------------------
  123. void glDisable2D( void )
  124. {
  125.         glPopAttrib();
  126.         glMatrixMode( GL_PROJECTION );
  127.         glPopMatrix();
  128.         glMatrixMode( GL_MODELVIEW );
  129.         glPopMatrix();
  130. }
  131.  
  132. //-----------------------------------------------------------------------------
  133. // Name: glPrintf
  134. // Desc: Prints a string of chars using GLUT's pre-defined char blitting API.
  135. //-----------------------------------------------------------------------------
  136. void glPrintf( int x, int y, void* font, char* string, ... )
  137. {
  138.         char *c;
  139.         char temp[256];
  140.         va_list ap;
  141.  
  142.         va_start( ap, string );
  143.         vsprintf( temp, string, ap );
  144.         va_end( ap );
  145.  
  146.         glEnable2D();
  147.  
  148.         glRasterPos2i(x,y);
  149.  
  150.         for (c=temp; *c != '\0'; c++)
  151.         {
  152.                 glutBitmapCharacter(font, *c);
  153.         }
  154.  
  155.         glDisable2D();
  156. }
  157.  
  158. //-----------------------------------------------------------------------------
  159. // Name: distance
  160. // Desc: Calculates the distance between two points.
  161. //-----------------------------------------------------------------------------
  162. float distance( const struct Vector3* v1, const struct Vector3* v2 )
  163. {
  164.         float d = 0.0f;
  165.         float x = v2->x - v1->x;
  166.         float y = v2->y - v1->y;
  167.         float z = v2->z - v1->z;
  168.  
  169.         x *= x;
  170.         y *= y;
  171.         z *= z;
  172.  
  173.         d = sqrt(x+y+z);
  174.  
  175.         return d;
  176. }
  177.  
  178.  
  179. //-----------------------------------------------------------------------------
  180. // Name: calculate_distances
  181. // Desc: Calulates the distance between each sphere and the camera.
  182. //-----------------------------------------------------------------------------
  183. void calculate_distances( void )
  184. {
  185.         int i;
  186.         struct Vector3 neg_camera;
  187.  
  188.         // In order to accurately calculate the distance between the spheres and
  189.         // the camera, the x and z values should be converted to negatives, and
  190.         // the y coordinate should be ignored.  The camera updates the y value
  191.         // still, but in a 3rd person shooter/adventure style game, the is calc-
  192.         // lations are done seperately from the camera to compensate for jumping
  193.         // and gravity, etc.
  194.         neg_camera.x = camera.vecPos.x * -1.0f;
  195.         neg_camera.y = 0.0f;
  196.         neg_camera.z = camera.vecPos.z * -1.0f;
  197.  
  198.         for( i = 0; i < sphere_count; i++ )
  199.         {
  200.                 spheres[i].distance = distance( &neg_camera, &spheres[i].position );
  201.         }
  202. }
  203.  
  204.  
  205. //-----------------------------------------------------------------------------
  206. // Name: texture_create
  207. // Desc: Creates a simple black and white checker board style texture.  Change it
  208. //               to whatever you like :)
  209. //-----------------------------------------------------------------------------
  210. void texture_create( void )
  211. {
  212.         GLubyte buffer[64][64][4];
  213.         int s, t;
  214.  
  215.         for( t = 0; t < 64; t++ )
  216.         {
  217.                 for( s = 0; s < 64; s++ )
  218.                 {
  219.                         GLubyte c = ((((t&0x8)==0)^((s&0x8))==0))*255;
  220.                         buffer[s][t][0] = c;
  221.                         buffer[s][t][1] = c;
  222.                         buffer[s][t][2] = c;
  223.                         buffer[s][t][3] = 255;
  224.                 }
  225.         }
  226.  
  227.         // Set the pixel alignment to default
  228.         glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
  229.  
  230.         // Generate 1 texture ID
  231.         glGenTextures( 1, &floor_tex );
  232.  
  233.         // Bind this texture so that we can edit it
  234.         glBindTexture( GL_TEXTURE_2D, floor_tex );
  235.  
  236.         // Create the actual texture with it's dimensions, format and texel data
  237.         glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 64, 64, 0,
  238.                                         GL_RGBA, GL_UNSIGNED_BYTE, buffer );
  239.  
  240.         // Enable bilinear filtering
  241.         glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
  242.         glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
  243. }
  244.  
  245. //-----------------------------------------------------------------------------
  246. // Name: floor_render
  247. // Desc: Renders the floor with the texture created above.
  248. //-----------------------------------------------------------------------------
  249. void floor_render( float size, float y )
  250. {
  251.         // Render the floor at the given height on the Y axis.
  252.         glPushAttrib( GL_ALL_ATTRIB_BITS );
  253.  
  254.         glPushMatrix();
  255.  
  256.         glTranslatef( 0.0f, y, 0.0f );
  257.  
  258.         glDisable( GL_LIGHTING );
  259.         glEnable( GL_TEXTURE_2D );
  260.         glBindTexture( GL_TEXTURE_2D, floor_tex );
  261.  
  262.         glBegin( GL_QUADS );
  263.         glColor3f( 1.0f, 1.0f, 1.0f );
  264.         glTexCoord2f( 0.0f, 0.0f );             glVertex3f( -size, y, -size );
  265.         glTexCoord2f( 0.0f, 1.0f );             glVertex3f( -size, y, +size );
  266.         glTexCoord2f( 1.0f, 1.0f );             glVertex3f( +size, y, +size );
  267.         glTexCoord2f( 1.0f, 0.0f );             glVertex3f( +size, y, -size );
  268.         glEnd();
  269.  
  270.         glPopMatrix();
  271.  
  272.         glPopAttrib();
  273. }
  274.  
  275. //-----------------------------------------------------------------------------
  276. // Name: spheres_init
  277. // Desc: Gives each sphere a random position in 3D space.
  278. //-----------------------------------------------------------------------------
  279. void spheres_init( void )
  280. {
  281.         int i;
  282.  
  283.         // Give each sphere a random position
  284.         for( i = 0; i < sphere_count; i++ )
  285.         {
  286.                 spheres[i].position.x = (float) ( ( rand() % 100 ) + 1 ) - 50;
  287.                 spheres[i].position.y = 0.0f;
  288.                 spheres[i].position.z = (float) ( ( rand() % 100 ) + 1 ) - 50;
  289.                 spheres[i].selected = 0;
  290.                 spheres[i].dead = 0;
  291.                 spheres[i].death_time = 0;
  292.                 spheres[i].distance = 0.0f;
  293.                 spheres[i].size = 2.0f;
  294.         }
  295. }
  296.  
  297. //-----------------------------------------------------------------------------
  298. // Name: spheres_render
  299. // Desc: Renders each sphere in it's random position
  300. //-----------------------------------------------------------------------------
  301. void spheres_render( void )
  302. {
  303.         int i;
  304.  
  305.         // Render each sphere with a solid green colour
  306.         glColor3f( 0.0f, 1.0f, 0.0f );
  307.  
  308.         for( i = 0; i < sphere_count; i++ )
  309.         {
  310.                 // Is this sphere dead?
  311.                 if( spheres[i].dead )
  312.                 {
  313.                         unsigned int current_time;
  314.  
  315.                         // Slowly decrease the size of the sphere when it's dying
  316.                         if( spheres[i].size > 0.0f )
  317.                                 spheres[i].size -= 0.1f;
  318.  
  319.                         // When time expires, bring the sphere back into play (respawn).
  320.                         // The sphere will fall from the sky after the respawn time expires.
  321.                         current_time = GetTickCount();
  322.                         if( (current_time - spheres[i].death_time) > respawn_time )
  323.                         {
  324.                                 spheres[i].position.x = (float) ( ( rand() % 100 ) + 1 ) - 50;
  325.                                 spheres[i].position.y = 50.0f;
  326.                                 spheres[i].position.z = (float) ( ( rand() % 100 ) + 1 ) - 50;
  327.                                 spheres[i].dead = 0;
  328.                                 spheres[i].size = 2.0f;
  329.                         }
  330.                 }
  331.  
  332.                 //if( !spheres[i].dead )
  333.                 if( spheres[i].size != 0.0f )
  334.                 {
  335.                         glPushMatrix();
  336.                         glTranslatef( -spheres[i].position.x, spheres[i].position.y, -spheres[i].position.z );
  337.                         glutSolidSphere( spheres[i].size, 20, 20 );
  338.                        
  339.                         // Render a slightly larger purple transparent sphere around
  340.                         // selected objects.
  341.                         if( spheres[i].selected )
  342.                         {
  343.                                 glPushAttrib( GL_ALL_ATTRIB_BITS );
  344.  
  345.                                 glColor4ub( 128, 0, 255, 64 );
  346.  
  347.                                 glDisable( GL_COLOR_MATERIAL );
  348.                                 glDisable( GL_LIGHTING );
  349.                         //      glDisable( GL_DEPTH_TEST );
  350.                                 glDepthMask( GL_FALSE );
  351.                                 glDisable( GL_TEXTURE_2D );
  352.                                 glEnable( GL_BLEND );
  353.                                 glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
  354.  
  355.                                 glutSolidSphere( spheres[i].size * 1.5f, 20, 20 );
  356.  
  357.                                 glPopAttrib();
  358.                         }
  359.  
  360.                         glPopMatrix();
  361.                 }
  362.  
  363.                 // If the sphere is in the sky, let it fall back down to the ground
  364.                 if( spheres[i].position.y > 0.0f )
  365.                 {
  366.                         spheres[i].position.y -= 0.5f;
  367.                 }
  368.         }
  369. }
  370.  
  371.  
  372. //-----------------------------------------------------------------------------
  373. // Name: draw_axes
  374. // Desc: Draws each axis using a line in the center of 3D space.  Red is X,
  375. //               green is Y, and blue is Z.  This will help us make sure we are not
  376. //               upside down.
  377. //-----------------------------------------------------------------------------
  378. void draw_axes( void )
  379. {
  380.         glPushAttrib( GL_ALL_ATTRIB_BITS );
  381.         glDisable( GL_LIGHTING );
  382.         glEnable( GL_LINE_SMOOTH );
  383.  
  384.         glPushMatrix();
  385.         glTranslatef( 0.0f, 0.0f, 0.0f );
  386.  
  387.         glBegin( GL_LINES );
  388.  
  389.         // X Axis (Red)
  390.         glColor3f( 1.0f, 0.0f, 0.0f );
  391.         glVertex3f( 0.0f, 0.0f, 0.0f );
  392.         glVertex3f( 2.0f, 0.0f, 0.0f );
  393.  
  394.         // Y Axis (Green)
  395.         glColor3f( 0.0f, 1.0f, 0.0f );
  396.         glVertex3f( 0.0f, 0.0f, 0.0f );
  397.         glVertex3f( 0.0f, 2.0f, 0.0f );
  398.  
  399.         // Z Axis (Blue)
  400.         glColor3f( 0.0f, 0.0f, 1.0f );
  401.         glVertex3f( 0.0f, 0.0f, 0.0f );
  402.         glVertex3f( 0.0f, 0.0f, 2.0f );
  403.  
  404.         glEnd();
  405.  
  406.         glPopMatrix();
  407.  
  408.         glPopAttrib();
  409. }
  410.  
  411. //-----------------------------------------------------------------------------
  412. // Name: draw_crosshair
  413. // Desc:
  414. //-----------------------------------------------------------------------------
  415. void draw_crosshair( void )
  416. {
  417.         float fViewport[4];
  418.         float w = 32.0f, h = 32.0f;
  419.  
  420.         // Get the current viewport. We want to make sure the crosshair
  421.         // is in the center of the screen, even if the window is resized.
  422.         glGetFloatv( GL_VIEWPORT, fViewport );
  423.  
  424.         // Enable 2D rendering
  425.         glEnable2D();
  426.  
  427.         glBegin( GL_LINES );
  428.                 glColor3f( 1.0f, 1.0f, 0.0f );
  429.                 glVertex2f( (fViewport[2]/2.0f)-(w/2.0f), fViewport[3]/2.0f );
  430.                 glVertex2f( (fViewport[2]/2.0f)+(w/2.0f), fViewport[3]/2.0f );
  431.                 glVertex2f( fViewport[2]/2.0f, (fViewport[3]/2.0f)-(h/2.0f) );
  432.                 glVertex2f( fViewport[2]/2.0f, (fViewport[3]/2.0f)+(h/2.0f) );
  433.         glEnd();
  434.  
  435.         // Disable 2D rendering
  436.         glDisable2D();
  437. }
  438.  
  439. //-----------------------------------------------------------------------------
  440. // Name: show_camera_stats
  441. // Desc:
  442. //-----------------------------------------------------------------------------
  443. void show_camera_stats( void )
  444. {
  445.         char string[128];
  446.  
  447.         sprintf( string, "Camera <%f,%f,%f>", camera.vecPos.x, camera.vecPos.y, camera.vecPos.z );
  448.         glPrintf( 30, 30, GLUT_BITMAP_9_BY_15, string );
  449. }
  450.  
  451. //-----------------------------------------------------------------------------
  452. // Name: show_stats
  453. // Desc:
  454. //-----------------------------------------------------------------------------
  455. void show_stats( void )
  456. {
  457.         char string[128];
  458.  
  459.         glColor3f( 0.0f, 0.5f, 1.0f );
  460.  
  461.         sprintf( string, "Kills: %d", kills );
  462.         glPrintf( 450, 30, GLUT_BITMAP_9_BY_15, string );
  463.  
  464.         if( sniper_mode )
  465.                 sprintf( string, "Sniper Mode: On" );
  466.         else
  467.                 sprintf( string, "Sniper Mode: Off" );
  468.         glPrintf( 450, 45, GLUT_BITMAP_9_BY_15, string );
  469. }
  470.  
  471. //-----------------------------------------------------------------------------
  472. // Name: print_selected_objects
  473. // Desc:
  474. //-----------------------------------------------------------------------------
  475. void print_selected_objects( void )
  476. {
  477.         int i;
  478.  
  479.         // List the number of hits
  480.         printf( "Number of hits: %d\n\n", hits );
  481.  
  482.         // List each the attributes of each object selected
  483.         for( i = 0; i < hits; i++ )
  484.         {
  485.                 GLubyte number = select_buffer[i*4];
  486.                 GLubyte min_z = select_buffer[i*4+1];
  487.                 GLubyte max_z = select_buffer[i*4+2];
  488.                 GLubyte name = select_buffer[i*4+3];
  489.  
  490.                 printf( "Number: %d\nMin Z: %d\nMax Z: %d\nName: %d\n\n",
  491.                         number, min_z, max_z, name );
  492.         }
  493. }
  494.  
  495. //-----------------------------------------------------------------------------
  496. // Name: kill_selected_objects
  497. // Desc: Marks all selected objects as dead.
  498. //-----------------------------------------------------------------------------
  499. void kill_selected_objects( void )
  500. {
  501.         int i;
  502.  
  503.         // Loop through the selection buffer and pick out the selected objects.
  504.         // This effect should be similar to that of an armour piercing sniper rifle.
  505.  
  506.         for( i = 0; i < hits; i++ )
  507.         {
  508.                 GLubyte name = select_buffer[i*4+3];
  509.  
  510.                 spheres[name].dead = 1;
  511.                 spheres[name].death_time = GetTickCount();
  512.  
  513.                 // Increment the kill counter
  514.                 kills++;
  515.         }
  516. }
  517.  
  518. //-----------------------------------------------------------------------------
  519. // Name: kill_closest_selected_object
  520. // Desc: Marks the closest selected object as dead.
  521. //-----------------------------------------------------------------------------
  522. void kill_closest_selected_object( void )
  523. {
  524.         int i = 0;
  525.         GLubyte name;
  526.  
  527.         // If we only have one object selected, just kill that one.
  528.         if( hits == 1 )
  529.         {
  530.                 name = select_buffer[i*4+3];
  531.                 spheres[name].dead = 1;
  532.                 spheres[name].death_time = GetTickCount();
  533.                 kills++;
  534.         }
  535.         else
  536.         {
  537.                 float d = spheres[select_buffer[i*4+3]].distance;
  538.                 int closest = 0;
  539.  
  540.                 // Find the object with the shortest distance
  541.                 /*for( i = 1; i < hits; i++ )
  542.                 {
  543.                         name = select_buffer[i*4+3];
  544.  
  545.                         if( d > spheres[name].distance )
  546.                         {
  547.                                 d = spheres[name].distance;
  548.                                 closest = name;
  549.                         }
  550.                 }
  551.  
  552.                 spheres[closest].dead = 1;
  553.                 spheres[closest].death_time = GetTickCount();*/
  554.  
  555.                 for( i = 0; i < hits; i++ )
  556.                 {
  557.                         name = select_buffer[i*4+3];
  558.                         d = min( d, spheres[name].distance );
  559.                 }
  560.  
  561.                 // Now set the closest sphere as dead
  562.                 for( i = 0; i < hits; i++ )
  563.                 {
  564.                         name = select_buffer[i*4+3];
  565.  
  566.                         if( spheres[name].distance == d )
  567.                         {
  568.                                 spheres[name].dead = 1;
  569.                                 spheres[name].death_time = GetTickCount();
  570.                                 kills++;
  571.                                 break;
  572.                         }
  573.                 }
  574.         }
  575. }
  576.  
  577. //-----------------------------------------------------------------------------
  578. // Name: draw_lazer_from_player_to_nearest_target
  579. // Desc: Draws an orange antialiased line from the player to the nearest targeted
  580. //               object.
  581. //-----------------------------------------------------------------------------
  582. void draw_lazer_from_player_to_nearest_target( void )
  583. {
  584.         int i = 0;
  585.         GLubyte name;
  586.         struct Vector3 p1, p2;
  587.  
  588.         // Don't do anything if there is no target in the crosshair
  589.         if( !hits )
  590.                 return;
  591.  
  592.         // Set the first point relative to the camera's position
  593.         p1.x = camera.vecPos.x;
  594.         p1.y = 0.0f; //camera.vecPos.y;
  595.         p1.z = camera.vecPos.z;
  596.  
  597.         // If we only have one object selected, then we know where to aim
  598.         // the lazer.
  599.         if( hits == 1 )
  600.         {
  601.                 name = select_buffer[i*4+3];
  602.                 p2.x = -spheres[name].position.x;
  603.                 p2.y = -spheres[name].position.y;
  604.                 p2.z = -spheres[name].position.z;
  605.         }
  606.         else
  607.         {
  608.                 float d = spheres[select_buffer[i*4+3]].distance;
  609.  
  610.                 for( i = 0; i < hits; i++ )
  611.                 {
  612.                         name = select_buffer[i*4+3];
  613.                         d = min( d, spheres[name].distance );
  614.                 }
  615.  
  616.                 // Now target the closest sphere with the lazer
  617.                 for( i = 0; i < hits; i++ )
  618.                 {
  619.                         name = select_buffer[i*4+3];
  620.  
  621.                         if( spheres[name].distance == d )
  622.                         {
  623.                                 name = select_buffer[i*4+3];
  624.                                 p2.x = -spheres[name].position.x;
  625.                                 p2.y = -spheres[name].position.y;
  626.                                 p2.z = -spheres[name].position.z;
  627.                                 break;
  628.                         }
  629.                 }
  630.         }
  631.  
  632.         // Draw the lazer as an orange line
  633.         glPushAttrib( GL_ALL_ATTRIB_BITS );
  634.         glDisable( GL_LIGHTING );
  635.         glDisable( GL_BLEND );
  636.  
  637.         //glEnable( GL_LINE_SMOOTH );
  638.         glLineWidth( 1.5f );
  639.  
  640.         glBegin( GL_LINES );
  641.         glColor3f( 1.0f, 0.5f, 0.0f );
  642.         glVertex3fv( (float*) &p1 );
  643.         glVertex3fv( (float*) &p2 );
  644.         glEnd();
  645.  
  646.         glPopAttrib();
  647. }
  648.  
  649. //-----------------------------------------------------------------------------
  650. // Name: do_selection
  651. // Desc:
  652. //-----------------------------------------------------------------------------
  653. void do_selection( int select_x, int select_y, int preselect )
  654. {
  655.         GLint iViewport[4];
  656.         float fViewport[4];
  657.         int i;
  658.  
  659.         // Set the selection buffer and specify it's size
  660.         glSelectBuffer( sphere_count*4, select_buffer );
  661.  
  662.         // Get a copy of the current viewport
  663.         glGetIntegerv( GL_VIEWPORT, iViewport );
  664.         glGetFloatv( GL_VIEWPORT, fViewport );
  665.  
  666.         // Switch into selection mode
  667.         glRenderMode( GL_SELECT );
  668.  
  669.         // Clear the name stack
  670.         glInitNames();
  671.         // Give the stack at least one name or else it will generate an error
  672.         glPushName(0);
  673.  
  674.         // Save the projection matrix
  675.         glMatrixMode( GL_PROJECTION );
  676.         glPushMatrix();
  677.         glLoadIdentity();
  678.  
  679.         // Restrict the rendering area to the given point using gluPickMatrix
  680.         gluPickMatrix( select_x, select_y, 1.0f, 1.0f, iViewport );
  681.         gluPerspective( 45.0f, (GLdouble) fViewport[2]/fViewport[3], 0.1f, 500.0f );
  682.  
  683.         // Now render selectable objects to the screen
  684.         glMatrixMode( GL_MODELVIEW );
  685. //      glutSwapBuffers();
  686.  
  687.        
  688.         // Render each sphere with a solid green colour
  689.         glColor3f( 0.0f, 1.0f, 0.0f );
  690.  
  691.         for( i = 0; i < sphere_count; i++ )
  692.         {
  693.         //      if( !spheres[i].dead )
  694.                 if( spheres[i].size != 0.0f )
  695.                 {
  696.                         glPushMatrix();
  697.                         glLoadName(i);
  698.                         glTranslatef( -spheres[i].position.x, spheres[i].position.y, -spheres[i].position.z );
  699.                         glutSolidSphere( spheres[i].size, 20, 20 );
  700.                         glPopMatrix();
  701.                 }
  702.         }
  703.  
  704.         glPopName();
  705.  
  706.         // Restore the projection matrix
  707.         glMatrixMode( GL_PROJECTION );
  708.         glPopMatrix();
  709.  
  710.         // Get the number of hits (the number of objects drawn within that
  711.         // specified area) and return to render mode
  712.         hits = glRenderMode( GL_RENDER );
  713.  
  714.         // Don't do anything except mark objects as selected in preselect mode
  715.         if( preselect )
  716.         {
  717.                 // Go through the list of objects and deselect them all
  718.                 for( i = 0; i < sphere_count; i++ )
  719.                         spheres[i].selected = 0;
  720.  
  721.                 // Now mark all selected objects
  722.                 for( i = 0; i < hits; i++ )
  723.                 {
  724.                         GLubyte name = select_buffer[i*4+3];
  725.                         char string[64];
  726.  
  727.                         spheres[name].selected = 1;
  728.  
  729.                         // For debugging purposes, display the distance between you and
  730.                         // each selected object.
  731.                         sprintf( string, "Name: %d  Distance %f", name, spheres[name].distance );
  732.                         glPrintf( 30, 45+(i*20), GLUT_BITMAP_9_BY_15, string );
  733.                 }
  734.  
  735.                 draw_lazer_from_player_to_nearest_target();
  736.         }
  737.         else
  738.         {
  739.                 // Show the number of selected objects in the console (optional)
  740.                 print_selected_objects();
  741.  
  742.                 // Kill selected object(s)
  743.                 if( sniper_mode )
  744.                         kill_selected_objects();
  745.                 else
  746.                         kill_closest_selected_object();
  747.         }
  748.  
  749.         // Return to the modelview matrix
  750.         glMatrixMode( GL_MODELVIEW );
  751. }
  752.  
  753.  
  754. //-----------------------------------------------------------------------------
  755. // Name: glh_extension_supported
  756. // Desc: Checks the list of OpenGL extensions supported by this videocard/driver
  757. //               to see if it's supported.  This function was borrowed from the NVIDIA
  758. //               SDK (v9.5).  I was too lazy to write my own extension checking function :)
  759. //               See glh_extensions.h
  760. //-----------------------------------------------------------------------------
  761. int glh_extension_supported( const char *extension )
  762. {
  763.     static const GLubyte *extensions = NULL;
  764.     const GLubyte *start;
  765.     GLubyte *where, *terminator;
  766.    
  767.     // Extension names should not have spaces.
  768.     where = (GLubyte *) strchr( extension, ' ');
  769.     if ( where || *extension == '\0')
  770.       return 0;
  771.    
  772.     if ( !extensions )
  773.       extensions = glGetString( GL_EXTENSIONS );
  774.  
  775.     // It takes a bit of care to be fool-proof about parsing the
  776.     // OpenGL extensions string.  Don't be fooled by sub-strings,
  777.     // etc.
  778.     start = extensions;
  779.     for (;;)
  780.     {
  781.         where = (GLubyte *) strstr( (const char *) start, extension );
  782.         if ( !where )
  783.             break;
  784.         terminator = where + strlen( extension );
  785.         if ( where == start || *(where - 1) == ' ' )
  786.         {
  787.             if ( *terminator == ' ' || *terminator == '\0' )
  788.             {
  789.                 return 1;
  790.             }
  791.         }
  792.         start = terminator;
  793.     }
  794.     return 0;
  795. }
  796.  
  797. //-----------------------------------------------------------------------------
  798. // Name: InitScene
  799. // Desc: Initializes extensions, textures, render states, etc. before rendering
  800. //-----------------------------------------------------------------------------
  801. int InitScene( void )
  802. {
  803.         //
  804.         // Set default render states
  805.         //
  806.  
  807.         // Enable depth testing
  808.         glEnable( GL_DEPTH_TEST );
  809.         glDepthFunc( GL_LEQUAL );
  810.         glClearDepth( 1.0f );
  811.  
  812.         // Enable lighting
  813.         glEnable( GL_LIGHTING );
  814.         glEnable( GL_LIGHT0 );
  815.        
  816.         // Enable colour material
  817.         glEnable( GL_COLOR_MATERIAL );
  818.  
  819.         // Disable texture mapping (for now)
  820.         glDisable( GL_TEXTURE_2D );
  821.  
  822.         // Disable blending
  823.         glDisable( GL_BLEND );
  824.  
  825.         // Disable dithering
  826.         glDisable( GL_DITHER );
  827.  
  828.         // Enable culling (counter clock wise)
  829.         glEnable( GL_CULL_FACE );
  830.         glCullFace( GL_CCW );
  831.  
  832.         // Enable fog
  833. //      glEnable( GL_FOG );
  834.  
  835.         // Enable perspective correction and polygon smoothing
  836.         glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
  837.         glHint( GL_POLYGON_SMOOTH_HINT, GL_NICEST );
  838.  
  839.         //
  840.         // Initialize scene objects and geometry
  841.         //
  842.  
  843.         texture_create();
  844.         spheres_init();
  845.  
  846.         memset( &camera, 0, sizeof( struct ThirdPersonCamera_t ) );
  847.         camera.fRadius = 10.0f;
  848.  
  849.         //
  850.         // Misc
  851.         //
  852.  
  853.         srand( time( NULL ) );
  854.  
  855.         return GL_TRUE;
  856. }
  857.  
  858. //-----------------------------------------------------------------------------
  859. // Name: DisplayFunction
  860. // Desc: Our display function used to render our graphics in the main loop of
  861. //               our GLUT application.
  862. //-----------------------------------------------------------------------------
  863. void DisplayFunction( void )
  864. {
  865.         int iViewport[4];
  866.  
  867.         // Clear the screen and depth buffer
  868.         glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );
  869.         // Reset matrices to default position, scale, and rotation
  870.         glLoadIdentity();
  871.  
  872.         // Position the camera behind our character and render it
  873.         glTranslatef( 0.0f, -2.0f, -camera.fRadius );
  874.         glRotatef( camera.vecRot.x, 1.0f, 0.0f, 0.0f );
  875.         glColor3f( 1.0f, 0.0f, 0.0f );
  876.         glutSolidCube( 3.0f );
  877.  
  878.         // Rotate the camera as necessary
  879.         glRotatef( camera.vecRot.y, 0.0f, 1.0f, 0.0f );
  880.         glTranslatef( -camera.vecPos.x, 0.0f, -camera.vecPos.z );
  881.  
  882.         // Calculate distances
  883.         calculate_distances();
  884.  
  885.         // Do pre-selection
  886.         glGetIntegerv( GL_VIEWPORT, iViewport );
  887.         do_selection( iViewport[2]/2, iViewport[3]/2, TRUE );
  888.  
  889.         // Render the floor
  890.         floor_render( 50.0f, -0.75f );
  891.  
  892.         // Render spheres
  893.         spheres_render();
  894.  
  895.         // Draw each axis
  896.         draw_axes();
  897.  
  898.         // Draw the crosshair
  899.         draw_crosshair();
  900.  
  901.         // Show camera's statistics
  902.         glColor3f( 0.0f, 0.0f, 1.0f );
  903.         show_camera_stats();
  904.  
  905.         // Show other stats
  906.         show_stats();
  907.  
  908.         // Display graphics to the user
  909.         glutSwapBuffers();
  910. }
  911.  
  912.  
  913. //-----------------------------------------------------------------------------
  914. // Name: IdleFunction
  915. // Desc: The function that is executed whenever the program is idle
  916. //-----------------------------------------------------------------------------
  917. void IdleFunction( void )
  918. {
  919.         // Continue to display graphics even when messages aren't
  920.         // being processed.
  921.         glutPostRedisplay();
  922. }
  923.  
  924. //-----------------------------------------------------------------------------
  925. // Name: KeyboardFunction
  926. // Desc: Handles keyboard input
  927. //-----------------------------------------------------------------------------
  928. void KeyboardFunction( GLubyte k, int x, int y )
  929. {
  930.         static float fRotSpeed = 1.0f;
  931.  
  932.         if (k=='q')
  933.     {
  934.                 camera.vecRot.x += fRotSpeed;
  935.                 if (camera.vecRot.x > 360) camera.vecRot.x -= 360;
  936.     }
  937.     if (k=='z')
  938.     {
  939.                 camera.vecRot.x -= fRotSpeed;
  940.                 if (camera.vecRot.x < -360) camera.vecRot.x += 360;
  941.     }
  942.  
  943.        
  944.         if (k=='c')
  945.     {
  946.                 camera.vecRot.y += fRotSpeed;
  947.                 if (camera.vecRot.y > 360) camera.vecRot.y -= 360;
  948.     }
  949.     if (k=='v')
  950.     {
  951.                 camera.vecRot.y -= fRotSpeed;
  952.                 if (camera.vecRot.y < -360) camera.vecRot.y += 360;
  953.     }
  954.  
  955.     if (k=='w')
  956.     {
  957.                 float xrotrad, yrotrad;
  958.                 yrotrad = (camera.vecRot.y / 180.0f * 3.141592654f);
  959.                 xrotrad = (camera.vecRot.x / 180.0f * 3.141592654f);
  960.                 camera.vecPos.x += (float)(sin(yrotrad));
  961.                 camera.vecPos.z -= (float)(cos(yrotrad));
  962.                 camera.vecPos.y -= (float)(sin(xrotrad));
  963.     }
  964.     if (k=='s')
  965.     {
  966.                 float xrotrad, yrotrad;
  967.                 yrotrad = (camera.vecRot.y / 180.0f * 3.141592654f);
  968.                 xrotrad = (camera.vecRot.x / 180.0f * 3.141592654f);
  969.                 camera.vecPos.x -= (float)(sin(yrotrad));
  970.                 camera.vecPos.z += (float)(cos(yrotrad));
  971.                 camera.vecPos.y += (float)(sin(xrotrad));
  972.     }
  973.     if (k=='d')
  974.     {
  975.                 float yrotrad;
  976.                 yrotrad = (camera.vecRot.y / 180.0f * 3.141592654f);
  977.                 camera.vecPos.x += (float)(cos(yrotrad)) * 0.5f;
  978.                 camera.vecPos.z += (float)(sin(yrotrad)) * 0.5f;
  979.     }
  980.     if (k =='a')
  981.     {
  982.                 float yrotrad;
  983.                 yrotrad = (camera.vecRot.y / 180.0f * 3.141592654f);
  984.                 camera.vecPos.x -= (float)(cos(yrotrad)) * 0.5f;
  985.                 camera.vecPos.z -= (float)(sin(yrotrad)) * 0.5f;
  986.     }
  987.  
  988.         // Has escape been pressed?
  989.         if( k == 27 )
  990.         {
  991.                 exit(0);
  992.         }
  993.  
  994.         // If not, then continue rendering
  995.         glutPostRedisplay();
  996. }
  997.  
  998. //-----------------------------------------------------------------------------
  999. // Name: MouseFunction
  1000. // Desc: Handles mouse input (movement)
  1001. //-----------------------------------------------------------------------------
  1002. void MouseFunction( int x, int y )
  1003. {
  1004.         int diffx = x - camera.fLastX;
  1005.         int diffy = y - camera.fLastY;
  1006.  
  1007.         camera.fLastX = x;
  1008.         camera.fLastY = y;
  1009.  
  1010.         camera.vecRot.x += (float) diffy;
  1011.         camera.vecRot.y += (float) diffx;
  1012.  
  1013.         if( camera.vecRot.x < -30.0f )
  1014.                 camera.vecRot.x = -30.0f;
  1015.         if( camera.vecRot.x > 90.0f )
  1016.                 camera.vecRot.x = 90.0f;
  1017.  
  1018. }
  1019.  
  1020. //-----------------------------------------------------------------------------
  1021. // Name: MouseClickFunction
  1022. // Desc: Handles mouse input (clicks)
  1023. //-----------------------------------------------------------------------------
  1024. void MouseClickFunction( int button, int state, int x, int y )
  1025. {
  1026.         int iViewport[4];
  1027.         int center_x;
  1028.         int center_y;
  1029.  
  1030.         if( ( button == GLUT_LEFT_BUTTON ) && ( state == GLUT_DOWN ) )
  1031.         {
  1032.                 glGetIntegerv( GL_VIEWPORT, iViewport );
  1033.  
  1034.                 center_x = iViewport[2]/2;
  1035.                 center_y = iViewport[3]/2;
  1036.  
  1037.                 printf( "\nCenter X: %d\nCenter Y: %d\n\n", center_x, center_y );
  1038.                 do_selection( center_x, center_y, FALSE );
  1039.         }
  1040.  
  1041.         if( ( button == GLUT_RIGHT_BUTTON ) && ( state == GLUT_DOWN ) )
  1042.                 sniper_mode = !sniper_mode;
  1043. }
  1044.  
  1045. //-----------------------------------------------------------------------------
  1046. // Name: ReshapeFunction
  1047. // Desc: Changes the viewport when the window is resized
  1048. //-----------------------------------------------------------------------------
  1049. void ReshapeFunction( GLsizei width, GLsizei height )
  1050. {
  1051.         // Prevent divide by zero exception
  1052.         if( !height ) height = 1;
  1053.  
  1054.         // Reset viewport
  1055.         glViewport( 0, 0, width, height );
  1056.         glMatrixMode( GL_PROJECTION );
  1057.         glLoadIdentity();
  1058.  
  1059.         // Reset perspective
  1060.         gluPerspective( 45.0f, (GLdouble) width/height, 0.1f, 500.0f );
  1061.         glMatrixMode( GL_MODELVIEW );
  1062.         glLoadIdentity();
  1063. }
  1064.  
  1065.  
  1066. //-----------------------------------------------------------------------------
  1067. // Name: main
  1068. // Desc: Program entry point.
  1069. //-----------------------------------------------------------------------------
  1070. int main( int argc, char* argv[] )
  1071. {
  1072.         // Initialize OpenGL via GLUT library
  1073.         glutInit( &argc, argv );
  1074.         glutInitWindowSize( 640, 480 );
  1075.         glutInitDisplayMode( GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA );
  1076.         glutCreateWindow( "Meta-Balls!" );
  1077. //      glutFullScreen();
  1078.  
  1079.         // Initialize scene objects and properties
  1080.         InitScene();
  1081.  
  1082.         // Set our input/output functions and begin the main loop
  1083.         glutIdleFunc( IdleFunction );
  1084.         glutDisplayFunc( DisplayFunction );
  1085.         glutKeyboardFunc( KeyboardFunction );
  1086.         glutReshapeFunc( ReshapeFunction );
  1087.         glutMouseFunc( MouseClickFunction );
  1088.         glutPassiveMotionFunc( MouseFunction );
  1089.         glutMainLoop();
  1090.  
  1091.         return 0;
  1092. }
clone this paste RAW Paste Data