[5] | 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 |
---|