[692] | 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-2005 The OGRE Team
|
---|
| 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 = bundlePath() + "/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_ITEM_NOT_FOUND,
|
---|
| 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 | tm += evt.timeSinceLastFrame / timeDensity ;
|
---|
| 621 |
|
---|
| 622 | if (noiseOn)
|
---|
| 623 | updateNoise();
|
---|
| 624 |
|
---|
| 625 | // Call default
|
---|
| 626 | return ExampleFrameListener::frameStarted(evt);
|
---|
| 627 | }
|
---|
| 628 | virtual bool processUnbufferedKeyInput(const FrameEvent& evt)
|
---|
| 629 | {
|
---|
| 630 | bool retval = ExampleFrameListener::processUnbufferedKeyInput(evt);
|
---|
| 631 |
|
---|
| 632 | Real changeSpeed = evt.timeSinceLastFrame ;
|
---|
| 633 |
|
---|
| 634 | // adjust keyboard speed with SHIFT (increase) and CONTROL (decrease)
|
---|
| 635 | if (mInputDevice->isKeyDown(KC_LSHIFT) || mInputDevice->isKeyDown(KC_RSHIFT)) {
|
---|
| 636 | changeSpeed *= 10.0f ;
|
---|
| 637 | }
|
---|
| 638 | if (mInputDevice->isKeyDown(KC_LCONTROL)) {
|
---|
| 639 | changeSpeed /= 10.0f ;
|
---|
| 640 | }
|
---|
| 641 |
|
---|
| 642 | #define ADJUST_RANGE(_value,_keyPlus,_keyMinus,_minVal,_maxVal,_change,_macro) {\
|
---|
| 643 | if (mInputDevice->isKeyDown(_keyPlus)) \
|
---|
| 644 | { _value+=_change ; if (_value>=_maxVal) _value = _maxVal ; _macro ; } ; \
|
---|
| 645 | if (mInputDevice->isKeyDown(_keyMinus)) \
|
---|
| 646 | { _value-=_change; if (_value<=_minVal) _value = _minVal ; _macro ; } ; \
|
---|
| 647 | }
|
---|
| 648 |
|
---|
| 649 | ADJUST_RANGE(displacement, KC_2, KC_1, -2, 2, 0.1f*changeSpeed, updateInfoDisplacement()) ;
|
---|
| 650 |
|
---|
| 651 | ADJUST_RANGE(density, KC_4, KC_3, 0.1, 500, 10.0f*changeSpeed, updateInfoDensity()) ;
|
---|
| 652 |
|
---|
| 653 | ADJUST_RANGE(timeDensity, KC_6, KC_5, 1, 10, 1.0f*changeSpeed, updateInfoTimeDensity()) ;
|
---|
| 654 |
|
---|
| 655 | #define SWITCH_VALUE(_key,_timeDelay, _macro) { \
|
---|
| 656 | if (mInputDevice->isKeyDown(_key) && timeoutDelay==0) { \
|
---|
| 657 | timeoutDelay = _timeDelay ; _macro ;} }
|
---|
| 658 |
|
---|
| 659 | timeoutDelay-=evt.timeSinceLastFrame ;
|
---|
| 660 | if (timeoutDelay<=0)
|
---|
| 661 | timeoutDelay = 0;
|
---|
| 662 |
|
---|
| 663 | SWITCH_VALUE(KC_O, 0.5f, currentMeshIndex++ ; setObject());
|
---|
| 664 |
|
---|
| 665 | SWITCH_VALUE(KC_N, 0.5f, noiseOn = !noiseOn ; setNoiseOn());
|
---|
| 666 |
|
---|
| 667 | SWITCH_VALUE(KC_M, 0.5f, currentLBXindex++ ; setMaterialBlending());
|
---|
| 668 |
|
---|
| 669 | SWITCH_VALUE(KC_C, 0.5f, currentCubeMapIndex++ ; setCubeMap());
|
---|
| 670 |
|
---|
| 671 | SWITCH_VALUE(KC_SPACE, 0.5f, goRandom());
|
---|
| 672 |
|
---|
| 673 | return retval ;
|
---|
| 674 | }
|
---|
| 675 | } ;
|
---|
| 676 |
|
---|
| 677 | class CubeMapApplication : public ExampleApplication
|
---|
| 678 | {
|
---|
| 679 | public:
|
---|
| 680 | CubeMapApplication() {}
|
---|
| 681 |
|
---|
| 682 | protected:
|
---|
| 683 | SceneNode *objectNode;
|
---|
| 684 |
|
---|
| 685 | // Just override the mandatory create scene method
|
---|
| 686 | void createScene(void)
|
---|
| 687 | {
|
---|
| 688 | // First check that cube mapping is supported
|
---|
| 689 | if (!Root::getSingleton().getRenderSystem()->getCapabilities()->hasCapability(RSC_CUBEMAPPING))
|
---|
| 690 | {
|
---|
| 691 | OGRE_EXCEPT(1, "Your card does not support cube mapping, so cannot "
|
---|
| 692 | "run this demo. Sorry!",
|
---|
| 693 | "CubeMapApplication::createScene");
|
---|
| 694 | }
|
---|
| 695 |
|
---|
| 696 | // Set ambient light
|
---|
| 697 | mSceneMgr->setAmbientLight(ColourValue(0.5, 0.5, 0.5));
|
---|
| 698 |
|
---|
| 699 | // Create a skybox
|
---|
| 700 | mSceneMgr->setSkyBox(true, SKYBOX_MATERIAL );
|
---|
| 701 |
|
---|
| 702 | // Create a light
|
---|
| 703 | Light* l = mSceneMgr->createLight("MainLight");
|
---|
| 704 | // Accept default settings: point light, white diffuse, just set position
|
---|
| 705 | // NB I could attach the light to a SceneNode if I wanted it to move automatically with
|
---|
| 706 | // other objects, but I don't
|
---|
| 707 | l->setPosition(20,80,50);
|
---|
| 708 |
|
---|
| 709 | objectNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();
|
---|
| 710 |
|
---|
| 711 | // show overlay
|
---|
| 712 | Overlay* overlay = OverlayManager::getSingleton().getByName("Example/CubeMappingOverlay");
|
---|
| 713 | overlay->show();
|
---|
| 714 | }
|
---|
| 715 |
|
---|
| 716 | void createFrameListener(void)
|
---|
| 717 | {
|
---|
| 718 | mFrameListener= new CubeMapListener(mWindow, mCamera, mSceneMgr, objectNode);
|
---|
| 719 | mRoot->addFrameListener(mFrameListener);
|
---|
| 720 | }
|
---|
| 721 | };
|
---|