//----------------------------------------------------------------------------- // Shogun3D's OpenGL Utility Toolkit framework. // // Disclamer: Use this code as you see fit, for both personal and/or commercial // usages. You don't exactly have to give me credit for using this // code in your own projects (although I would appreciate it if you // did), but you could at let me know that this has benefited you // in one way or another, because I didn't write this code just for // myself you know ^^ // // File: main.c // Desc: This code will hopefully show you how easy it is to create a 3rd // person game :) // Date: August 20, 2010 //----------------------------------------------------------------------------- // Include files #ifdef WIN32 // For windows builds #include #endif #include #include #include #include #include //----------------------------------------------------------------------------- // 3D vector //----------------------------------------------------------------------------- struct Vector3 { float x, y, z; }; //----------------------------------------------------------------------------- // Third Person Camera structure //----------------------------------------------------------------------------- struct ThirdPersonCamera_t { struct Vector3 vecPos; struct Vector3 vecRot; float fRadius; // Distance between the camera and the object. float fLastX; float fLastY; }; //----------------------------------------------------------------------------- // Sphere structure //----------------------------------------------------------------------------- struct Sphere_t { struct Vector3 position; // Position in 3D space int selected; // Did OpenGL select this one? int dead; // Is this sphere dead? unsigned int death_time; // How long has this sphere been dead? // Respawn after X milliseconds float distance; // Distance between you and the sphere. float size; // The size of the sphere. Decreases during // death phase. }; //----------------------------------------------------------------------------- // Global variables //----------------------------------------------------------------------------- #define sphere_count 20 // Number of spheres in the game #define respawn_time 5000 // After a sphere is shot dead, respawn after this // amount of time. struct ThirdPersonCamera_t camera; struct Sphere_t spheres[sphere_count]; GLuint floor_tex = 0; GLuint select_buffer[sphere_count*4] = {0}; GLint hits = 0; float jump_height = 0.0f; GLboolean sniper_mode = GL_FALSE; GLint kills = 0; //----------------------------------------------------------------------------- // Name: glEnable2D // Desc: Enabled 2D primitive rendering by setting up the appropriate orthographic // perspectives and matrices. //----------------------------------------------------------------------------- void glEnable2D( void ) { GLint iViewport[4]; // Get a copy of the viewport glGetIntegerv( GL_VIEWPORT, iViewport ); // Save a copy of the projection matrix so that we can restore it // when it's time to do 3D rendering again. glMatrixMode( GL_PROJECTION ); glPushMatrix(); glLoadIdentity(); // Set up the orthographic projection glOrtho( iViewport[0], iViewport[0]+iViewport[2], iViewport[1]+iViewport[3], iViewport[1], -1, 1 ); glMatrixMode( GL_MODELVIEW ); glPushMatrix(); glLoadIdentity(); // Make sure depth testing and lighting are disabled for 2D rendering until // we are finished rendering in 2D glPushAttrib( GL_DEPTH_BUFFER_BIT | GL_LIGHTING_BIT ); glDisable( GL_DEPTH_TEST ); glDisable( GL_LIGHTING ); } //----------------------------------------------------------------------------- // Name: glDisable2D // Desc: Disables 2D rendering and restores the previous matrix and render states // before they were modified. //----------------------------------------------------------------------------- void glDisable2D( void ) { glPopAttrib(); glMatrixMode( GL_PROJECTION ); glPopMatrix(); glMatrixMode( GL_MODELVIEW ); glPopMatrix(); } //----------------------------------------------------------------------------- // Name: glPrintf // Desc: Prints a string of chars using GLUT's pre-defined char blitting API. //----------------------------------------------------------------------------- void glPrintf( int x, int y, void* font, char* string, ... ) { char *c; char temp[256]; va_list ap; va_start( ap, string ); vsprintf( temp, string, ap ); va_end( ap ); glEnable2D(); glRasterPos2i(x,y); for (c=temp; *c != '\0'; c++) { glutBitmapCharacter(font, *c); } glDisable2D(); } //----------------------------------------------------------------------------- // Name: distance // Desc: Calculates the distance between two points. //----------------------------------------------------------------------------- float distance( const struct Vector3* v1, const struct Vector3* v2 ) { float d = 0.0f; float x = v2->x - v1->x; float y = v2->y - v1->y; float z = v2->z - v1->z; x *= x; y *= y; z *= z; d = sqrt(x+y+z); return d; } //----------------------------------------------------------------------------- // Name: calculate_distances // Desc: Calulates the distance between each sphere and the camera. //----------------------------------------------------------------------------- void calculate_distances( void ) { int i; struct Vector3 neg_camera; // In order to accurately calculate the distance between the spheres and // the camera, the x and z values should be converted to negatives, and // the y coordinate should be ignored. The camera updates the y value // still, but in a 3rd person shooter/adventure style game, the is calc- // lations are done seperately from the camera to compensate for jumping // and gravity, etc. neg_camera.x = camera.vecPos.x * -1.0f; neg_camera.y = 0.0f; neg_camera.z = camera.vecPos.z * -1.0f; for( i = 0; i < sphere_count; i++ ) { spheres[i].distance = distance( &neg_camera, &spheres[i].position ); } } //----------------------------------------------------------------------------- // Name: texture_create // Desc: Creates a simple black and white checker board style texture. Change it // to whatever you like :) //----------------------------------------------------------------------------- void texture_create( void ) { GLubyte buffer[64][64][4]; int s, t; for( t = 0; t < 64; t++ ) { for( s = 0; s < 64; s++ ) { GLubyte c = ((((t&0x8)==0)^((s&0x8))==0))*255; buffer[s][t][0] = c; buffer[s][t][1] = c; buffer[s][t][2] = c; buffer[s][t][3] = 255; } } // Set the pixel alignment to default glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); // Generate 1 texture ID glGenTextures( 1, &floor_tex ); // Bind this texture so that we can edit it glBindTexture( GL_TEXTURE_2D, floor_tex ); // Create the actual texture with it's dimensions, format and texel data glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 64, 64, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer ); // Enable bilinear filtering glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); } //----------------------------------------------------------------------------- // Name: floor_render // Desc: Renders the floor with the texture created above. //----------------------------------------------------------------------------- void floor_render( float size, float y ) { // Render the floor at the given height on the Y axis. glPushAttrib( GL_ALL_ATTRIB_BITS ); glPushMatrix(); glTranslatef( 0.0f, y, 0.0f ); glDisable( GL_LIGHTING ); glEnable( GL_TEXTURE_2D ); glBindTexture( GL_TEXTURE_2D, floor_tex ); glBegin( GL_QUADS ); glColor3f( 1.0f, 1.0f, 1.0f ); glTexCoord2f( 0.0f, 0.0f ); glVertex3f( -size, y, -size ); glTexCoord2f( 0.0f, 1.0f ); glVertex3f( -size, y, +size ); glTexCoord2f( 1.0f, 1.0f ); glVertex3f( +size, y, +size ); glTexCoord2f( 1.0f, 0.0f ); glVertex3f( +size, y, -size ); glEnd(); glPopMatrix(); glPopAttrib(); } //----------------------------------------------------------------------------- // Name: spheres_init // Desc: Gives each sphere a random position in 3D space. //----------------------------------------------------------------------------- void spheres_init( void ) { int i; // Give each sphere a random position for( i = 0; i < sphere_count; i++ ) { spheres[i].position.x = (float) ( ( rand() % 100 ) + 1 ) - 50; spheres[i].position.y = 0.0f; spheres[i].position.z = (float) ( ( rand() % 100 ) + 1 ) - 50; spheres[i].selected = 0; spheres[i].dead = 0; spheres[i].death_time = 0; spheres[i].distance = 0.0f; spheres[i].size = 2.0f; } } //----------------------------------------------------------------------------- // Name: spheres_render // Desc: Renders each sphere in it's random position //----------------------------------------------------------------------------- void spheres_render( void ) { int i; // Render each sphere with a solid green colour glColor3f( 0.0f, 1.0f, 0.0f ); for( i = 0; i < sphere_count; i++ ) { // Is this sphere dead? if( spheres[i].dead ) { unsigned int current_time; // Slowly decrease the size of the sphere when it's dying if( spheres[i].size > 0.0f ) spheres[i].size -= 0.1f; // When time expires, bring the sphere back into play (respawn). // The sphere will fall from the sky after the respawn time expires. current_time = GetTickCount(); if( (current_time - spheres[i].death_time) > respawn_time ) { spheres[i].position.x = (float) ( ( rand() % 100 ) + 1 ) - 50; spheres[i].position.y = 50.0f; spheres[i].position.z = (float) ( ( rand() % 100 ) + 1 ) - 50; spheres[i].dead = 0; spheres[i].size = 2.0f; } } //if( !spheres[i].dead ) if( spheres[i].size != 0.0f ) { glPushMatrix(); glTranslatef( -spheres[i].position.x, spheres[i].position.y, -spheres[i].position.z ); glutSolidSphere( spheres[i].size, 20, 20 ); // Render a slightly larger purple transparent sphere around // selected objects. if( spheres[i].selected ) { glPushAttrib( GL_ALL_ATTRIB_BITS ); glColor4ub( 128, 0, 255, 64 ); glDisable( GL_COLOR_MATERIAL ); glDisable( GL_LIGHTING ); // glDisable( GL_DEPTH_TEST ); glDepthMask( GL_FALSE ); glDisable( GL_TEXTURE_2D ); glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); glutSolidSphere( spheres[i].size * 1.5f, 20, 20 ); glPopAttrib(); } glPopMatrix(); } // If the sphere is in the sky, let it fall back down to the ground if( spheres[i].position.y > 0.0f ) { spheres[i].position.y -= 0.5f; } } } //----------------------------------------------------------------------------- // Name: draw_axes // Desc: Draws each axis using a line in the center of 3D space. Red is X, // green is Y, and blue is Z. This will help us make sure we are not // upside down. //----------------------------------------------------------------------------- void draw_axes( void ) { glPushAttrib( GL_ALL_ATTRIB_BITS ); glDisable( GL_LIGHTING ); glEnable( GL_LINE_SMOOTH ); glPushMatrix(); glTranslatef( 0.0f, 0.0f, 0.0f ); glBegin( GL_LINES ); // X Axis (Red) glColor3f( 1.0f, 0.0f, 0.0f ); glVertex3f( 0.0f, 0.0f, 0.0f ); glVertex3f( 2.0f, 0.0f, 0.0f ); // Y Axis (Green) glColor3f( 0.0f, 1.0f, 0.0f ); glVertex3f( 0.0f, 0.0f, 0.0f ); glVertex3f( 0.0f, 2.0f, 0.0f ); // Z Axis (Blue) glColor3f( 0.0f, 0.0f, 1.0f ); glVertex3f( 0.0f, 0.0f, 0.0f ); glVertex3f( 0.0f, 0.0f, 2.0f ); glEnd(); glPopMatrix(); glPopAttrib(); } //----------------------------------------------------------------------------- // Name: draw_crosshair // Desc: //----------------------------------------------------------------------------- void draw_crosshair( void ) { float fViewport[4]; float w = 32.0f, h = 32.0f; // Get the current viewport. We want to make sure the crosshair // is in the center of the screen, even if the window is resized. glGetFloatv( GL_VIEWPORT, fViewport ); // Enable 2D rendering glEnable2D(); glBegin( GL_LINES ); glColor3f( 1.0f, 1.0f, 0.0f ); glVertex2f( (fViewport[2]/2.0f)-(w/2.0f), fViewport[3]/2.0f ); glVertex2f( (fViewport[2]/2.0f)+(w/2.0f), fViewport[3]/2.0f ); glVertex2f( fViewport[2]/2.0f, (fViewport[3]/2.0f)-(h/2.0f) ); glVertex2f( fViewport[2]/2.0f, (fViewport[3]/2.0f)+(h/2.0f) ); glEnd(); // Disable 2D rendering glDisable2D(); } //----------------------------------------------------------------------------- // Name: show_camera_stats // Desc: //----------------------------------------------------------------------------- void show_camera_stats( void ) { char string[128]; sprintf( string, "Camera <%f,%f,%f>", camera.vecPos.x, camera.vecPos.y, camera.vecPos.z ); glPrintf( 30, 30, GLUT_BITMAP_9_BY_15, string ); } //----------------------------------------------------------------------------- // Name: show_stats // Desc: //----------------------------------------------------------------------------- void show_stats( void ) { char string[128]; glColor3f( 0.0f, 0.5f, 1.0f ); sprintf( string, "Kills: %d", kills ); glPrintf( 450, 30, GLUT_BITMAP_9_BY_15, string ); if( sniper_mode ) sprintf( string, "Sniper Mode: On" ); else sprintf( string, "Sniper Mode: Off" ); glPrintf( 450, 45, GLUT_BITMAP_9_BY_15, string ); } //----------------------------------------------------------------------------- // Name: print_selected_objects // Desc: //----------------------------------------------------------------------------- void print_selected_objects( void ) { int i; // List the number of hits printf( "Number of hits: %d\n\n", hits ); // List each the attributes of each object selected for( i = 0; i < hits; i++ ) { GLubyte number = select_buffer[i*4]; GLubyte min_z = select_buffer[i*4+1]; GLubyte max_z = select_buffer[i*4+2]; GLubyte name = select_buffer[i*4+3]; printf( "Number: %d\nMin Z: %d\nMax Z: %d\nName: %d\n\n", number, min_z, max_z, name ); } } //----------------------------------------------------------------------------- // Name: kill_selected_objects // Desc: Marks all selected objects as dead. //----------------------------------------------------------------------------- void kill_selected_objects( void ) { int i; // Loop through the selection buffer and pick out the selected objects. // This effect should be similar to that of an armour piercing sniper rifle. for( i = 0; i < hits; i++ ) { GLubyte name = select_buffer[i*4+3]; spheres[name].dead = 1; spheres[name].death_time = GetTickCount(); // Increment the kill counter kills++; } } //----------------------------------------------------------------------------- // Name: kill_closest_selected_object // Desc: Marks the closest selected object as dead. //----------------------------------------------------------------------------- void kill_closest_selected_object( void ) { int i = 0; GLubyte name; // If we only have one object selected, just kill that one. if( hits == 1 ) { name = select_buffer[i*4+3]; spheres[name].dead = 1; spheres[name].death_time = GetTickCount(); kills++; } else { float d = spheres[select_buffer[i*4+3]].distance; int closest = 0; // Find the object with the shortest distance /*for( i = 1; i < hits; i++ ) { name = select_buffer[i*4+3]; if( d > spheres[name].distance ) { d = spheres[name].distance; closest = name; } } spheres[closest].dead = 1; spheres[closest].death_time = GetTickCount();*/ for( i = 0; i < hits; i++ ) { name = select_buffer[i*4+3]; d = min( d, spheres[name].distance ); } // Now set the closest sphere as dead for( i = 0; i < hits; i++ ) { name = select_buffer[i*4+3]; if( spheres[name].distance == d ) { spheres[name].dead = 1; spheres[name].death_time = GetTickCount(); kills++; break; } } } } //----------------------------------------------------------------------------- // Name: draw_lazer_from_player_to_nearest_target // Desc: Draws an orange antialiased line from the player to the nearest targeted // object. //----------------------------------------------------------------------------- void draw_lazer_from_player_to_nearest_target( void ) { int i = 0; GLubyte name; struct Vector3 p1, p2; // Don't do anything if there is no target in the crosshair if( !hits ) return; // Set the first point relative to the camera's position p1.x = camera.vecPos.x; p1.y = 0.0f; //camera.vecPos.y; p1.z = camera.vecPos.z; // If we only have one object selected, then we know where to aim // the lazer. if( hits == 1 ) { name = select_buffer[i*4+3]; p2.x = -spheres[name].position.x; p2.y = -spheres[name].position.y; p2.z = -spheres[name].position.z; } else { float d = spheres[select_buffer[i*4+3]].distance; for( i = 0; i < hits; i++ ) { name = select_buffer[i*4+3]; d = min( d, spheres[name].distance ); } // Now target the closest sphere with the lazer for( i = 0; i < hits; i++ ) { name = select_buffer[i*4+3]; if( spheres[name].distance == d ) { name = select_buffer[i*4+3]; p2.x = -spheres[name].position.x; p2.y = -spheres[name].position.y; p2.z = -spheres[name].position.z; break; } } } // Draw the lazer as an orange line glPushAttrib( GL_ALL_ATTRIB_BITS ); glDisable( GL_LIGHTING ); glDisable( GL_BLEND ); //glEnable( GL_LINE_SMOOTH ); glLineWidth( 1.5f ); glBegin( GL_LINES ); glColor3f( 1.0f, 0.5f, 0.0f ); glVertex3fv( (float*) &p1 ); glVertex3fv( (float*) &p2 ); glEnd(); glPopAttrib(); } //----------------------------------------------------------------------------- // Name: do_selection // Desc: //----------------------------------------------------------------------------- void do_selection( int select_x, int select_y, int preselect ) { GLint iViewport[4]; float fViewport[4]; int i; // Set the selection buffer and specify it's size glSelectBuffer( sphere_count*4, select_buffer ); // Get a copy of the current viewport glGetIntegerv( GL_VIEWPORT, iViewport ); glGetFloatv( GL_VIEWPORT, fViewport ); // Switch into selection mode glRenderMode( GL_SELECT ); // Clear the name stack glInitNames(); // Give the stack at least one name or else it will generate an error glPushName(0); // Save the projection matrix glMatrixMode( GL_PROJECTION ); glPushMatrix(); glLoadIdentity(); // Restrict the rendering area to the given point using gluPickMatrix gluPickMatrix( select_x, select_y, 1.0f, 1.0f, iViewport ); gluPerspective( 45.0f, (GLdouble) fViewport[2]/fViewport[3], 0.1f, 500.0f ); // Now render selectable objects to the screen glMatrixMode( GL_MODELVIEW ); // glutSwapBuffers(); // Render each sphere with a solid green colour glColor3f( 0.0f, 1.0f, 0.0f ); for( i = 0; i < sphere_count; i++ ) { // if( !spheres[i].dead ) if( spheres[i].size != 0.0f ) { glPushMatrix(); glLoadName(i); glTranslatef( -spheres[i].position.x, spheres[i].position.y, -spheres[i].position.z ); glutSolidSphere( spheres[i].size, 20, 20 ); glPopMatrix(); } } glPopName(); // Restore the projection matrix glMatrixMode( GL_PROJECTION ); glPopMatrix(); // Get the number of hits (the number of objects drawn within that // specified area) and return to render mode hits = glRenderMode( GL_RENDER ); // Don't do anything except mark objects as selected in preselect mode if( preselect ) { // Go through the list of objects and deselect them all for( i = 0; i < sphere_count; i++ ) spheres[i].selected = 0; // Now mark all selected objects for( i = 0; i < hits; i++ ) { GLubyte name = select_buffer[i*4+3]; char string[64]; spheres[name].selected = 1; // For debugging purposes, display the distance between you and // each selected object. sprintf( string, "Name: %d Distance %f", name, spheres[name].distance ); glPrintf( 30, 45+(i*20), GLUT_BITMAP_9_BY_15, string ); } draw_lazer_from_player_to_nearest_target(); } else { // Show the number of selected objects in the console (optional) print_selected_objects(); // Kill selected object(s) if( sniper_mode ) kill_selected_objects(); else kill_closest_selected_object(); } // Return to the modelview matrix glMatrixMode( GL_MODELVIEW ); } //----------------------------------------------------------------------------- // Name: glh_extension_supported // Desc: Checks the list of OpenGL extensions supported by this videocard/driver // to see if it's supported. This function was borrowed from the NVIDIA // SDK (v9.5). I was too lazy to write my own extension checking function :) // See glh_extensions.h //----------------------------------------------------------------------------- int glh_extension_supported( const char *extension ) { static const GLubyte *extensions = NULL; const GLubyte *start; GLubyte *where, *terminator; // Extension names should not have spaces. where = (GLubyte *) strchr( extension, ' '); if ( where || *extension == '\0') return 0; if ( !extensions ) extensions = glGetString( GL_EXTENSIONS ); // It takes a bit of care to be fool-proof about parsing the // OpenGL extensions string. Don't be fooled by sub-strings, // etc. start = extensions; for (;;) { where = (GLubyte *) strstr( (const char *) start, extension ); if ( !where ) break; terminator = where + strlen( extension ); if ( where == start || *(where - 1) == ' ' ) { if ( *terminator == ' ' || *terminator == '\0' ) { return 1; } } start = terminator; } return 0; } //----------------------------------------------------------------------------- // Name: InitScene // Desc: Initializes extensions, textures, render states, etc. before rendering //----------------------------------------------------------------------------- int InitScene( void ) { // // Set default render states // // Enable depth testing glEnable( GL_DEPTH_TEST ); glDepthFunc( GL_LEQUAL ); glClearDepth( 1.0f ); // Enable lighting glEnable( GL_LIGHTING ); glEnable( GL_LIGHT0 ); // Enable colour material glEnable( GL_COLOR_MATERIAL ); // Disable texture mapping (for now) glDisable( GL_TEXTURE_2D ); // Disable blending glDisable( GL_BLEND ); // Disable dithering glDisable( GL_DITHER ); // Enable culling (counter clock wise) glEnable( GL_CULL_FACE ); glCullFace( GL_CCW ); // Enable fog // glEnable( GL_FOG ); // Enable perspective correction and polygon smoothing glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST ); glHint( GL_POLYGON_SMOOTH_HINT, GL_NICEST ); // // Initialize scene objects and geometry // texture_create(); spheres_init(); memset( &camera, 0, sizeof( struct ThirdPersonCamera_t ) ); camera.fRadius = 10.0f; // // Misc // srand( time( NULL ) ); return GL_TRUE; } //----------------------------------------------------------------------------- // Name: DisplayFunction // Desc: Our display function used to render our graphics in the main loop of // our GLUT application. //----------------------------------------------------------------------------- void DisplayFunction( void ) { int iViewport[4]; // Clear the screen and depth buffer glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ); // Reset matrices to default position, scale, and rotation glLoadIdentity(); // Position the camera behind our character and render it glTranslatef( 0.0f, -2.0f, -camera.fRadius ); glRotatef( camera.vecRot.x, 1.0f, 0.0f, 0.0f ); glColor3f( 1.0f, 0.0f, 0.0f ); glutSolidCube( 3.0f ); // Rotate the camera as necessary glRotatef( camera.vecRot.y, 0.0f, 1.0f, 0.0f ); glTranslatef( -camera.vecPos.x, 0.0f, -camera.vecPos.z ); // Calculate distances calculate_distances(); // Do pre-selection glGetIntegerv( GL_VIEWPORT, iViewport ); do_selection( iViewport[2]/2, iViewport[3]/2, TRUE ); // Render the floor floor_render( 50.0f, -0.75f ); // Render spheres spheres_render(); // Draw each axis draw_axes(); // Draw the crosshair draw_crosshair(); // Show camera's statistics glColor3f( 0.0f, 0.0f, 1.0f ); show_camera_stats(); // Show other stats show_stats(); // Display graphics to the user glutSwapBuffers(); } //----------------------------------------------------------------------------- // Name: IdleFunction // Desc: The function that is executed whenever the program is idle //----------------------------------------------------------------------------- void IdleFunction( void ) { // Continue to display graphics even when messages aren't // being processed. glutPostRedisplay(); } //----------------------------------------------------------------------------- // Name: KeyboardFunction // Desc: Handles keyboard input //----------------------------------------------------------------------------- void KeyboardFunction( GLubyte k, int x, int y ) { static float fRotSpeed = 1.0f; if (k=='q') { camera.vecRot.x += fRotSpeed; if (camera.vecRot.x > 360) camera.vecRot.x -= 360; } if (k=='z') { camera.vecRot.x -= fRotSpeed; if (camera.vecRot.x < -360) camera.vecRot.x += 360; } if (k=='c') { camera.vecRot.y += fRotSpeed; if (camera.vecRot.y > 360) camera.vecRot.y -= 360; } if (k=='v') { camera.vecRot.y -= fRotSpeed; if (camera.vecRot.y < -360) camera.vecRot.y += 360; } if (k=='w') { float xrotrad, yrotrad; yrotrad = (camera.vecRot.y / 180.0f * 3.141592654f); xrotrad = (camera.vecRot.x / 180.0f * 3.141592654f); camera.vecPos.x += (float)(sin(yrotrad)); camera.vecPos.z -= (float)(cos(yrotrad)); camera.vecPos.y -= (float)(sin(xrotrad)); } if (k=='s') { float xrotrad, yrotrad; yrotrad = (camera.vecRot.y / 180.0f * 3.141592654f); xrotrad = (camera.vecRot.x / 180.0f * 3.141592654f); camera.vecPos.x -= (float)(sin(yrotrad)); camera.vecPos.z += (float)(cos(yrotrad)); camera.vecPos.y += (float)(sin(xrotrad)); } if (k=='d') { float yrotrad; yrotrad = (camera.vecRot.y / 180.0f * 3.141592654f); camera.vecPos.x += (float)(cos(yrotrad)) * 0.5f; camera.vecPos.z += (float)(sin(yrotrad)) * 0.5f; } if (k =='a') { float yrotrad; yrotrad = (camera.vecRot.y / 180.0f * 3.141592654f); camera.vecPos.x -= (float)(cos(yrotrad)) * 0.5f; camera.vecPos.z -= (float)(sin(yrotrad)) * 0.5f; } // Has escape been pressed? if( k == 27 ) { exit(0); } // If not, then continue rendering glutPostRedisplay(); } //----------------------------------------------------------------------------- // Name: MouseFunction // Desc: Handles mouse input (movement) //----------------------------------------------------------------------------- void MouseFunction( int x, int y ) { int diffx = x - camera.fLastX; int diffy = y - camera.fLastY; camera.fLastX = x; camera.fLastY = y; camera.vecRot.x += (float) diffy; camera.vecRot.y += (float) diffx; if( camera.vecRot.x < -30.0f ) camera.vecRot.x = -30.0f; if( camera.vecRot.x > 90.0f ) camera.vecRot.x = 90.0f; } //----------------------------------------------------------------------------- // Name: MouseClickFunction // Desc: Handles mouse input (clicks) //----------------------------------------------------------------------------- void MouseClickFunction( int button, int state, int x, int y ) { int iViewport[4]; int center_x; int center_y; if( ( button == GLUT_LEFT_BUTTON ) && ( state == GLUT_DOWN ) ) { glGetIntegerv( GL_VIEWPORT, iViewport ); center_x = iViewport[2]/2; center_y = iViewport[3]/2; printf( "\nCenter X: %d\nCenter Y: %d\n\n", center_x, center_y ); do_selection( center_x, center_y, FALSE ); } if( ( button == GLUT_RIGHT_BUTTON ) && ( state == GLUT_DOWN ) ) sniper_mode = !sniper_mode; } //----------------------------------------------------------------------------- // Name: ReshapeFunction // Desc: Changes the viewport when the window is resized //----------------------------------------------------------------------------- void ReshapeFunction( GLsizei width, GLsizei height ) { // Prevent divide by zero exception if( !height ) height = 1; // Reset viewport glViewport( 0, 0, width, height ); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); // Reset perspective gluPerspective( 45.0f, (GLdouble) width/height, 0.1f, 500.0f ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); } //----------------------------------------------------------------------------- // Name: main // Desc: Program entry point. //----------------------------------------------------------------------------- int main( int argc, char* argv[] ) { // Initialize OpenGL via GLUT library glutInit( &argc, argv ); glutInitWindowSize( 640, 480 ); glutInitDisplayMode( GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGBA ); glutCreateWindow( "Meta-Balls!" ); // glutFullScreen(); // Initialize scene objects and properties InitScene(); // Set our input/output functions and begin the main loop glutIdleFunc( IdleFunction ); glutDisplayFunc( DisplayFunction ); glutKeyboardFunc( KeyboardFunction ); glutReshapeFunc( ReshapeFunction ); glutMouseFunc( MouseClickFunction ); glutPassiveMotionFunc( MouseFunction ); glutMainLoop(); return 0; }