/* ========================================================================== * (C) 2006 Universitat Jaume I * ========================================================================== * PROYECT: GAME TOOLS * ==========================================================================*/ /** CONTENT: * * * @file main.cpp /** COMMENTS: * Model must be in "media/models" folder. * Lod file must be in "media/GT" folder. /*===========================================================================*/ #include "ExampleApplication.h" #include "GeoLodStripsLibrary.h" #include "GeoMeshLoader.h" // Distance values #define dist_min 1100 #define dist_max 2500 // Model name #define model_name "dwarf2" //Global variables Entity* entity; Geometry::LodStripsLibrary* myStrips; Ogre::Mesh *ogreMesh=NULL; Geometry::GeoMeshLoader *meshloader=NULL; SceneNode* node; MaterialPtr *mat; ColourValue color=ColourValue::Red; Camera* theCam; Entity* pPlaneEnt; OverlayElement* mInfo; OverlayElement* mInfo2; OverlayElement* mHelp; OverlayElement* mLOD; OverlayElement* mShad; SceneManager* SceneMgrAux; char LODStringAuto[]="(F3) LOD Mode: AUTOMATIC"; char LODStringManu[]="(F3) LOD Mode: MANUAL"; char ShadON[] ="(F2) Shadows ON"; char ShadOFF[] ="(F2) Shadows OFF"; char HelpString[]="(F1) Quit Help\n" "This demo shows an example of the LODStrips model in action. The models in the scene\n" "are associated to a LodStrips object that manage their level of detail.\n" "The level of detail of the objects depend on the distance to the camera. When the\n" "camera goes away from them, the level of detail decreases, and when the camera gets\n" "closer to them the level of detail increases to restore the original geometry of the\n" "model.\n" "The current level of detail can be seen in real-time in the bottom-left corner of the screen.\n" "The level of detail begins to decrease at a certain distance of the crowd, and stops\n" "decreasing when the objects reach the their minimum LOD. This 'lodding' distance is\n" "customizable from the source code of the demo.\n\n" "(F3) LOD Mode ( AUTOMATIC vs MANUAL )\n" " MANUAL MODE: Use (+) and (-) keys to change de LOD\n"; char NoHelpString[]="\n\n\n\n\n\n\n\n\n\n\n\n\n(F1) Help\n"; int num_ogres = 90; class CustomIndexData : public Geometry::IndexData { private: Ogre::Mesh *targetMesh; Ogre::HardwareIndexBufferSharedPtr ibuf; Ogre::RenderOperation mRenderOp; unsigned long* pIdx; public: CustomIndexData(Ogre::Mesh *ogremesh):Geometry::IndexData(){ targetMesh=ogremesh; pIdx=NULL; } virtual ~CustomIndexData(void){} virtual void Begin(unsigned int submeshid, unsigned int indexcount){ targetMesh->getSubMesh(submeshid)->_getRenderOperation(mRenderOp,0); ibuf = mRenderOp.indexData->indexBuffer; mRenderOp.indexData->indexCount = indexcount; pIdx = static_cast(ibuf->lock(Ogre::HardwareBuffer::HBL_NORMAL)); } virtual void SetIndex(unsigned int i, unsigned int index){ pIdx[i] = index; //lodStripsLib->dataRetrievalInterface->GetIndex(k+offset); } virtual void End(){ ibuf->unlock(); } virtual void BorrowIndexData(const Geometry::IndexData *){} }; class FresnelFrameListener : public ExampleFrameListener { float miButtonTimer; public: FresnelFrameListener(RenderWindow* win, Camera* cam) : ExampleFrameListener(win, cam, false, false) { miButtonTimer=0; } bool frameStarted(const FrameEvent& evt) { Vector3 dist; int distance=0,inc2=0; static int modo=0; static int shadows=1; float tiempo = evt.timeSinceLastFrame; miButtonTimer -= tiempo; if (shadows == 0) { SceneMgrAux->setShadowTechnique(SHADOWTYPE_NONE); } else { SceneMgrAux->setShadowTechnique(SHADOWTYPE_TEXTURE_MODULATIVE); } // Move upto 80 units/second Real MoveFactor = 180.0 * evt.timeSinceLastFrame; // Copy the current state of the input devices mInputDevice->capture(); // 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; //LOD selection static float lodfactor=0; static float lodfactorBefore = -1.0f; dist = node->getPosition() - mCamera->getPosition(); distance =dist.length(); if ( modo == 0 ) //Automatic LOD { int difdist = dist_max - dist_min; int i=0; lodfactor = (float)(distance - dist_min) / (float)(dist_max - dist_min); lodfactor = 1.0f - lodfactor; } else { // lodfactor = lodfactorBefore; } if (( mInputDevice->isKeyDown(Ogre::KC_ADD) ) && (modo == 1)) lodfactor += 0.001f; if (( mInputDevice->isKeyDown(Ogre::KC_SUBTRACT) ) && (modo == 1)) lodfactor -= 0.001f; if (lodfactor<0.0f) lodfactor=0.0f; if (lodfactor>1.0f) lodfactor=1.0f; if (fabsf(lodfactorBefore-lodfactor)>0.03f || (lodfactorBefore>0.0f && lodfactor==0.0f) || (lodfactorBefore<1.0f && lodfactor==1.0f)) { myStrips->GoToLod(lodfactor); lodfactorBefore=lodfactor; } if ( mInputDevice->isKeyDown(Ogre::KC_F3) && ( miButtonTimer <= 0 ) ) { miButtonTimer = 0.5; if (modo == 0) { modo=1; mLOD->setCaption(LODStringManu); } else { modo=0; mLOD->setCaption(LODStringAuto); } } if ( mInputDevice->isKeyDown(Ogre::KC_F2) && ( miButtonTimer <= 0 ) ) { miButtonTimer = 0.5; if (shadows == 0) { shadows = 1; mShad->setCaption(ShadON); } else { shadows = 0; mShad->setCaption(ShadOFF); } } // Move the node if(mInputDevice->isKeyDown(Ogre::KC_UP) || mInputDevice->isKeyDown(Ogre::KC_W) || mInputDevice->isKeyDown(Ogre::KC_NUMPAD5)) mTranslateVector.z = -mMoveScale; if(mInputDevice->isKeyDown(Ogre::KC_DOWN) || mInputDevice->isKeyDown(Ogre::KC_S) || mInputDevice->isKeyDown(Ogre::KC_NUMPAD2)) mTranslateVector.z = mMoveScale; if (mInputDevice->isKeyDown(Ogre::KC_A) || mInputDevice->isKeyDown(Ogre::KC_NUMPAD1)) mTranslateVector.x = -mMoveScale; if (mInputDevice->isKeyDown(Ogre::KC_D) || mInputDevice->isKeyDown(Ogre::KC_NUMPAD3)) mTranslateVector.x = mMoveScale; /* if (mInputDevice->isKeyDown(Ogre::KC_K)) mCamera->setDetailLevel(SDL_WIREFRAME);*/ static bool newpush = true; if (!mInputDevice->isKeyDown(Ogre::KC_F1)) newpush = true; static bool showing_help = false; if (mInputDevice->isKeyDown(Ogre::KC_F1) && newpush) { newpush = false; if (showing_help = !showing_help) mHelp->setCaption(HelpString); else mHelp->setCaption(NoHelpString); } if(mInputDevice->isKeyDown(Ogre::KC_LEFT)) mCamera->yaw(mRotScale); if(mInputDevice->isKeyDown(Ogre::KC_RIGHT)) mCamera->yaw(-mRotScale); if(mInputDevice->isKeyDown(Ogre::KC_ESCAPE)) { delete myStrips; delete [] mat; return false; } 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); } SceneMgrAux->setShadowFarDistance(distance + 200); char cadena[256]; const RenderTarget::FrameStats& stats = mWindow->getStatistics(); sprintf(cadena,"\nDistance: %d\nLOD factor: %f\nTriangle Count: %d\n" , distance, lodfactor,stats.triangleCount); mInfo->setCaption(cadena); sprintf(cadena,"Current FPS: %f\n",stats.lastFPS); mInfo2->setCaption(cadena); mCamera->yaw(mRotX); mCamera->pitch(mRotY); mCamera->moveRelative(mTranslateVector); return true; } }; class LodStripsApplication : public ExampleApplication { protected: public: LodStripsApplication() {} ~LodStripsApplication() {} protected: // Just override the mandatory create scene method void createScene(void) { SceneMgrAux = mSceneMgr; mSceneMgr->setAmbientLight(ColourValue(0.2, 0.2, 0.2)); mSceneMgr->setShadowTechnique(SHADOWTYPE_TEXTURE_MODULATIVE); mSceneMgr->setShadowTextureSettings(2048,1); mSceneMgr->setShadowFarDistance(1024); mSceneMgr->setShadowColour(ColourValue(0.5, 0.5, 0.5)); mat = new MaterialPtr[1]; theCam = mCamera; theCam->setPosition(-35,50,dist_min-600.0f); // Set ambient light // Create a directional light Light* l = mSceneMgr->createLight("MainLight"); l->setType(Light::LT_DIRECTIONAL); l->setDirection(-0.5,-1.0,-1.0); l->setCastShadows(true); mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox"); // My node to which all objects will be attached SceneNode* myRootNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); // Define a floor plane mesh Plane plane( Vector3::UNIT_Y, 0 ); MeshManager::getSingleton().createPlane("ground", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, plane, 20000,10000,6,6,true,1,250,250,Vector3::UNIT_Z); Entity* groundEntity = mSceneMgr->createEntity( "GroundEntity", "ground" ); mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(groundEntity); groundEntity->setMaterialName("SnowTerrain"); groundEntity->setCastShadows(false); std::string model_file=model_name; model_file.append(".mesh"); //Models entity = mSceneMgr->createEntity(model_name, "../../../OgreStuff/media/GT/ogrolod.mesh"); ogreMesh = entity->getMesh().getPointer(); // load LOD info from the object meshloader=new Geometry::GeoMeshLoader; Geometry::Mesh *themesh = meshloader->load("../../../OgreStuff/media/GT/ogrolod.mesh"); node = mSceneMgr->getRootSceneNode()->createChildSceneNode(); node->attachObject( entity ); node->setVisible(false); std::string lod_file="../../media/GT/"; lod_file.append(model_name); lod_file.append(".lod"); if (!meshloader->GetLodStripsData()) OGRE_EXCEPT(1, "The loaded mesh does not contain any LOD info","LOD Demo"); myStrips = new Geometry::LodStripsLibrary( meshloader->GetLodStripsData(), themesh, new CustomIndexData(ogreMesh) ); entity->setNormaliseNormals(true); entity->setMaterialName("LODStripsDemo/Ogro"); num_ogres=0; for (int i=-4; i<4; i++) // 7 for (int j=0; j<8; j++) // 4 { char newObjName[16]=""; sprintf(newObjName,"arbol_%d_%d",i,j); Ogre::SceneNode * auxnode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); Ogre::Entity *auxen = entity->clone(newObjName); auxnode->attachObject(auxen); auxnode->rotate(Ogre::Vector3(0,1,0),Ogre::Degree(180.0f),Ogre::Node::TS_WORLD); auxnode->scale(30.0f,30.0f,30.0f); float randomsepx = (float)((rand()%18)-9); float randomsepy = (float)((rand()%12)-6); auxnode->translate(i*70.0f+randomsepx,-0.3f,-j*70.0f-randomsepx); auxen->setNormaliseNormals(true); auxen->setCastShadows(true); num_ogres++; } node->translate(0,0,-500.0f); // show overlay Overlay* pOver = OverlayManager::getSingleton().getByName("Demo_LodStrips/Overlay"); mInfo = OverlayManager::getSingleton().getOverlayElement("Demo_LodStrips/Info_1"); mInfo2 = OverlayManager::getSingleton().getOverlayElement("Demo_LodStrips/Info_2"); mHelp = OverlayManager::getSingleton().getOverlayElement("Demo_LodStrips/Help"); mLOD = OverlayManager::getSingleton().getOverlayElement("Demo_LodStrips/ModoLOD"); mShad = OverlayManager::getSingleton().getOverlayElement("Demo_LodStrips/Shadows"); mHelp->setCaption(NoHelpString); mLOD->setCaption(LODStringAuto); mShad->setCaption(ShadON); pOver->show(); //mWindow->getStatistics(); } void createFrameListener(void) { mFrameListener= new FresnelFrameListener(mWindow, mCamera); mFrameListener->showDebugOverlay(false); mRoot->addFrameListener(mFrameListener); } }; #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 #define WIN32_LEAN_AND_MEAN #include "windows.h" #endif #ifdef __cplusplus extern "C" { #endif #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT ) #else int main(int argc, char **argv) #endif { // Create application object LodStripsApplication app; try { app.go(); } catch( Exception& e ) { #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL); #else std::cerr << "An exception has occured: " << e.getFullDescription(); #endif } return 0; } #ifdef __cplusplus } #endif