#include #include #include <../CEGUIRenderer/include/OgreCEGUIRenderer.h> #include <../CEGUIRenderer/include/OgreCEGUIResourceProvider.h> #include <../CEGUIRenderer/include/OgreCEGUITexture.h> #include #include //#include "OgreReferenceAppLayer.h" //#include "OgreRefAppWorld.h" #include "TestCullingTerrainApplication.h" #include "TerrainFrameListener.h" #define WIN32_LEAN_AND_MEAN #include /**********************************************/ /* EntityState implementation */ /**********************************************/ Vector3 EntityState::msMinPos = Vector3::ZERO; Vector3 EntityState::msMaxPos = Vector3::ZERO; EntityState::EntityState(Entity *ent, State entityState, Real speed): mEntity(ent), mState(entityState), mAnimationSpeed(speed) { switch(entityState) { case MOVING: mAnimationState = mEntity->getAnimationState("Walk"); break; case WAITING: mAnimationState = mEntity->getAnimationState("Idle"); break; case STOP: mAnimationState = NULL; break; default: break; } // enable animation state if (mAnimationState) { mAnimationState->setLoop(true); mAnimationState->setEnabled(true); } mTimeElapsed = Math::RangeRandom(1, 5); } //----------------------------------------------------------------------- EntityState::~EntityState() { mAnimationState = NULL; mEntity = NULL; } //----------------------------------------------------------------------- Entity *EntityState::GetEntity() { return mEntity; } //----------------------------------------------------------------------- EntityState::State EntityState::GetState() { return mState; } //----------------------------------------------------------------------- void EntityState::update(Real timeSinceLastFrame) { mTimeElapsed -= timeSinceLastFrame * mAnimationSpeed; if (!mEntity || !mAnimationState) return; if (mState == MOVING) // toggle between moving (longer) and waiting (short) { SceneNode *parent = mEntity->getParentSceneNode(); if (!parent) return; if (mTimeElapsed <= 0) // toggle animation state { if (mAnimationState->getAnimationName() == "Idle") { SetAnimationState("Walk", true); mTimeElapsed = walk_duration; // walk for mTimeElapsed units // choose random rotation Radian rnd = Radian(Math::UnitRandom() * Math::PI * rotate_factor); //mEntity->getParentSceneNode()->rotate(); parent->yaw(rnd); } else { SetAnimationState("Idle", true); mTimeElapsed = wait_duration; // wait for mTimeElapsed seconds } } if (mAnimationState->getAnimationName() == "Walk") // move forward { // store old position, just in case we get out of bounds Vector3 oldPos = parent->getPosition(); parent->translate(parent->getLocalAxes(), Vector3(move_factor * mAnimationSpeed, 0, 0)); // HACK: if out of bounds => reset to old position and set animationstate to idle if (OutOfBounds(parent)) { parent->setPosition(oldPos); SetAnimationState("Idle", true); mTimeElapsed = wait_duration; } } } // add time to drive animation mAnimationState->addTime(timeSinceLastFrame * mAnimationSpeed); } //----------------------------------------------------------------------- void EntityState::SetAnimationState(String stateStr, bool loop) { if (!mEntity) return; mAnimationState = mEntity->getAnimationState(stateStr); mAnimationState->setLoop(loop); mAnimationState->setEnabled(true); } //----------------------------------------------------------------------- bool EntityState::OutOfBounds(SceneNode *node) { Vector3 pos = node->getPosition(); if ((pos > msMinPos) && (pos < msMaxPos)) return false; return true; } /*********************************************************/ /* TestCullingTerrainApplication implementation */ /*********************************************************/ TestCullingTerrainApplication::TestCullingTerrainApplication(): mTerrainContentGenerator(NULL), mRayQueryExecutor(NULL) { } //----------------------------------------------------------------------- TestCullingTerrainApplication::~TestCullingTerrainApplication() { OGRE_DELETE(mTerrainContentGenerator); OGRE_DELETE(mRayQueryExecutor); deleteEntityStates(); } //----------------------------------------------------------------------- void TestCullingTerrainApplication::deleteEntityStates() { for (int i = 0; i < (int)mEntityStates.size(); ++i) { OGRE_DELETE(mEntityStates[i]); } mEntityStates.clear(); } //----------------------------------------------------------------------- void TestCullingTerrainApplication::createCamera() { // create the camera mCamera = mSceneMgr->createCamera("PlayerCam"); /** set a nice viewpoint * we use a camera node here and apply all transformations on it instead * of applying all transformations directly to the camera * because then the camera is displayed correctly in the visualization */ mCamNode = mSceneMgr->getRootSceneNode()-> createChildSceneNode("CamNode1", Vector3(707, 5000, 528)); //mCamera->setPosition(707, 5000, 528); mCamNode->setOrientation(Quaternion(-0.3486, 0.0122, 0.9365, 0.0329)); mCamNode->attachObject(mCamera); //-- create visualization camera mVizCamera = mSceneMgr->createCamera("VizCam"); mVizCamera->setPosition(mCamNode->getPosition()); mVizCamera->setNearClipDistance(1); mCamera->setNearClipDistance(1); // infinite far plane? if (mRoot->getRenderSystem()->getCapabilities()->hasCapability(RSC_INFINITE_FAR_PLANE)) { mVizCamera->setFarClipDistance(0); mCamera->setFarClipDistance(0); } else { mVizCamera->setFarClipDistance(20000); mCamera->setFarClipDistance(20000); } } //----------------------------------------------------------------------- bool TestCullingTerrainApplication::setup() { bool carryOn = ExampleApplication::setup(); if (carryOn) createRenderTargetListener(); return carryOn; } //----------------------------------------------------------------------- void TestCullingTerrainApplication::createRenderTargetListener() { mWindow->addListener(new VisualizationRenderTargetListener(mSceneMgr)); } //----------------------------------------------------------------------- void TestCullingTerrainApplication::createScene() { Real scale = 3; mSceneMgr->setOption("NodeVizScale", &scale); // Set ambient light mAmbientLight = ColourValue(0.5 , 0.5, 0.5); mSceneMgr->setAmbientLight(mAmbientLight); //-- create light mSunLight = mSceneMgr->createLight("SunLight"); mSunLight->setType(Light::LT_DIRECTIONAL); //mSunLight->setType(Light::LT_SPOTLIGHT); //mSunLight->setSpotlightRange(Degree(30), Degree(50)); mSunLight->setPosition(707, 2000, 500); mSunLight->setCastShadows(true); // set light angle not too small over the surface, otherwise shadows textures will be broken Vector3 dir(0.5, 1, 0.5); dir.normalise(); mSunLight->setDirection(dir); //mSunLight->setDirection(Vector3::NEGATIVE_UNIT_Y); mSunLight->setDiffuseColour(1, 1, 1); mSunLight->setSpecularColour(1, 1, 1); // -- 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/CloudyNoonSkyBox", 5000, true); 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(); /* // occluder plane to test visibility Plane plane; plane.normal = Vector3::UNIT_Y; plane.d = -60; MeshManager::getSingleton().createPlane("Myplane", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane, 5000,5000,100,100,true,1,5,5,Vector3::UNIT_Z); Entity* pPlaneEnt = mSceneMgr->createEntity( "plane", "Myplane" ); pPlaneEnt->setMaterialName("Examples/Rockwall"); pPlaneEnt->setCastShadows(true); mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(pPlaneEnt); */ // Use 512x512 texture in GL since we can't go higher than the window res mSceneMgr->setShadowTextureSettings(512, 2); mSceneMgr->setShadowColour(ColourValue(0.5, 0.5, 0.5)); //-- terrain content setup // HACK: necessary to call once before the content creation for // terrain initialisation mSceneMgr->_renderScene(mCamera, mWindow->getViewport(0), true); // ray query executor: needed to clamp to terrain mRayQueryExecutor = new RayQueryExecutor(mSceneMgr); mTerrainMinPos = EntityState::msMinPos = Vector3(0, 0, 0); mTerrainMaxPos = EntityState::msMaxPos = Vector3(5000, 5000, 5000); mTerrainContentGenerator = new TerrainContentGenerator(mSceneMgr); // if no objects in file, we generate new objects if (!mTerrainContentGenerator->LoadObjects("objects.out")) { // the objects are generated randomly distributed over the terrain generateScene(1000, 0); // create soldiers, trees, ninjas generateScene(500, 1); generateScene(100, 2); } } //----------------------------------------------------------------------- void TestCullingTerrainApplication::generateScene(int num, int objectType) { float val = TerrainFrameListener::msObjectScales[objectType]; Vector3 scale(val, val, val); const float maxHeight = 75; // to provide much occlusion, // height is restricted to maxHeight => no objects are created on peaks mTerrainContentGenerator->SetMinPos(Vector3(mTerrainMinPos)); mTerrainContentGenerator->SetMaxPos(Vector3(mTerrainMaxPos.x, maxHeight, mTerrainMaxPos.z)); std::stringstream d; d << "objscale: " << scale[0]; Ogre::LogManager::getSingleton().logMessage(d.str()); mTerrainContentGenerator->SetScale(scale); mTerrainContentGenerator->SetOffset(TerrainFrameListener::msObjectTerrainOffsets[objectType]); mTerrainContentGenerator->GenerateScene(num, TerrainFrameListener::msObjectCaptions[objectType]); if (objectType != 0) // from our objects, only robot has animation phases return; EntityList *entList = mTerrainContentGenerator->GetGeneratedEntities(); //-- add animation state for new robots (located at the end of the list) for (int i = (int)entList->size() - num; i < (int)entList->size(); ++i) { mEntityStates.push_back(new EntityState((*entList)[i], EntityState::WAITING, Math::RangeRandom(0.5, 1.5))); } // release limitations on height => it is possible for the user to put single // objects on peaks of the terrain (will be only few, not relevant for occlusion) mTerrainContentGenerator->SetMaxPos(mTerrainMaxPos); } //----------------------------------------------------------------------- void TestCullingTerrainApplication::updateAnimations(Real timeSinceLastFrame) { for (int i = 0; i < (int)mEntityStates.size(); ++i) { SceneNode *sn = mEntityStates[i]->GetEntity()->getParentSceneNode(); mEntityStates[i]->update(timeSinceLastFrame); if (mEntityStates[i]->GetState() == EntityState::MOVING) { Clamp2Terrain(sn, 0); //sn->setNodeVisible(false); } } } //----------------------------------------------------------------------- EntityStates &TestCullingTerrainApplication::getEntityStates() { return mEntityStates; } //----------------------------------------------------------------------- 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() { mTerrainFrameListener = new TerrainFrameListener(mWindow, mCamera, mSceneMgr, mGUIRenderer, mTerrainContentGenerator, mVizCamera, mCamNode, mSunLight, this); mRoot->addFrameListener(mTerrainFrameListener); } //----------------------------------------------------------------------- void TestCullingTerrainApplication::chooseSceneManager() { mSceneMgr = mRoot->getSceneManager(ST_EXTERIOR_CLOSE); } //----------------------------------------------------------------------- bool TestCullingTerrainApplication::Clamp2Terrain(SceneNode *node, int terrainOffs) { // clamp scene node to terrain Vector3 pos = node->getPosition(); Vector3 queryResult; if (mRayQueryExecutor->executeRayQuery(&queryResult, Vector3(pos.x, MAX_HEIGHT, pos.z), Vector3::NEGATIVE_UNIT_Y)) { node->setPosition(pos.x, queryResult.y + terrainOffs, pos.z); return true; } return false; } /**************************************************************/ /* VisualizationRenderTargetListener implementation */ /**************************************************************/ //----------------------------------------------------------------------- VisualizationRenderTargetListener::VisualizationRenderTargetListener(SceneManager *sceneMgr) :RenderTargetListener(), mSceneMgr(sceneMgr) { } //----------------------------------------------------------------------- void VisualizationRenderTargetListener::preViewportUpdate(const RenderTargetViewportEvent &evt) { // visualization viewport const bool showViz = evt.source->getZOrder() == VIZ_VIEWPORT_Z_ORDER; const bool nShowViz = !showViz; mSavedShadowTechnique = mSceneMgr->getShadowTechnique(); mSavedAmbientLight = mSceneMgr->getAmbientLight(); // -- ambient light must be full for visualization, shadows disabled if (showViz) { mSceneMgr->setAmbientLight(ColourValue(1, 1, 1)); mSceneMgr->setShadowTechnique(SHADOWTYPE_NONE); } mSceneMgr->setOption("PrepareVisualization", &showViz); mSceneMgr->setOption("SkyBoxEnabled", &nShowViz); //mSceneMgr->setOption("SkyPlaneEnabled", &showViz); RenderTargetListener::preViewportUpdate(evt); } //----------------------------------------------------------------------- void VisualizationRenderTargetListener::postRenderTargetUpdate(const RenderTargetEvent &evt) { // reset values mSceneMgr->setShadowTechnique(mSavedShadowTechnique); mSceneMgr->setAmbientLight(mSavedAmbientLight); RenderTargetListener::postRenderTargetUpdate(evt); } //----------------------------------------------------------------------- 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; }