/******************************************************************************\ FILE: eventHandler.cpp PURPOSE: Handles the SDL events Created by Eric Akers 16 Dec 2003 ChangeLog: ELA - 16 Dec 2003 - Initial Working Version Copyright (C) 2003 Eric Akers This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA \******************************************************************************/ /* Header Files ############################################################# */ #include #include #include #include #include "connectFive.h" #include "guiContainer.h" #include "eventHandler.h" /* Macros ################################################################### */ /* Structures ############################################################### */ /* Global Variables ######################################################### */ // Dynamic rotation globals int screenBaseX = 0, screenBaseZ = 0; int lastScreenOffsetX = 0, lastScreenOffsetY = 0; bool mouseMotion = false; GLdouble screenRotateX = 0.0, screenRotateZ = 0.0; GLdouble distanceEyeCenter = DEFAULT_DISTANCE_EYE_CENTER; // Translation globals GLdouble screenMoveX = 0.0, screenMoveY = 0.0; // The font GLFont font; // Highlighting which position on the board to select int highlightCheckerX = -1, highlightCheckerY = -1; // Flag that determines when mouse picking happens bool mousePick = false; /* Function Declarations #################################################### */ /* Static Function Declarations ############################################# */ static void processHits( GLint hits, GLuint * buffer ); static void doPick( int x, int y ); /* Function Definitions #################################################### */ void eventHandler() { // Disable key repeat SDL_EnableKeyRepeat( 0, 0 ); SDL_Event currentEvent; bool mouseMotionEvent = false; // SDL_EnableKeyRepeat( 100, SDL_DEFAULT_REPEAT_INTERVAL ); SDL_EnableKeyRepeat( 100, 200 ); bool quit = false; while( !quit ) { // Mouse motion events happen too quickly. Try not to handle every one. mouseMotionEvent = false; SDL_Event lastMouseMotionEvent; // Count each event so that we can stop if there are continuous events at // a good round number. int count = 1; // Check each event // while( SDL_PollEvent( ¤tEvent ) ) { while( SDL_WaitEvent( ¤tEvent ) ) { count++; // Call Each event handler switch( currentEvent.type ) { case SDL_KEYDOWN: handleKeyDownEvent( currentEvent ); break; case SDL_KEYUP: handleKeyUpEvent( currentEvent ); break; case SDL_MOUSEMOTION: if( mouseMotionEvent ) { // Accumulate the relative movements lastMouseMotionEvent.motion.xrel += currentEvent.motion.xrel; lastMouseMotionEvent.motion.yrel += currentEvent.motion.yrel; } else { // The first mouse motion of this cycle mouseMotionEvent = true; lastMouseMotionEvent = currentEvent; } break; case SDL_MOUSEBUTTONDOWN: handleMouseButtonDownEvent( currentEvent ); break; case SDL_MOUSEBUTTONUP: handleMouseButtonUpEvent( currentEvent ); break; case SDL_ACTIVEEVENT: // Application has become visible display(); break; case SDL_QUIT: // Quit requested handleQuitEvent( currentEvent ); quit = true; break; case SDL_USEREVENT: // The user event occurred in demo mode. This is used for display // purposes only. display(); break; case PLAY_COMPUTER_MOVE: { // The user event used to place a computer move. int x = *((int*)currentEvent.user.data1); int y = *((int*)currentEvent.user.data2); delete (int*)currentEvent.user.data1; delete (int*)currentEvent.user.data2; printf( "PLAY COMPUTER MOVE EVENT: (%d,%d)\n", x, y ); printf( "\tState of board: %d\n", currentState->getPlayerAt(x, y) ); assert( currentState->getPlayerAt(x, y) == Board::BLANK ); int boardPlayer; char oldPlayer = getCurrentPlayer(); if( getCurrentPlayer() == PLAYER_1 ) { setCurrentPlayer( PLAYER_2 ); boardPlayer = Board::PLAYER_ONE; } else { setCurrentPlayer( PLAYER_1 ); boardPlayer = Board::PLAYER_TWO; } currentState->setPlayerMove( x, y, boardPlayer ); setLastMove( x, y ); // Set the labels for this play setGameLabel( getCurrentPlayer(), x, y ); // See if the game has been won if( currentState->isWinningState() ) { // Set game winner mode setGameWinner( oldPlayer ); } else { // See if the other player is also a computer if( getCurrentPlayerType() == COMPUTER_PLAYER ) { getNextComputerMove( x, y ); } } display(); break; } default: printf( "Unhandeled event!\n" ); break; } // switch( currentEvent ) // Make sure not to try to do too many events before handling a mouse // motion event. if( count >= MAX_EVENTS ) { break; } } // while( SDL_PollEvent ) // Check for a mouse motion event. These are handled here because mouse // motion events will flood the event queue otherwise, and take too much // time to handle each one separately. if( mouseMotionEvent ) { handleMouseMotionEvent( lastMouseMotionEvent ); } } // while( !quit ) } /* Static Function Definitions ############################################## */ void handleKeyDownEvent( SDL_Event & event ) { switch( event.key.keysym.sym ) { case SDLK_a: // Zoom In if( (distanceEyeCenter -= ZOOM_CHANGE) < MIN_ZOOM_DISTANCE ) { distanceEyeCenter = MIN_ZOOM_DISTANCE; } break; case SDLK_z: // Zoom Out if( (distanceEyeCenter += ZOOM_CHANGE) > MAX_ZOOM_DISTANCE ) { distanceEyeCenter = MAX_ZOOM_DISTANCE; } break; case SDLK_LEFT: // Translate the screen left if( (screenMoveX -= TRANSLATE_CHANGE) < (-MAX_TRANSLATE_DISTANCE) ) { screenMoveX = -MAX_TRANSLATE_DISTANCE; } break; case SDLK_RIGHT: // Translate the screen right if( (screenMoveX += TRANSLATE_CHANGE) > MAX_TRANSLATE_DISTANCE ) { screenMoveX = MAX_TRANSLATE_DISTANCE; } break; case SDLK_UP: // Translate the screen up if( (screenMoveY += TRANSLATE_CHANGE) > MAX_TRANSLATE_DISTANCE ) { screenMoveY = MAX_TRANSLATE_DISTANCE; } break; case SDLK_DOWN: // Translate the screen down if( (screenMoveY -= TRANSLATE_CHANGE) < (-MAX_TRANSLATE_DISTANCE) ) { screenMoveY = -MAX_TRANSLATE_DISTANCE; } break; case SDLK_c: // Center the image (translation only) screenMoveX = 0.0; screenMoveY = 0.0; break; case SDLK_d: // Reset all rotations screenRotateX = 0.0; screenRotateZ = 0.0; screenBaseX = 0; screenBaseZ = 0; lastScreenOffsetX = 0; lastScreenOffsetY = 0; break; case SDLK_ESCAPE: if( getGameMode() == MODE_DEMO ) { // Quit the game exit( 0 ); } else { // Set the mode to demo mode changeGameMode( MODE_DEMO ); } break; default: // Don't bother redrawing return; } // switch // Redraw display(); } void handleKeyUpEvent( SDL_Event & event ) { display(); } void handleMouseButtonDownEvent( SDL_Event & event ) { if( currentMenu->doMouseEvent( event.button.button, event.button.state, event.button.x, event.button.y ) ) { // Redraw display(); return; } // For rotations using the mouse if( event.button.button == SDL_BUTTON_LEFT ) { // Save the position where the button down event occurred screenBaseX = event.button.x; screenBaseZ = event.button.y; // Set the movement in motion mouseMotion = true; } else if( event.button.button == SDL_BUTTON_RIGHT ) { // This is for picking. Do not perform during demo mode // or finished game mode char mode = getGameMode(); char playerType = getCurrentPlayerType(); if( mode != MODE_DEMO && mode != MODE_GAME_FINISHED && playerType != COMPUTER_PLAYER ) { doPick( event.button.x, event.button.y ); mousePick = true; } } // Redraw if necessary display(); } void handleMouseButtonUpEvent( SDL_Event & event ) { if( currentMenu->doMouseEvent( event.button.button, event.button.state, event.button.x, event.button.y ) ) { // Redraw display(); return; } // For rotations using the mouse if( event.button.button == SDL_BUTTON_LEFT ) { // Save the last offset so that there will not be a jump // at the start of the next rotation lastScreenOffsetX += ( event.button.x - screenBaseX ); lastScreenOffsetY += ( event.button.y - screenBaseZ ); // Stop the rotations mouseMotion = false; } // For object picking else if( event.button.button == SDL_BUTTON_RIGHT && mousePick ) { // This is for picking mousePick = false; // Set the selected checker as the next chosen position if( highlightCheckerX != -1 ) { setNextPlay( highlightCheckerX, highlightCheckerY ); } } // Redraw if necessary display(); } void handleMouseMotionEvent( SDL_Event & event ) { if( mouseMotion == true ) { int newX = ( event.motion.x - screenBaseX ) + lastScreenOffsetX; int newY = ( event.motion.y - screenBaseZ ) + lastScreenOffsetY; // Scale pixel offsets to angle in degrees GLdouble scale = 360.0 / ROTATION_SCALE; // ??? pixels == 360 degrees screenRotateZ = scale * newX; screenRotateX = scale * newY; } else if( mousePick == true ) { doPick( event.motion.x, event.motion.y ); } // Redraw if necessary display(); } void handleQuitEvent( SDL_Event & event ) {} // Perform picking at the given mouse location static void doPick( int x, int y ) { // Get the viewport for picking GLint viewport[4]; glGetIntegerv( GL_VIEWPORT, viewport ); // Set the buffer for picking const int BUFSIZE = 512; GLuint selectBuf[BUFSIZE]; glSelectBuffer( BUFSIZE, selectBuf ); // Change to select mode when drawing (void) glRenderMode( GL_SELECT ); // Reset the name stack glInitNames(); // Setup the projection matrix glMatrixMode( GL_PROJECTION ); glPushMatrix(); glLoadIdentity(); // create 2x2 pixel picking region near cursor location gluPickMatrix( (GLdouble)x, (GLdouble)viewport[3] - y, 2.0, 2.0, viewport); setupProjectionMatrix( WIN_WIDTH, WIN_HEIGHT, FOVY, ZNEAR, ZFAR ); // Draw the scene setupModelViewMatrix(); drawScene(); glMatrixMode( GL_PROJECTION ); glPopMatrix(); glFlush(); // Now change back to render mode and determine the number of hits int nHits = glRenderMode( GL_RENDER ); // process each hit processHits( nHits, selectBuf ); } // Process the picking results to determine which checker was picked static void processHits( GLint hits, GLuint * buffer ) { bool found = false; GLfloat minZ; // The range of the z is from 0 to 1 GLuint *ptr = buffer; GLuint numNames; for( int i=0; i