# 3rd Person Shooter Programming Tutorial (OpenGL)

By: a guest on Jan 16th, 2012  |  syntax: C  |  size: 30.04 KB  |  views: 59  |  expires: Never
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?
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();
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();
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.
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;
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?
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;
328.                                 spheres[i].size = 2.0f;
329.                         }
330.                 }
331.
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 );
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.
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];
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.
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.                         {
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();
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.         {
694.                 if( spheres[i].size != 0.0f )
695.                 {
696.                         glPushMatrix();
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
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.
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 ) );
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
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.     {
958.                 yrotrad = (camera.vecRot.y / 180.0f * 3.141592654f);
959.                 xrotrad = (camera.vecRot.x / 180.0f * 3.141592654f);
963.     }
964.     if (k=='s')
965.     {
967.                 yrotrad = (camera.vecRot.y / 180.0f * 3.141592654f);
968.                 xrotrad = (camera.vecRot.x / 180.0f * 3.141592654f);
972.     }
973.     if (k=='d')
974.     {
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.     {
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 );
1058.
1059.         // Reset perspective
1060.         gluPerspective( 45.0f, (GLdouble) width/height, 0.1f, 500.0f );
1061.         glMatrixMode( GL_MODELVIEW );
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
Top