/** \file TestCullingTerrainApplication.cpp \brief Tests the visibility culling algorithm */ #include #include #include <../CEGUIRenderer/include/OgreCEGUIRenderer.h> #include <../CEGUIRenderer/include/OgreCEGUIResourceProvider.h> #include <../CEGUIRenderer/include/OgreCEGUITexture.h> #include #include "Ogre.h" #include "TestCullingTerrainApplication.h" #define WIN32_LEAN_AND_MEAN #include /*******************************************************/ /* TestCullingTerrainApplication implementation */ /*******************************************************/ TestCullingTerrainApplication::~TestCullingTerrainApplication() { if(mTerrainContentGenerator) delete mTerrainContentGenerator; } //----------------------------------------------------------------------- void TestCullingTerrainApplication::createCamera() { // Create the camera mCamera = mSceneMgr->createCamera("CullCamera"); // Set a nice viewpoint mCamera->setPosition(707, 2500, 528); mCamera->setOrientation(Quaternion(-0.3486, 0.0122, 0.9365, 0.0329)); //--create cull camera mVisualizationCamera = mSceneMgr->createCamera("VisualizationCamera"); mVisualizationCamera->setPosition(707, 2500, 528); mVisualizationCamera->setOrientation(Quaternion(-0.3486, 0.0122, 0.9365, 0.0329)); mVisualizationCamera->setNearClipDistance(1); mCamera->setNearClipDistance(1); // Infinite far plane? if (mRoot->getRenderSystem()->getCapabilities()->hasCapability(RSC_INFINITE_FAR_PLANE)) { mVisualizationCamera->setFarClipDistance(0); mCamera->setFarClipDistance(0); } else { mVisualizationCamera->setFarClipDistance(1000); mCamera->setFarClipDistance(1000); } } //----------------------------------------------------------------------- void TestCullingTerrainApplication::createScene() { // Set ambient light mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5)); // Create a light Light* l = mSceneMgr->createLight("MainLight"); // Accept default settings: point light, white diffuse, just set position // NB I could attach the light to a SceneNode if I wanted it to move automatically with // other objects, but I don't l->setPosition(20,80,50); // --Fog // NB it's VERY important to set this before calling setWorldGeometry // because the vertex program picked will be different ColourValue fadeColour(0.93, 0.86, 0.76); mWindow->getViewport(0)->setBackgroundColour(fadeColour); //mSceneMgr->setFog( FOG_LINEAR, fadeColour, .001, 500, 1000); // Create a skybox mSceneMgr->setSkyBox(true, "Examples/SpaceSkyBox", 3500, false); //mSceneMgr->setSkyDome( true, "Examples/CloudySky", 5, 8, 500, false ); std::string terrain_cfg("terrain.cfg"); #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE terrain_cfg = mResourcePath + terrain_cfg; #endif mSceneMgr->setWorldGeometry(terrain_cfg); // CEGUI setup setupGui(); // HACK: necessary to call once before the content creation for // terrain initialisation mSceneMgr->_renderScene(mCamera, mWindow->getViewport(0), true); mTerrainContentGenerator = new TerrainContentGenerator(mSceneMgr); // mTerrainContentGenerator->GenerateScene(500, "ninja.mesh"); mTerrainContentGenerator->SetMaxPos(Vector3(3000.0f, 5000.0f, 3000.0f)); mTerrainContentGenerator->GenerateScene(1500, "robot.mesh"); // no limitations needed anymore: the user can set // objects also on peaks of terrain mTerrainContentGenerator->SetMaxHeight(5000); } //----------------------------------------------------------------------- void TestCullingTerrainApplication::setupGui() { mGUIRenderer = new CEGUI::OgreCEGUIRenderer(mWindow, Ogre::RENDER_QUEUE_OVERLAY, false, 3000, ST_EXTERIOR_CLOSE); mGUISystem = new CEGUI::System(mGUIRenderer); // Mouse CEGUI::SchemeManager::getSingleton().loadScheme((CEGUI::utf8*)"TaharezLook.scheme"); CEGUI::MouseCursor::getSingleton().setImage("TaharezLook", "MouseArrow"); mGUISystem->setDefaultMouseCursor( (CEGUI::utf8*)"TaharezLook", (CEGUI::utf8*)"MouseArrow"); CEGUI::MouseCursor::getSingleton().show(); } //----------------------------------------------------------------------- void TestCullingTerrainApplication::createFrameListener() { mFrameListener= new MouseQueryListener(mWindow, mCamera, mSceneMgr, mGUIRenderer, mTerrainContentGenerator, mVisualizationCamera); mFrameListener->showDebugOverlay(true); mRoot->addFrameListener(mFrameListener); } //----------------------------------------------------------------------- void TestCullingTerrainApplication::chooseSceneManager() { mSceneMgr = mRoot->getSceneManager(ST_EXTERIOR_CLOSE); } /***********************************************/ /* MouseQueryListener implementation */ /***********************************************/ //----------------------------------------------------------------------- MouseQueryListener::MouseQueryListener(RenderWindow* win, Camera* cam, SceneManager *sceneManager, CEGUI::Renderer *renderer, TerrainContentGenerator *sceneGenerator, Camera *vizCamera): ExampleFrameListener(win, cam, false, true), mGUIRenderer(renderer), mShutdownRequested(false), mLMouseDown(false), mRMouseDown(false), mSceneMgr(sceneManager), mCurrentObject(NULL), mTerrainContentGenerator(sceneGenerator), mVisibilityThreshold(0), mCurrentAlgorithm(GtpVisibility::VisibilityEnvironment::COHERENT_HIERARCHICAL_CULLING), mShowOctree(false), mUseCulling(true), mUseOptimization(true), mUseCullCamera(false), mVisualizationCamera(vizCamera) { // Reduce move speed mMoveSpeed = 50; mRotateSpeed *= 2; // Register this so that we get mouse events. mEventProcessor->addMouseListener(this); mEventProcessor->addMouseMotionListener(this); mEventProcessor->addKeyListener(this); mRayQueryExecutor = new RayQueryExecutor(mSceneMgr); // show overlay Overlay* pOver = OverlayManager::getSingleton().getByName("Example/VisibilityDemoOverlay"); mAlgorithmInfo = OverlayManager::getSingleton().getOverlayElement("Example/Visibility/AlgorithmInfo"); mThresholdInfo = OverlayManager::getSingleton().getOverlayElement("Example/Visibility/ThresholdInfo"); mFrustumCulledNodesInfo = OverlayManager::getSingleton().getOverlayElement("Example/Visibility/FrustumCulledNodesInfo"); mQueryCulledNodesInfo = OverlayManager::getSingleton().getOverlayElement("Example/Visibility/QueryCulledNodesInfo"); mTraversedNodesInfo = OverlayManager::getSingleton().getOverlayElement("Example/Visibility/TraversedNodesInfo"); mHierarchyNodesInfo = OverlayManager::getSingleton().getOverlayElement("Example/Visibility/HierarchyNodesInfo"); mRenderedNodesInfo = OverlayManager::getSingleton().getOverlayElement("Example/Visibility/RenderedNodesInfo"); mObjectsInfo = OverlayManager::getSingleton().getOverlayElement("Example/Visibility/ObjectsInfo"); mUseOptimizationInfo = OverlayManager::getSingleton().getOverlayElement("Example/Visibility/UseOptimizationInfo"); mQueriesIssuedInfo = OverlayManager::getSingleton().getOverlayElement("Example/Visibility/QueriesIssuedInfo"); mAlgorithmInfo->setCaption(": " + mCurrentAlgorithmCaptions[mCurrentAlgorithm]); mThresholdInfo->setCaption(": 0"); mFrustumCulledNodesInfo->setCaption(": 0"); mQueryCulledNodesInfo->setCaption(": 0"); mTraversedNodesInfo->setCaption(": 0"); mHierarchyNodesInfo->setCaption(": 0"); mRenderedNodesInfo->setCaption(": 0"); mObjectsInfo->setCaption(": 0"); mUseOptimizationInfo->setCaption(": true"); mQueriesIssuedInfo->setCaption(": 0"); setAlgorithm(mCurrentAlgorithm); mSceneMgr->setOption("UseOptimization", &mUseOptimization); mSceneMgr->setOption("UseCulling", &mUseCulling); mSceneMgr->setOption("CullCamera", &mUseCullCamera); mSceneMgr->setOption("ShowOctree", &mShowOctree); pOver->show(); } //----------------------------------------------------------------------- MouseQueryListener::~MouseQueryListener( ) { delete mRayQueryExecutor; } //----------------------------------------------------------------------- void MouseQueryListener::mouseMoved (MouseEvent *e) { // Update CEGUI with the mouse motion CEGUI::System::getSingleton().injectMouseMove(e->getRelX() * mGUIRenderer->getWidth(), e->getRelY() * mGUIRenderer->getHeight()); } //----------------------------------------------------------------------- void MouseQueryListener::mousePressed(MouseEvent* e) { // Left mouse button down if (e->getButtonID() & InputEvent::BUTTON0_MASK) { CEGUI::MouseCursor::getSingleton().hide(); // Setup the ray scene query Ray mouseRay = mCamera->getCameraToViewportRay(e->getX(), e->getY()); Vector3 queryResult; // Get results, create a node/entity on the position mCurrentObject = mTerrainContentGenerator->GenerateSceneObject( mouseRay.getOrigin(), mouseRay.getDirection(), "robot.mesh"); mLMouseDown = true; } // Right mouse button down else if (e->getButtonID() & InputEvent::BUTTON1_MASK) { CEGUI::MouseCursor::getSingleton().hide(); mRMouseDown = true; } // else if } // mousePressed //----------------------------------------------------------------------- void MouseQueryListener::mouseReleased(MouseEvent* e) { // Left mouse button up if (e->getButtonID() & InputEvent::BUTTON0_MASK) { CEGUI::MouseCursor::getSingleton().show(); mLMouseDown = false; } // Right mouse button up else if (e->getButtonID() & InputEvent::BUTTON1_MASK) { CEGUI::MouseCursor::getSingleton().show(); mRMouseDown = false; } } //----------------------------------------------------------------------- void MouseQueryListener::mouseDragged(MouseEvent *e) { // If we are dragging the left mouse button. if (mLMouseDown) { Vector3 queryResult; Ray mouseRay = mCamera->getCameraToViewportRay(e->getX(), e->getY()); if(mRayQueryExecutor->executeRayQuery(&queryResult, mouseRay)) { if(mCurrentObject) mCurrentObject->setPosition(queryResult); } } // If we are dragging the right mouse button. if (mRMouseDown) { mCamera->yaw( -e->getRelX() * mRotateSpeed ); mCamera->pitch( -e->getRelY() * mRotateSpeed ); } } //----------------------------------------------------------------------- bool MouseQueryListener::frameStarted(const FrameEvent &evt) { clamp2Terrain(mCamera); clamp2Terrain(mVisualizationCamera); return ExampleFrameListener::frameStarted(evt); } void MouseQueryListener::clamp2Terrain(Camera *cam) { // clamp to terrain Vector3 camPos = cam->getPosition(); Vector3 queryResult; if(mRayQueryExecutor->executeRayQuery(&queryResult, Vector3(camPos.x, 5000.0f, camPos.z), Vector3::NEGATIVE_UNIT_Y)) { cam->setPosition(cam->getPosition().x, queryResult.y + 10, cam->getPosition().z); } } //----------------------------------------------------------------------- bool MouseQueryListener::frameEnded(const FrameEvent& evt) { if (mShutdownRequested) return false; if (timeDelay >= 0) timeDelay -= evt.timeSinceLastFrame; KEY_PRESSED(KC_SPACE, 0.3, nextAlgorithm()); KEY_PRESSED(KC_SUBTRACT, 0, changeThreshold(-10)); KEY_PRESSED(KC_ADD, 0, changeThreshold(10)); KEY_PRESSED(KC_O, 0.3, toggleUseOptimization()); KEY_PRESSED(KC_Y, 0.3, toggleShowOctree()); KEY_PRESSED(KC_C, 0.3, toggleUseCulling()); KEY_PRESSED(KC_V, 0.3, toggleCullCamera()); KEY_PRESSED(KC_X, 0.3, FixVizCamera()); updateStats(); //if(mWindow->getViewport(1)) mWindow->getViewport(1)->update(); return ExampleFrameListener::frameStarted(evt) && ExampleFrameListener::frameEnded(evt); } //----------------------------------------------------------------------- void MouseQueryListener::changeThreshold(int incr) { mVisibilityThreshold += incr; if(mVisibilityThreshold < 0) mVisibilityThreshold = 0; char str[100]; sprintf(str,": %d", mVisibilityThreshold); mSceneMgr->setOption("Threshold", &mVisibilityThreshold); mThresholdInfo->setCaption(str); } //----------------------------------------------------------------------- void MouseQueryListener::nextAlgorithm() { mCurrentAlgorithm = ++mCurrentAlgorithm % GtpVisibility::VisibilityEnvironment::NUM_CULLING_MANAGERS, setAlgorithm(mCurrentAlgorithm); } //----------------------------------------------------------------------- void MouseQueryListener::setAlgorithm(int algorithm) { mAlgorithmInfo->setCaption(": " + mCurrentAlgorithmCaptions[mCurrentAlgorithm]); mSceneMgr->setOption("Algorithm", &mCurrentAlgorithm); } //----------------------------------------------------------------------- void MouseQueryListener::updateStats() { unsigned int opt = 0; char str[100]; mSceneMgr->getOption("NumFrustumCulledNodes", &opt); sprintf(str,": %d", opt); mFrustumCulledNodesInfo->setCaption(str); mSceneMgr->getOption("NumQueriesIssued", &opt); sprintf(str,": %d", opt); mQueriesIssuedInfo->setCaption(str); mSceneMgr->getOption("NumQueryCulledNodes", &opt); sprintf(str,": %d", opt); mQueryCulledNodesInfo->setCaption(str); mSceneMgr->getOption("NumTraversedNodes", &opt); sprintf(str,": %d", opt); mTraversedNodesInfo->setCaption(str); mSceneMgr->getOption("NumHierarchyNodes", &opt); sprintf(str,": %d", opt); mHierarchyNodesInfo->setCaption(str); mSceneMgr->getOption("NumRenderedNodes", &opt); sprintf(str,": %d", opt); mRenderedNodesInfo->setCaption(str); sprintf(str,": %d", mTerrainContentGenerator->GetObjectCount()); mObjectsInfo->setCaption(str); } //----------------------------------------------------------------------- void MouseQueryListener::toggleUseOptimization() { mUseOptimization = !mUseOptimization; mSceneMgr->setOption("UseOptimization", &mUseOptimization); if(mUseOptimization) mUseOptimizationInfo->setCaption(": true"); else mUseOptimizationInfo->setCaption(": false"); } //----------------------------------------------------------------------- void MouseQueryListener::toggleShowOctree() { mShowOctree = !mShowOctree; mSceneMgr->setOption("ShowOctree", &mShowOctree); } //----------------------------------------------------------------------- void MouseQueryListener::toggleUseCulling() { mUseCulling = !mUseCulling; mSceneMgr->setOption("UseCulling", &mUseCulling); } //----------------------------------------------------------------------- void MouseQueryListener::toggleCullCamera() { mUseCullCamera = !mUseCullCamera; if(mUseCullCamera) { mWindow->addViewport(mVisualizationCamera, 10, 0.5, 0.5, 1, 1); mWindow->getViewport(1)->setClearEveryFrame(true); } else mWindow->removeViewport(10); mSceneMgr->setOption("CullCamera", &mUseCullCamera); } //----------------------------------------------------------------------- void MouseQueryListener::FixVizCamera() { mVisualizationCamera->setPosition(mCamera->getPosition()); mVisualizationCamera->setOrientation(mCamera->getOrientation()); clamp2Terrain(mVisualizationCamera); } //----------------------------------------------------------------------- void MouseQueryListener::keyPressed(KeyEvent* e) { if(e->getKey() == KC_ESCAPE) { mShutdownRequested = true; e->consume(); return; } CEGUI::System::getSingleton().injectKeyDown(e->getKey()); CEGUI::System::getSingleton().injectChar(e->getKeyChar()); e->consume(); } //----------------------------------------------------------------------- void MouseQueryListener::keyReleased(KeyEvent* e) { CEGUI::System::getSingleton().injectKeyUp(e->getKey()); e->consume(); } //----------------------------------------------------------------------- void MouseQueryListener::keyClicked(KeyEvent* e) { // Do nothing e->consume(); } //----------------------------------------------------------------------- INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT ) { // Create application object TestCullingTerrainApplication app; try { app.go(); } catch( Ogre::Exception& e ) { MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL); } return 0; }