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 | }; |
---|