1 | /* |
---|
2 | ----------------------------------------------------------------------------- |
---|
3 | This source file is part of OGRE |
---|
4 | (Object-oriented Graphics Rendering Engine) |
---|
5 | For the latest info, see http://www.ogre3d.org/ |
---|
6 | |
---|
7 | Copyright (c) 2000-2006 Torus Knot Software Ltd |
---|
8 | Also see acknowledgements in Readme.html |
---|
9 | |
---|
10 | You may use this sample code for anything you like, it is not covered by the |
---|
11 | LGPL 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 | |
---|
23 | AnimationState* 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 */ |
---|
35 | SceneNode *headNode ; |
---|
36 | Overlay* waterOverlay ; |
---|
37 | ParticleSystem *particleSystem ; |
---|
38 | ParticleEmitter *particleEmitter ; |
---|
39 | SceneManager *sceneMgr ; |
---|
40 | |
---|
41 | void 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 |
---|
92 | class WaterCircle |
---|
93 | { |
---|
94 | private: |
---|
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 | } |
---|
203 | public: |
---|
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 | } ; |
---|
247 | bool WaterCircle::first = true ; |
---|
248 | HardwareVertexBufferSharedPtr WaterCircle::posnormVertexBuffer = |
---|
249 | HardwareVertexBufferSharedPtr() ; |
---|
250 | HardwareIndexBufferSharedPtr WaterCircle::indexBuffer = |
---|
251 | HardwareIndexBufferSharedPtr() ; |
---|
252 | HardwareVertexBufferSharedPtr* WaterCircle::texcoordsVertexBuffers = 0 ; |
---|
253 | |
---|
254 | /* =========================================================================*/ |
---|
255 | /* WaterListener class */ |
---|
256 | /* =========================================================================*/ |
---|
257 | // Event handler |
---|
258 | class WaterListener: public ExampleFrameListener |
---|
259 | { |
---|
260 | protected: |
---|
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 | |
---|
424 | public: |
---|
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 | |
---|
530 | class WaterApplication : public ExampleApplication |
---|
531 | { |
---|
532 | public: |
---|
533 | WaterApplication() |
---|
534 | : waterMesh(0) |
---|
535 | { |
---|
536 | |
---|
537 | } |
---|
538 | |
---|
539 | ~WaterApplication() { |
---|
540 | delete waterMesh; |
---|
541 | } |
---|
542 | |
---|
543 | protected: |
---|
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 |
---|
648 | extern "C" { |
---|
649 | #endif |
---|
650 | |
---|
651 | #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 |
---|
652 | INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT ) |
---|
653 | #else |
---|
654 | int 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 |
---|