/* ----------------------------------------------------------------------------- This source file is part of OGRE (Object-oriented Graphics Rendering Engine) For the latest info, see http://www.ogre3d.org/ Copyright (c) 2000-2005 The OGRE Team Also see acknowledgements in Readme.html You may use this sample code for anything you like, it is not covered by the LGPL like the rest of the engine. ----------------------------------------------------------------------------- */ /* ----------------------------------------------------------------------------- Filename: ExampleFrameListener.h Description: Defines an example frame listener which responds to frame events. This frame listener just moves a specified camera around based on keyboard and mouse movements. Mouse: Freelook W or Up: Forward S or Down:Backward A: Step left D: Step right PgUp: Move upwards PgDown: Move downwards F: Toggle frame rate stats on/off R: Render mode T: Cycle texture filtering Bilinear, Trilinear, Anisotropic(8) P: Toggle on/off display of camera position / orientation ----------------------------------------------------------------------------- */ #ifndef __ExampleFrameListener_H__ #define __ExampleFrameListener_H__ #include "Ogre.h" #include "OgreKeyEvent.h" #include "OgreEventListeners.h" #include "OgreStringConverter.h" #include "OgreException.h" using namespace Ogre; class ExampleFrameListener: public FrameListener, public KeyListener { protected: int mSceneDetailIndex ; Real mMoveSpeed; Degree mRotateSpeed; Overlay* mDebugOverlay; void updateStats(void) { static String currFps = "Current FPS: "; static String avgFps = "Average FPS: "; static String bestFps = "Best FPS: "; static String worstFps = "Worst FPS: "; static String tris = "Triangle Count: "; // update stats when necessary try { OverlayElement* guiAvg = OverlayManager::getSingleton().getOverlayElement("Core/AverageFps"); OverlayElement* guiCurr = OverlayManager::getSingleton().getOverlayElement("Core/CurrFps"); OverlayElement* guiBest = OverlayManager::getSingleton().getOverlayElement("Core/BestFps"); OverlayElement* guiWorst = OverlayManager::getSingleton().getOverlayElement("Core/WorstFps"); const RenderTarget::FrameStats& stats = mWindow->getStatistics(); guiAvg->setCaption(avgFps + StringConverter::toString(stats.avgFPS)); guiCurr->setCaption(currFps + StringConverter::toString(stats.lastFPS)); guiBest->setCaption(bestFps + StringConverter::toString(stats.bestFPS) +" "+StringConverter::toString(stats.bestFrameTime)+" ms"); guiWorst->setCaption(worstFps + StringConverter::toString(stats.worstFPS) +" "+StringConverter::toString(stats.worstFrameTime)+" ms"); OverlayElement* guiTris = OverlayManager::getSingleton().getOverlayElement("Core/NumTris"); guiTris->setCaption(tris + StringConverter::toString(stats.triangleCount)); OverlayElement* guiDbg = OverlayManager::getSingleton().getOverlayElement("Core/DebugText"); guiDbg->setCaption(mWindow->getDebugText()); } catch(...) { // ignore } } public: // Constructor takes a RenderWindow because it uses that to determine input context ExampleFrameListener(RenderWindow* win, Camera* cam, bool useBufferedInputKeys = false, bool useBufferedInputMouse = false) { mDebugOverlay = OverlayManager::getSingleton().getByName("Core/DebugOverlay"); mUseBufferedInputKeys = useBufferedInputKeys; mUseBufferedInputMouse = useBufferedInputMouse; mInputTypeSwitchingOn = mUseBufferedInputKeys || mUseBufferedInputMouse; mRotateSpeed = 36; mMoveSpeed = 100; if (mInputTypeSwitchingOn) { mEventProcessor = new EventProcessor(); mEventProcessor->initialise(win); mEventProcessor->startProcessingEvents(); mEventProcessor->addKeyListener(this); mInputDevice = mEventProcessor->getInputReader(); } else { mInputDevice = PlatformManager::getSingleton().createInputReader(); mInputDevice->initialise(win,true, true); } mCamera = cam; mWindow = win; mStatsOn = true; mNumScreenShots = 0; mTimeUntilNextToggle = 0; mSceneDetailIndex = 0; mMoveScale = 0.0f; mRotScale = 0.0f; mTranslateVector = Vector3::ZERO; mAniso = 1; mFiltering = TFO_BILINEAR; showDebugOverlay(true); } virtual ~ExampleFrameListener() { if (mInputTypeSwitchingOn) { delete mEventProcessor; } else { PlatformManager::getSingleton().destroyInputReader( mInputDevice ); } } virtual bool processUnbufferedKeyInput(const FrameEvent& evt) { if (mInputDevice->isKeyDown(KC_A)) { // Move camera left mTranslateVector.x = -mMoveScale; } if (mInputDevice->isKeyDown(KC_D)) { // Move camera RIGHT mTranslateVector.x = mMoveScale; } /* Move camera forward by keypress. */ if (mInputDevice->isKeyDown(KC_UP) || mInputDevice->isKeyDown(KC_W) ) { mTranslateVector.z = -mMoveScale; } /* Move camera backward by keypress. */ if (mInputDevice->isKeyDown(KC_DOWN) || mInputDevice->isKeyDown(KC_S) ) { mTranslateVector.z = mMoveScale; } if (mInputDevice->isKeyDown(KC_PGUP)) { // Move camera up mTranslateVector.y = mMoveScale; } if (mInputDevice->isKeyDown(KC_PGDOWN)) { // Move camera down mTranslateVector.y = -mMoveScale; } if (mInputDevice->isKeyDown(KC_RIGHT)) { mCamera->yaw(-mRotScale); } if (mInputDevice->isKeyDown(KC_LEFT)) { mCamera->yaw(mRotScale); } if( mInputDevice->isKeyDown( KC_ESCAPE) ) { return false; } // see if switching is on, and you want to toggle if (mInputTypeSwitchingOn && mInputDevice->isKeyDown(KC_M) && mTimeUntilNextToggle <= 0) { switchMouseMode(); mTimeUntilNextToggle = 1; } if (mInputTypeSwitchingOn && mInputDevice->isKeyDown(KC_K) && mTimeUntilNextToggle <= 0) { // must be going from immediate keyboard to buffered keyboard switchKeyMode(); mTimeUntilNextToggle = 1; } if (mInputDevice->isKeyDown(KC_F) && mTimeUntilNextToggle <= 0) { mStatsOn = !mStatsOn; showDebugOverlay(mStatsOn); mTimeUntilNextToggle = 1; } if (mInputDevice->isKeyDown(KC_T) && mTimeUntilNextToggle <= 0) { switch(mFiltering) { case TFO_BILINEAR: mFiltering = TFO_TRILINEAR; mAniso = 1; break; case TFO_TRILINEAR: mFiltering = TFO_ANISOTROPIC; mAniso = 8; break; case TFO_ANISOTROPIC: mFiltering = TFO_BILINEAR; mAniso = 1; break; default: break; } MaterialManager::getSingleton().setDefaultTextureFiltering(mFiltering); MaterialManager::getSingleton().setDefaultAnisotropy(mAniso); showDebugOverlay(mStatsOn); mTimeUntilNextToggle = 1; } if (mInputDevice->isKeyDown(KC_SYSRQ) && mTimeUntilNextToggle <= 0) { char tmp[20]; sprintf(tmp, "screenshot_%d.png", ++mNumScreenShots); mWindow->writeContentsToFile(tmp); mTimeUntilNextToggle = 0.5; mWindow->setDebugText(String("Wrote ") + tmp); } if (mInputDevice->isKeyDown(KC_R) && mTimeUntilNextToggle <=0) { mSceneDetailIndex = (mSceneDetailIndex+1)%3 ; switch(mSceneDetailIndex) { case 0 : mCamera->setDetailLevel(SDL_SOLID) ; break ; case 1 : mCamera->setDetailLevel(SDL_WIREFRAME) ; break ; case 2 : mCamera->setDetailLevel(SDL_POINTS) ; break ; } mTimeUntilNextToggle = 0.5; } static bool displayCameraDetails = false; if (mInputDevice->isKeyDown(KC_P) && mTimeUntilNextToggle <= 0) { displayCameraDetails = !displayCameraDetails; mTimeUntilNextToggle = 0.5; if (!displayCameraDetails) mWindow->setDebugText(""); } if (displayCameraDetails) { // Print camera details mWindow->setDebugText("P: " + StringConverter::toString(mCamera->getDerivedPosition()) + " " + "O: " + StringConverter::toString(mCamera->getDerivedOrientation())); } // Return true to continue rendering return true; } bool processUnbufferedMouseInput(const FrameEvent& evt) { /* Rotation factors, may not be used if the second mouse button is pressed. */ /* If the second mouse button is pressed, then the mouse movement results in sliding the camera, otherwise we rotate. */ if( mInputDevice->getMouseButton( 1 ) ) { mTranslateVector.x += mInputDevice->getMouseRelativeX() * 0.13; mTranslateVector.y -= mInputDevice->getMouseRelativeY() * 0.13; } else { mRotX = Degree(-mInputDevice->getMouseRelativeX() * 0.13); mRotY = Degree(-mInputDevice->getMouseRelativeY() * 0.13); } return true; } void moveCamera() { // Make all the changes to the camera // Note that YAW direction is around a fixed axis (freelook style) rather than a natural YAW (e.g. airplane) mCamera->yaw(mRotX); mCamera->pitch(mRotY); mCamera->moveRelative(mTranslateVector); } void showDebugOverlay(bool show) { if (mDebugOverlay) { if (show) { mDebugOverlay->show(); } else { mDebugOverlay->hide(); } } } // Override frameStarted event to process that (don't care about frameEnded) bool frameStarted(const FrameEvent& evt) { if(mWindow->isClosed()) return false; if (!mInputTypeSwitchingOn) { mInputDevice->capture(); } if ( !mUseBufferedInputMouse || !mUseBufferedInputKeys) { // one of the input modes is immediate, so setup what is needed for immediate mouse/key movement if (mTimeUntilNextToggle >= 0) mTimeUntilNextToggle -= evt.timeSinceLastFrame; // If this is the first frame, pick a speed if (evt.timeSinceLastFrame == 0) { mMoveScale = 1; mRotScale = 0.1; } // Otherwise scale movement units by time passed since last frame else { // Move about 100 units per second, mMoveScale = mMoveSpeed * evt.timeSinceLastFrame; // Take about 10 seconds for full rotation mRotScale = mRotateSpeed * evt.timeSinceLastFrame; } mRotX = 0; mRotY = 0; mTranslateVector = Vector3::ZERO; } if (mUseBufferedInputKeys) { // no need to do any processing here, it is handled by event processor and // you get the results as KeyEvents } else { if (processUnbufferedKeyInput(evt) == false) { return false; } } if (mUseBufferedInputMouse) { // no need to do any processing here, it is handled by event processor and // you get the results as MouseEvents } else { if (processUnbufferedMouseInput(evt) == false) { return false; } } if ( !mUseBufferedInputMouse || !mUseBufferedInputKeys) { // one of the input modes is immediate, so update the movement vector moveCamera(); } return true; } bool frameEnded(const FrameEvent& evt) { updateStats(); return true; } void switchMouseMode() { mUseBufferedInputMouse = !mUseBufferedInputMouse; mInputDevice->setBufferedInput(mUseBufferedInputKeys, mUseBufferedInputMouse); } void switchKeyMode() { mUseBufferedInputKeys = !mUseBufferedInputKeys; mInputDevice->setBufferedInput(mUseBufferedInputKeys, mUseBufferedInputMouse); } void keyClicked(KeyEvent* e) { if (e->getKeyChar() == 'm') { switchMouseMode(); } else if (e->getKeyChar() == 'k') { switchKeyMode(); } } void keyPressed(KeyEvent* e) {} void keyReleased(KeyEvent* e) {} protected: EventProcessor* mEventProcessor; InputReader* mInputDevice; Camera* mCamera; Vector3 mTranslateVector; RenderWindow* mWindow; bool mStatsOn; bool mUseBufferedInputKeys, mUseBufferedInputMouse, mInputTypeSwitchingOn; unsigned int mNumScreenShots; float mMoveScale; Degree mRotScale; // just to stop toggles flipping too fast Real mTimeUntilNextToggle ; Radian mRotX, mRotY; TextureFilterOptions mFiltering; int mAniso; }; #endif