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

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