diff options
author | David Walter Seikel | 2013-01-13 17:24:39 +1000 |
---|---|---|
committer | David Walter Seikel | 2013-01-13 17:24:39 +1000 |
commit | 393b5cd1dc438872af89d334ef6e5fcc59f27d47 (patch) | |
tree | 6a14521219942a08a1b95cb2f5a923a9edd60f63 /libraries/irrlicht-1.8/source/Irrlicht/CQuake3ShaderSceneNode.cpp | |
parent | Add a note about rasters suggested start up code. (diff) | |
download | SledjHamr-393b5cd1dc438872af89d334ef6e5fcc59f27d47.zip SledjHamr-393b5cd1dc438872af89d334ef6e5fcc59f27d47.tar.gz SledjHamr-393b5cd1dc438872af89d334ef6e5fcc59f27d47.tar.bz2 SledjHamr-393b5cd1dc438872af89d334ef6e5fcc59f27d47.tar.xz |
Added Irrlicht 1.8, but without all the Windows binaries.
Diffstat (limited to '')
-rw-r--r-- | libraries/irrlicht-1.8/source/Irrlicht/CQuake3ShaderSceneNode.cpp | 1376 |
1 files changed, 1376 insertions, 0 deletions
diff --git a/libraries/irrlicht-1.8/source/Irrlicht/CQuake3ShaderSceneNode.cpp b/libraries/irrlicht-1.8/source/Irrlicht/CQuake3ShaderSceneNode.cpp new file mode 100644 index 0000000..9219782 --- /dev/null +++ b/libraries/irrlicht-1.8/source/Irrlicht/CQuake3ShaderSceneNode.cpp | |||
@@ -0,0 +1,1376 @@ | |||
1 | // Copyright (C) 2002-2012 Thomas Alten / Nikolaus Gebhardt | ||
2 | // This file is part of the "Irrlicht Engine". | ||
3 | // For conditions of distribution and use, see copyright notice in irrlicht.h | ||
4 | |||
5 | #include "IrrCompileConfig.h" | ||
6 | |||
7 | #ifdef _IRR_COMPILE_WITH_BSP_LOADER_ | ||
8 | |||
9 | #include "CQuake3ShaderSceneNode.h" | ||
10 | #include "ISceneManager.h" | ||
11 | #include "IVideoDriver.h" | ||
12 | #include "ICameraSceneNode.h" | ||
13 | #include "SViewFrustum.h" | ||
14 | #include "IMeshManipulator.h" | ||
15 | #include "SMesh.h" | ||
16 | #include "IMaterialRenderer.h" | ||
17 | #include "CShadowVolumeSceneNode.h" | ||
18 | |||
19 | namespace irr | ||
20 | { | ||
21 | namespace scene | ||
22 | { | ||
23 | |||
24 | // who, if not you.. | ||
25 | using namespace quake3; | ||
26 | |||
27 | /*! | ||
28 | */ | ||
29 | CQuake3ShaderSceneNode::CQuake3ShaderSceneNode( | ||
30 | scene::ISceneNode* parent, scene::ISceneManager* mgr,s32 id, | ||
31 | io::IFileSystem *fileSystem, const scene::IMeshBuffer *original, | ||
32 | const IShader * shader) | ||
33 | : scene::IMeshSceneNode(parent, mgr, id, | ||
34 | core::vector3df(0.f, 0.f, 0.f), | ||
35 | core::vector3df(0.f, 0.f, 0.f), | ||
36 | core::vector3df(1.f, 1.f, 1.f)), | ||
37 | Shader(shader), Mesh(0), Shadow(0), Original(0), MeshBuffer(0), TimeAbs(0.f) | ||
38 | { | ||
39 | #ifdef _DEBUG | ||
40 | core::stringc dName = "CQuake3ShaderSceneNode "; | ||
41 | dName += Shader->name; | ||
42 | |||
43 | setDebugName( dName.c_str() ); | ||
44 | #endif | ||
45 | |||
46 | // name the Scene Node | ||
47 | this->Name = Shader->name; | ||
48 | |||
49 | // take lightmap vertex type | ||
50 | MeshBuffer = new SMeshBuffer(); | ||
51 | |||
52 | Mesh = new SMesh (); | ||
53 | Mesh->addMeshBuffer ( MeshBuffer ); | ||
54 | MeshBuffer->drop (); | ||
55 | |||
56 | //Original = new SMeshBufferLightMap(); | ||
57 | Original = (const scene::SMeshBufferLightMap*) original; | ||
58 | Original->grab(); | ||
59 | |||
60 | // clone meshbuffer to modifiable buffer | ||
61 | cloneBuffer(MeshBuffer, Original, | ||
62 | Original->getMaterial().ColorMask != 0); | ||
63 | |||
64 | // load all Textures in all stages | ||
65 | loadTextures( fileSystem ); | ||
66 | |||
67 | setAutomaticCulling( scene::EAC_OFF ); | ||
68 | } | ||
69 | |||
70 | |||
71 | /*! | ||
72 | */ | ||
73 | CQuake3ShaderSceneNode::~CQuake3ShaderSceneNode() | ||
74 | { | ||
75 | if (Shadow) | ||
76 | Shadow->drop(); | ||
77 | |||
78 | if (Mesh) | ||
79 | Mesh->drop(); | ||
80 | |||
81 | if (Original) | ||
82 | Original->drop(); | ||
83 | } | ||
84 | |||
85 | |||
86 | |||
87 | /* | ||
88 | create single copies | ||
89 | */ | ||
90 | void CQuake3ShaderSceneNode::cloneBuffer( scene::SMeshBuffer *dest, const scene::SMeshBufferLightMap * buffer, bool translateCenter ) | ||
91 | { | ||
92 | dest->Material = buffer->Material; | ||
93 | dest->Indices = buffer->Indices; | ||
94 | |||
95 | const u32 vsize = buffer->Vertices.size(); | ||
96 | |||
97 | dest->Vertices.set_used( vsize ); | ||
98 | for ( u32 i = 0; i!= vsize; ++i ) | ||
99 | { | ||
100 | const video::S3DVertex2TCoords& src = buffer->Vertices[i]; | ||
101 | video::S3DVertex &dst = dest->Vertices[i]; | ||
102 | |||
103 | dst.Pos = src.Pos; | ||
104 | dst.Normal = src.Normal; | ||
105 | dst.Color = 0xFFFFFFFF; | ||
106 | dst.TCoords = src.TCoords; | ||
107 | |||
108 | if ( i == 0 ) | ||
109 | dest->BoundingBox.reset ( src.Pos ); | ||
110 | else | ||
111 | dest->BoundingBox.addInternalPoint ( src.Pos ); | ||
112 | } | ||
113 | |||
114 | // move the (temp) Mesh to a ScenePosititon | ||
115 | // set Scene Node Position | ||
116 | |||
117 | if ( translateCenter ) | ||
118 | { | ||
119 | MeshOffset = dest->BoundingBox.getCenter(); | ||
120 | setPosition( MeshOffset ); | ||
121 | |||
122 | core::matrix4 m; | ||
123 | m.setTranslation( -MeshOffset ); | ||
124 | SceneManager->getMeshManipulator()->transform( dest, m ); | ||
125 | } | ||
126 | |||
127 | // No Texture!. Use Shader-Pointer for sorting | ||
128 | dest->Material.setTexture(0, (video::ITexture*) Shader); | ||
129 | } | ||
130 | |||
131 | |||
132 | /* | ||
133 | load the textures for all stages | ||
134 | */ | ||
135 | void CQuake3ShaderSceneNode::loadTextures( io::IFileSystem * fileSystem ) | ||
136 | { | ||
137 | const SVarGroup *group; | ||
138 | u32 i; | ||
139 | |||
140 | video::IVideoDriver *driver = SceneManager->getVideoDriver(); | ||
141 | |||
142 | // generic stage | ||
143 | u32 mipmap = 0; | ||
144 | group = Shader->getGroup( 1 ); | ||
145 | if ( group->isDefined ( "nomipmaps" ) ) | ||
146 | { | ||
147 | mipmap = 2 | (driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS)? 1: 0 ); | ||
148 | driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false); | ||
149 | } | ||
150 | |||
151 | // clear all stages and prefill empty | ||
152 | Q3Texture.setAllocStrategy ( core::ALLOC_STRATEGY_SAFE ); | ||
153 | Q3Texture.clear(); | ||
154 | for ( i = 0; i != Shader->VarGroup->VariableGroup.size(); ++i ) | ||
155 | { | ||
156 | Q3Texture.push_back( SQ3Texture() ); | ||
157 | } | ||
158 | |||
159 | u32 pos; | ||
160 | |||
161 | // get texture map | ||
162 | for ( i = 0; i < Shader->VarGroup->VariableGroup.size(); ++i ) | ||
163 | { | ||
164 | group = Shader->getGroup( i ); | ||
165 | |||
166 | const core::stringc &mapname = group->get( "map" ); | ||
167 | if ( 0 == mapname.size() ) | ||
168 | continue; | ||
169 | |||
170 | // our lightmap is passed in material.Texture[2] | ||
171 | if ( mapname == "$lightmap" ) | ||
172 | { | ||
173 | Q3Texture [i].Texture.push_back( Original->getMaterial().getTexture(1) ); | ||
174 | } | ||
175 | else | ||
176 | { | ||
177 | pos = 0; | ||
178 | getTextures( Q3Texture [i].Texture, mapname, pos, fileSystem, driver ); | ||
179 | } | ||
180 | } | ||
181 | |||
182 | // get anim map | ||
183 | for ( i = 0; i < Shader->VarGroup->VariableGroup.size(); ++i ) | ||
184 | { | ||
185 | if ( Q3Texture [i].Texture.size() ) | ||
186 | continue; | ||
187 | |||
188 | group = Shader->getGroup( i ); | ||
189 | |||
190 | const core::stringc &animmap = group->get( "animmap" ); | ||
191 | if ( 0 == animmap.size() ) | ||
192 | continue; | ||
193 | |||
194 | // first parameter is frequency | ||
195 | pos = 0; | ||
196 | Q3Texture [i].TextureFrequency = core::max_( 0.0001f, getAsFloat( animmap, pos ) ); | ||
197 | |||
198 | getTextures( Q3Texture [i].Texture, animmap, pos,fileSystem, driver ); | ||
199 | } | ||
200 | |||
201 | // get clamp map | ||
202 | for ( i = 0; i < Shader->VarGroup->VariableGroup.size(); ++i ) | ||
203 | { | ||
204 | if ( Q3Texture [i].Texture.size() ) | ||
205 | continue; | ||
206 | |||
207 | group = Shader->getGroup( i ); | ||
208 | |||
209 | const core::stringc &clampmap = group->get( "clampmap" ); | ||
210 | if ( 0 == clampmap.size() ) | ||
211 | continue; | ||
212 | |||
213 | Q3Texture [i].TextureAddressMode = video::ETC_CLAMP_TO_EDGE; | ||
214 | pos = 0; | ||
215 | getTextures( Q3Texture [i].Texture, clampmap, pos,fileSystem, driver ); | ||
216 | } | ||
217 | |||
218 | if ( mipmap & 2 ) | ||
219 | driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, mipmap & 1); | ||
220 | } | ||
221 | |||
222 | /* | ||
223 | Register each texture stage, if first is visible | ||
224 | */ | ||
225 | void CQuake3ShaderSceneNode::OnRegisterSceneNode() | ||
226 | { | ||
227 | if ( isVisible() ) | ||
228 | { | ||
229 | SceneManager->registerNodeForRendering(this, getRenderStage() ); | ||
230 | } | ||
231 | ISceneNode::OnRegisterSceneNode(); | ||
232 | } | ||
233 | |||
234 | /* | ||
235 | is this a transparent node ? | ||
236 | */ | ||
237 | E_SCENE_NODE_RENDER_PASS CQuake3ShaderSceneNode::getRenderStage() const | ||
238 | { | ||
239 | E_SCENE_NODE_RENDER_PASS ret = ESNRP_SOLID; | ||
240 | |||
241 | // generic stage | ||
242 | const SVarGroup *group; | ||
243 | |||
244 | group = Shader->getGroup( 1 ); | ||
245 | /* | ||
246 | else | ||
247 | if ( group->getIndex( "portal" ) >= 0 ) | ||
248 | { | ||
249 | ret = ESNRP_TRANSPARENT_EFFECT; | ||
250 | } | ||
251 | else | ||
252 | */ | ||
253 | if ( group->isDefined( "sort", "opaque" ) ) | ||
254 | { | ||
255 | ret = ESNRP_SOLID; | ||
256 | } | ||
257 | else | ||
258 | if ( group->isDefined( "sort", "additive" ) ) | ||
259 | { | ||
260 | ret = ESNRP_TRANSPARENT; | ||
261 | } | ||
262 | else | ||
263 | if ( strstr ( Shader->name.c_str(), "flame" ) || | ||
264 | group->isDefined( "surfaceparm", "water" ) || | ||
265 | group->isDefined( "sort", "underwater" ) || | ||
266 | group->isDefined( "sort", "underwater" ) | ||
267 | ) | ||
268 | { | ||
269 | ret = ESNRP_TRANSPARENT_EFFECT; | ||
270 | } | ||
271 | else | ||
272 | { | ||
273 | // Look if first drawing stage needs graphical underlay | ||
274 | for ( u32 stage = 2; stage < Shader->VarGroup->VariableGroup.size(); ++stage ) | ||
275 | { | ||
276 | if ( 0 == Q3Texture [ stage ].Texture.size() ) | ||
277 | continue; | ||
278 | |||
279 | group = Shader->getGroup( stage ); | ||
280 | |||
281 | SBlendFunc blendfunc ( video::EMFN_MODULATE_1X ); | ||
282 | getBlendFunc( group->get( "blendfunc" ), blendfunc ); | ||
283 | getBlendFunc( group->get( "alphafunc" ), blendfunc ); | ||
284 | |||
285 | //ret = blendfunc.isTransparent ? ESNRP_TRANSPARENT : ESNRP_SOLID; | ||
286 | if ( blendfunc.isTransparent ) | ||
287 | { | ||
288 | ret = ESNRP_TRANSPARENT; | ||
289 | } | ||
290 | break; | ||
291 | } | ||
292 | } | ||
293 | |||
294 | return ret; | ||
295 | } | ||
296 | |||
297 | |||
298 | /* | ||
299 | render in multipass technique | ||
300 | */ | ||
301 | void CQuake3ShaderSceneNode::render() | ||
302 | { | ||
303 | video::IVideoDriver* driver = SceneManager->getVideoDriver(); | ||
304 | E_SCENE_NODE_RENDER_PASS pass = SceneManager->getSceneNodeRenderPass(); | ||
305 | |||
306 | video::SMaterial material; | ||
307 | const SVarGroup *group; | ||
308 | |||
309 | material.Lighting = false; | ||
310 | material.setTexture(1, 0); | ||
311 | material.NormalizeNormals = false; | ||
312 | |||
313 | // generic stage | ||
314 | group = Shader->getGroup( 1 ); | ||
315 | material.BackfaceCulling = getCullingFunction( group->get( "cull" ) ); | ||
316 | |||
317 | u32 pushProjection = 0; | ||
318 | core::matrix4 projection ( core::matrix4::EM4CONST_NOTHING ); | ||
319 | |||
320 | // decal ( solve z-fighting ) | ||
321 | if ( group->isDefined( "polygonoffset" ) ) | ||
322 | { | ||
323 | projection = driver->getTransform( video::ETS_PROJECTION ); | ||
324 | |||
325 | core::matrix4 decalProjection ( projection ); | ||
326 | |||
327 | /* | ||
328 | f32 n = SceneManager->getActiveCamera()->getNearValue(); | ||
329 | f32 f = SceneManager->getActiveCamera()->getFarValue (); | ||
330 | |||
331 | f32 delta = 0.01f; | ||
332 | f32 pz = 0.2f; | ||
333 | f32 epsilon = -2.f * f * n * delta / ( ( f + n ) * pz * ( pz + delta ) ); | ||
334 | decalProjection[10] *= 1.f + epsilon; | ||
335 | */ | ||
336 | // TODO: involve camera | ||
337 | decalProjection[10] -= 0.0002f; | ||
338 | driver->setTransform( video::ETS_PROJECTION, decalProjection ); | ||
339 | pushProjection |= 1; | ||
340 | } | ||
341 | |||
342 | driver->setTransform(video::ETS_WORLD, AbsoluteTransformation ); | ||
343 | if (Shadow) | ||
344 | Shadow->updateShadowVolumes(); | ||
345 | |||
346 | //! render all stages | ||
347 | u32 drawCount = (pass == ESNRP_TRANSPARENT_EFFECT) ? 1 : 0; | ||
348 | core::matrix4 textureMatrix ( core::matrix4::EM4CONST_NOTHING ); | ||
349 | for ( u32 stage = 1; stage < Shader->VarGroup->VariableGroup.size(); ++stage ) | ||
350 | { | ||
351 | SQ3Texture &q = Q3Texture[stage]; | ||
352 | |||
353 | // advance current stage | ||
354 | textureMatrix.makeIdentity(); | ||
355 | animate( stage, textureMatrix ); | ||
356 | |||
357 | // stage finished, no drawing stage ( vertex transform only ) | ||
358 | video::ITexture * tex = q.Texture.size() ? q.Texture [ q.TextureIndex ] : 0; | ||
359 | if ( 0 == tex ) | ||
360 | continue; | ||
361 | |||
362 | // current stage | ||
363 | group = Shader->getGroup( stage ); | ||
364 | |||
365 | material.setTexture(0, tex ); | ||
366 | material.ZBuffer = getDepthFunction( group->get( "depthfunc" ) ); | ||
367 | |||
368 | if ( group->isDefined( "depthwrite" ) ) | ||
369 | { | ||
370 | material.ZWriteEnable = true; | ||
371 | } | ||
372 | else | ||
373 | { | ||
374 | material.ZWriteEnable = drawCount == 0; | ||
375 | } | ||
376 | |||
377 | //resolve quake3 blendfunction to irrlicht Material Type | ||
378 | SBlendFunc blendfunc ( video::EMFN_MODULATE_1X ); | ||
379 | getBlendFunc( group->get( "blendfunc" ), blendfunc ); | ||
380 | getBlendFunc( group->get( "alphafunc" ), blendfunc ); | ||
381 | |||
382 | material.MaterialType = blendfunc.type; | ||
383 | material.MaterialTypeParam = blendfunc.param0; | ||
384 | |||
385 | material.TextureLayer[0].TextureWrapU = q.TextureAddressMode; | ||
386 | material.TextureLayer[0].TextureWrapV = q.TextureAddressMode; | ||
387 | //material.TextureLayer[0].TrilinearFilter = 1; | ||
388 | //material.TextureLayer[0].AnisotropicFilter = 0xFF; | ||
389 | material.setTextureMatrix( 0, textureMatrix ); | ||
390 | |||
391 | driver->setMaterial( material ); | ||
392 | driver->drawMeshBuffer( MeshBuffer ); | ||
393 | drawCount += 1; | ||
394 | |||
395 | } | ||
396 | |||
397 | if ( DebugDataVisible & scene::EDS_MESH_WIRE_OVERLAY ) | ||
398 | { | ||
399 | video::SMaterial deb_m; | ||
400 | deb_m.Wireframe = true; | ||
401 | deb_m.Lighting = false; | ||
402 | deb_m.BackfaceCulling = material.BackfaceCulling; | ||
403 | driver->setMaterial( deb_m ); | ||
404 | |||
405 | driver->drawMeshBuffer( MeshBuffer ); | ||
406 | } | ||
407 | |||
408 | // show normals | ||
409 | if ( DebugDataVisible & scene::EDS_NORMALS ) | ||
410 | { | ||
411 | video::SMaterial deb_m; | ||
412 | |||
413 | IAnimatedMesh * arrow = SceneManager->addArrowMesh ( | ||
414 | "__debugnormalq3", | ||
415 | 0xFFECEC00,0xFF999900, | ||
416 | 4, 8, | ||
417 | 8.f, 6.f, | ||
418 | 0.5f,1.f | ||
419 | ); | ||
420 | if ( 0 == arrow ) | ||
421 | { | ||
422 | arrow = SceneManager->getMesh ( "__debugnormalq3" ); | ||
423 | } | ||
424 | const IMesh *mesh = arrow->getMesh ( 0 ); | ||
425 | |||
426 | // find a good scaling factor | ||
427 | |||
428 | core::matrix4 m2; | ||
429 | |||
430 | // draw normals | ||
431 | const scene::IMeshBuffer* mb = MeshBuffer; | ||
432 | const u32 vSize = video::getVertexPitchFromType(mb->getVertexType()); | ||
433 | const video::S3DVertex* v = ( const video::S3DVertex*)mb->getVertices(); | ||
434 | |||
435 | //f32 colCycle = 270.f / (f32) core::s32_max ( mb->getVertexCount() - 1, 1 ); | ||
436 | |||
437 | for ( u32 i=0; i != mb->getVertexCount(); ++i ) | ||
438 | { | ||
439 | // Align to v->normal | ||
440 | m2.buildRotateFromTo ( core::vector3df ( 0.f, 1.f, 0 ), v->Normal ); | ||
441 | m2.setTranslation ( v->Pos + AbsoluteTransformation.getTranslation () ); | ||
442 | /* | ||
443 | core::quaternion quatRot( v->Normal.Z, 0.f, -v->Normal.X, 1 + v->Normal.Y ); | ||
444 | quatRot.normalize(); | ||
445 | quatRot.getMatrix ( m2, v->Pos ); | ||
446 | |||
447 | m2 [ 12 ] += AbsoluteTransformation [ 12 ]; | ||
448 | m2 [ 13 ] += AbsoluteTransformation [ 13 ]; | ||
449 | m2 [ 14 ] += AbsoluteTransformation [ 14 ]; | ||
450 | */ | ||
451 | driver->setTransform(video::ETS_WORLD, m2 ); | ||
452 | |||
453 | deb_m.Lighting = true; | ||
454 | /* | ||
455 | irr::video::SColorHSL color; | ||
456 | irr::video::SColor rgb(0); | ||
457 | color.Hue = i * colCycle * core::DEGTORAD; | ||
458 | color.Saturation = 1.f; | ||
459 | color.Luminance = 0.5f; | ||
460 | color.toRGB( deb_m.EmissiveColor ); | ||
461 | */ | ||
462 | switch ( i ) | ||
463 | { | ||
464 | case 0: deb_m.EmissiveColor.set(0xFFFFFFFF); break; | ||
465 | case 1: deb_m.EmissiveColor.set(0xFFFF0000); break; | ||
466 | case 2: deb_m.EmissiveColor.set(0xFF00FF00); break; | ||
467 | case 3: deb_m.EmissiveColor.set(0xFF0000FF); break; | ||
468 | default: | ||
469 | deb_m.EmissiveColor = v->Color; break; | ||
470 | } | ||
471 | driver->setMaterial( deb_m ); | ||
472 | |||
473 | for ( u32 a = 0; a != mesh->getMeshBufferCount(); ++a ) | ||
474 | driver->drawMeshBuffer ( mesh->getMeshBuffer ( a ) ); | ||
475 | |||
476 | v = (const video::S3DVertex*) ( (u8*) v + vSize ); | ||
477 | } | ||
478 | driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); | ||
479 | } | ||
480 | |||
481 | |||
482 | if ( pushProjection & 1 ) | ||
483 | { | ||
484 | driver->setTransform( video::ETS_PROJECTION, projection ); | ||
485 | } | ||
486 | |||
487 | if ( DebugDataVisible & scene::EDS_BBOX ) | ||
488 | { | ||
489 | video::SMaterial deb_m; | ||
490 | deb_m.Lighting = false; | ||
491 | driver->setMaterial(deb_m); | ||
492 | driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); | ||
493 | driver->draw3DBox( getBoundingBox(), video::SColor(255,255,0,0)); | ||
494 | } | ||
495 | |||
496 | } | ||
497 | |||
498 | |||
499 | //! Removes a child from this scene node. | ||
500 | //! Implemented here, to be able to remove the shadow properly, if there is one, | ||
501 | //! or to remove attached childs. | ||
502 | bool CQuake3ShaderSceneNode::removeChild(ISceneNode* child) | ||
503 | { | ||
504 | if (child && Shadow == child) | ||
505 | { | ||
506 | Shadow->drop(); | ||
507 | Shadow = 0; | ||
508 | } | ||
509 | |||
510 | return ISceneNode::removeChild(child); | ||
511 | } | ||
512 | |||
513 | |||
514 | //! Creates shadow volume scene node as child of this node | ||
515 | //! and returns a pointer to it. | ||
516 | IShadowVolumeSceneNode* CQuake3ShaderSceneNode::addShadowVolumeSceneNode( | ||
517 | const IMesh* shadowMesh, s32 id, bool zfailmethod, f32 infinity) | ||
518 | { | ||
519 | if (!SceneManager->getVideoDriver()->queryFeature(video::EVDF_STENCIL_BUFFER)) | ||
520 | return 0; | ||
521 | |||
522 | if (!shadowMesh) | ||
523 | shadowMesh = Mesh; // if null is given, use the mesh of node | ||
524 | |||
525 | if (Shadow) | ||
526 | Shadow->drop(); | ||
527 | |||
528 | Shadow = new CShadowVolumeSceneNode(shadowMesh, this, SceneManager, id, zfailmethod, infinity); | ||
529 | return Shadow; | ||
530 | } | ||
531 | |||
532 | |||
533 | /*! | ||
534 | 3.3.1 deformVertexes wave <div> <func> <base> <amplitude> <phase> <freq> | ||
535 | Designed for water surfaces, modifying the values differently at each point. | ||
536 | It accepts the standard wave functions of the type sin, triangle, square, sawtooth | ||
537 | or inversesawtooth. The "div" parameter is used to control the wave "spread" | ||
538 | - a value equal to the tessSize of the surface is a good default value | ||
539 | (tessSize is subdivision size, in game units, used for the shader when seen in the game world) . | ||
540 | */ | ||
541 | void CQuake3ShaderSceneNode::deformvertexes_wave( f32 dt, SModifierFunction &function ) | ||
542 | { | ||
543 | function.wave = core::reciprocal( function.wave ); | ||
544 | |||
545 | const f32 phase = function.phase; | ||
546 | |||
547 | const u32 vsize = Original->Vertices.size(); | ||
548 | for ( u32 i = 0; i != vsize; ++i ) | ||
549 | { | ||
550 | const video::S3DVertex2TCoords &src = Original->Vertices[i]; | ||
551 | video::S3DVertex &dst = MeshBuffer->Vertices[i]; | ||
552 | |||
553 | if ( 0 == function.count ) | ||
554 | dst.Pos = src.Pos - MeshOffset; | ||
555 | |||
556 | const f32 wavephase = (dst.Pos.X + dst.Pos.Y + dst.Pos.Z) * function.wave; | ||
557 | function.phase = phase + wavephase; | ||
558 | |||
559 | const f32 f = function.evaluate( dt ); | ||
560 | |||
561 | dst.Pos.X += f * src.Normal.X; | ||
562 | dst.Pos.Y += f * src.Normal.Y; | ||
563 | dst.Pos.Z += f * src.Normal.Z; | ||
564 | |||
565 | if ( i == 0 ) | ||
566 | MeshBuffer->BoundingBox.reset ( dst.Pos ); | ||
567 | else | ||
568 | MeshBuffer->BoundingBox.addInternalPoint ( dst.Pos ); | ||
569 | } | ||
570 | function.count = 1; | ||
571 | } | ||
572 | |||
573 | /*! | ||
574 | deformVertexes move x y z func base amplitude phase freq | ||
575 | The move parameter is used to make a brush, curve patch or model | ||
576 | appear to move together as a unit. The x y z values are the distance | ||
577 | and direction in game units the object appears to move relative to | ||
578 | it's point of origin in the map. The func base amplitude phase freq values are | ||
579 | the same as found in other waveform manipulations. | ||
580 | |||
581 | The product of the function modifies the values x, y, and z. | ||
582 | Therefore, if you have an amplitude of 5 and an x value of 2, | ||
583 | the object will travel 10 units from its point of origin along the x axis. | ||
584 | This results in a total of 20 units of motion along the x axis, since the | ||
585 | amplitude is the variation both above and below the base. | ||
586 | |||
587 | It must be noted that an object made with this shader does not actually | ||
588 | change position, it only appears to. | ||
589 | |||
590 | Design Notes: | ||
591 | If an object is made up of surfaces with different shaders, all must have | ||
592 | matching deformVertexes move values or the object will appear to tear itself apart. | ||
593 | */ | ||
594 | void CQuake3ShaderSceneNode::deformvertexes_move( f32 dt, SModifierFunction &function ) | ||
595 | { | ||
596 | function.wave = core::reciprocal( function.wave ); | ||
597 | const f32 f = function.evaluate( dt ); | ||
598 | |||
599 | const u32 vsize = Original->Vertices.size(); | ||
600 | for ( u32 i = 0; i != vsize; ++i ) | ||
601 | { | ||
602 | const video::S3DVertex2TCoords &src = Original->Vertices[i]; | ||
603 | video::S3DVertex &dst = MeshBuffer->Vertices[i]; | ||
604 | |||
605 | if ( 0 == function.count ) | ||
606 | dst.Pos = src.Pos - MeshOffset; | ||
607 | |||
608 | dst.Pos.X += f * function.x; | ||
609 | dst.Pos.Y += f * function.y; | ||
610 | dst.Pos.Z += f * function.z; | ||
611 | |||
612 | if ( i == 0 ) | ||
613 | MeshBuffer->BoundingBox.reset ( dst.Pos ); | ||
614 | else | ||
615 | MeshBuffer->BoundingBox.addInternalPoint ( dst.Pos ); | ||
616 | } | ||
617 | function.count = 1; | ||
618 | |||
619 | } | ||
620 | |||
621 | /*! | ||
622 | 3.3.2 deformVertexes normal <div> <func> <base> <amplitude ~0.1-~0.5> <frequency ~1.0-~4.0> | ||
623 | This deformation affects the normals of a vertex without actually moving it, | ||
624 | which will effect later shader options like lighting and especially environment mapping. | ||
625 | If the shader stages don't use normals in any of their calculations, there will | ||
626 | be no visible effect. | ||
627 | |||
628 | Design Notes: Putting values of 0.1 t o 0.5 in Amplitude and 1.0 to 4.0 in the | ||
629 | Frequency can produce some satisfying results. Some things that have been | ||
630 | done with it: A small fluttering bat, falling leaves, rain, flags. | ||
631 | */ | ||
632 | void CQuake3ShaderSceneNode::deformvertexes_normal( f32 dt, SModifierFunction &function ) | ||
633 | { | ||
634 | function.func = SINUS; | ||
635 | const u32 vsize = Original->Vertices.size(); | ||
636 | for ( u32 i = 0; i != vsize; ++i ) | ||
637 | { | ||
638 | const video::S3DVertex2TCoords &src = Original->Vertices[i]; | ||
639 | video::S3DVertex &dst = MeshBuffer->Vertices[i]; | ||
640 | |||
641 | function.base = atan2f ( src.Pos.X, src.Pos.Y ); | ||
642 | function.phase = src.Pos.X + src.Pos.Z; | ||
643 | |||
644 | const f32 lat = function.evaluate( dt ); | ||
645 | |||
646 | function.base = src.Normal.Y; | ||
647 | function.phase = src.Normal.Z + src.Normal.X; | ||
648 | |||
649 | const f32 lng = function.evaluate( dt ); | ||
650 | |||
651 | dst.Normal.X = cosf ( lat ) * sinf ( lng ); | ||
652 | dst.Normal.Y = sinf ( lat ) * sinf ( lng ); | ||
653 | dst.Normal.Z = cosf ( lng ); | ||
654 | |||
655 | } | ||
656 | } | ||
657 | |||
658 | |||
659 | /*! | ||
660 | 3.3.3 deformVertexes bulge <bulgeWidth> <bulgeHeight> <bulgeSpeed> | ||
661 | This forces a bulge to move along the given s and t directions. Designed for use | ||
662 | on curved pipes. | ||
663 | |||
664 | Specific parameter definitions for deform keywords: | ||
665 | <div> This is roughly defined as the size of the waves that occur. | ||
666 | It is measured in game units. Smaller values create a greater | ||
667 | density of smaller wave forms occurring in a given area. | ||
668 | Larger values create a lesser density of waves, or otherwise put, | ||
669 | the appearance of larger waves. To look correct this value should | ||
670 | closely correspond to the value (in pixels) set for tessSize (tessellation size) | ||
671 | of the texture. A value of 100.0 is a good default value | ||
672 | (which means your tessSize should be close to that for things to look "wavelike"). | ||
673 | |||
674 | <func> This is the type of wave form being created. Sin stands for sine wave, | ||
675 | a regular smoothly flowing wave. Triangle is a wave with a sharp ascent | ||
676 | and a sharp decay. It will make a choppy looking wave forms. | ||
677 | A square wave is simply on or off for the period of the | ||
678 | frequency with no in between. The sawtooth wave has the ascent of a | ||
679 | triangle wave, but has the decay cut off sharply like a square wave. | ||
680 | An inversesawtooth wave reverses this. | ||
681 | |||
682 | <base> This is the distance, in game units that the apparent surface of the | ||
683 | texture is displaced from the actual surface of the brush as placed | ||
684 | in the editor. A positive value appears above the brush surface. | ||
685 | A negative value appears below the brush surface. | ||
686 | An example of this is the Quad effect, which essentially is a | ||
687 | shell with a positive base value to stand it away from the model | ||
688 | surface and a 0 (zero) value for amplitude. | ||
689 | |||
690 | <amplitude> The distance that the deformation moves away from the base value. | ||
691 | See Wave Forms in the introduction for a description of amplitude. | ||
692 | |||
693 | <phase> See Wave Forms in the introduction for a description of phase) | ||
694 | |||
695 | <frequency> See Wave Forms in the introduction for a description of frequency) | ||
696 | |||
697 | Design Note: The div and amplitude parameters, when used in conjunction with | ||
698 | liquid volumes like water should take into consideration how much the water | ||
699 | will be moving. A large ocean area would have have massive swells (big div values) | ||
700 | that rose and fell dramatically (big amplitude values). While a small, quiet pool | ||
701 | may move very little. | ||
702 | */ | ||
703 | void CQuake3ShaderSceneNode::deformvertexes_bulge( f32 dt, SModifierFunction &function ) | ||
704 | { | ||
705 | function.func = SINUS; | ||
706 | function.wave = core::reciprocal( function.bulgewidth ); | ||
707 | |||
708 | dt *= function.bulgespeed * 0.1f; | ||
709 | const f32 phase = function.phase; | ||
710 | |||
711 | const u32 vsize = Original->Vertices.size(); | ||
712 | for ( u32 i = 0; i != vsize; ++i ) | ||
713 | { | ||
714 | const video::S3DVertex2TCoords &src = Original->Vertices[i]; | ||
715 | video::S3DVertex &dst = MeshBuffer->Vertices[i]; | ||
716 | |||
717 | const f32 wavephase = (Original->Vertices[i].TCoords.X ) * function.wave; | ||
718 | function.phase = phase + wavephase; | ||
719 | |||
720 | const f32 f = function.evaluate( dt ); | ||
721 | |||
722 | if ( 0 == function.count ) | ||
723 | dst.Pos = src.Pos - MeshOffset; | ||
724 | |||
725 | dst.Pos.X += f * src.Normal.X; | ||
726 | dst.Pos.Y += f * src.Normal.Y; | ||
727 | dst.Pos.Z += f * src.Normal.Z; | ||
728 | |||
729 | if ( i == 0 ) | ||
730 | MeshBuffer->BoundingBox.reset ( dst.Pos ); | ||
731 | else | ||
732 | MeshBuffer->BoundingBox.addInternalPoint ( dst.Pos ); | ||
733 | } | ||
734 | |||
735 | function.count = 1; | ||
736 | } | ||
737 | |||
738 | |||
739 | /*! | ||
740 | deformVertexes autosprite | ||
741 | |||
742 | This function can be used to make any given triangle quad | ||
743 | (pair of triangles that form a square rectangle) automatically behave | ||
744 | like a sprite without having to make it a separate entity. This means | ||
745 | that the "sprite" on which the texture is placed will rotate to always | ||
746 | appear at right angles to the player's view as a sprite would. Any four-sided | ||
747 | brush side, flat patch, or pair of triangles in a model can have the autosprite | ||
748 | effect on it. The brush face containing a texture with this shader keyword must | ||
749 | be square. | ||
750 | */ | ||
751 | void CQuake3ShaderSceneNode::deformvertexes_autosprite( f32 dt, SModifierFunction &function ) | ||
752 | { | ||
753 | u32 vsize = Original->Vertices.size(); | ||
754 | u32 g; | ||
755 | u32 i; | ||
756 | |||
757 | const core::vector3df& camPos = SceneManager->getActiveCamera()->getPosition(); | ||
758 | |||
759 | video::S3DVertex * dv = MeshBuffer->Vertices.pointer(); | ||
760 | const video::S3DVertex2TCoords * vin = Original->Vertices.const_pointer(); | ||
761 | |||
762 | core::matrix4 lookat ( core::matrix4::EM4CONST_NOTHING ); | ||
763 | core::quaternion q; | ||
764 | for ( i = 0; i < vsize; i += 4 ) | ||
765 | { | ||
766 | // quad-plane | ||
767 | core::vector3df center = 0.25f * ( vin[i+0].Pos + vin[i+1].Pos + vin[i+2].Pos + vin[i+3].Pos ); | ||
768 | core::vector3df forward = camPos - center; | ||
769 | |||
770 | q.rotationFromTo ( vin[i].Normal, forward ); | ||
771 | q.getMatrixCenter ( lookat, center, MeshOffset ); | ||
772 | |||
773 | for ( g = 0; g < 4; ++g ) | ||
774 | { | ||
775 | lookat.transformVect ( dv[i+g].Pos, vin[i+g].Pos ); | ||
776 | lookat.rotateVect ( dv[i+g].Normal, vin[i+g].Normal ); | ||
777 | } | ||
778 | |||
779 | } | ||
780 | function.count = 1; | ||
781 | } | ||
782 | |||
783 | |||
784 | /*! | ||
785 | deformVertexes autosprite2 | ||
786 | Is a slightly modified "sprite" that only rotates around the middle of its longest axis. | ||
787 | This allows you to make a pillar of fire that you can walk around, or an energy beam | ||
788 | stretched across the room. | ||
789 | */ | ||
790 | |||
791 | struct sortaxis | ||
792 | { | ||
793 | core::vector3df v; | ||
794 | bool operator < ( const sortaxis &other ) const | ||
795 | { | ||
796 | return v.getLengthSQ () < other.v.getLengthSQ (); | ||
797 | } | ||
798 | }; | ||
799 | /*! | ||
800 | */ | ||
801 | void CQuake3ShaderSceneNode::deformvertexes_autosprite2( f32 dt, SModifierFunction &function ) | ||
802 | { | ||
803 | u32 vsize = Original->Vertices.size(); | ||
804 | u32 g; | ||
805 | u32 i; | ||
806 | |||
807 | const core::vector3df camPos = SceneManager->getActiveCamera()->getAbsolutePosition(); | ||
808 | |||
809 | video::S3DVertex * dv = MeshBuffer->Vertices.pointer(); | ||
810 | const video::S3DVertex2TCoords * vin = Original->Vertices.const_pointer(); | ||
811 | |||
812 | core::matrix4 lookat ( core::matrix4::EM4CONST_NOTHING ); | ||
813 | |||
814 | core::array < sortaxis > axis; | ||
815 | axis.set_used ( 3 ); | ||
816 | |||
817 | for ( i = 0; i < vsize; i += 4 ) | ||
818 | { | ||
819 | // quad-plane | ||
820 | core::vector3df center = 0.25f * ( vin[i+0].Pos + vin[i+1].Pos + vin[i+2].Pos + vin[i+3].Pos ); | ||
821 | |||
822 | // longes axe | ||
823 | axis[0].v = vin[i+1].Pos - vin[i+0].Pos; | ||
824 | axis[1].v = vin[i+2].Pos - vin[i+0].Pos; | ||
825 | axis[2].v = vin[i+3].Pos - vin[i+0].Pos; | ||
826 | axis.set_sorted ( false ); | ||
827 | axis.sort (); | ||
828 | |||
829 | lookat.buildAxisAlignedBillboard ( camPos, center, MeshOffset, axis[1].v, vin[i+0].Normal ); | ||
830 | |||
831 | for ( g = 0; g < 4; ++g ) | ||
832 | { | ||
833 | lookat.transformVect ( dv[i+g].Pos, vin[i+g].Pos ); | ||
834 | lookat.rotateVect ( dv[i+g].Normal, vin[i+g].Normal ); | ||
835 | } | ||
836 | } | ||
837 | function.count = 1; | ||
838 | } | ||
839 | |||
840 | /* | ||
841 | Generate Vertex Color | ||
842 | */ | ||
843 | void CQuake3ShaderSceneNode::vertextransform_rgbgen( f32 dt, SModifierFunction &function ) | ||
844 | { | ||
845 | u32 i; | ||
846 | const u32 vsize = Original->Vertices.size(); | ||
847 | |||
848 | switch ( function.rgbgen ) | ||
849 | { | ||
850 | case IDENTITY: | ||
851 | //rgbgen identity | ||
852 | for ( i = 0; i != vsize; ++i ) | ||
853 | MeshBuffer->Vertices[i].Color.set(0xFFFFFFFF); | ||
854 | break; | ||
855 | |||
856 | case IDENTITYLIGHTING: | ||
857 | // rgbgen identitylighting TODO: overbright | ||
858 | for ( i = 0; i != vsize; ++i ) | ||
859 | MeshBuffer->Vertices[i].Color.set(0xFF7F7F7F); | ||
860 | break; | ||
861 | |||
862 | case EXACTVERTEX: | ||
863 | // alphagen exactvertex TODO lighting | ||
864 | case VERTEX: | ||
865 | // rgbgen vertex | ||
866 | for ( i = 0; i != vsize; ++i ) | ||
867 | MeshBuffer->Vertices[i].Color=Original->Vertices[i].Color; | ||
868 | break; | ||
869 | case WAVE: | ||
870 | { | ||
871 | // rgbGen wave <func> <base> <amp> <phase> <freq> | ||
872 | f32 f = function.evaluate( dt ) * 255.f; | ||
873 | s32 value = core::clamp( core::floor32(f), 0, 255 ); | ||
874 | value = 0xFF000000 | value << 16 | value << 8 | value; | ||
875 | |||
876 | for ( i = 0; i != vsize; ++i ) | ||
877 | MeshBuffer->Vertices[i].Color.set(value); | ||
878 | } break; | ||
879 | case CONSTANT: | ||
880 | { | ||
881 | //rgbgen const ( x y z ) | ||
882 | video::SColorf cf( function.x, function.y, function.z ); | ||
883 | video::SColor col = cf.toSColor(); | ||
884 | for ( i = 0; i != vsize; ++i ) | ||
885 | MeshBuffer->Vertices[i].Color=col; | ||
886 | } break; | ||
887 | default: | ||
888 | break; | ||
889 | } | ||
890 | } | ||
891 | |||
892 | /* | ||
893 | Generate Vertex Color, Alpha | ||
894 | */ | ||
895 | void CQuake3ShaderSceneNode::vertextransform_alphagen( f32 dt, SModifierFunction &function ) | ||
896 | { | ||
897 | u32 i; | ||
898 | const u32 vsize = Original->Vertices.size(); | ||
899 | |||
900 | switch ( function.alphagen ) | ||
901 | { | ||
902 | case IDENTITY: | ||
903 | //alphagen identity | ||
904 | for ( i = 0; i != vsize; ++i ) | ||
905 | MeshBuffer->Vertices[i].Color.setAlpha ( 0xFF ); | ||
906 | break; | ||
907 | |||
908 | case EXACTVERTEX: | ||
909 | // alphagen exactvertex TODO lighting | ||
910 | case VERTEX: | ||
911 | // alphagen vertex | ||
912 | for ( i = 0; i != vsize; ++i ) | ||
913 | MeshBuffer->Vertices[i].Color.setAlpha ( Original->Vertices[i].Color.getAlpha() ); | ||
914 | break; | ||
915 | case CONSTANT: | ||
916 | { | ||
917 | // alphagen const | ||
918 | u32 a = (u32) ( function.x * 255.f ); | ||
919 | for ( i = 0; i != vsize; ++i ) | ||
920 | MeshBuffer->Vertices[i].Color.setAlpha ( a ); | ||
921 | } break; | ||
922 | |||
923 | case LIGHTINGSPECULAR: | ||
924 | { | ||
925 | // alphagen lightingspecular TODO!!! | ||
926 | const SViewFrustum *frustum = SceneManager->getActiveCamera()->getViewFrustum(); | ||
927 | const core::matrix4 &view = frustum->getTransform ( video::ETS_VIEW ); | ||
928 | |||
929 | const f32 *m = view.pointer(); | ||
930 | |||
931 | for ( i = 0; i != vsize; ++i ) | ||
932 | { | ||
933 | const core::vector3df &n = Original->Vertices[i].Normal; | ||
934 | MeshBuffer->Vertices[i].Color.setAlpha ((u32)( 128.f *(1.f+(n.X*m[0]+n.Y*m[1]+n.Z*m[2])))); | ||
935 | } | ||
936 | |||
937 | } break; | ||
938 | |||
939 | |||
940 | case WAVE: | ||
941 | { | ||
942 | // alphagen wave | ||
943 | f32 f = function.evaluate( dt ) * 255.f; | ||
944 | s32 value = core::clamp( core::floor32(f), 0, 255 ); | ||
945 | |||
946 | for ( i = 0; i != vsize; ++i ) | ||
947 | MeshBuffer->Vertices[i].Color.setAlpha ( value ); | ||
948 | } break; | ||
949 | default: | ||
950 | break; | ||
951 | } | ||
952 | } | ||
953 | |||
954 | |||
955 | |||
956 | /* | ||
957 | Generate Texture Coordinates | ||
958 | */ | ||
959 | void CQuake3ShaderSceneNode::vertextransform_tcgen( f32 dt, SModifierFunction &function ) | ||
960 | { | ||
961 | u32 i; | ||
962 | const u32 vsize = Original->Vertices.size(); | ||
963 | |||
964 | switch ( function.tcgen ) | ||
965 | { | ||
966 | case TURBULENCE: | ||
967 | //tcgen turb | ||
968 | { | ||
969 | function.wave = core::reciprocal( function.phase ); | ||
970 | |||
971 | const f32 phase = function.phase; | ||
972 | |||
973 | for ( i = 0; i != vsize; ++i ) | ||
974 | { | ||
975 | const video::S3DVertex2TCoords &src = Original->Vertices[i]; | ||
976 | video::S3DVertex &dst = MeshBuffer->Vertices[i]; | ||
977 | |||
978 | const f32 wavephase = (src.Pos.X + src.Pos.Y + src.Pos.Z) * function.wave; | ||
979 | function.phase = phase + wavephase; | ||
980 | |||
981 | const f32 f = function.evaluate( dt ); | ||
982 | |||
983 | dst.TCoords.X = src.TCoords.X + f * src.Normal.X; | ||
984 | dst.TCoords.Y = src.TCoords.Y + f * src.Normal.Y; | ||
985 | } | ||
986 | } | ||
987 | break; | ||
988 | |||
989 | case TEXTURE: | ||
990 | // tcgen texture | ||
991 | for ( i = 0; i != vsize; ++i ) | ||
992 | MeshBuffer->Vertices[i].TCoords = Original->Vertices[i].TCoords; | ||
993 | break; | ||
994 | case LIGHTMAP: | ||
995 | // tcgen lightmap | ||
996 | for ( i = 0; i != vsize; ++i ) | ||
997 | MeshBuffer->Vertices[i].TCoords = Original->Vertices[i].TCoords2; | ||
998 | break; | ||
999 | case ENVIRONMENT: | ||
1000 | { | ||
1001 | // tcgen environment | ||
1002 | const SViewFrustum *frustum = SceneManager->getActiveCamera()->getViewFrustum(); | ||
1003 | const core::matrix4 &view = frustum->getTransform ( video::ETS_VIEW ); | ||
1004 | |||
1005 | const f32 *m = view.pointer(); | ||
1006 | |||
1007 | core::vector3df n; | ||
1008 | for ( i = 0; i != vsize; ++i ) | ||
1009 | { | ||
1010 | //const core::vector3df &n = Original->Vertices[i].Normal; | ||
1011 | |||
1012 | n = frustum->cameraPosition - Original->Vertices[i].Pos; | ||
1013 | n.normalize(); | ||
1014 | n += Original->Vertices[i].Normal; | ||
1015 | n.normalize(); | ||
1016 | |||
1017 | MeshBuffer->Vertices[i].TCoords.X = 0.5f*(1.f+(n.X*m[0]+n.Y*m[1]+n.Z*m[2])); | ||
1018 | MeshBuffer->Vertices[i].TCoords.Y = 0.5f*(1.f+(n.X*m[4]+n.Y*m[5]+n.Z*m[6])); | ||
1019 | } | ||
1020 | |||
1021 | } break; | ||
1022 | default: | ||
1023 | break; | ||
1024 | } | ||
1025 | } | ||
1026 | |||
1027 | |||
1028 | #if 0 | ||
1029 | /* | ||
1030 | Transform Texture Coordinates | ||
1031 | */ | ||
1032 | void CQuake3ShaderSceneNode::transformtex( const core::matrix4 &m, const u32 addressMode ) | ||
1033 | { | ||
1034 | u32 i; | ||
1035 | const u32 vsize = MeshBuffer->Vertices.size(); | ||
1036 | |||
1037 | f32 tx1; | ||
1038 | f32 ty1; | ||
1039 | |||
1040 | if ( addressMode ) | ||
1041 | { | ||
1042 | for ( i = 0; i != vsize; ++i ) | ||
1043 | { | ||
1044 | core::vector2df &tx = MeshBuffer->Vertices[i].TCoords; | ||
1045 | |||
1046 | tx1 = m[0] * tx.X + m[4] * tx.Y + m[8]; | ||
1047 | ty1 = m[1] * tx.X + m[5] * tx.Y + m[9]; | ||
1048 | |||
1049 | tx.X = tx1; | ||
1050 | tx.Y = ty1; | ||
1051 | } | ||
1052 | } | ||
1053 | else | ||
1054 | { | ||
1055 | |||
1056 | for ( i = 0; i != vsize; ++i ) | ||
1057 | { | ||
1058 | core::vector2df &tx = MeshBuffer->Vertices[i].TCoords; | ||
1059 | |||
1060 | tx1 = m[0] * tx.X + m[4] * tx.Y + m[8]; | ||
1061 | ty1 = m[1] * tx.X + m[5] * tx.Y + m[9]; | ||
1062 | |||
1063 | tx.X = tx1 <= 0.f ? 0.f : tx1 >= 1.f ? 1.f : tx1; | ||
1064 | tx.Y = ty1 <= 0.f ? 0.f : ty1 >= 1.f ? 1.f : ty1; | ||
1065 | |||
1066 | //tx.X = core::clamp( tx1, 0.f, 1.f ); | ||
1067 | //tx.Y = core::clamp( ty1, 0.f, 1.f ); | ||
1068 | } | ||
1069 | } | ||
1070 | } | ||
1071 | |||
1072 | #endif | ||
1073 | |||
1074 | |||
1075 | /* | ||
1076 | Texture & Vertex Transform Animator | ||
1077 | |||
1078 | Return a Texture Transformation for this stage | ||
1079 | Vertex transformation are called if found | ||
1080 | |||
1081 | */ | ||
1082 | void CQuake3ShaderSceneNode::animate( u32 stage,core::matrix4 &texture ) | ||
1083 | { | ||
1084 | const SVarGroup *group = Shader->getGroup( stage ); | ||
1085 | |||
1086 | // select current texture | ||
1087 | SQ3Texture &q3Tex = Q3Texture [ stage ]; | ||
1088 | if ( q3Tex.TextureFrequency != 0.f ) | ||
1089 | { | ||
1090 | s32 v = core::floor32( TimeAbs * q3Tex.TextureFrequency ); | ||
1091 | q3Tex.TextureIndex = v % q3Tex.Texture.size(); | ||
1092 | } | ||
1093 | |||
1094 | core::matrix4 m2; | ||
1095 | SModifierFunction function; | ||
1096 | |||
1097 | f32 f[16]; | ||
1098 | |||
1099 | // walk group for all modifiers | ||
1100 | for ( u32 g = 0; g != group->Variable.size(); ++g ) | ||
1101 | { | ||
1102 | const SVariable &v = group->Variable[g]; | ||
1103 | |||
1104 | // get the modifier | ||
1105 | static const c8 * modifierList[] = | ||
1106 | { | ||
1107 | "tcmod","deformvertexes","rgbgen","tcgen","map","alphagen" | ||
1108 | }; | ||
1109 | |||
1110 | u32 pos = 0; | ||
1111 | function.masterfunc0 = (eQ3ModifierFunction) isEqual( v.name, pos, modifierList, 6 ); | ||
1112 | |||
1113 | if ( UNKNOWN == function.masterfunc0 ) | ||
1114 | continue; | ||
1115 | |||
1116 | switch ( function.masterfunc0 ) | ||
1117 | { | ||
1118 | //tcmod | ||
1119 | case TCMOD: | ||
1120 | m2.makeIdentity(); | ||
1121 | break; | ||
1122 | default: | ||
1123 | break; | ||
1124 | } | ||
1125 | |||
1126 | // get the modifier function | ||
1127 | static const c8 * funclist[] = | ||
1128 | { | ||
1129 | "scroll","scale","rotate","stretch","turb", | ||
1130 | "wave","identity","vertex", | ||
1131 | "texture","lightmap","environment","$lightmap", | ||
1132 | "bulge","autosprite","autosprite2","transform", | ||
1133 | "exactvertex","const","lightingspecular","move","normal", | ||
1134 | "identitylighting" | ||
1135 | }; | ||
1136 | static const c8 * groupToken[] = { "(", ")" }; | ||
1137 | |||
1138 | pos = 0; | ||
1139 | function.masterfunc1 = (eQ3ModifierFunction) isEqual( v.content, pos, funclist, 22 ); | ||
1140 | if ( function.masterfunc1 != UNKNOWN ) | ||
1141 | function.masterfunc1 = (eQ3ModifierFunction) ((u32) function.masterfunc1 + FUNCTION2 + 1); | ||
1142 | |||
1143 | switch ( function.masterfunc1 ) | ||
1144 | { | ||
1145 | case SCROLL: | ||
1146 | // tcMod scroll <sSpeed> <tSpeed> | ||
1147 | f[0] = getAsFloat( v.content, pos ) * TimeAbs; | ||
1148 | f[1] = getAsFloat( v.content, pos ) * TimeAbs; | ||
1149 | m2.setTextureTranslate( f[0], f[1] ); | ||
1150 | break; | ||
1151 | case SCALE: | ||
1152 | // tcmod scale <sScale> <tScale> | ||
1153 | f[0] = getAsFloat( v.content, pos ); | ||
1154 | f[1] = getAsFloat( v.content, pos ); | ||
1155 | m2.setTextureScale( f[0], f[1] ); | ||
1156 | break; | ||
1157 | case ROTATE: | ||
1158 | // tcmod rotate <degress per second> | ||
1159 | m2.setTextureRotationCenter( getAsFloat( v.content, pos ) * | ||
1160 | core::DEGTORAD * | ||
1161 | TimeAbs | ||
1162 | ); | ||
1163 | break; | ||
1164 | case TRANSFORM: | ||
1165 | // tcMod <transform> <m00> <m01> <m10> <m11> <t0> <t1> | ||
1166 | memset(f, 0, sizeof ( f )); | ||
1167 | f[10] = f[15] = 1.f; | ||
1168 | |||
1169 | f[0] = getAsFloat( v.content, pos ); | ||
1170 | f[1] = getAsFloat( v.content, pos ); | ||
1171 | f[4] = getAsFloat( v.content, pos ); | ||
1172 | f[5] = getAsFloat( v.content, pos ); | ||
1173 | f[8] = getAsFloat( v.content, pos ); | ||
1174 | f[9] = getAsFloat( v.content, pos ); | ||
1175 | m2.setM ( f ); | ||
1176 | break; | ||
1177 | |||
1178 | case STRETCH: // stretch | ||
1179 | case TURBULENCE: // turb | ||
1180 | case WAVE: // wave | ||
1181 | case IDENTITY: // identity | ||
1182 | case IDENTITYLIGHTING: | ||
1183 | case VERTEX: // vertex | ||
1184 | case MOVE: | ||
1185 | case CONSTANT: | ||
1186 | { | ||
1187 | // turb == sin, default == sin | ||
1188 | function.func = SINUS; | ||
1189 | |||
1190 | if ( function.masterfunc0 == DEFORMVERTEXES ) | ||
1191 | { | ||
1192 | switch ( function.masterfunc1 ) | ||
1193 | { | ||
1194 | case WAVE: | ||
1195 | // deformvertexes wave | ||
1196 | function.wave = getAsFloat( v.content, pos ); | ||
1197 | break; | ||
1198 | case MOVE: | ||
1199 | //deformvertexes move | ||
1200 | function.x = getAsFloat( v.content, pos ); | ||
1201 | function.z = getAsFloat( v.content, pos ); | ||
1202 | function.y = getAsFloat( v.content, pos ); | ||
1203 | break; | ||
1204 | default: | ||
1205 | break; | ||
1206 | } | ||
1207 | } | ||
1208 | |||
1209 | switch ( function.masterfunc1 ) | ||
1210 | { | ||
1211 | case STRETCH: | ||
1212 | case TURBULENCE: | ||
1213 | case WAVE: | ||
1214 | case MOVE: | ||
1215 | getModifierFunc( function, v.content, pos ); | ||
1216 | break; | ||
1217 | default: | ||
1218 | break; | ||
1219 | } | ||
1220 | |||
1221 | switch ( function.masterfunc1 ) | ||
1222 | { | ||
1223 | case STRETCH: | ||
1224 | //tcMod stretch <func> <base> <amplitude> <phase> <frequency> | ||
1225 | f[0] = core::reciprocal( function.evaluate(TimeAbs) ); | ||
1226 | m2.setTextureScaleCenter( f[0], f[0] ); | ||
1227 | break; | ||
1228 | case TURBULENCE: | ||
1229 | //tcMod turb <base> <amplitude> <phase> <freq> | ||
1230 | //function.tcgen = TURBULENCE; | ||
1231 | m2.setTextureRotationCenter( function.frequency * | ||
1232 | core::DEGTORAD * | ||
1233 | TimeAbs | ||
1234 | ); | ||
1235 | break; | ||
1236 | case WAVE: | ||
1237 | case IDENTITY: | ||
1238 | case IDENTITYLIGHTING: | ||
1239 | case VERTEX: | ||
1240 | case EXACTVERTEX: | ||
1241 | case CONSTANT: | ||
1242 | case LIGHTINGSPECULAR: | ||
1243 | case MOVE: | ||
1244 | switch ( function.masterfunc0 ) | ||
1245 | { | ||
1246 | case DEFORMVERTEXES: | ||
1247 | switch ( function.masterfunc1 ) | ||
1248 | { | ||
1249 | case WAVE: | ||
1250 | deformvertexes_wave( TimeAbs, function ); | ||
1251 | break; | ||
1252 | case MOVE: | ||
1253 | deformvertexes_move( TimeAbs, function ); | ||
1254 | break; | ||
1255 | default: | ||
1256 | break; | ||
1257 | } | ||
1258 | break; | ||
1259 | case RGBGEN: | ||
1260 | function.rgbgen = function.masterfunc1; | ||
1261 | if ( function.rgbgen == CONSTANT ) | ||
1262 | { | ||
1263 | isEqual ( v.content, pos, groupToken, 2 ); | ||
1264 | function.x = getAsFloat( v.content, pos ); | ||
1265 | function.y = getAsFloat( v.content, pos ); | ||
1266 | function.z = getAsFloat( v.content, pos ); | ||
1267 | } | ||
1268 | //vertextransform_rgbgen( TimeAbs, function ); | ||
1269 | break; | ||
1270 | case ALPHAGEN: | ||
1271 | function.alphagen = function.masterfunc1; | ||
1272 | if ( function.alphagen == CONSTANT ) | ||
1273 | { | ||
1274 | function.x = getAsFloat( v.content, pos ); | ||
1275 | } | ||
1276 | |||
1277 | //vertextransform_alphagen( TimeAbs, function ); | ||
1278 | break; | ||
1279 | default: | ||
1280 | break; | ||
1281 | } | ||
1282 | break; | ||
1283 | default: | ||
1284 | break; | ||
1285 | } | ||
1286 | |||
1287 | } break; | ||
1288 | case TEXTURE: | ||
1289 | case LIGHTMAP: | ||
1290 | case ENVIRONMENT: | ||
1291 | // "texture","lightmap","environment" | ||
1292 | function.tcgen = function.masterfunc1; | ||
1293 | break; | ||
1294 | case DOLLAR_LIGHTMAP: | ||
1295 | // map == lightmap, tcgen == lightmap | ||
1296 | function.tcgen = LIGHTMAP; | ||
1297 | break; | ||
1298 | case BULGE: | ||
1299 | // deformvertexes bulge | ||
1300 | function.bulgewidth = getAsFloat( v.content, pos ); | ||
1301 | function.bulgeheight = getAsFloat( v.content, pos ); | ||
1302 | function.bulgespeed = getAsFloat( v.content, pos ); | ||
1303 | |||
1304 | deformvertexes_bulge(TimeAbs, function); | ||
1305 | break; | ||
1306 | |||
1307 | case NORMAL: | ||
1308 | // deformvertexes normal | ||
1309 | function.amp = getAsFloat( v.content, pos ); | ||
1310 | function.frequency = getAsFloat( v.content, pos ); | ||
1311 | |||
1312 | deformvertexes_normal(TimeAbs, function); | ||
1313 | break; | ||
1314 | |||
1315 | case AUTOSPRITE: | ||
1316 | // deformvertexes autosprite | ||
1317 | deformvertexes_autosprite(TimeAbs, function); | ||
1318 | break; | ||
1319 | |||
1320 | case AUTOSPRITE2: | ||
1321 | // deformvertexes autosprite2 | ||
1322 | deformvertexes_autosprite2(TimeAbs, function); | ||
1323 | break; | ||
1324 | default: | ||
1325 | break; | ||
1326 | } // func | ||
1327 | |||
1328 | switch ( function.masterfunc0 ) | ||
1329 | { | ||
1330 | case TCMOD: | ||
1331 | texture *= m2; | ||
1332 | break; | ||
1333 | default: | ||
1334 | break; | ||
1335 | } | ||
1336 | |||
1337 | } // group | ||
1338 | |||
1339 | vertextransform_rgbgen( TimeAbs, function ); | ||
1340 | vertextransform_alphagen( TimeAbs, function ); | ||
1341 | vertextransform_tcgen( TimeAbs, function ); | ||
1342 | } | ||
1343 | |||
1344 | |||
1345 | void CQuake3ShaderSceneNode::OnAnimate(u32 timeMs) | ||
1346 | { | ||
1347 | TimeAbs = f32( timeMs ) * (1.f/1000.f); | ||
1348 | ISceneNode::OnAnimate( timeMs ); | ||
1349 | } | ||
1350 | |||
1351 | const core::aabbox3d<f32>& CQuake3ShaderSceneNode::getBoundingBox() const | ||
1352 | { | ||
1353 | return MeshBuffer->getBoundingBox(); | ||
1354 | } | ||
1355 | |||
1356 | |||
1357 | u32 CQuake3ShaderSceneNode::getMaterialCount() const | ||
1358 | { | ||
1359 | return Q3Texture.size(); | ||
1360 | } | ||
1361 | |||
1362 | video::SMaterial& CQuake3ShaderSceneNode::getMaterial(u32 i) | ||
1363 | { | ||
1364 | video::SMaterial& m = MeshBuffer->Material; | ||
1365 | m.setTexture(0, 0); | ||
1366 | if ( Q3Texture [ i ].TextureIndex ) | ||
1367 | m.setTexture(0, Q3Texture [ i ].Texture [ Q3Texture [ i ].TextureIndex ]); | ||
1368 | return m; | ||
1369 | } | ||
1370 | |||
1371 | |||
1372 | } // end namespace scene | ||
1373 | } // end namespace irr | ||
1374 | |||
1375 | #endif | ||
1376 | |||