source: GTP/trunk/App/Demos/Geom/Demo_LodTrees/main.cpp @ 1840

Revision 1840, 17.1 KB checked in by gumbau, 18 years ago (diff)

Added shadows to the terrain

Line 
1/*      ==========================================================================
2 *      (C) 2006 Universitat Jaume I
3 *      ==========================================================================
4 *      PROYECT:        GAME TOOLS
5 *      ==========================================================================*/
6/**     CONTENT:       
7        *
8        *
9        *       @file   main.cpp
10/** COMMENTS:
11        * Model must be in "media/models" folder.
12        * Lod file must be in "media/GT" folder.
13/*===========================================================================*/
14#include "ExampleApplication.h"
15#include "GeoLodTreeLibrary.h"
16#include "GeoMeshLoader.h"
17
18
19// Distance values
20#define dist_min 40
21#define dist_max 800
22
23#define ENABLE_TERRAIN_SHADOWS
24#define TERRAIN_SHADOW_SIZE 2048
25
26//Global variables
27Geometry::GeoMeshLoader *meshloader=NULL;
28bool force_maxLODfactor = false;
29const int num_tree_types=10;
30Vector3 *centers=NULL;
31
32ColourValue color=ColourValue::Red;
33
34Camera* theCam;
35Entity* pPlaneEnt;
36
37OverlayElement* mInfo;
38OverlayElement* mInfo2;
39OverlayElement* mHelp;
40Ogre::Light *theLight = NULL;
41Ogre::Viewport *shadowViewport = NULL;
42RenderTarget *render_target = NULL;
43
44char HelpString[]="(F1) Quit Help\n"
45                        "This demo shows an example of the LodTree model in action. The scene is composed of\n"
46                        "several tree groups which are associated to a LodTree object that manage the level\n"
47                        "of detail of both their trunk and leaves. The level of detail of the objects depends\n"
48                        "on the distance to the camera. When the camera goes away from them, the level of detail\n"
49                        "decreases, and when the camera gets closer to them increases to restore the original\n"
50                        "geometry of the model.\n"
51                        "The level of detail begins to decrease at a certain distance of each group, and stops\n"
52                        "decreasing when the objects reach the their minimum LOD. This 'lodding' distance is\n"
53                        "customizable from the source code of the demo.\n"
54                        "The user can compare the differences in performance disabling the LOD management while\n"
55                        "maintaining pressed F2.";
56
57char NoHelpString[]="\n\n\n\n\n\n\n\n\n\n\n\n\n(F1) Help\n";
58
59
60
61
62class LodTreeFrameListener : public ExampleFrameListener
63{
64        int manage;
65        Ogre::RaySceneQuery * raySceneQuery;
66        float *lodfactorBefore; // one lodfactor per LOD object type
67        Geometry::LodTreeLibrary **lod_tree_types;
68
69        Ogre::TexturePtr shadow_map;
70
71public:
72
73        LodTreeFrameListener(RenderWindow* win, Camera* cam,RaySceneQuery *rsq,Geometry::LodTreeLibrary **lod_trees)
74        : ExampleFrameListener(win, cam, false, false)
75    {
76                manage=1;
77                raySceneQuery=rsq;
78                lodfactorBefore=new float[num_tree_types];
79                for (int i=0; i<num_tree_types; i++)
80                        lodfactorBefore[i]=-1;
81                lod_tree_types=lod_trees;               
82        }
83
84        bool frameStarted(const FrameEvent& evt)
85    {
86                // Move upto 80 units/second
87                Real MoveFactor = 120.0 * evt.timeSinceLastFrame;
88
89                // Copy the current state of the input devices
90                mInputDevice->capture();
91
92                // If this is the first frame, pick a speed
93                if (evt.timeSinceLastFrame == 0)
94                {
95                        mMoveScale = 1;
96                        mRotScale = 0.1;
97                }
98                // Otherwise scale movement units by time passed since last frame
99                else
100                {
101                        // Move about 100 units per second,
102                        mMoveScale = mMoveSpeed * evt.timeSinceLastFrame;
103                        // Take about 10 seconds for full rotation
104                        mRotScale = mRotateSpeed * evt.timeSinceLastFrame;
105                }
106
107                mRotX = 0;
108        mRotY = 0;
109            mTranslateVector = Vector3::ZERO;
110
111                //LOD selection
112                for (int i=0; i<num_tree_types; i++)
113                {       
114                        Vector3 dist = centers[i] - mCamera->getPosition();
115                        int distance = dist.length();
116
117                        float lodfactor = 0.0f;
118                        if (distance < dist_min)
119                                lodfactor = 1.0f;
120                        else if (distance > dist_max)
121                                lodfactor = 0.0f;
122                        else
123                        {
124                lodfactor = (float)(distance - dist_min) / (float)(dist_max - dist_min);
125                                lodfactor = 1.0f - lodfactor;
126                        }
127
128                        assert(lodfactor>=0.0f);
129                        assert(lodfactor<=1.0f);
130
131                        if (force_maxLODfactor)
132                                lodfactor=1.0f;
133
134                        if (fabsf(lodfactorBefore[i]-lodfactor)>0.05f)
135                        {
136                                lod_tree_types[i]->GoToLod(lodfactor);
137                                lodfactorBefore[i]=lodfactor;
138                        }
139                }
140
141                // Move the cam
142                if(mInputDevice->isKeyDown(Ogre::KC_UP) ||
143                   mInputDevice->isKeyDown(Ogre::KC_W) ||
144                   mInputDevice->isKeyDown(Ogre::KC_NUMPAD5))
145                  mTranslateVector.z = -mMoveScale;
146
147                if(mInputDevice->isKeyDown(Ogre::KC_DOWN) ||
148                   mInputDevice->isKeyDown(Ogre::KC_S) ||
149                   mInputDevice->isKeyDown(Ogre::KC_NUMPAD2))
150                  mTranslateVector.z = mMoveScale;
151
152                if (mInputDevice->isKeyDown(Ogre::KC_A) ||
153                        mInputDevice->isKeyDown(Ogre::KC_NUMPAD1))
154                        mTranslateVector.x = -mMoveScale;
155
156                if (mInputDevice->isKeyDown(Ogre::KC_D) ||
157                        mInputDevice->isKeyDown(Ogre::KC_NUMPAD3))
158                        mTranslateVector.x = mMoveScale;
159
160                if(mInputDevice->isKeyDown(Ogre::KC_LEFT))
161                  mCamera->yaw(mRotScale);
162
163                force_maxLODfactor=mInputDevice->isKeyDown(Ogre::KC_F2);                 
164
165                if(mInputDevice->isKeyDown(Ogre::KC_RIGHT))
166                  mCamera->yaw(-mRotScale);
167
168                static bool newpush = true;
169                if (!mInputDevice->isKeyDown(Ogre::KC_F1))
170                        newpush = true;
171
172                static bool showing_help = false;
173                if (mInputDevice->isKeyDown(Ogre::KC_F1) && newpush)
174                {
175                        newpush = false;
176                        if (showing_help = !showing_help)
177                mHelp->setCaption(HelpString);
178                        else
179                mHelp->setCaption(NoHelpString);
180                }
181
182
183                if(mInputDevice->isKeyDown(Ogre::KC_ESCAPE))
184                    return false;
185
186        if( mInputDevice->getMouseButton( 1 ) )
187        {
188            mTranslateVector.x += mInputDevice->getMouseRelativeX() * 0.13;
189            mTranslateVector.y -= mInputDevice->getMouseRelativeY() * 0.13;
190        }
191        else
192        {
193            mRotX = Degree(-mInputDevice->getMouseRelativeX() * 0.13);
194            mRotY = Degree(-mInputDevice->getMouseRelativeY() * 0.13);
195        }
196
197                mCamera->yaw(mRotX);
198        mCamera->pitch(mRotY);
199        mCamera->moveRelative(mTranslateVector);
200
201                // make the camera walk onto the ground
202                Ogre::Ray ray(mCamera->getPosition()+Ogre::Vector3(0.0f,200.0f,0.0f), Ogre::Vector3::NEGATIVE_UNIT_Y);
203                raySceneQuery->setRay(ray);
204                RaySceneQueryResult &rayRes = raySceneQuery->execute();
205                RaySceneQueryResult::iterator itr = rayRes.begin();
206                if (itr != rayRes.end() && itr->worldFragment)
207                        mCamera->setPosition(itr->worldFragment->singleIntersection+Ogre::Vector3(0.0f,15.0f,0.0f));
208
209
210                char cadena[256];
211        const RenderTarget::FrameStats& stats = mWindow->getStatistics();
212                sprintf(cadena,"Current FPS: %f\n",stats.lastFPS);
213                mInfo2->setCaption(cadena);
214
215                return true;
216    }
217};
218
219class CustomIndexData : public Geometry::IndexData
220{
221private:
222        Ogre::Mesh *targetMesh;
223        Ogre::HardwareIndexBufferSharedPtr ibuf;
224        Ogre::RenderOperation mRenderOp;
225        unsigned long* pIdx;
226public:
227        CustomIndexData(Ogre::Mesh *ogremesh):Geometry::IndexData(){
228                targetMesh=ogremesh;
229                pIdx=NULL;
230        }
231        virtual ~CustomIndexData(void){}
232
233        virtual void Begin(unsigned int submeshid, unsigned int indexcount){
234                targetMesh->getSubMesh(submeshid)->_getRenderOperation(mRenderOp,0);
235                ibuf = mRenderOp.indexData->indexBuffer;
236                mRenderOp.indexData->indexCount = indexcount;
237                pIdx = static_cast<unsigned long*>(ibuf->lock(Ogre::HardwareBuffer::HBL_NORMAL));
238        }
239        virtual void SetIndex(unsigned int i, unsigned int index){
240                pIdx[i] = index;
241        }
242        virtual void End(){
243                ibuf->unlock();
244        }
245
246        virtual void BorrowIndexData(const Geometry::IndexData *){}
247};
248
249
250#include "OgreTerrainSceneManager.h"
251
252class LodTreeApplication : public ExampleApplication, public RenderTargetListener
253{
254protected:
255public:
256    LodTreeApplication(){
257                raySceneQuery=NULL;
258                centers=new Vector3[num_tree_types]; // one center per object
259        }
260    ~LodTreeApplication(){}
261
262        Ogre::RaySceneQuery * raySceneQuery;
263        Geometry::LodTreeLibrary **lod_tree_types;
264
265protected:
266   
267    void chooseSceneManager(void)
268    {
269        mSceneMgr = mRoot->createSceneManager("TerrainSceneManager");
270    }
271
272    // render target events
273    void preRenderTargetUpdate(const RenderTargetEvent& evt)
274    {
275                if (render_target)
276                {
277                        (static_cast<TerrainSceneManager*>(mSceneMgr))->getTerrainRootNode()->setVisible(false);
278                        mSceneMgr->setSkyBox(false, "Examples/CloudyNoonSkyBox");
279                        mSceneMgr->setFog(FOG_EXP, Ogre::ColourValue(0.5f,0.5f,0.5f), 1000 );
280                        mInfo2->hide();
281                }
282    }
283    void postRenderTargetUpdate(const RenderTargetEvent& evt)
284    {
285                if (render_target)
286                {
287                        (static_cast<TerrainSceneManager*>(mSceneMgr))->getTerrainRootNode()->setVisible(true);
288                        mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox");
289                        mSceneMgr->setFog( FOG_EXP, Ogre::ColourValue(0.4f,0.5f,0.6f), 0.001 );
290                        mInfo2->show();
291//                      render_target->removeAllListeners();
292//                      render_target->removeAllViewports();
293                        render_target->setAutoUpdated(false);
294                }
295        }
296
297
298    // Just override the mandatory create scene method
299    void createScene(void)
300    {
301        theCam = mCamera;
302                theCam->setPosition(500,100,dist_min+600);
303        // Set ambient light
304        mSceneMgr->setAmbientLight(ColourValue(0.4, 0.4, 0.4));
305                theCam->setNearClipDistance(0.1f);
306
307//              mSceneMgr->setFog( FOG_EXP, Ogre::ColourValue(0.4f,0.5f,0.6f), 0.001 );
308
309        // Create a directional light
310                theLight = mSceneMgr->createLight("MainLight");
311                theLight->setType(Light::LT_DIRECTIONAL);
312        theLight->setDirection(0.1,-1.0,-0.2);         
313       
314                // terrain
315                mSceneMgr->setWorldGeometry( "terrain.cfg" );
316     
317        mSceneMgr->setSkyBox(true, "Examples/CloudyNoonSkyBox");
318
319        // My node to which all objects will be attached
320        SceneNode* myRootNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
321
322                // initialize the rayscene queryer
323                raySceneQuery = mSceneMgr->createRayQuery(Ray());
324
325                // the blacksmith
326                Vector3 BS_center=Ogre::Vector3(780.0f,200.0f,650.0f);
327                Ogre::Ray ray(BS_center, Ogre::Vector3::NEGATIVE_UNIT_Y);
328                raySceneQuery->setRay(ray);
329                RaySceneQueryResult &rayRes = raySceneQuery->execute();
330                RaySceneQueryResult::iterator itr = rayRes.begin();
331                if (itr != rayRes.end() && itr->worldFragment)
332                        BS_center=itr->worldFragment->singleIntersection-Ogre::Vector3(0.0f,1.0f,0.0f);
333
334                Ogre::Entity *entBS = mSceneMgr->createEntity("blacksmith","../../../OgreStuff/media/models/blacksmith.mesh");
335                Ogre::SceneNode * nodeBS = mSceneMgr->getRootSceneNode()->createChildSceneNode();
336                nodeBS->attachObject(entBS);
337                nodeBS->translate(BS_center);
338                nodeBS->scale(0.1f,0.1f,0.1f);
339
340                lod_tree_types = new Geometry::LodTreeLibrary*[num_tree_types];
341
342                // trees
343                lod_tree_types[0] = CreateLODTrees("../../../OgreStuff/media/GT/ML06a_01.mesh",5,780,630,200,200,centers[0], 4.0f);
344                lod_tree_types[1] = CreateLODTrees("../../../OgreStuff/media/GT/ML13a_02.mesh",4,150,150,200,200,centers[1], 2.0f);
345                lod_tree_types[2] = CreateLODTrees("../../../OgreStuff/media/GT/ML15a_03.mesh",10,300,400,200,200,centers[2], 6.0f);
346                lod_tree_types[3] = CreateLODTrees("../../../OgreStuff/media/GT/ML06a_01.mesh",5,330,900,500,500,centers[3], 3.0f);
347                lod_tree_types[4] = CreateLODTrees("../../../OgreStuff/media/GT/ML13a_02.mesh",5,1100,900,300,300,centers[4], 2.0f);
348                lod_tree_types[5] = CreateLODTrees("../../../OgreStuff/media/GT/ML15a_03.mesh",10,1100,300,200,200,centers[5], 6.0f);
349                lod_tree_types[6] = CreateLODTrees("../../../OgreStuff/media/GT/ML06a_01.mesh",7,900,500,300,300,centers[6], 2.0f);
350                lod_tree_types[7] = CreateLODTrees("../../../OgreStuff/media/GT/ML13a_02.mesh",5,500,950,200,200,centers[7], 3.0f);
351                lod_tree_types[8] = CreateLODTrees("../../../OgreStuff/media/GT/ML15a_03.mesh",9,600,400,200,200,centers[8], 6.0f);
352                lod_tree_types[9] = CreateLODTrees("../../../OgreStuff/media/GT/ML06a_01.mesh",7,950,1100,200,200,centers[9], 2.5f);
353
354        // show overlay
355        Overlay* pOver = OverlayManager::getSingleton().getByName("Demo_LodStrips/Overlay");   
356        mInfo = OverlayManager::getSingleton().getOverlayElement("Demo_LodStrips/Info_1");
357                mInfo2 = OverlayManager::getSingleton().getOverlayElement("Demo_LodStrips/Info_2");
358                mHelp = OverlayManager::getSingleton().getOverlayElement("Demo_LodStrips/Help");
359                mHelp->setCaption(NoHelpString);
360            pOver->show();
361
362                mInfo->setCaption("\nMaintain F2 to disable LOD");
363
364#ifdef ENABLE_TERRAIN_SHADOWS
365
366                // create the shadow texture
367                TexturePtr shadow_map = Ogre::TextureManager::getSingleton().createManual("TheShadowMap",
368                        ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,TEX_TYPE_2D,
369                        TERRAIN_SHADOW_SIZE,TERRAIN_SHADOW_SIZE,0,PF_R8G8B8,TU_RENDERTARGET);
370
371                HardwarePixelBufferSharedPtr shadowBuffer = shadow_map->getBuffer();
372                render_target = shadowBuffer->getRenderTarget();
373
374                Ogre::Camera *lightCam = mSceneMgr->createCamera("lightCam");
375                lightCam->setProjectionType(Ogre::PT_ORTHOGRAPHIC);
376                lightCam->setAspectRatio(1.0);
377                lightCam->setFOVy(Degree(164));
378                lightCam->rotate(Vector3(1,0,0),Degree(-90));
379                lightCam->move(BS_center+Ogre::Vector3(-50,400,78));
380
381                shadowViewport = render_target->addViewport(lightCam);
382                shadowViewport->setClearEveryFrame(true);
383                shadowViewport->setBackgroundColour(ColourValue::White);
384
385                render_target->addListener(this);
386
387                MaterialPtr terrainMat = MaterialManager::getSingleton().getByName("Demos/TerrainMixed");
388                Ogre::Pass *thePass = terrainMat->getTechnique(0)->createPass();
389                thePass->setSceneBlending(Ogre::SBT_MODULATE);
390                Ogre::TextureUnitState *texState = thePass->createTextureUnitState();
391                texState->setTextureName("TheShadowMap");
392                thePass->_load();
393
394                terrainMat->compile();
395                terrainMat->load();
396
397#endif
398    }
399
400    void destroyScene(void)
401        {
402                if (raySceneQuery)
403                        delete raySceneQuery;
404                delete[] lod_tree_types;
405        }
406
407    void createFrameListener(void)
408    {
409        mFrameListener= new LodTreeFrameListener(mWindow, mCamera, raySceneQuery, lod_tree_types);
410        mFrameListener->showDebugOverlay(false);
411        mRoot->addFrameListener(mFrameListener);
412    }
413
414        Geometry::LodTreeLibrary *CreateLODTrees(const char *filename, int numObjs, float cx, float cz, float w, float h, Vector3 &outcenter, float scale)
415        {
416                static int iname = 0;
417                char newMeshName[16]="";
418                sprintf(newMeshName,"tree_%d",iname);
419
420
421                // load LOD info from the object
422                meshloader=new Geometry::GeoMeshLoader;
423                Geometry::Mesh *themesh = meshloader->load((char*)filename);
424
425                if (!meshloader->GetLodStripsData())
426            OGRE_EXCEPT(1, "The loaded mesh does not contain LOD info for the trunk","LOD Demo");
427                if (!meshloader->GetTreeSimpSeq())
428            OGRE_EXCEPT(1, "The loaded mesh does not contain LOD info for the foliage","LOD Demo");
429
430                Ogre::Entity *entity = mSceneMgr->createEntity(newMeshName,filename);           
431//              if (!entity->getMesh().unique())
432//              {
433                        static int iclone = 0;
434                        char newCloneMesh[16]="";
435                        sprintf(newCloneMesh,"clonemesh_%d",iclone);
436                        char newCloneEntity[16]="";
437                        sprintf(newCloneEntity,"cloneentity_%d",iclone);
438                        iclone++;
439
440                        Ogre::MeshPtr newmesh = entity->getMesh()->clone(newCloneMesh);
441                        entity = mSceneMgr->createEntity(newCloneEntity,newCloneMesh);
442//              }
443                Ogre::Mesh *ogreMesh = entity->getMesh().getPointer();
444                entity->setNormaliseNormals(true);
445
446                Geometry::LodTreeLibrary *mytree = new Geometry::LodTreeLibrary(
447                                                                                                meshloader->GetLodStripsData(),
448                                                                                                meshloader->GetTreeSimpSeq(),
449                                                                                                themesh,
450                                                                                                new CustomIndexData(ogreMesh) );
451
452                outcenter=Vector3::ZERO;
453
454                for (int i=0; i<numObjs; i++)
455                {
456                        char newTreeName[16]="";
457                        sprintf(newTreeName,"arbol_%d_%d",iname,i);
458                        Ogre::SceneNode * auxnode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
459                        Ogre::Entity *auxent = entity->clone(newTreeName);
460                        auxnode->attachObject( auxent );
461
462                        float kx = (rand()%100)/100.0f;
463                        float kz = (rand()%100)/100.0f;
464
465                        Ogre::Vector3 treepos(kx*(cx-w*0.5f) + (1.0f-kx)*(cx+w*0.5f), 200.0f,
466                                                                  kz*(cz-h*0.5f) + (1.0f-kz)*(cz+h*0.5f));
467
468                        Ogre::Ray ray(treepos,Ogre::Vector3::NEGATIVE_UNIT_Y);
469                        raySceneQuery->setRay(ray);
470                        RaySceneQueryResult &rayRes = raySceneQuery->execute();
471                        RaySceneQueryResult::iterator itr = rayRes.begin();
472                        if (itr != rayRes.end() && itr->worldFragment)
473                                treepos = itr->worldFragment->singleIntersection;
474
475                        auxnode->translate(treepos);
476                        auxnode->scale(scale,scale,scale);
477                        auxnode->rotate(Ogre::Vector3(0,1,0),Ogre::Degree(rand()%360));
478                        auxent->setNormaliseNormals(true);
479                        outcenter+=treepos;
480                }
481                outcenter/=numObjs;
482                iname++;
483
484                return mytree;
485        }
486
487        float Rand(float minN, float maxN)
488        {
489                return (((rand()%1000)/1000.0f)*(maxN-minN))+minN;
490        }
491
492};
493
494
495
496#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
497#define WIN32_LEAN_AND_MEAN
498#include "windows.h"
499#endif
500
501#ifdef __cplusplus
502extern "C" {
503#endif
504
505#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
506INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
507#else
508int main(int argc, char **argv)
509#endif
510{
511    // Create application object
512    LodTreeApplication app;
513
514    try {
515        app.go();
516    } catch( Exception& e ) {
517#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
518        MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
519#else
520        std::cerr << "An exception has occured: " << e.getFullDescription();
521#endif
522    }
523
524
525    return 0;
526}
527
528#ifdef __cplusplus
529}
530#endif
Note: See TracBrowser for help on using the repository browser.