/** \file TestCullingTerrainApplication.cpp \brief Tests the occlusion 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" #include "OgreOcclusionCullingSceneTraverser.h" #define WIN32_LEAN_AND_MEAN #include "windows.h" //RaySceneQuery* mRaySceneQuery = 0; /***********************************************/ /* TestCullingTerrainApplication implementation */ /***********************************************/ /*TestCullingTerrainApplication::~TestCullingTerrainApplication() { delete mRaySceneQuery; }*/ //----------------------------------------------------------------------- void TestCullingTerrainApplication::createCamera( void ) { // Create the camera mCamera = mSceneMgr->createCamera("PlayerCam"); // Position it at 500 in Z direction mCamera->setPosition(Vector3(128,25,128)); // Look back along -Z mCamera->lookAt(Vector3(0,0,-300)); mCamera->setNearClipDistance( 1 ); mCamera->setFarClipDistance( 1000 ); } //----------------------------------------------------------------------- void TestCullingTerrainApplication::createScene(void) { // 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); //mSceneMgr->setFog( FOG_EXP, fadeColour, 0.005 ); // Create a skybox //mSceneMgr->setSkyBox(true, "Examples/SpaceSkyBox", 500, false); //mSceneMgr->setSkyDome( true, "Examples/CloudySky", 5, 8, 500, false ); /* // Define the required skyplane Plane plane; // 5000 world units from the camera plane.d = 5000; // Above the camera, facing down plane.normal = -Vector3::UNIT_Y; // Create the plane 10000 units wide, tile the texture 3 times mSceneMgr->setSkyPlane(true, plane, "Examples/SpaceSkyPlane",10000,3);*/ std::string terrain_cfg("terrain.cfg"); #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE terrain_cfg = mResourcePath + terrain_cfg; #endif mSceneMgr -> setWorldGeometry( terrain_cfg ); // Infinite far plane? if (mRoot->getRenderSystem()->getCapabilities()->hasCapability(RSC_INFINITE_FAR_PLANE)) { mCamera->setFarClipDistance(0); } // Set a nice viewpoint mCamera->setPosition(707,2500,528); mCamera->setOrientation(Quaternion(-0.3486, 0.0122, 0.9365, 0.0329)); /* Entity *robotEnt = mSceneMgr->createEntity( "Robot", "robot.mesh" ); SceneNode *robotNode = mSceneMgr->getRootSceneNode()->createChildSceneNode( "RobotNode", Vector3( 750, 25, 600 )); robotNode->attachObject( robotEnt ); robotNode->scale( .3, .3, .3 ); robotNode->yaw( Degree( 160 ) ); Entity *ogreEnt = mSceneMgr->createEntity( "Ogre", "ogrehead.mesh" ); SceneNode *ogreNode = mSceneMgr->getRootSceneNode()->createChildSceneNode( "Ogre", Vector3( 800, 50, 830 ) ); ogreNode->attachObject( ogreEnt ); ogreNode->scale(.2,.2,.2); ogreNode->yaw( Degree( 20 ) ); Entity *ogreEnt2 = mSceneMgr->createEntity( "Ogre2", "ogrehead.mesh" ); SceneNode *ogreNode2 = mSceneMgr->getRootSceneNode()->createChildSceneNode( "Ogre2", Vector3( 700, 50, 730 ) ); ogreNode2->attachObject( ogreEnt2 ); ogreNode2->scale(.05,.05,.05); ogreNode->yaw( Degree( 40 ) );*/ // CEGUI setup setupGui(); } //----------------------------------------------------------------------- void TestCullingTerrainApplication::setupGui( void ) { 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(void) { mFrameListener= new MouseQueryListener(mWindow, mCamera, mSceneMgr, mGUIRenderer); mFrameListener->showDebugOverlay(true); mRoot->addFrameListener(mFrameListener); } //----------------------------------------------------------------------- void TestCullingTerrainApplication::chooseSceneManager(void) { //mSceneMgr = mRoot->getSceneManager(ST_GENERIC); mSceneMgr = mRoot->getSceneManager(ST_EXTERIOR_CLOSE); } /***********************************************/ /* MouseQueryListener implementation */ /***********************************************/ //----------------------------------------------------------------------- MouseQueryListener::MouseQueryListener(RenderWindow* win, Camera* cam, SceneManager *sceneManager, CEGUI::Renderer *renderer) : ExampleFrameListener(win, cam, false, true), mGUIRenderer(renderer), mShutdownRequested(false) { // Setup default variables mCurrentObject = NULL; mLMouseDown = false; mRMouseDown = false; mSceneMgr = sceneManager; // Reduce move speed mMoveSpeed = 50; mRotateSpeed *= 2; mCurrentAlgorithm = OcclusionCullingSceneTraverser::RENDER_COHERENT; mThreshold = 0; // Register this so that we get mouse events. mEventProcessor->addMouseListener(this); mEventProcessor->addMouseMotionListener(this); mEventProcessor->addKeyListener(this); mRaySceneQuery = mSceneMgr->createRayQuery( Ray() ); // show overlay Overlay* pOver = OverlayManager::getSingleton().getByName("Example/OcclusionCullingDemoOverlay"); mAlgorithmInfo = OverlayManager::getSingleton().getOverlayElement("Example/Occlusion/AlgorithmInfo"); mThresholdInfo = OverlayManager::getSingleton().getOverlayElement("Example/Occlusion/ThresholdInfo"); mFrustumCulledNodesInfo = OverlayManager::getSingleton().getOverlayElement("Example/Occlusion/FrustumCulledNodesInfo"); mQueryCulledNodesInfo = OverlayManager::getSingleton().getOverlayElement("Example/Occlusion/QueryCulledNodesInfo"); mTraversedNodesInfo = OverlayManager::getSingleton().getOverlayElement("Example/Occlusion/TraversedNodesInfo"); mSceneNodesInfo = OverlayManager::getSingleton().getOverlayElement("Example/Occlusion/SceneNodesInfo"); mHierarchyNodesInfo = OverlayManager::getSingleton().getOverlayElement("Example/Occlusion/HierarchyNodesInfo"); mAlgorithmInfo->setCaption(": " + mCurrentAlgorithmCaptions[mCurrentAlgorithm]); mThresholdInfo->setCaption(": 0"); mFrustumCulledNodesInfo->setCaption(": 0"); mQueryCulledNodesInfo->setCaption(": 0"); mTraversedNodesInfo->setCaption(": 0"); mSceneNodesInfo->setCaption(": 0"); mHierarchyNodesInfo->setCaption(": 0"); pOver->show(); } //----------------------------------------------------------------------- MouseQueryListener::~MouseQueryListener( ) { delete mRaySceneQuery; } //----------------------------------------------------------------------- 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() ); mRaySceneQuery->setRay( mouseRay ); // Execute query RaySceneQueryResult &result = mRaySceneQuery->execute(); RaySceneQueryResult::iterator itr = result.begin( ); // Get results, create a node/entity on the position if ( itr != result.end() && itr->worldFragment ) { char name[16]; sprintf( name, "Robot%d", mCount++ ); Entity *ent = mSceneMgr->createEntity( name, "robot.mesh" ); mCurrentObject = mSceneMgr->getRootSceneNode( )->createChildSceneNode( String(name) + "Node", itr->worldFragment->singleIntersection ); mCurrentObject->attachObject( ent ); mCurrentObject->setScale( 0.1f, 0.1f, 0.1f ); } 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 ) { Ray mouseRay = mCamera->getCameraToViewportRay( e->getX(), e->getY() ); mRaySceneQuery->setRay( mouseRay ); RaySceneQueryResult &result = mRaySceneQuery->execute(); RaySceneQueryResult::iterator itr = result.begin( ); if ( itr != result.end() && itr->worldFragment ) { mCurrentObject->setPosition( itr->worldFragment->singleIntersection ); } } // 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) { // clamp to terrain Vector3 camPos = mCamera->getPosition( ); Ray cameraRay( Vector3(camPos.x, 5000.0f, camPos.z), Vector3::NEGATIVE_UNIT_Y ); mRaySceneQuery->setRay( cameraRay ); // Perform the scene query RaySceneQueryResult &queryResult = mRaySceneQuery->execute(); RaySceneQueryResult::iterator it = queryResult.begin( ); if (it != queryResult.end() && it->worldFragment) { SceneQuery::WorldFragment* wf = it->worldFragment; mCamera->setPosition(mCamera->getPosition().x, wf->singleIntersection.y + 10, mCamera->getPosition().z); } return ExampleFrameListener::frameStarted(evt); } //----------------------------------------------------------------------- bool MouseQueryListener::frameEnded(const FrameEvent& evt) { if (mShutdownRequested) return false; if (timeDelay >= 0) timeDelay -= evt.timeSinceLastFrame; KEY_PRESSED(KC_SPACE, 0.3, changeAlgorithm()); KEY_PRESSED(KC_SUBTRACT, 0, changeThreshold(-10)); KEY_PRESSED(KC_ADD, 0, changeThreshold(10)); //KEY_PRESSED(KC_T, 1, change); changeStats(); return ExampleFrameListener::frameStarted(evt) && ExampleFrameListener::frameEnded(evt); } //----------------------------------------------------------------------- void MouseQueryListener::changeThreshold(int incr) { mThreshold += incr; if(mThreshold < 0) mThreshold = 0; char str[100]; sprintf(str,": %d", mThreshold); mSceneMgr->setOption("Threshold", &mThreshold); mThresholdInfo->setCaption(str); } //----------------------------------------------------------------------- void MouseQueryListener::changeAlgorithm() { mCurrentAlgorithm = ++mCurrentAlgorithm % OcclusionCullingSceneTraverser::NUM_RENDERMODES; mAlgorithmInfo->setCaption(": " + mCurrentAlgorithmCaptions[mCurrentAlgorithm]); mSceneMgr->setOption("Algorithm", &mCurrentAlgorithm); } //----------------------------------------------------------------------- void MouseQueryListener::changeStats() { unsigned int opt = 0; char str[100]; mSceneMgr->getOption("NumFrustumCulledNodes", &opt); sprintf(str,": %d", opt); mFrustumCulledNodesInfo->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("NumSceneNodes", &opt); sprintf(str,": %d", opt); mSceneNodesInfo->setCaption(str); mSceneMgr->getOption("NumOctreeNodes", &opt); sprintf(str,": %d", opt); mHierarchyNodesInfo->setCaption(str); } //----------------------------------------------------------------------- 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; }