Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/Samples/Water/src/Water.cpp @ 3

Last change on this file since 3 was 3, checked in by anonymous, 17 years ago

=update

File size: 20.4 KB
Line 
1/*
2-----------------------------------------------------------------------------
3This source file is part of OGRE
4    (Object-oriented Graphics Rendering Engine)
5For the latest info, see http://www.ogre3d.org/
6
7Copyright (c) 2000-2006 Torus Knot Software Ltd
8Also see acknowledgements in Readme.html
9
10You may use this sample code for anything you like, it is not covered by the
11LGPL like the rest of the engine.
12-----------------------------------------------------------------------------
13*/
14/* Static water simulation by eru
15 * Started 29.05.2003, 20:54:37
16 */
17#include "ExampleApplication.h"
18#include "OgreBillboardParticleRenderer.h"
19#include "WaterMesh.h"
20
21#include <iostream>
22
23AnimationState* mAnimState;
24
25// Mesh stuff
26#define MESH_NAME "WaterMesh"
27#define ENTITY_NAME "WaterEntity"
28#define MATERIAL_PREFIX "Examples/Water"
29#define MATERIAL_NAME "Examples/Water0"
30#define COMPLEXITY 64           // watch out - number of polys is 2*ACCURACY*ACCURACY !
31#define PLANE_SIZE 3000.0f
32#define CIRCLES_MATERIAL "Examples/Water/Circles"
33
34/* Some global variables */
35SceneNode *headNode ;
36Overlay* waterOverlay ;
37ParticleSystem *particleSystem ;
38ParticleEmitter *particleEmitter ;
39SceneManager *sceneMgr ;
40
41void prepareCircleMaterial()
42{
43        char *bmap = new char[256 * 256 * 4] ;
44        memset(bmap, 127, 256 * 256 * 4);
45        for(int b=0;b<16;b++) {
46                int x0 = b % 4 ;
47                int y0 = b >> 2 ;
48                Real radius = 4.0f + 1.4 * (float) b ;
49                for(int x=0;x<64;x++) {
50                        for(int y=0;y<64;y++) {
51                                Real dist = Math::Sqrt((x-32)*(x-32)+(y-32)*(y-32)); // 0..ca.45
52                                dist = fabs(dist -radius -2) / 2.0f ;
53                                dist = dist * 255.0f;
54                                if (dist>255)
55                                        dist=255 ;
56                                int colour = 255-(int)dist ;
57                                colour = (int)( ((Real)(15-b))/15.0f * (Real) colour );
58
59                                bmap[4*(256*(y+64*y0)+x+64*x0)+0]=colour ;
60                                bmap[4*(256*(y+64*y0)+x+64*x0)+1]=colour ;
61                                bmap[4*(256*(y+64*y0)+x+64*x0)+2]=colour ;
62                                bmap[4*(256*(y+64*y0)+x+64*x0)+3]=colour ;
63                        }
64                }
65        }
66
67        DataStreamPtr imgstream(new MemoryDataStream(bmap, 256 * 256 * 4));
68        //~ Image img;
69        //~ img.loadRawData( imgstream, 256, 256, PF_A8R8G8B8 );
70        //~ TextureManager::getSingleton().loadImage( CIRCLES_MATERIAL , img );
71        TextureManager::getSingleton().loadRawData(CIRCLES_MATERIAL,
72        ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
73                imgstream, 256, 256, PF_A8R8G8B8);
74        MaterialPtr material =
75                MaterialManager::getSingleton().create( CIRCLES_MATERIAL,
76        ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME);
77        TextureUnitState *texLayer = material->getTechnique(0)->getPass(0)->createTextureUnitState( CIRCLES_MATERIAL );
78        texLayer->setTextureAddressingMode( TextureUnitState::TAM_CLAMP );
79        material->setSceneBlending( SBT_ADD );
80        material->setDepthWriteEnabled( false ) ;
81    material->load();
82    // finished with bmap so release the memory
83    delete [] bmap;
84}
85
86
87/* =========================================================================*/
88/*               WaterCircle class                                          */
89/* =========================================================================*/
90#define CIRCLE_SIZE 500.0
91#define CIRCLE_TIME 0.5f
92class WaterCircle
93{
94private:
95        String name ;
96        SceneNode *node ;
97        MeshPtr mesh ;
98        SubMesh *subMesh ;
99        Entity *entity ;
100        Real tm ;
101        static bool first ;
102        // some buffers shared by all circles
103        static HardwareVertexBufferSharedPtr posnormVertexBuffer ;
104        static HardwareIndexBufferSharedPtr indexBuffer ; // indices for 2 faces
105        static HardwareVertexBufferSharedPtr *texcoordsVertexBuffers ;
106
107        float *texBufData;
108        void _prepareMesh()
109        {
110                int i,lvl ;
111
112                mesh = MeshManager::getSingleton().createManual(name,
113            ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME) ;
114                subMesh = mesh->createSubMesh();
115                subMesh->useSharedVertices=false;
116
117                int numVertices = 4 ;
118
119                if (first) { // first Circle, create some static common data
120                        first = false ;
121
122                        // static buffer for position and normals
123                        posnormVertexBuffer =
124                                HardwareBufferManager::getSingleton().createVertexBuffer(
125                                        6*sizeof(float), // size of one vertex data
126                                        4, // number of vertices
127                                        HardwareBuffer::HBU_STATIC_WRITE_ONLY, // usage
128                                        false); // no shadow buffer
129                        float *posnormBufData = (float*) posnormVertexBuffer->
130                                lock(HardwareBuffer::HBL_DISCARD);
131                        for(i=0;i<numVertices;i++) {
132                                posnormBufData[6*i+0]=((Real)(i%2)-0.5f)*CIRCLE_SIZE; // pos X
133                                posnormBufData[6*i+1]=0; // pos Y
134                                posnormBufData[6*i+2]=((Real)(i/2)-0.5f)*CIRCLE_SIZE; // pos Z
135                                posnormBufData[6*i+3]=0 ; // normal X
136                                posnormBufData[6*i+4]=1 ; // normal Y
137                                posnormBufData[6*i+5]=0 ; // normal Z
138                        }
139                        posnormVertexBuffer->unlock();
140
141                        // static buffers for 16 sets of texture coordinates
142                        texcoordsVertexBuffers = new HardwareVertexBufferSharedPtr[16];
143                        for(lvl=0;lvl<16;lvl++) {
144                                texcoordsVertexBuffers[lvl] =
145                                        HardwareBufferManager::getSingleton().createVertexBuffer(
146                                                2*sizeof(float), // size of one vertex data
147                                                numVertices, // number of vertices
148                                                HardwareBuffer::HBU_STATIC_WRITE_ONLY, // usage
149                                                false); // no shadow buffer
150                                float *texcoordsBufData = (float*) texcoordsVertexBuffers[lvl]->
151                                        lock(HardwareBuffer::HBL_DISCARD);
152                                float x0 = (Real)(lvl % 4) * 0.25 ;
153                                float y0 = (Real)(lvl / 4) * 0.25 ;
154                                y0 = 0.75-y0 ; // upside down
155                                for(i=0;i<4;i++) {
156                                        texcoordsBufData[i*2 + 0]=
157                                                x0 + 0.25 * (Real)(i%2) ;
158                                        texcoordsBufData[i*2 + 1]=
159                                                y0 + 0.25 * (Real)(i/2) ;
160                                }
161                                texcoordsVertexBuffers[lvl]->unlock();
162                        }
163
164                        // Index buffer for 2 faces
165                        unsigned short faces[6] = {2,1,0,  2,3,1};
166                        indexBuffer =
167                                HardwareBufferManager::getSingleton().createIndexBuffer(
168                                        HardwareIndexBuffer::IT_16BIT,
169                                        6,
170                                        HardwareBuffer::HBU_STATIC_WRITE_ONLY);
171                        indexBuffer->writeData(0,
172                                indexBuffer->getSizeInBytes(),
173                                faces,
174                                true); // true?
175                }
176
177                // Initialize vertex data
178                subMesh->vertexData = new VertexData();
179                subMesh->vertexData->vertexStart = 0;
180                subMesh->vertexData->vertexCount = 4;
181                // first, set vertex buffer bindings
182                VertexBufferBinding *vbind = subMesh->vertexData->vertexBufferBinding ;
183                vbind->setBinding(0, posnormVertexBuffer);
184                vbind->setBinding(1, texcoordsVertexBuffers[0]);
185                // now, set vertex buffer declaration
186                VertexDeclaration *vdecl = subMesh->vertexData->vertexDeclaration ;
187                vdecl->addElement(0, 0, VET_FLOAT3, VES_POSITION);
188                vdecl->addElement(0, 3*sizeof(float), VET_FLOAT3, VES_NORMAL);
189                vdecl->addElement(1, 0, VET_FLOAT2, VES_TEXTURE_COORDINATES);
190
191                // Initialize index data
192                subMesh->indexData->indexBuffer = indexBuffer;
193                subMesh->indexData->indexStart = 0;
194                subMesh->indexData->indexCount = 6;
195
196                // set mesh bounds
197                AxisAlignedBox circleBounds(-CIRCLE_SIZE/2.0f, 0, -CIRCLE_SIZE/2.0f,
198                        CIRCLE_SIZE/2.0f, 0, CIRCLE_SIZE/2.0f);
199                mesh->_setBounds(circleBounds);
200        mesh->load();
201        mesh->touch();
202        }
203public:
204        int lvl ;
205        void setTextureLevel()
206        {
207                subMesh->vertexData->vertexBufferBinding->setBinding(1, texcoordsVertexBuffers[lvl]);
208        }
209        WaterCircle(const String& name, Real x, Real y)
210        {
211                this->name = name ;
212                _prepareMesh();
213                node = static_cast<SceneNode*> (sceneMgr->getRootSceneNode()->createChild(name));
214                node->translate(x*(PLANE_SIZE/COMPLEXITY), 10, y*(PLANE_SIZE/COMPLEXITY));
215                entity = sceneMgr->createEntity(name, name);
216                entity->setMaterialName(CIRCLES_MATERIAL);
217                node->attachObject(entity);
218                tm = 0 ;
219                lvl = 0 ;
220                setTextureLevel();
221        }
222        ~WaterCircle()
223        {
224                MeshManager::getSingleton().remove(mesh->getHandle());
225                sceneMgr->destroyEntity(entity->getName());
226                static_cast<SceneNode*> (sceneMgr->getRootSceneNode())->removeChild(node->getName());
227        }
228        void animate(Real timeSinceLastFrame)
229        {
230                int lastlvl = lvl ;
231                tm += timeSinceLastFrame ;
232                lvl = (int) ( (Real)(tm)/CIRCLE_TIME * 16 );
233                if (lvl<16 && lvl!=lastlvl) {
234                        setTextureLevel();
235                }
236        }
237        static void clearStaticBuffers()
238        {
239                posnormVertexBuffer = HardwareVertexBufferSharedPtr() ;
240                indexBuffer = HardwareIndexBufferSharedPtr() ;
241                for(int i=0;i<16;i++) {
242                        texcoordsVertexBuffers[i] = HardwareVertexBufferSharedPtr() ;
243                }
244                delete [] texcoordsVertexBuffers;
245        }
246} ;
247bool WaterCircle::first = true ;
248HardwareVertexBufferSharedPtr WaterCircle::posnormVertexBuffer =
249        HardwareVertexBufferSharedPtr() ;
250HardwareIndexBufferSharedPtr WaterCircle::indexBuffer =
251        HardwareIndexBufferSharedPtr() ;
252HardwareVertexBufferSharedPtr* WaterCircle::texcoordsVertexBuffers = 0 ;
253
254/* =========================================================================*/
255/*               WaterListener class                                          */
256/* =========================================================================*/
257// Event handler
258class WaterListener: public ExampleFrameListener
259{
260protected:
261        WaterMesh *waterMesh ;
262        Entity *waterEntity ;
263        int materialNumber ;
264        bool skyBoxOn ;
265        Real timeoutDelay ;
266
267#define RAIN_HEIGHT_RANDOM 5
268#define RAIN_HEIGHT_CONSTANT 5
269
270
271        typedef std::vector<WaterCircle*> WaterCircles ;
272        WaterCircles circles ;
273
274        void processCircles(Real timeSinceLastFrame)
275        {
276                for(unsigned int i=0;i<circles.size();i++) {
277                        circles[i]->animate(timeSinceLastFrame);
278                }
279                bool found ;
280                do {
281                        found = false ;
282                        for(WaterCircles::iterator it = circles.begin() ;
283                                        it != circles.end();
284                                        ++it) {
285                                if ((*it)->lvl>=16) {
286                                        delete (*it);
287                                        circles.erase(it);
288                                        found = true ;
289                                        break ;
290                                }
291                        }
292                } while (found) ;
293        }
294
295        void processParticles()
296        {
297                static int pindex = 0 ;
298                ParticleIterator pit = particleSystem->_getIterator() ;
299                while(!pit.end()) {
300                        Particle *particle = pit.getNext();
301                        Vector3 ppos = particle->position;
302                        if (ppos.y<=0 && particle->timeToLive>0) { // hits the water!
303                                // delete particle
304                                particle->timeToLive = 0.0f;
305                                // push the water
306                                float x = ppos.x / PLANE_SIZE * COMPLEXITY ;
307                                float y = ppos.z / PLANE_SIZE * COMPLEXITY ;
308                                float h = rand() % RAIN_HEIGHT_RANDOM + RAIN_HEIGHT_CONSTANT ;
309                                if (x<1) x=1 ;
310                                if (x>COMPLEXITY-1) x=COMPLEXITY-1;
311                                if (y<1) y=1 ;
312                                if (y>COMPLEXITY-1) y=COMPLEXITY-1;
313                                waterMesh->push(x,y,-h) ;
314                                WaterCircle *circle = new WaterCircle(
315                                        "Circle#"+StringConverter::toString(pindex++),
316                                        x, y);
317                                circles.push_back(circle);
318                        }
319                }
320        }
321
322        /** Head animation */
323        Real headDepth ;
324        void animateHead(Real timeSinceLastFrame)
325        {
326                // sine track? :)
327                static double sines[4] = {0,100,200,300};
328                static const double adds[4] = {0.3,-1.6,1.1,0.5};
329                static Vector3 oldPos = Vector3::UNIT_Z;
330                for(int i=0;i<4;i++) {
331                        sines[i]+=adds[i]*timeSinceLastFrame;
332                }
333                Real tx = ((sin(sines[0]) + sin(sines[1])) / 4 + 0.5 ) * (float)(COMPLEXITY-2) + 1 ;
334                Real ty = ((sin(sines[2]) + sin(sines[3])) / 4 + 0.5 ) * (float)(COMPLEXITY-2) + 1 ;
335                waterMesh->push(tx,ty, -headDepth);
336                Real step = PLANE_SIZE / COMPLEXITY ;
337                headNode->resetToInitialState();
338                headNode->scale(3,3,3);
339                Vector3 newPos = Vector3(step*tx, headDepth, step*ty);
340                Vector3 diffPos = newPos - oldPos ;
341                Quaternion headRotation = Vector3::UNIT_Z.getRotationTo(diffPos);
342                oldPos = newPos ;
343                headNode->translate(newPos);
344                headNode->rotate(headRotation);
345        }
346
347        // GUI updaters
348        void updateInfoParamC()
349        {
350                OverlayManager::getSingleton().getOverlayElement("Example/Water/Param_C") \
351                        ->setCaption("[1/2]Ripple speed: "+StringConverter::toString(waterMesh->PARAM_C));
352        }
353        void updateInfoParamD()
354        {
355                OverlayManager::getSingleton().getOverlayElement("Example/Water/Param_D") \
356                        ->setCaption("[3/4]Distance: "+StringConverter::toString(waterMesh->PARAM_D));
357        }
358        void updateInfoParamU()
359        {
360                OverlayManager::getSingleton().getOverlayElement("Example/Water/Param_U") \
361                        ->setCaption("[5/6]Viscosity: "+StringConverter::toString(waterMesh->PARAM_U));
362        }
363        void updateInfoParamT()
364        {
365                OverlayManager::getSingleton().getOverlayElement("Example/Water/Param_T") \
366                        ->setCaption("[7/8]Frame time: "+StringConverter::toString(waterMesh->PARAM_T));
367        }
368        void updateInfoNormals()
369        {
370                OverlayManager::getSingleton().getOverlayElement("Example/Water/Normals") \
371                        ->setCaption(String("[N]Normals: ")+((waterMesh->useFakeNormals)?"fake":"real"));
372        }
373        void switchNormals()
374        {
375                waterMesh->useFakeNormals = !waterMesh->useFakeNormals ;
376                updateInfoNormals() ;
377        }
378        void updateInfoHeadDepth()
379        {
380                OverlayManager::getSingleton().getOverlayElement("Example/Water/Depth") \
381                        ->setCaption(String("[U/J]Head depth: ")+StringConverter::toString(headDepth));
382        }
383        void updateInfoSkyBox()
384        {
385                OverlayManager::getSingleton().getOverlayElement("Example/Water/SkyBox")
386                        ->setCaption(String("[B]SkyBox: ")+String((skyBoxOn)?"On":"Off") );
387        }
388        void updateMaterial()
389        {
390                String materialName = MATERIAL_PREFIX+StringConverter::toString(materialNumber);
391                MaterialPtr material = MaterialManager::getSingleton().getByName(materialName);
392                if (material.isNull())
393        {
394                        if(materialNumber)
395            {
396                                materialNumber = 0 ;
397                                updateMaterial();
398                                return ;
399                        }
400            else
401            {
402                                OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR,
403                                        "Material "+materialName+"doesn't exist!",
404                                        "WaterListener::updateMaterial");
405                        }
406                }
407                waterEntity->setMaterialName(materialName);
408                OverlayManager::getSingleton().getOverlayElement("Example/Water/Material") \
409                        ->setCaption(String("[M]Material: ")+materialName);
410        }
411
412        void switchMaterial()
413        {
414                materialNumber++;
415                updateMaterial();
416        }
417        void switchSkyBox()
418        {
419                skyBoxOn = !skyBoxOn;
420                sceneMgr->setSkyBox(skyBoxOn, "Examples/SceneSkyBox2");
421                updateInfoSkyBox();
422        }
423
424public:
425    WaterListener(RenderWindow* win, Camera* cam,
426                WaterMesh *waterMesh, Entity *waterEntity)
427        : ExampleFrameListener(win, cam)
428    {
429                this->waterMesh = waterMesh ;
430                this->waterEntity = waterEntity ;
431                materialNumber = 8;
432                timeoutDelay = 0.0f;
433                headDepth = 2.0f;
434                skyBoxOn = false ;
435
436                updateMaterial();
437                updateInfoParamC();
438                updateInfoParamD();
439                updateInfoParamU();
440                updateInfoParamT();
441                updateInfoNormals();
442                updateInfoHeadDepth();
443                updateInfoSkyBox();
444    }
445
446        virtual ~WaterListener ()
447        {
448                // If when you finish the application is still raining there
449                // are water circles that are still being processed
450                unsigned int activeCircles = this->circles.size ();
451
452                // Kill the active water circles
453                for (unsigned int i = 0; i < activeCircles; i++)
454                        delete (this->circles[i]);
455        }
456
457    bool frameStarted(const FrameEvent& evt)
458    {
459                using namespace OIS;
460
461                if( ExampleFrameListener::frameStarted(evt) == false )
462                {
463                        // check if we are exiting, if so, clear static HardwareBuffers to avoid segfault
464                        WaterCircle::clearStaticBuffers();
465                        return false;
466                }
467
468        mAnimState->addTime(evt.timeSinceLastFrame);
469
470                // process keyboard events
471                Real changeSpeed = evt.timeSinceLastFrame ;
472
473                // adjust keyboard speed with SHIFT (increase) and CONTROL (decrease)
474                if (mKeyboard->isKeyDown(OIS::KC_LSHIFT) || mKeyboard->isKeyDown(OIS::KC_RSHIFT)) {
475                        changeSpeed *= 10.0f ;
476                }
477                if (mKeyboard->isKeyDown(OIS::KC_LCONTROL)) { 
478                        changeSpeed /= 10.0f ;
479                }
480
481                // rain
482                processCircles(evt.timeSinceLastFrame);
483                if (mKeyboard->isKeyDown(OIS::KC_SPACE)) {
484                        particleEmitter->setEmissionRate(20.0f);
485                } else {
486                        particleEmitter->setEmissionRate(0.0f);
487                }
488                processParticles();
489
490                // adjust values (some macros for faster change
491#define ADJUST_RANGE(_value,_plus,_minus,_minVal,_maxVal,_change,_macro) {\
492        if (mKeyboard->isKeyDown(_plus)) \
493                { _value+=_change ; if (_value>=_maxVal) _value = _maxVal ; _macro ; } ; \
494        if (mKeyboard->isKeyDown(_minus)) \
495                { _value-=_change; if (_value<=_minVal) _value = _minVal ; _macro ; } ; \
496}
497
498                ADJUST_RANGE(headDepth, KC_U, KC_J, 0, 10, 0.5*changeSpeed, updateInfoHeadDepth()) ;
499
500                ADJUST_RANGE(waterMesh->PARAM_C, KC_2, KC_1, 0, 10, 0.1f*changeSpeed, updateInfoParamC()) ;
501
502                ADJUST_RANGE(waterMesh->PARAM_D, KC_4, KC_3, 0.1, 10, 0.1f*changeSpeed, updateInfoParamD()) ;
503
504                ADJUST_RANGE(waterMesh->PARAM_U, KC_6, KC_5, -2, 10, 0.1f*changeSpeed, updateInfoParamU()) ;
505
506                ADJUST_RANGE(waterMesh->PARAM_T, KC_8, KC_7, 0, 10, 0.1f*changeSpeed, updateInfoParamT()) ;
507
508                timeoutDelay-=evt.timeSinceLastFrame ;
509                if (timeoutDelay<=0)
510                        timeoutDelay = 0;
511
512#define SWITCH_VALUE(_key,_timeDelay, _macro) { \
513                if (mKeyboard->isKeyDown(_key) && timeoutDelay==0) { \
514                        timeoutDelay = _timeDelay ; _macro ;} }
515
516                SWITCH_VALUE(KC_N, 0.5f, switchNormals());
517
518                SWITCH_VALUE(KC_M, 0.5f, switchMaterial());
519
520                SWITCH_VALUE(KC_B, 0.5f, switchSkyBox());
521
522                animateHead(evt.timeSinceLastFrame);
523
524                waterMesh->updateMesh(evt.timeSinceLastFrame);
525
526                return true;
527    }
528};
529
530class WaterApplication : public ExampleApplication
531{
532public:
533    WaterApplication()
534        : waterMesh(0)
535    {
536
537    }
538
539    ~WaterApplication() {
540        delete waterMesh;
541    }
542
543protected:
544        WaterMesh *waterMesh ;
545        Entity *waterEntity ;
546
547// Just override the mandatory create scene method
548    void createScene(void)
549    {
550                sceneMgr = mSceneMgr ;
551        // Set ambient light
552        mSceneMgr->setAmbientLight(ColourValue(0.75, 0.75, 0.75));
553
554        // Create a light
555        Light* l = mSceneMgr->createLight("MainLight");
556        // Accept default settings: point light, white diffuse, just set position
557        // NB I could attach the light to a SceneNode if I wanted it to move automatically with
558        //  other objects, but I don't
559        l->setPosition(200,300,100);
560
561                // Create water mesh and entity
562                waterMesh = new WaterMesh(MESH_NAME, PLANE_SIZE, COMPLEXITY);
563                waterEntity = mSceneMgr->createEntity(ENTITY_NAME,
564                        MESH_NAME);
565                //~ waterEntity->setMaterialName(MATERIAL_NAME);
566                SceneNode *waterNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
567                waterNode->attachObject(waterEntity);
568
569        // Add a head, give it it's own node
570        headNode = waterNode->createChildSceneNode();
571        Entity *ent = mSceneMgr->createEntity("head", "ogrehead.mesh");
572        headNode->attachObject(ent);
573
574                // Make sure the camera track this node
575        //~ mCamera->setAutoTracking(true, headNode);
576
577                // Create the camera node, set its position & attach camera
578        SceneNode* camNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
579                camNode->translate(0, 500, PLANE_SIZE);
580                camNode->yaw(Degree(-45));
581        camNode->attachObject(mCamera);
582
583                // Create light node
584        SceneNode* lightNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
585                lightNode->attachObject(l);
586
587        // set up spline animation of light node
588        Animation* anim = mSceneMgr->createAnimation("WaterLight", 20);
589                NodeAnimationTrack *track ;
590        TransformKeyFrame *key ;
591                // create a random spline for light
592                track = anim->createNodeTrack(0, lightNode);
593                key = track->createNodeKeyFrame(0);
594                for(int ff=1;ff<=19;ff++) {
595                        key = track->createNodeKeyFrame(ff);
596                        Vector3 lpos (
597                                rand()%(int)PLANE_SIZE , //- PLANE_SIZE/2,
598                                rand()%300+100,
599                                rand()%(int)PLANE_SIZE //- PLANE_SIZE/2
600                                );
601                        key->setTranslate(lpos);
602                }
603                key = track->createNodeKeyFrame(20);
604
605        // Create a new animation state to track this
606        mAnimState = mSceneMgr->createAnimationState("WaterLight");
607        mAnimState->setEnabled(true);
608
609        // Put in a bit of fog for the hell of it
610        //mSceneMgr->setFog(FOG_EXP, ColourValue::White, 0.0002);
611
612                // show overlay
613                waterOverlay = OverlayManager::getSingleton().getByName("Example/WaterOverlay");
614                waterOverlay->show();
615
616        // Let there be rain
617        particleSystem = mSceneMgr->createParticleSystem("rain",
618            "Examples/Water/Rain");
619                particleEmitter = particleSystem->getEmitter(0);
620        SceneNode* rNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
621        rNode->translate(PLANE_SIZE/2.0f, 3000, PLANE_SIZE/2.0f);
622        rNode->attachObject(particleSystem);
623        // Fast-forward the rain so it looks more natural
624        particleSystem->fastForward(20);
625                // It can't be set in .particle file, and we need it ;)
626                static_cast<BillboardParticleRenderer*>(particleSystem->getRenderer())->setBillboardOrigin(BBO_BOTTOM_CENTER);
627
628                prepareCircleMaterial();
629        }
630
631    // Create new frame listener
632    void createFrameListener(void)
633    {
634        mFrameListener= new WaterListener(mWindow, mCamera, waterMesh, waterEntity);
635        mRoot->addFrameListener(mFrameListener);
636    }
637
638};
639
640
641
642#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
643#define WIN32_LEAN_AND_MEAN
644#include "windows.h"
645#endif
646
647#ifdef __cplusplus
648extern "C" {
649#endif
650
651#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
652INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT )
653#else
654int main(int argc, char **argv)
655#endif
656{
657    // Create application object
658    WaterApplication app;
659
660        srand(time(0));
661
662    try {
663        app.go();
664    } catch( Exception& e ) {
665#if OGRE_PLATFORM == OGRE_PLATFORM_WIN32
666        MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL);
667#else
668        std::cerr << "An exception has occured: " << e.getFullDescription();
669#endif
670    }
671
672    return 0;
673}
674
675#ifdef __cplusplus
676}
677#endif
Note: See TracBrowser for help on using the repository browser.