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