[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 | |
---|
| 15 | /** |
---|
| 16 | \file |
---|
| 17 | CubeMapping.h |
---|
| 18 | \brief |
---|
| 19 | Specialisation of OGRE's framework application to show the |
---|
| 20 | cube mapping feature where a wrap-around environment is reflected |
---|
| 21 | off of an object. |
---|
| 22 | Extended with Perlin noise to show we can. |
---|
| 23 | */ |
---|
| 24 | |
---|
| 25 | #include "ExampleApplication.h" |
---|
| 26 | |
---|
| 27 | #define ENTITY_NAME "CubeMappedEntity" |
---|
| 28 | #define MESH_NAME "CubeMappedMesh" |
---|
| 29 | |
---|
| 30 | #define MATERIAL_NAME "Examples/SceneCubeMap2" |
---|
| 31 | #define SKYBOX_MATERIAL "Examples/SceneSkyBox2" |
---|
| 32 | |
---|
| 33 | /* ==================================================================== */ |
---|
| 34 | /* Perlin Noise data and algorithms - copied from Perlin himself :) */ |
---|
| 35 | /* ==================================================================== */ |
---|
| 36 | #define lerp(t,a,b) ( (a)+(t)*((b)-(a)) ) |
---|
| 37 | #define fade(t) ( (t)*(t)*(t)*(t)*((t)*((t)*6-15)+10) ) |
---|
| 38 | double grad(int hash, double x, double y, double z) { |
---|
| 39 | int h = hash & 15; // CONVERT LO 4 BITS OF HASH CODE |
---|
| 40 | double u = h<8||h==12||h==13 ? x : y, // INTO 12 GRADIENT DIRECTIONS. |
---|
| 41 | v = h<4||h==12||h==13 ? y : z; |
---|
| 42 | return ((h&1) == 0 ? u : -u) + ((h&2) == 0 ? v : -v); |
---|
| 43 | } |
---|
| 44 | int p[512]={ |
---|
| 45 | 151,160,137,91,90,15, |
---|
| 46 | 131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23, |
---|
| 47 | 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33, |
---|
| 48 | 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166, |
---|
| 49 | 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244, |
---|
| 50 | 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196, |
---|
| 51 | 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123, |
---|
| 52 | 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42, |
---|
| 53 | 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9, |
---|
| 54 | 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228, |
---|
| 55 | 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107, |
---|
| 56 | 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, |
---|
| 57 | 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180, |
---|
| 58 | |
---|
| 59 | 151,160,137,91,90,15, |
---|
| 60 | 131,13,201,95,96,53,194,233,7,225,140,36,103,30,69,142,8,99,37,240,21,10,23, |
---|
| 61 | 190, 6,148,247,120,234,75,0,26,197,62,94,252,219,203,117,35,11,32,57,177,33, |
---|
| 62 | 88,237,149,56,87,174,20,125,136,171,168, 68,175,74,165,71,134,139,48,27,166, |
---|
| 63 | 77,146,158,231,83,111,229,122,60,211,133,230,220,105,92,41,55,46,245,40,244, |
---|
| 64 | 102,143,54, 65,25,63,161, 1,216,80,73,209,76,132,187,208, 89,18,169,200,196, |
---|
| 65 | 135,130,116,188,159,86,164,100,109,198,173,186, 3,64,52,217,226,250,124,123, |
---|
| 66 | 5,202,38,147,118,126,255,82,85,212,207,206,59,227,47,16,58,17,182,189,28,42, |
---|
| 67 | 223,183,170,213,119,248,152, 2,44,154,163, 70,221,153,101,155,167, 43,172,9, |
---|
| 68 | 129,22,39,253, 19,98,108,110,79,113,224,232,178,185, 112,104,218,246,97,228, |
---|
| 69 | 251,34,242,193,238,210,144,12,191,179,162,241, 81,51,145,235,249,14,239,107, |
---|
| 70 | 49,192,214, 31,181,199,106,157,184, 84,204,176,115,121,50,45,127, 4,150,254, |
---|
| 71 | 138,236,205,93,222,114,67,29,24,72,243,141,128,195,78,66,215,61,156,180 |
---|
| 72 | }; |
---|
| 73 | |
---|
| 74 | double noise3(double x, double y, double z) { |
---|
| 75 | int X = ((int)floor(x)) & 255, // FIND UNIT CUBE THAT |
---|
| 76 | Y = ((int)floor(y)) & 255, // CONTAINS POINT. |
---|
| 77 | Z = ((int)floor(z)) & 255; |
---|
| 78 | x -= floor(x); // FIND RELATIVE X,Y,Z |
---|
| 79 | y -= floor(y); // OF POINT IN CUBE. |
---|
| 80 | z -= floor(z); |
---|
| 81 | double u = fade(x), // COMPUTE FADE CURVES |
---|
| 82 | v = fade(y), // FOR EACH OF X,Y,Z. |
---|
| 83 | w = fade(z); |
---|
| 84 | int A = p[X ]+Y, AA = p[A]+Z, AB = p[A+1]+Z, // HASH COORDINATES OF |
---|
| 85 | B = p[X+1]+Y, BA = p[B]+Z, BB = p[B+1]+Z; // THE 8 CUBE CORNERS, |
---|
| 86 | |
---|
| 87 | return lerp(w, lerp(v, lerp(u, grad(p[AA ], x , y , z ), // AND ADD |
---|
| 88 | grad(p[BA ], x-1, y , z )), // BLENDED |
---|
| 89 | lerp(u, grad(p[AB ], x , y-1, z ), // RESULTS |
---|
| 90 | grad(p[BB ], x-1, y-1, z ))),// FROM 8 |
---|
| 91 | lerp(v, lerp(u, grad(p[AA+1], x , y , z-1 ), // CORNERS |
---|
| 92 | grad(p[BA+1], x-1, y , z-1 )), // OF CUBE |
---|
| 93 | lerp(u, grad(p[AB+1], x , y-1, z-1 ), |
---|
| 94 | grad(p[BB+1], x-1, y-1, z-1 )))); |
---|
| 95 | } |
---|
| 96 | |
---|
| 97 | /* ==================================================================== */ |
---|
| 98 | /* Main part */ |
---|
| 99 | /* ==================================================================== */ |
---|
| 100 | |
---|
| 101 | class CubeMapListener : public ExampleFrameListener |
---|
| 102 | { |
---|
| 103 | private: |
---|
| 104 | // main variables |
---|
| 105 | Real tm ; |
---|
| 106 | Real timeoutDelay ; |
---|
| 107 | SceneManager *mSceneMgr ; |
---|
| 108 | SceneNode *objectNode ; |
---|
| 109 | |
---|
| 110 | // mesh-specific data |
---|
| 111 | MeshPtr originalMesh ; |
---|
| 112 | MeshPtr clonedMesh ; |
---|
| 113 | |
---|
| 114 | Entity *objectEntity ; |
---|
| 115 | std::vector<MaterialPtr> clonedMaterials ; |
---|
| 116 | |
---|
| 117 | // configuration |
---|
| 118 | Real displacement ; |
---|
| 119 | Real density ; |
---|
| 120 | Real timeDensity ; |
---|
| 121 | bool noiseOn ; |
---|
| 122 | size_t currentMeshIndex ; |
---|
| 123 | StringVector availableMeshes ; |
---|
| 124 | size_t currentLBXindex ; |
---|
| 125 | LayerBlendOperationEx currentLBX ; |
---|
| 126 | size_t currentCubeMapIndex ; |
---|
| 127 | StringVector availableCubeMaps ; |
---|
| 128 | MaterialPtr material ; |
---|
| 129 | |
---|
| 130 | void _updatePositionNoise(int numVertices, float *dstVertices, |
---|
| 131 | float *defaultVertices) |
---|
| 132 | { |
---|
| 133 | for(int i=0;i<3*numVertices;i+=3) { |
---|
| 134 | double n = 1 + displacement * noise3( |
---|
| 135 | defaultVertices[i]/density + tm, |
---|
| 136 | defaultVertices[i+1]/density + tm, |
---|
| 137 | defaultVertices[i+2]/density + tm); |
---|
| 138 | dstVertices[i+0] = defaultVertices[i] * n ; |
---|
| 139 | dstVertices[i+1] = defaultVertices[i+1] * n ; |
---|
| 140 | dstVertices[i+2] = defaultVertices[i+2] * n ; |
---|
| 141 | } |
---|
| 142 | } |
---|
| 143 | |
---|
| 144 | float* _normalsGetCleared(VertexData *vertexData) |
---|
| 145 | { |
---|
| 146 | const VertexElement *normVE = vertexData-> |
---|
| 147 | vertexDeclaration->findElementBySemantic(VES_NORMAL); |
---|
| 148 | HardwareVertexBufferSharedPtr normHVB = vertexData-> |
---|
| 149 | vertexBufferBinding->getBuffer(normVE->getSource()); |
---|
| 150 | float* normals = (float*) normHVB->lock(0, normHVB->getSizeInBytes(), |
---|
| 151 | HardwareBuffer::HBL_DISCARD); |
---|
| 152 | memset(normals, 0, normHVB->getSizeInBytes()); |
---|
| 153 | return normals; |
---|
| 154 | } |
---|
| 155 | |
---|
| 156 | void _normalsSaveNormalized(VertexData *vertexData, float *normals) |
---|
| 157 | { |
---|
| 158 | const VertexElement *normVE = vertexData-> |
---|
| 159 | vertexDeclaration->findElementBySemantic(VES_NORMAL); |
---|
| 160 | HardwareVertexBufferSharedPtr normHVB = vertexData-> |
---|
| 161 | vertexBufferBinding->getBuffer(normVE->getSource()); |
---|
| 162 | size_t numVertices = normHVB->getNumVertices(); |
---|
| 163 | for(size_t i=0;i<numVertices;i++, normals+=3) { |
---|
| 164 | Vector3 n(normals[0], normals[1], normals[2]); |
---|
| 165 | n.normalise(); |
---|
| 166 | normals[0] = n.x ; |
---|
| 167 | normals[1] = n.y ; |
---|
| 168 | normals[2] = n.z ; |
---|
| 169 | } |
---|
| 170 | normHVB->unlock(); |
---|
| 171 | } |
---|
| 172 | |
---|
| 173 | void _updateVertexDataNoiseAndNormals( |
---|
| 174 | VertexData *dstData, |
---|
| 175 | VertexData *orgData, |
---|
| 176 | IndexData *indexData, |
---|
| 177 | float *normals) |
---|
| 178 | { |
---|
| 179 | size_t i ; |
---|
| 180 | |
---|
| 181 | // Find destination vertex buffer |
---|
| 182 | const VertexElement *dstVEPos = dstData-> |
---|
| 183 | vertexDeclaration->findElementBySemantic(VES_POSITION); |
---|
| 184 | HardwareVertexBufferSharedPtr dstHVBPos = dstData-> |
---|
| 185 | vertexBufferBinding->getBuffer(dstVEPos->getSource()); |
---|
| 186 | // Find source vertex buffer |
---|
| 187 | const VertexElement *orgVEPos = orgData-> |
---|
| 188 | vertexDeclaration->findElementBySemantic(VES_POSITION); |
---|
| 189 | HardwareVertexBufferSharedPtr orgHVBPos = orgData-> |
---|
| 190 | vertexBufferBinding->getBuffer(orgVEPos->getSource()); |
---|
| 191 | // Lock these buffers |
---|
| 192 | float *dstDataPos = (float*) dstHVBPos->lock(0, dstHVBPos->getSizeInBytes(), |
---|
| 193 | HardwareBuffer::HBL_DISCARD); |
---|
| 194 | float *orgDataPos = (float*) orgHVBPos->lock(0, orgHVBPos->getSizeInBytes(), |
---|
| 195 | HardwareBuffer::HBL_READ_ONLY); |
---|
| 196 | // make noise |
---|
| 197 | size_t numVertices = orgHVBPos->getNumVertices(); |
---|
| 198 | for(i=0;i<3*numVertices;i+=3) { |
---|
| 199 | double n = 1 + displacement * noise3( |
---|
| 200 | orgDataPos[i]/density + tm, |
---|
| 201 | orgDataPos[i+1]/density + tm, |
---|
| 202 | orgDataPos[i+2]/density + tm); |
---|
| 203 | dstDataPos[i+0] = orgDataPos[i] * n ; |
---|
| 204 | dstDataPos[i+1] = orgDataPos[i+1] * n ; |
---|
| 205 | dstDataPos[i+2] = orgDataPos[i+2] * n ; |
---|
| 206 | } |
---|
| 207 | // Unlock original position buffer |
---|
| 208 | orgHVBPos->unlock(); |
---|
| 209 | |
---|
| 210 | // calculate normals |
---|
| 211 | HardwareIndexBufferSharedPtr indexHB = indexData->indexBuffer ; |
---|
| 212 | unsigned short * vertexIndices = (unsigned short*) indexHB->lock( |
---|
| 213 | 0, indexHB->getSizeInBytes(), HardwareBuffer::HBL_READ_ONLY); |
---|
| 214 | size_t numFaces = indexData->indexCount / 3 ; |
---|
| 215 | for(i=0 ; i<numFaces ; i++, vertexIndices+=3) { |
---|
| 216 | //~ int p0 = 0; |
---|
| 217 | //~ int p1 = 1; |
---|
| 218 | //~ int p2 = 2; |
---|
| 219 | int p0 = vertexIndices[0] ; |
---|
| 220 | int p1 = vertexIndices[1] ; |
---|
| 221 | int p2 = vertexIndices[2] ; |
---|
| 222 | |
---|
| 223 | //~ Vector3 v0(10,0,20); |
---|
| 224 | //~ Vector3 v1(30,0,20); |
---|
| 225 | //~ Vector3 v2(20,-1,50); |
---|
| 226 | Vector3 v0(dstDataPos[3*p0], dstDataPos[3*p0+1], dstDataPos[3*p0+2]); |
---|
| 227 | Vector3 v1(dstDataPos[3*p1], dstDataPos[3*p1+1], dstDataPos[3*p1+2]); |
---|
| 228 | Vector3 v2(dstDataPos[3*p2], dstDataPos[3*p2+1], dstDataPos[3*p2+2]); |
---|
| 229 | |
---|
| 230 | Vector3 diff1 = v1 - v2 ; |
---|
| 231 | Vector3 diff2 = v1 - v0 ; |
---|
| 232 | Vector3 fn = diff1.crossProduct(diff2); |
---|
| 233 | #define _ADD_VECTOR_TO_REALS(ptr,vec) { *(ptr)+=vec.x; *((ptr)+1)+=vec.y; *((ptr)+2)+=vec.z; } |
---|
| 234 | _ADD_VECTOR_TO_REALS(normals+3*p0, fn); |
---|
| 235 | _ADD_VECTOR_TO_REALS(normals+3*p1, fn); |
---|
| 236 | _ADD_VECTOR_TO_REALS(normals+3*p2, fn); |
---|
| 237 | #undef _ADD_VECTOR_TO_REALS |
---|
| 238 | } |
---|
| 239 | indexHB->unlock(); |
---|
| 240 | |
---|
| 241 | // Unlock destination position buffer |
---|
| 242 | dstHVBPos->unlock(); |
---|
| 243 | } |
---|
| 244 | |
---|
| 245 | void updateNoise() |
---|
| 246 | { |
---|
| 247 | float *sharedNormals = 0 ; |
---|
| 248 | for(int m=0;m<clonedMesh->getNumSubMeshes();m++) { // for each subMesh |
---|
| 249 | SubMesh *subMesh = clonedMesh->getSubMesh(m); |
---|
| 250 | SubMesh *orgSubMesh = originalMesh->getSubMesh(m); |
---|
| 251 | if (subMesh->useSharedVertices) { |
---|
| 252 | if (!sharedNormals) { // first of shared |
---|
| 253 | sharedNormals = _normalsGetCleared(clonedMesh->sharedVertexData); |
---|
| 254 | } |
---|
| 255 | _updateVertexDataNoiseAndNormals( |
---|
| 256 | clonedMesh->sharedVertexData, |
---|
| 257 | originalMesh->sharedVertexData, |
---|
| 258 | subMesh->indexData, |
---|
| 259 | sharedNormals); |
---|
| 260 | } else { |
---|
| 261 | float* normals = _normalsGetCleared(subMesh->vertexData); |
---|
| 262 | _updateVertexDataNoiseAndNormals( |
---|
| 263 | subMesh->vertexData, |
---|
| 264 | orgSubMesh->vertexData, |
---|
| 265 | subMesh->indexData, |
---|
| 266 | normals); |
---|
| 267 | _normalsSaveNormalized(subMesh->vertexData, normals); |
---|
| 268 | } |
---|
| 269 | } |
---|
| 270 | if (sharedNormals) { |
---|
| 271 | _normalsSaveNormalized(clonedMesh->sharedVertexData, sharedNormals); |
---|
| 272 | } |
---|
| 273 | } |
---|
| 274 | |
---|
| 275 | void clearEntity() |
---|
| 276 | { |
---|
| 277 | // delete cloned materials |
---|
| 278 | for(unsigned int m=0;m<clonedMaterials.size();m++) { |
---|
| 279 | MaterialManager::getSingleton().remove(clonedMaterials[m]->getHandle()) ; |
---|
| 280 | } |
---|
| 281 | clonedMaterials.clear(); |
---|
| 282 | |
---|
| 283 | // detach and destroy entity |
---|
| 284 | objectNode->detachAllObjects(); |
---|
| 285 | mSceneMgr->destroyEntity(ENTITY_NAME); |
---|
| 286 | |
---|
| 287 | // destroy mesh as well, to reset its geometry |
---|
| 288 | MeshManager::getSingleton().remove(clonedMesh->getHandle()); |
---|
| 289 | |
---|
| 290 | objectEntity = 0 ; |
---|
| 291 | } |
---|
| 292 | |
---|
| 293 | VertexData* _prepareVertexData(VertexData *orgVD) |
---|
| 294 | { |
---|
| 295 | if (!orgVD) |
---|
| 296 | return 0 ; |
---|
| 297 | |
---|
| 298 | // Hacky bit: reorganise vertex buffers to a buffer-per-element |
---|
| 299 | // Since this demo was written a while back to assume that |
---|
| 300 | // Really this demo should be replaced with a vertex program noise |
---|
| 301 | // distortion, but left the software for now since it's nice for older |
---|
| 302 | // card owners |
---|
| 303 | VertexDeclaration* newDecl = orgVD->vertexDeclaration->clone(); |
---|
| 304 | const VertexDeclaration::VertexElementList& elems = newDecl->getElements(); |
---|
| 305 | VertexDeclaration::VertexElementList::const_iterator di; |
---|
| 306 | unsigned short buf = 0; |
---|
| 307 | for (di = elems.begin(); di != elems.end(); ++di) |
---|
| 308 | { |
---|
| 309 | newDecl->modifyElement(buf, buf, 0, di->getType(), di->getSemantic(), di->getIndex()); |
---|
| 310 | buf++; |
---|
| 311 | } |
---|
| 312 | orgVD->reorganiseBuffers(newDecl); |
---|
| 313 | |
---|
| 314 | |
---|
| 315 | VertexData* newVD = new VertexData(); |
---|
| 316 | // copy things that do not change |
---|
| 317 | newVD->vertexCount = orgVD->vertexCount ; |
---|
| 318 | newVD->vertexStart = orgVD->vertexStart ; |
---|
| 319 | // now copy vertex buffers, looking in the declarations |
---|
| 320 | VertexDeclaration* newVDecl = newVD->vertexDeclaration ; |
---|
| 321 | VertexBufferBinding* newVBind = newVD->vertexBufferBinding ; |
---|
| 322 | // note: I assume various semantics are not shared among buffers |
---|
| 323 | const VertexDeclaration::VertexElementList& orgVEL = orgVD->vertexDeclaration->getElements() ; |
---|
| 324 | VertexDeclaration::VertexElementList::const_iterator veli, velend; |
---|
| 325 | velend = orgVEL.end(); |
---|
| 326 | // For each declaration, prepare buffer |
---|
| 327 | for( veli = orgVEL.begin() ; veli != velend ; ++veli) |
---|
| 328 | { |
---|
| 329 | VertexElementSemantic ves = (*veli).getSemantic(); |
---|
| 330 | int source = (*veli).getSource() ; |
---|
| 331 | HardwareVertexBufferSharedPtr orgBuf = orgVD->vertexBufferBinding-> |
---|
| 332 | getBuffer( source ); |
---|
| 333 | // check usage for the new buffer |
---|
| 334 | bool dynamic = false ; |
---|
| 335 | switch(ves) { |
---|
| 336 | case VES_NORMAL : |
---|
| 337 | case VES_POSITION : |
---|
| 338 | dynamic = true ; |
---|
| 339 | break ; |
---|
| 340 | case VES_BLEND_INDICES : |
---|
| 341 | case VES_BLEND_WEIGHTS : |
---|
| 342 | case VES_DIFFUSE : |
---|
| 343 | case VES_SPECULAR : |
---|
| 344 | case VES_TEXTURE_COORDINATES : |
---|
| 345 | default : |
---|
| 346 | dynamic = false ; |
---|
| 347 | break ; |
---|
| 348 | } |
---|
| 349 | if (dynamic) { // create a new dynamic buffer with write access |
---|
| 350 | HardwareVertexBufferSharedPtr newBuf = |
---|
| 351 | HardwareBufferManager::getSingleton().createVertexBuffer( |
---|
| 352 | orgBuf->getVertexSize(), orgBuf->getNumVertices(), |
---|
| 353 | HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY_DISCARDABLE, |
---|
| 354 | //~ HardwareBuffer::HBU_DYNAMIC, |
---|
| 355 | true |
---|
| 356 | //~ false |
---|
| 357 | ); |
---|
| 358 | newBuf->copyData(*orgBuf, 0, 0, orgBuf->getSizeInBytes(), true); |
---|
| 359 | newVBind->setBinding( source, newBuf ); |
---|
| 360 | } else { // use the old one |
---|
| 361 | newVBind->setBinding( source, orgBuf ); |
---|
| 362 | } |
---|
| 363 | // add element for declaration |
---|
| 364 | newVDecl->addElement(source, (*veli).getOffset(), (*veli).getType(), |
---|
| 365 | ves, (*veli).getIndex()); |
---|
| 366 | } |
---|
| 367 | return newVD; |
---|
| 368 | } |
---|
| 369 | |
---|
| 370 | void prepareClonedMesh() |
---|
| 371 | { |
---|
| 372 | // we create new Mesh based on the original one, but changing |
---|
| 373 | // HBU flags (inside _prepareVertexData) |
---|
| 374 | clonedMesh = MeshManager::getSingleton().createManual(MESH_NAME, |
---|
| 375 | ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME); |
---|
| 376 | clonedMesh->_setBounds(originalMesh->getBounds()); |
---|
| 377 | clonedMesh->_setBoundingSphereRadius(originalMesh->getBoundingSphereRadius()); |
---|
| 378 | //~ if (originalMesh->sharedVertexData) |
---|
| 379 | //~ clonedMesh->sharedVertexData = originalMesh->sharedVertexData->clone(); |
---|
| 380 | clonedMesh->sharedVertexData = |
---|
| 381 | _prepareVertexData(originalMesh->sharedVertexData); |
---|
| 382 | for(int sm=0;sm<originalMesh->getNumSubMeshes();sm++) { |
---|
| 383 | SubMesh *orgSM = originalMesh->getSubMesh(sm); |
---|
| 384 | SubMesh *newSM = clonedMesh->createSubMesh(); |
---|
| 385 | if (orgSM->isMatInitialised()) { |
---|
| 386 | newSM->setMaterialName(orgSM->getMaterialName()); |
---|
| 387 | } |
---|
| 388 | newSM->useSharedVertices = orgSM->useSharedVertices ; |
---|
| 389 | // prepare vertex data |
---|
| 390 | newSM->vertexData = _prepareVertexData(orgSM->vertexData); |
---|
| 391 | // reuse index data |
---|
| 392 | newSM->indexData->indexBuffer = orgSM->indexData->indexBuffer ; |
---|
| 393 | newSM->indexData->indexStart = orgSM->indexData->indexStart ; |
---|
| 394 | newSM->indexData->indexCount = orgSM->indexData->indexCount ; |
---|
| 395 | } |
---|
| 396 | } |
---|
| 397 | |
---|
| 398 | void prepareEntity(const String& meshName) |
---|
| 399 | { |
---|
| 400 | if (objectEntity) { |
---|
| 401 | clearEntity(); |
---|
| 402 | } |
---|
| 403 | |
---|
| 404 | // load mesh if necessary - note, I assume this is the only point |
---|
| 405 | // Mesh can get loaded, since I want to make sure about its HBU etc. |
---|
| 406 | originalMesh = MeshManager::getSingleton().getByName(meshName); |
---|
| 407 | if (originalMesh.isNull()) { |
---|
| 408 | originalMesh = MeshManager::getSingleton().load(meshName, |
---|
| 409 | ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, |
---|
| 410 | HardwareBuffer::HBU_STATIC_WRITE_ONLY, |
---|
| 411 | HardwareBuffer::HBU_STATIC_WRITE_ONLY, |
---|
| 412 | true, true); //so we can still read it |
---|
| 413 | if (originalMesh.isNull()) { |
---|
| 414 | OGRE_EXCEPT(Exception::ERR_ITEM_NOT_FOUND, |
---|
| 415 | "Can't find a mesh: '"+meshName+"'", |
---|
| 416 | "CubeMapListener::prepareEntity"); |
---|
| 417 | } |
---|
| 418 | } |
---|
| 419 | |
---|
| 420 | |
---|
| 421 | prepareClonedMesh(); |
---|
| 422 | |
---|
| 423 | // create an entity based on cloned mesh |
---|
| 424 | objectEntity = mSceneMgr->createEntity( ENTITY_NAME, MESH_NAME); |
---|
| 425 | objectEntity->setMaterialName( material->getName() ); |
---|
| 426 | Pass* pass = material->getTechnique(0)->getPass(0); |
---|
| 427 | |
---|
| 428 | // go through subentities and set materials as required |
---|
| 429 | for(int m=0;m<clonedMesh->getNumSubMeshes();m++) { |
---|
| 430 | SubMesh *subMesh = clonedMesh->getSubMesh(m); |
---|
| 431 | SubEntity *subEntity = objectEntity->getSubEntity(m); |
---|
| 432 | // check if this submesh has material set |
---|
| 433 | if (subMesh->isMatInitialised()) { |
---|
| 434 | const String& matName = subMesh->getMaterialName(); |
---|
| 435 | MaterialPtr subMat = |
---|
| 436 | MaterialManager::getSingleton().getByName(matName); |
---|
| 437 | if (!subMat.isNull()) { // clone material, add layers from global material |
---|
| 438 | subMat->load(); |
---|
| 439 | MaterialPtr cloned = subMat->clone( |
---|
| 440 | "CubeMapTempMaterial#"+StringConverter::toString(m)); |
---|
| 441 | Pass* clonedPass = cloned->getTechnique(0)->getPass(0); |
---|
| 442 | // can't help it - have to do it :) |
---|
| 443 | if (meshName=="knot.mesh") { |
---|
| 444 | for(size_t tl=0;tl<clonedPass->getNumTextureUnitStates();tl++) { |
---|
| 445 | TextureUnitState *tlayer = clonedPass->getTextureUnitState(tl); |
---|
| 446 | tlayer->setScrollAnimation(1.0 , 0); |
---|
| 447 | } |
---|
| 448 | } |
---|
| 449 | // add layers |
---|
| 450 | for(size_t tl=0;tl<pass->getNumTextureUnitStates();tl++) { |
---|
| 451 | TextureUnitState *orgTL = pass->getTextureUnitState(tl); |
---|
| 452 | TextureUnitState *newTL = clonedPass->createTextureUnitState( |
---|
| 453 | orgTL->getTextureName()); |
---|
| 454 | *newTL = *orgTL ; |
---|
| 455 | newTL->setColourOperationEx(currentLBX); |
---|
| 456 | } |
---|
| 457 | subEntity->setMaterialName(cloned->getName()); |
---|
| 458 | clonedMaterials.push_back(cloned); |
---|
| 459 | } |
---|
| 460 | } |
---|
| 461 | } |
---|
| 462 | |
---|
| 463 | objectNode->attachObject(objectEntity); |
---|
| 464 | |
---|
| 465 | // update noise to avoid one frame w/o noise |
---|
| 466 | if (noiseOn) |
---|
| 467 | updateNoise(); |
---|
| 468 | } |
---|
| 469 | |
---|
| 470 | void updateInfoDisplacement() |
---|
| 471 | { |
---|
| 472 | OverlayManager::getSingleton().getOverlayElement("Example/CubeMapping/Displacement") |
---|
| 473 | ->setCaption("[1/2] Displacement: "+StringConverter::toString(displacement)); |
---|
| 474 | } |
---|
| 475 | void updateInfoDensity() |
---|
| 476 | { |
---|
| 477 | OverlayManager::getSingleton().getOverlayElement("Example/CubeMapping/Density") |
---|
| 478 | ->setCaption("[3/4] Noise density: "+StringConverter::toString(density)); |
---|
| 479 | } |
---|
| 480 | void updateInfoTimeDensity() |
---|
| 481 | { |
---|
| 482 | OverlayManager::getSingleton().getOverlayElement("Example/CubeMapping/TimeDensity") |
---|
| 483 | ->setCaption("[5/6] Time density: "+StringConverter::toString(timeDensity)); |
---|
| 484 | } |
---|
| 485 | void setObject() |
---|
| 486 | { |
---|
| 487 | currentMeshIndex %= availableMeshes.size(); |
---|
| 488 | const String& meshName = availableMeshes[currentMeshIndex]; |
---|
| 489 | printf("Switching to object: %s\n", meshName.c_str()); |
---|
| 490 | prepareEntity(meshName); |
---|
| 491 | OverlayManager::getSingleton().getOverlayElement("Example/CubeMapping/Object") |
---|
| 492 | ->setCaption("[O] Object: "+meshName); |
---|
| 493 | } |
---|
| 494 | void setNoiseOn() |
---|
| 495 | { |
---|
| 496 | OverlayManager::getSingleton().getOverlayElement("Example/CubeMapping/Noise") |
---|
| 497 | ->setCaption(String("[N] Noise: ")+ ((noiseOn)?"on":"off") ); |
---|
| 498 | } |
---|
| 499 | void setMaterialBlending() |
---|
| 500 | { |
---|
| 501 | currentLBXindex %= 5; |
---|
| 502 | String lbxName ; |
---|
| 503 | #define _LAZYERU_(a,b,c) case a : currentLBX = b ; lbxName = c ; break ; |
---|
| 504 | switch (currentLBXindex) { |
---|
| 505 | _LAZYERU_(0, LBX_ADD, "ADD") |
---|
| 506 | _LAZYERU_(1, LBX_MODULATE, "MODULATE") |
---|
| 507 | _LAZYERU_(2, LBX_MODULATE_X2, "MODULATE X2") |
---|
| 508 | _LAZYERU_(3, LBX_MODULATE_X4, "MODULATE X4") |
---|
| 509 | _LAZYERU_(4, LBX_SOURCE1, "SOURCE1") |
---|
| 510 | _LAZYERU_(5, LBX_SOURCE2, "SOURCE2") |
---|
| 511 | // more? |
---|
| 512 | } |
---|
| 513 | #undef _LAZYERU_ |
---|
| 514 | // reset entities, materials and so on |
---|
| 515 | prepareEntity(availableMeshes[currentMeshIndex]); |
---|
| 516 | OverlayManager::getSingleton().getOverlayElement("Example/CubeMapping/Material") |
---|
| 517 | ->setCaption("[M] Material blend:"+lbxName); |
---|
| 518 | } |
---|
| 519 | void setCubeMap() |
---|
| 520 | { |
---|
| 521 | currentCubeMapIndex %= availableCubeMaps.size(); |
---|
| 522 | unsigned int i ; |
---|
| 523 | String cubeMapName = availableCubeMaps[currentCubeMapIndex]; |
---|
| 524 | Pass *pass = material->getTechnique(0)->getPass(0); |
---|
| 525 | for(i=0;i<(int)pass->getTextureUnitState(0)->getNumFrames();i++) { |
---|
| 526 | String oldTexName = pass->getTextureUnitState(0)-> |
---|
| 527 | getFrameTextureName(i); |
---|
| 528 | TexturePtr oldTex = TextureManager::getSingleton().getByName(oldTexName); |
---|
| 529 | TextureManager::getSingleton().remove(oldTexName); |
---|
| 530 | } |
---|
| 531 | pass->getTextureUnitState(0)->setCubicTextureName(cubeMapName, true); |
---|
| 532 | |
---|
| 533 | MaterialPtr mat2 = |
---|
| 534 | MaterialManager::getSingleton().getByName(SKYBOX_MATERIAL); |
---|
| 535 | Pass* pass2 = mat2->getTechnique(0)->getPass(0); |
---|
| 536 | for(i=0;i<(int)pass2->getTextureUnitState(0)->getNumFrames();i++) { |
---|
| 537 | String oldTexName = pass2->getTextureUnitState(0)-> |
---|
| 538 | getFrameTextureName(i); |
---|
| 539 | TexturePtr oldTex = TextureManager::getSingleton().getByName(oldTexName); |
---|
| 540 | TextureManager::getSingleton().remove(oldTexName); |
---|
| 541 | } |
---|
| 542 | pass2->getTextureUnitState(0)->setCubicTextureName(cubeMapName, false); |
---|
| 543 | |
---|
| 544 | mSceneMgr->setSkyBox(true, SKYBOX_MATERIAL ); |
---|
| 545 | |
---|
| 546 | prepareEntity(availableMeshes[currentMeshIndex]); |
---|
| 547 | OverlayManager::getSingleton().getOverlayElement("Example/CubeMapping/CubeMap") |
---|
| 548 | ->setCaption("[C] CubeMap:"+cubeMapName); |
---|
| 549 | } |
---|
| 550 | |
---|
| 551 | #define RANDOM_FROM(a,b) (((float)(rand() & 65535)) / 65536.0f * ((b)-(a)) + (a)) |
---|
| 552 | void goRandom() |
---|
| 553 | { |
---|
| 554 | displacement = RANDOM_FROM(0.0f, 1.0f); |
---|
| 555 | updateInfoDisplacement(); |
---|
| 556 | |
---|
| 557 | density = RANDOM_FROM(1.0f, 300.0f); |
---|
| 558 | updateInfoDensity(); |
---|
| 559 | |
---|
| 560 | timeDensity = RANDOM_FROM(1.0f, 10.0f); |
---|
| 561 | updateInfoTimeDensity(); |
---|
| 562 | } |
---|
| 563 | |
---|
| 564 | #define MEDIA_FILENAME "media.cfg" |
---|
| 565 | void readConfig() |
---|
| 566 | { |
---|
| 567 | std::string media_filename(MEDIA_FILENAME); |
---|
| 568 | #if OGRE_PLATFORM == OGRE_PLATFORM_APPLE |
---|
| 569 | media_filename = macBundlePath() + "/Contents/Resources/" + media_filename; |
---|
| 570 | #endif |
---|
| 571 | ConfigFile cfg; |
---|
| 572 | cfg.load( media_filename ); |
---|
| 573 | availableMeshes = cfg.getMultiSetting("Mesh"); |
---|
| 574 | availableCubeMaps = cfg.getMultiSetting("CubeMap"); |
---|
| 575 | } |
---|
| 576 | |
---|
| 577 | public: |
---|
| 578 | CubeMapListener(RenderWindow* win, Camera* cam, |
---|
| 579 | SceneManager *sceneMgr, SceneNode *objectNode) |
---|
| 580 | : ExampleFrameListener(win, cam) |
---|
| 581 | { |
---|
| 582 | this->mSceneMgr = sceneMgr ; |
---|
| 583 | this->objectNode = objectNode ; |
---|
| 584 | |
---|
| 585 | tm = 0 ; |
---|
| 586 | timeoutDelay = 0 ; |
---|
| 587 | displacement = 0.1f; |
---|
| 588 | density = 50.0f; |
---|
| 589 | timeDensity = 5.0f; |
---|
| 590 | objectEntity = 0 ; |
---|
| 591 | |
---|
| 592 | material = MaterialManager::getSingleton().getByName(MATERIAL_NAME); |
---|
| 593 | |
---|
| 594 | if (material.isNull()) { |
---|
| 595 | OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED, |
---|
| 596 | "Can't find material: "+String(MATERIAL_NAME), |
---|
| 597 | "CubeMapListener::CubeMapListener"); |
---|
| 598 | } |
---|
| 599 | |
---|
| 600 | readConfig(); |
---|
| 601 | |
---|
| 602 | currentMeshIndex = 0 ; |
---|
| 603 | setObject(); |
---|
| 604 | |
---|
| 605 | currentLBXindex = 0 ; |
---|
| 606 | setMaterialBlending(); |
---|
| 607 | |
---|
| 608 | currentCubeMapIndex = 0 ; |
---|
| 609 | setCubeMap(); |
---|
| 610 | |
---|
| 611 | noiseOn = true ; |
---|
| 612 | setNoiseOn(); |
---|
| 613 | |
---|
| 614 | updateInfoDisplacement(); |
---|
| 615 | updateInfoDensity(); |
---|
| 616 | updateInfoTimeDensity(); |
---|
| 617 | } |
---|
| 618 | virtual bool frameStarted(const FrameEvent& evt) |
---|
| 619 | { |
---|
| 620 | // Call default |
---|
| 621 | if( ExampleFrameListener::frameStarted(evt) == false ) |
---|
| 622 | return false; |
---|
| 623 | |
---|
| 624 | tm += evt.timeSinceLastFrame / timeDensity ; |
---|
| 625 | |
---|
| 626 | if (noiseOn) |
---|
| 627 | updateNoise(); |
---|
| 628 | |
---|
| 629 | objectNode->yaw(Degree(20*evt.timeSinceLastFrame)); |
---|
| 630 | |
---|
| 631 | return true; |
---|
| 632 | } |
---|
| 633 | virtual bool processUnbufferedKeyInput(const FrameEvent& evt) |
---|
| 634 | { |
---|
| 635 | using namespace OIS; |
---|
| 636 | |
---|
| 637 | bool retval = ExampleFrameListener::processUnbufferedKeyInput(evt); |
---|
| 638 | |
---|
| 639 | Real changeSpeed = evt.timeSinceLastFrame ; |
---|
| 640 | |
---|
| 641 | // adjust keyboard speed with SHIFT (increase) and CONTROL (decrease) |
---|
| 642 | if (mKeyboard->isKeyDown(KC_LSHIFT) || mKeyboard->isKeyDown(KC_RSHIFT)) { |
---|
| 643 | changeSpeed *= 10.0f ; |
---|
| 644 | } |
---|
| 645 | if (mKeyboard->isKeyDown(KC_LCONTROL)) { |
---|
| 646 | changeSpeed /= 10.0f ; |
---|
| 647 | } |
---|
| 648 | |
---|
| 649 | #define ADJUST_RANGE(_value,_keyPlus,_keyMinus,_minVal,_maxVal,_change,_macro) {\ |
---|
| 650 | if (mKeyboard->isKeyDown(_keyPlus)) \ |
---|
| 651 | { _value+=_change ; if (_value>=_maxVal) _value = _maxVal ; _macro ; } ; \ |
---|
| 652 | if (mKeyboard->isKeyDown(_keyMinus)) \ |
---|
| 653 | { _value-=_change; if (_value<=_minVal) _value = _minVal ; _macro ; } ; \ |
---|
| 654 | } |
---|
| 655 | |
---|
| 656 | ADJUST_RANGE(displacement, KC_2, KC_1, -2, 2, 0.1f*changeSpeed, updateInfoDisplacement()) ; |
---|
| 657 | |
---|
| 658 | ADJUST_RANGE(density, KC_4, KC_3, 0.1, 500, 10.0f*changeSpeed, updateInfoDensity()) ; |
---|
| 659 | |
---|
| 660 | ADJUST_RANGE(timeDensity, KC_6, KC_5, 1, 10, 1.0f*changeSpeed, updateInfoTimeDensity()) ; |
---|
| 661 | |
---|
| 662 | #define SWITCH_VALUE(_key,_timeDelay, _macro) { \ |
---|
| 663 | if (mKeyboard->isKeyDown(_key) && timeoutDelay==0) { \ |
---|
| 664 | timeoutDelay = _timeDelay ; _macro ;} } |
---|
| 665 | |
---|
| 666 | timeoutDelay-=evt.timeSinceLastFrame ; |
---|
| 667 | if (timeoutDelay<=0) |
---|
| 668 | timeoutDelay = 0; |
---|
| 669 | |
---|
| 670 | SWITCH_VALUE(KC_O, 0.5f, currentMeshIndex++ ; setObject()); |
---|
| 671 | |
---|
| 672 | SWITCH_VALUE(KC_N, 0.5f, noiseOn = !noiseOn ; setNoiseOn()); |
---|
| 673 | |
---|
| 674 | SWITCH_VALUE(KC_M, 0.5f, currentLBXindex++ ; setMaterialBlending()); |
---|
| 675 | |
---|
| 676 | SWITCH_VALUE(KC_C, 0.5f, currentCubeMapIndex++ ; setCubeMap()); |
---|
| 677 | |
---|
| 678 | SWITCH_VALUE(KC_SPACE, 0.5f, goRandom()); |
---|
| 679 | |
---|
| 680 | return retval ; |
---|
| 681 | } |
---|
| 682 | } ; |
---|
| 683 | |
---|
| 684 | class CubeMapApplication : public ExampleApplication |
---|
| 685 | { |
---|
| 686 | public: |
---|
| 687 | CubeMapApplication() {} |
---|
| 688 | |
---|
| 689 | protected: |
---|
| 690 | SceneNode *objectNode; |
---|
| 691 | |
---|
| 692 | // Just override the mandatory create scene method |
---|
| 693 | void createScene(void) |
---|
| 694 | { |
---|
| 695 | // First check that cube mapping is supported |
---|
| 696 | if (!Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_CUBEMAPPING)) |
---|
| 697 | { |
---|
| 698 | OGRE_EXCEPT(Exception::ERR_NOT_IMPLEMENTED, "Your card does not support cube mapping, so cannot " |
---|
| 699 | "run this demo. Sorry!", |
---|
| 700 | "CubeMapApplication::createScene"); |
---|
| 701 | } |
---|
| 702 | |
---|
| 703 | // Set ambient light |
---|
| 704 | mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5)); |
---|
| 705 | |
---|
| 706 | // Create a skybox |
---|
| 707 | mSceneMgr->setSkyBox(true, SKYBOX_MATERIAL ); |
---|
| 708 | |
---|
| 709 | // Create a light |
---|
| 710 | Light* l = mSceneMgr->createLight("MainLight"); |
---|
| 711 | // Accept default settings: point light, white diffuse, just set position |
---|
| 712 | // NB I could attach the light to a SceneNode if I wanted it to move automatically with |
---|
| 713 | // other objects, but I don't |
---|
| 714 | l->setPosition(20,80,50); |
---|
| 715 | |
---|
| 716 | objectNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(); |
---|
| 717 | |
---|
| 718 | // show overlay |
---|
| 719 | Overlay* overlay = OverlayManager::getSingleton().getByName("Example/CubeMappingOverlay"); |
---|
| 720 | overlay->show(); |
---|
| 721 | } |
---|
| 722 | |
---|
| 723 | void createFrameListener(void) |
---|
| 724 | { |
---|
| 725 | mFrameListener= new CubeMapListener(mWindow, mCamera, mSceneMgr, objectNode); |
---|
| 726 | mRoot->addFrameListener(mFrameListener); |
---|
| 727 | } |
---|
| 728 | }; |
---|