/* ========================================================================== * (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 "GeoLodTreeLibrary.h" #include "GeoMeshLoader.h" // Distance values #define dist_min 40 #define dist_max 800 //Global variables Geometry::GeoMeshLoader *meshloader=NULL; bool force_maxLODfactor = false; const int num_tree_types=10; Vector3 *centers=NULL; ColourValue color=ColourValue::Red; Camera* theCam; Entity* pPlaneEnt; OverlayElement* mInfo; OverlayElement* mInfo2; OverlayElement* mHelp; char HelpString[]="(F1) Quit Help\n" "This demo shows an example of the LodTree model in action. The scene is composed of\n" "several tree groups which are associated to a LodTree object that manage the level\n" "of detail of both their trunk and leaves. The level of detail of the objects depends\n" "on the distance to the camera. When the camera goes away from them, the level of detail\n" "decreases, and when the camera gets closer to them increases to restore the original\n" "geometry of the model.\n" "The level of detail begins to decrease at a certain distance of each group, 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" "The user can compare the differences in performance disabling the LOD management while\n" "maintaining pressed F2."; char NoHelpString[]="\n\n\n\n\n\n\n\n\n\n\n\n\n(F1) Help\n"; class LodTreeFrameListener : public ExampleFrameListener { int manage; Ogre::RaySceneQuery * raySceneQuery; float *lodfactorBefore; // one lodfactor per LOD object type Geometry::LodTreeLibrary **lod_tree_types; Ogre::TexturePtr shadow_map; public: LodTreeFrameListener(RenderWindow* win, Camera* cam,RaySceneQuery *rsq,Geometry::LodTreeLibrary **lod_trees) : ExampleFrameListener(win, cam, false, false) { manage=1; raySceneQuery=rsq; lodfactorBefore=new float[num_tree_types]; for (int i=0; icapture(); // 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 for (int i=0; igetPosition(); int distance = dist.length(); float lodfactor = 0.0f; if (distance < dist_min) lodfactor = 1.0f; else if (distance > dist_max) lodfactor = 0.0f; else { lodfactor = (float)(distance - dist_min) / (float)(dist_max - dist_min); lodfactor = 1.0f - lodfactor; } assert(lodfactor>=0.0f); assert(lodfactor<=1.0f); if (force_maxLODfactor) lodfactor=1.0f; if (fabsf(lodfactorBefore[i]-lodfactor)>0.1f) { lod_tree_types[i]->GoToLod(lodfactor); lodfactorBefore[i]=lodfactor; } } // Move the cam 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_LEFT)) mCamera->yaw(mRotScale); force_maxLODfactor=mInputDevice->isKeyDown(Ogre::KC_F2); if(mInputDevice->isKeyDown(Ogre::KC_RIGHT)) mCamera->yaw(-mRotScale); 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_ESCAPE)) 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); } mCamera->yaw(mRotX); mCamera->pitch(mRotY); mCamera->moveRelative(mTranslateVector); // make the camera walk onto the ground Ogre::Ray ray(mCamera->getPosition()+Ogre::Vector3(0.0f,200.0f,0.0f), Ogre::Vector3::NEGATIVE_UNIT_Y); raySceneQuery->setRay(ray); RaySceneQueryResult &rayRes = raySceneQuery->execute(); RaySceneQueryResult::iterator itr = rayRes.begin(); if (itr != rayRes.end() && itr->worldFragment) mCamera->setPosition(itr->worldFragment->singleIntersection+Ogre::Vector3(0.0f,15.0f,0.0f)); char cadena[256]; const RenderTarget::FrameStats& stats = mWindow->getStatistics(); sprintf(cadena,"Current FPS: %f\n",stats.lastFPS); mInfo2->setCaption(cadena); return true; } void CalculateShadowMap(void) { } }; 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; } virtual void End(){ ibuf->unlock(); } virtual void BorrowIndexData(const Geometry::IndexData *){} }; class LodTreeApplication : public ExampleApplication { protected: public: LodTreeApplication(){ raySceneQuery=NULL; centers=new Vector3[num_tree_types]; // one center per object } ~LodTreeApplication(){} Ogre::RaySceneQuery * raySceneQuery; Geometry::LodTreeLibrary **lod_tree_types; protected: void chooseSceneManager(void) { // Get the SceneManager, in this case a generic one // mSceneMgr = mRoot->getSceneManager(Ogre::ST_EXTERIOR_CLOSE); mSceneMgr = mRoot->createSceneManager("TerrainSceneManager"); } // Just override the mandatory create scene method void createScene(void) { theCam = mCamera; theCam->setPosition(500,100,dist_min+600); // Set ambient light mSceneMgr->setAmbientLight(ColourValue(0.4, 0.4, 0.4)); theCam->setNearClipDistance(0.1f); mSceneMgr->setFog( FOG_EXP, Ogre::ColourValue(0.4f,0.5f,0.6f), 0.001 ); // Create a directional light Light* l = mSceneMgr->createLight("MainLight"); l->setType(Light::LT_DIRECTIONAL); l->setDirection(0.1,-1.0,-0.2); // terrain mSceneMgr->setWorldGeometry( "terrain.cfg" ); mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox"); // My node to which all objects will be attached SceneNode* myRootNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); // initialize the rayscene queryer raySceneQuery = mSceneMgr->createRayQuery(Ray()); // the blacksmith Vector3 BS_center=Ogre::Vector3(780.0f,200.0f,650.0f); Ogre::Ray ray(BS_center, Ogre::Vector3::NEGATIVE_UNIT_Y); raySceneQuery->setRay(ray); RaySceneQueryResult &rayRes = raySceneQuery->execute(); RaySceneQueryResult::iterator itr = rayRes.begin(); if (itr != rayRes.end() && itr->worldFragment) BS_center=itr->worldFragment->singleIntersection-Ogre::Vector3(0.0f,1.0f,0.0f); Ogre::Entity *entBS = mSceneMgr->createEntity("blacksmith","../../../OgreStuff/media/models/blacksmith.mesh"); Ogre::SceneNode * nodeBS = mSceneMgr->getRootSceneNode()->createChildSceneNode(); nodeBS->attachObject(entBS); nodeBS->translate(BS_center); nodeBS->scale(0.1f,0.1f,0.1f); lod_tree_types = new Geometry::LodTreeLibrary*[num_tree_types]; // trees lod_tree_types[0] = CreateLODTrees("../../../OgreStuff/media/GT/ML06a_01.mesh",5,780,630,200,200,centers[0], 4.0f); lod_tree_types[1] = CreateLODTrees("../../../OgreStuff/media/GT/ML13a_02.mesh",4,150,150,200,200,centers[1], 2.0f); lod_tree_types[2] = CreateLODTrees("../../../OgreStuff/media/GT/ML15a_03.mesh",10,300,400,200,200,centers[2], 6.0f); lod_tree_types[3] = CreateLODTrees("../../../OgreStuff/media/GT/ML06a_01.mesh",5,330,900,500,500,centers[3], 3.0f); lod_tree_types[4] = CreateLODTrees("../../../OgreStuff/media/GT/ML13a_02.mesh",5,1100,900,300,300,centers[4], 2.0f); lod_tree_types[5] = CreateLODTrees("../../../OgreStuff/media/GT/ML15a_03.mesh",10,1100,300,200,200,centers[5], 6.0f); lod_tree_types[6] = CreateLODTrees("../../../OgreStuff/media/GT/ML06a_01.mesh",7,900,500,300,300,centers[6], 2.0f); lod_tree_types[7] = CreateLODTrees("../../../OgreStuff/media/GT/ML13a_02.mesh",5,500,950,200,200,centers[7], 3.0f); lod_tree_types[8] = CreateLODTrees("../../../OgreStuff/media/GT/ML15a_03.mesh",9,600,400,200,200,centers[8], 6.0f); lod_tree_types[9] = CreateLODTrees("../../../OgreStuff/media/GT/ML06a_01.mesh",7,950,1100,200,200,centers[9], 2.5f); // 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"); mHelp->setCaption(NoHelpString); pOver->show(); mInfo->setCaption("\nMaintain F2 to disable LOD"); // create the shadow texture TexturePtr shadow_map = Ogre::TextureManager::getSingleton().createManual("TheShadowMap", ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,TEX_TYPE_2D, 256,256,0,PF_R8G8B8,TU_STATIC_WRITE_ONLY|TU_RENDERTARGET); /* // en vez de crear la textura aqui se puee intentar cargar de fichero una y modificarla HardwarePixelBufferSharedPtr shadowBuffer = shadow_map->getBuffer(); RenderTarget *render_target = shadowBuffer->getRenderTarget();*/ HardwarePixelBufferSharedPtr shadowBuffer = shadow_map->getBuffer(); RenderTarget *render_target = shadowBuffer->getRenderTarget(); // RenderTarget *rttTex = shadow_map->getBuffer()->getRenderTarget(); // mSceneMgr->createCamera("lightCam"); } void destroyScene(void) { if (raySceneQuery) delete raySceneQuery; delete[] lod_tree_types; } void createFrameListener(void) { mFrameListener= new LodTreeFrameListener(mWindow, mCamera, raySceneQuery, lod_tree_types); mFrameListener->showDebugOverlay(false); mRoot->addFrameListener(mFrameListener); } Geometry::LodTreeLibrary *CreateLODTrees(const char *filename, int numObjs, float cx, float cz, float w, float h, Vector3 &outcenter, float scale) { static int iname = 0; char newMeshName[16]=""; sprintf(newMeshName,"tree_%d",iname); // load LOD info from the object meshloader=new Geometry::GeoMeshLoader; Geometry::Mesh *themesh = meshloader->load((char*)filename); if (!meshloader->GetLodStripsData()) OGRE_EXCEPT(1, "The loaded mesh does not contain LOD info for the trunk","LOD Demo"); if (!meshloader->GetTreeSimpSeq()) OGRE_EXCEPT(1, "The loaded mesh does not contain LOD info for the foliage","LOD Demo"); Ogre::Entity *entity = mSceneMgr->createEntity(newMeshName,filename); // if (!entity->getMesh().unique()) // { static int iclone = 0; char newCloneMesh[16]=""; sprintf(newCloneMesh,"clonemesh_%d",iclone); char newCloneEntity[16]=""; sprintf(newCloneEntity,"cloneentity_%d",iclone); iclone++; Ogre::MeshPtr newmesh = entity->getMesh()->clone(newCloneMesh); entity = mSceneMgr->createEntity(newCloneEntity,newCloneMesh); // } Ogre::Mesh *ogreMesh = entity->getMesh().getPointer(); entity->setNormaliseNormals(true); Geometry::LodTreeLibrary *mytree = new Geometry::LodTreeLibrary( meshloader->GetLodStripsData(), meshloader->GetTreeSimpSeq(), themesh, new CustomIndexData(ogreMesh) ); outcenter=Vector3::ZERO; for (int i=0; igetRootSceneNode()->createChildSceneNode(); Ogre::Entity *auxent = entity->clone(newTreeName); auxnode->attachObject( auxent ); float kx = (rand()%100)/100.0f; float kz = (rand()%100)/100.0f; Ogre::Vector3 treepos(kx*(cx-w*0.5f) + (1.0f-kx)*(cx+w*0.5f), 200.0f, kz*(cz-h*0.5f) + (1.0f-kz)*(cz+h*0.5f)); Ogre::Ray ray(treepos,Ogre::Vector3::NEGATIVE_UNIT_Y); raySceneQuery->setRay(ray); RaySceneQueryResult &rayRes = raySceneQuery->execute(); RaySceneQueryResult::iterator itr = rayRes.begin(); if (itr != rayRes.end() && itr->worldFragment) treepos = itr->worldFragment->singleIntersection; auxnode->translate(treepos); auxnode->scale(scale,scale,scale); auxnode->rotate(Ogre::Vector3(0,1,0),Ogre::Degree(rand()%360)); auxent->setNormaliseNormals(true); outcenter+=treepos; } outcenter/=numObjs; iname++; return mytree; } float Rand(float minN, float maxN) { return (((rand()%1000)/1000.0f)*(maxN-minN))+minN; } }; #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 LodTreeApplication 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