/** \file TestCullingApplication.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 "OgreLight.h" #include "tinyxml.h" #include "TestCullingDotSceneApplication.h" #define WIN32_LEAN_AND_MEAN #include "windows.h" /***********************************************/ /* TestCullingDotSceneApplication implementation */ /***********************************************/ void TestCullingDotSceneApplication::ParseDotScene( const String &SceneName, const String& groupName ) { TiXmlDocument *XMLDoc; TiXmlElement *XMLRoot, *XMLNodes, *XMLPathFind; try { DataStreamPtr pStream = ResourceGroupManager::getSingleton().openResource( SceneName, groupName ); String data = pStream->getAsString(); // Open the .scene File XMLDoc = new TiXmlDocument(); XMLDoc->Parse( data.c_str() ); pStream->close(); pStream.setNull(); if( XMLDoc->Error() ) { //We'll just log, and continue on gracefully LogManager::getSingleton().logMessage("Error in dotscene demo app!!!!!"); delete XMLDoc; return; } } catch(...) { //We'll just log, and continue on gracefully LogManager::getSingleton().logMessage("Error in dotscene demo app!!!!!"); delete XMLDoc; return; } // Validate the File XMLRoot = XMLDoc->RootElement(); if( String( XMLRoot->Value()) != "scene" ) { LogManager::getSingleton().logMessage( "Error: Invalid .scene File. Missing " ); delete XMLDoc; return; } XMLNodes = XMLRoot->FirstChildElement( "nodes" ); // Read in the scene nodes if( XMLNodes ) { TiXmlElement *XMLNode, *XMLPosition, *XMLRotation, *XMLScale, *XMLEntity, *XMLBillboardSet, *XMLLight; XMLNode = XMLNodes->FirstChildElement( "node" ); while( XMLNode ) { // Process the current node // Grab the name of the node String NodeName = XMLNode->Attribute("name"); // First create the new scene node SceneNode* NewNode = static_cast( mSceneMgr->getRootSceneNode()->createChild( NodeName ) ); Vector3 TempVec; String TempValue; // Now position it... XMLPosition = XMLNode->FirstChildElement("position"); if( XMLPosition ) { TempValue = XMLPosition->Attribute("x"); TempVec.x = StringConverter::parseReal(TempValue); TempValue = XMLPosition->Attribute("y"); TempVec.y = StringConverter::parseReal(TempValue); TempValue = XMLPosition->Attribute("z"); TempVec.z = StringConverter::parseReal(TempValue); NewNode->setPosition( TempVec ); } // Rotate it... XMLRotation = XMLNode->FirstChildElement("rotation"); if( XMLRotation ) { Quaternion TempQuat; TempValue = XMLRotation->Attribute("qx"); TempQuat.x = StringConverter::parseReal(TempValue); TempValue = XMLRotation->Attribute("qy"); TempQuat.y = StringConverter::parseReal(TempValue); TempValue = XMLRotation->Attribute("qz"); TempQuat.z = StringConverter::parseReal(TempValue); TempValue = XMLRotation->Attribute("qw"); TempQuat.w = StringConverter::parseReal(TempValue); NewNode->setOrientation( TempQuat ); } // Scale it. XMLScale = XMLNode->FirstChildElement("scale"); if( XMLScale ) { TempValue = XMLScale->Attribute("x"); TempVec.x = StringConverter::parseReal(TempValue); TempValue = XMLScale->Attribute("y"); TempVec.y = StringConverter::parseReal(TempValue); TempValue = XMLScale->Attribute("z"); TempVec.z = StringConverter::parseReal(TempValue); NewNode->setScale( TempVec ); } XMLLight = XMLNode->FirstChildElement( "light" ); if( XMLLight ) NewNode->attachObject( LoadLight( XMLLight ) ); // Check for an Entity XMLEntity = XMLNode->FirstChildElement("entity"); if( XMLEntity ) { if( XMLEntity->Attribute("static") ) { if( strcmp( XMLEntity->Attribute("static"), "false" )==0 ){ String EntityName, EntityMeshFilename; EntityName = XMLEntity->Attribute( "name" ); EntityMeshFilename = XMLEntity->Attribute( "meshFile" ); // Create entity Entity* NewEntity = mSceneMgr->createEntity(EntityName, EntityMeshFilename); NewNode->attachObject( NewEntity ); } } } XMLBillboardSet = XMLNode->FirstChildElement( "billboardSet" ); if( XMLBillboardSet ) { String TempValue; BillboardSet* bSet = mSceneMgr->createBillboardSet( NewNode->getName() ); BillboardType Type; TempValue = XMLBillboardSet->Attribute( "type" ); if( TempValue == "orientedCommon" ) Type = BBT_ORIENTED_COMMON; else if( TempValue == "orientedSelf" ) Type = BBT_ORIENTED_SELF; else Type = BBT_POINT; BillboardOrigin Origin; TempValue = XMLBillboardSet->Attribute( "type" ); if( TempValue == "bottom_left" ) Origin = BBO_BOTTOM_LEFT; else if( TempValue == "bottom_center" ) Origin = BBO_BOTTOM_CENTER; else if( TempValue == "bottomRight" ) Origin = BBO_BOTTOM_RIGHT; else if( TempValue == "left" ) Origin = BBO_CENTER_LEFT; else if( TempValue == "right" ) Origin = BBO_CENTER_RIGHT; else if( TempValue == "topLeft" ) Origin = BBO_TOP_LEFT; else if( TempValue == "topCenter" ) Origin = BBO_TOP_CENTER; else if( TempValue == "topRight" ) Origin = BBO_TOP_RIGHT; else Origin = BBO_CENTER; bSet->setBillboardType( Type ); bSet->setBillboardOrigin( Origin ); TempValue = XMLBillboardSet->Attribute( "name" ); bSet->setMaterialName( TempValue ); int width, height; width = StringConverter::parseReal( XMLBillboardSet->Attribute( "width" ) ); height = StringConverter::parseReal( XMLBillboardSet->Attribute( "height" ) ); bSet->setDefaultDimensions( width, height ); bSet->setVisible( true ); NewNode->attachObject( bSet ); TiXmlElement *XMLBillboard; XMLBillboard = XMLBillboardSet->FirstChildElement( "billboard" ); while( XMLBillboard ) { Billboard *b; TempValue; TempVec = Vector3( 0, 0, 0 ); ColourValue TempColour(1,1,1,1); XMLPosition = XMLBillboard->FirstChildElement( "position" ); if( XMLPosition ){ TempValue = XMLPosition->Attribute("x"); TempVec.x = StringConverter::parseReal(TempValue); TempValue = XMLPosition->Attribute("y"); TempVec.y = StringConverter::parseReal(TempValue); TempValue = XMLPosition->Attribute("z"); TempVec.z = StringConverter::parseReal(TempValue); } TiXmlElement* XMLColour = XMLBillboard->FirstChildElement( "colourDiffuse" ); if( XMLColour ) { TempValue = XMLColour->Attribute("r"); TempColour.r = StringConverter::parseReal(TempValue); TempValue = XMLColour->Attribute("g"); TempColour.g = StringConverter::parseReal(TempValue); TempValue = XMLColour->Attribute("b"); TempColour.b = StringConverter::parseReal(TempValue); } b = bSet->createBillboard( TempVec, TempColour); XMLBillboard = XMLBillboard->NextSiblingElement( "billboard" ); } } // Move to the next node XMLNode = XMLNode->NextSiblingElement( "node" ); } } // Close the XML File delete XMLDoc; } Light* TestCullingDotSceneApplication::LoadLight( TiXmlElement *XMLLight ) { TiXmlElement *XMLDiffuse, *XMLSpecular, *XMLAttentuation, *XMLPosition; // Create a light (point | directional | spot | radPoint) Light* light = mSceneMgr->createLight( XMLLight->Attribute("name") ); if( !XMLLight->Attribute("type") || String(XMLLight->Attribute("type")) == "point" ) light->setType( Light::LT_POINT ); else if( String(XMLLight->Attribute("type")) == "directional") light->setType( Light::LT_DIRECTIONAL ); else if( String(XMLLight->Attribute("type")) == "spot") light->setType( Light::LT_SPOTLIGHT ); else if( String(XMLLight->Attribute("type")) == "radPoint") light->setType( Light::LT_POINT ); XMLDiffuse = XMLLight->FirstChildElement("colourDiffuse"); if( XMLDiffuse ) { ColourValue Diffuse; Diffuse.r = Ogre::StringConverter::parseReal( XMLDiffuse->Attribute("r") ); Diffuse.g = Ogre::StringConverter::parseReal( XMLDiffuse->Attribute("g") ); Diffuse.b = Ogre::StringConverter::parseReal( XMLDiffuse->Attribute("b") ); Diffuse.a = 1; light->setDiffuseColour(Diffuse); } XMLSpecular = XMLLight->FirstChildElement("colourSpecular"); if( XMLSpecular ) { ColourValue Specular; Specular.r = Ogre::StringConverter::parseReal( XMLSpecular->Attribute("r") ); Specular.g = Ogre::StringConverter::parseReal( XMLSpecular->Attribute("g") ); Specular.b = Ogre::StringConverter::parseReal( XMLSpecular->Attribute("b") ); Specular.a = 1; light->setSpecularColour(Specular); } XMLAttentuation = XMLLight->FirstChildElement("lightAttenuation"); if( XMLAttentuation ) { //get defaults incase not all values specified Real range, constant, linear, quadratic; range = light->getAttenuationRange(); constant = light->getAttenuationConstant(); linear = light->getAttenuationLinear(); quadratic = light->getAttenuationQuadric(); if( XMLAttentuation->Attribute("range") ) range = StringConverter::parseReal( XMLAttentuation->Attribute("range") ); if( XMLAttentuation->Attribute("constant") ) constant = StringConverter::parseReal( XMLAttentuation->Attribute("constant") ); if( XMLAttentuation->Attribute("linear") ) linear = StringConverter::parseReal( XMLAttentuation->Attribute("linear") ); if( XMLAttentuation->Attribute("quadratic") ) quadratic = StringConverter::parseReal( XMLAttentuation->Attribute("quadratic") ); light->setAttenuation( range, constant, linear, quadratic ); } XMLPosition = XMLLight->FirstChildElement("position"); if( XMLPosition ) { Vector3 p = Vector3(0,0,0); if( XMLPosition->Attribute("x") ) p.x = StringConverter::parseReal( XMLPosition->Attribute("x") ); if( XMLPosition->Attribute("y") ) p.y = StringConverter::parseReal( XMLPosition->Attribute("y") ); if( XMLPosition->Attribute("z") ) p.z = StringConverter::parseReal( XMLPosition->Attribute("z") ); light->setPosition( p ); } //castShadows (true | false) "true" light->setCastShadows( true ); if( XMLLight->Attribute("visible") ) if( String(XMLLight->Attribute("visible")) == "false" ) light->setCastShadows( false ); //visible (true | false) "true" light->setVisible( true ); if( XMLLight->Attribute("visible") ) if( String(XMLLight->Attribute("visible")) == "false" ) light->setVisible( false ); return light; } //----------------------------------------------------------------------- void TestCullingDotSceneApplication::createScene(void) { mSceneMgr->setAmbientLight(ColourValue(0.09f, 0.09f, 0.09f)); mSceneMgr->setSkyBox(true, "Examples/MorningSkyBox" ); //This is default, though, set it anyway :) ResourceGroupManager::getSingleton().setWorldResourceGroupName("General"); mSceneMgr->setWorldGeometry( "MyScene.scene" ); //mSceneMgr->SetOctreeVisible( 1 ); ParseDotScene( "MyScene.scene", "General" ); // CEGUI setup setupGui(); } //----------------------------------------------------------------------- void TestCullingDotSceneApplication::setupGui( void ) { mGUIRenderer = new CEGUI::OgreCEGUIRenderer(mWindow, Ogre::RENDER_QUEUE_OVERLAY, false, 3000, ST_GENERIC); 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( ); /* CEGUI::Window* sheet = CEGUI::WindowManager::getSingleton().loadWindowLayout( (CEGUI::utf8*)"ogregui.layout"); mGUISystem->setGUISheet(sheet);*/ } //----------------------------------------------------------------------- void TestCullingDotSceneApplication::createFrameListener(void) { mFrameListener= new MouseQueryListener(mWindow, mCamera, mSceneMgr, mGUIRenderer); mFrameListener->showDebugOverlay(true); mRoot->addFrameListener(mFrameListener); } //----------------------------------------------------------------------- void TestCullingDotSceneApplication::chooseSceneManager(void) { mSceneMgr = mRoot->getSceneManager(ST_GENERIC); } //----------------------------------------------------------------------- void TestCullingDotSceneApplication::createViewports(void) { // Create one viewport, entire window Viewport* vp = mWindow->addViewport(mCamera); // Look back along -Z mCamera->lookAt(Vector3(0, 0, -300)); mCamera->setPosition(0 , 100, 600); } /***********************************************/ /* 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 = 0;//GtpVisibility::VisibilityEnvironment::FRUSTUM_CULLING; mThreshold = 0; // Register this so that we get mouse events. mEventProcessor->addMouseListener(this); mEventProcessor->addMouseMotionListener(this); mEventProcessor->addKeyListener(this); // show overlay Overlay* pOver = OverlayManager::getSingleton().getByName("Example/VisibilityDemoOverlay"); 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"); mAlgorithmInfo->setCaption(": " + mCurrentAlgorithmCaptions[mCurrentAlgorithm]); mThresholdInfo->setCaption(": 0"); mFrustumCulledNodesInfo->setCaption(": 0"); mQueryCulledNodesInfo->setCaption(": 0"); mTraversedNodesInfo->setCaption(": 0"); pOver->show(); } // MouseQueryListener //----------------------------------------------------------------------- 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( ); mLMouseDown = true; } // if // 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 ) { mCamera->yaw( -e->getRelX() * mRotateSpeed ); mCamera->pitch( -e->getRelY() * mRotateSpeed ); } // If we are dragging the right mouse button. if ( mRMouseDown ) { Vector3 translation; translation.x += -e->getRelX() * 0.13; translation.y -= -e->getRelY() * 0.13; mCamera->moveRelative(translation); } } //----------------------------------------------------------------------- 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.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 % VisibilitySceneTraverser::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); } //----------------------------------------------------------------------- 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 TestCullingDotSceneApplication 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; }