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 */
CQuake3ShaderSceneNode(scene::ISceneNode * parent,scene::ISceneManager * mgr,s32 id,io::IFileSystem * fileSystem,const scene::IMeshBuffer * original,const IShader * shader)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 */
~CQuake3ShaderSceneNode()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 */
cloneBuffer(scene::SMeshBuffer * dest,const scene::SMeshBufferLightMap * buffer,bool translateCenter)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 */
loadTextures(io::IFileSystem * fileSystem)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 */
OnRegisterSceneNode()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 */
getRenderStage() const237 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 */
render()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.
removeChild(ISceneNode * child)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.
addShadowVolumeSceneNode(const IMesh * shadowMesh,s32 id,bool zfailmethod,f32 infinity)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 */
deformvertexes_wave(f32 dt,SModifierFunction & function)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 */
deformvertexes_move(f32 dt,SModifierFunction & function)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 */
deformvertexes_normal(f32 dt,SModifierFunction & function)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 */
deformvertexes_bulge(f32 dt,SModifierFunction & function)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 */
deformvertexes_autosprite(f32 dt,SModifierFunction & function)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;
operator <irr::scene::sortaxis794 	bool operator < ( const sortaxis &other ) const
795 	{
796 		return v.getLengthSQ () < other.v.getLengthSQ ();
797 	}
798 };
799 /*!
800 */
deformvertexes_autosprite2(f32 dt,SModifierFunction & function)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 */
vertextransform_rgbgen(f32 dt,SModifierFunction & function)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 */
vertextransform_alphagen(f32 dt,SModifierFunction & function)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 */
vertextransform_tcgen(f32 dt,SModifierFunction & function)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 */
animate(u32 stage,core::matrix4 & texture)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 
OnAnimate(u32 timeMs)1345 void CQuake3ShaderSceneNode::OnAnimate(u32 timeMs)
1346 {
1347 	TimeAbs = f32( timeMs ) * (1.f/1000.f);
1348 	ISceneNode::OnAnimate( timeMs );
1349 }
1350 
getBoundingBox() const1351 const core::aabbox3d<f32>& CQuake3ShaderSceneNode::getBoundingBox() const
1352 {
1353 	return MeshBuffer->getBoundingBox();
1354 }
1355 
1356 
getMaterialCount() const1357 u32 CQuake3ShaderSceneNode::getMaterialCount() const
1358 {
1359 	return Q3Texture.size();
1360 }
1361 
getMaterial(u32 i)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 
1377