1 /*!
2 	Model Factory.
3 	create the additional scenenodes for ( bullets, health... )
4 
5 	Defines the Entities for Quake3
6 */
7 
8 #include <irrlicht.h>
9 #include "q3factory.h"
10 #include "sound.h"
11 
12 using namespace irr;
13 using namespace scene;
14 using namespace gui;
15 using namespace video;
16 using namespace core;
17 using namespace quake3;
18 
19 //! This list is based on the original quake3.
20 static const SItemElement Quake3ItemElement [] = {
21 {	"item_health",
22 	{"models/powerups/health/medium_cross.md3",
23 	"models/powerups/health/medium_sphere.md3"},
24 	"sound/items/n_health.wav",
25 	"icons/iconh_yellow",
26 	"25 Health",
27 	25,
28 	HEALTH,
29 	SUB_NONE,
30 	SPECIAL_SFX_BOUNCE | SPECIAL_SFX_ROTATE_1
31 },
32 {	"item_health_large",
33 	"models/powerups/health/large_cross.md3",
34 	"models/powerups/health/large_sphere.md3",
35 	"sound/items/l_health.wav",
36 	"icons/iconh_red",
37 	"50 Health",
38 	50,
39 	HEALTH,
40 	SUB_NONE,
41 	SPECIAL_SFX_BOUNCE | SPECIAL_SFX_ROTATE_1
42 },
43 {
44 	"item_health_mega",
45 	"models/powerups/health/mega_cross.md3",
46 	"models/powerups/health/mega_sphere.md3",
47 	"sound/items/m_health.wav",
48 	"icons/iconh_mega",
49 	"Mega Health",
50 	100,
51 	HEALTH,
52 	SUB_NONE,
53 	SPECIAL_SFX_BOUNCE | SPECIAL_SFX_ROTATE_1
54 },
55 {
56 	"item_health_small",
57 	"models/powerups/health/small_cross.md3",
58 	"models/powerups/health/small_sphere.md3",
59 	"sound/items/s_health.wav",
60 	"icons/iconh_green",
61 	"5 Health",
62 	5,
63 	HEALTH,
64 	SUB_NONE,
65 	SPECIAL_SFX_BOUNCE | SPECIAL_SFX_ROTATE_1
66 },
67 {	"ammo_bullets",
68 	"models/powerups/ammo/machinegunam.md3",
69 	"",
70 	"sound/misc/am_pkup.wav",
71 	"icons/icona_machinegun",
72 	"Bullets",
73 	50,
74 	AMMO,
75 	MACHINEGUN,
76 	SPECIAL_SFX_BOUNCE,
77 },
78 {
79 	"ammo_cells",
80 	"models/powerups/ammo/plasmaam.md3",
81 	"",
82 	"sound/misc/am_pkup.wav",
83 	"icons/icona_plasma",
84 	"Cells",
85 	30,
86 	AMMO,
87 	PLASMAGUN,
88 	SPECIAL_SFX_BOUNCE
89 },
90 {	"ammo_rockets",
91 	"models/powerups/ammo/rocketam.md3",
92 	"",
93 	"",
94 	"icons/icona_rocket",
95 	"Rockets",
96 	5,
97 	AMMO,
98 	ROCKET_LAUNCHER,
99 	SPECIAL_SFX_ROTATE
100 },
101 {
102 	"ammo_shells",
103 	"models/powerups/ammo/shotgunam.md3",
104 	"",
105 	"sound/misc/am_pkup.wav",
106 	"icons/icona_shotgun",
107 	"Shells",
108 	10,
109 	AMMO,
110 	SHOTGUN,
111 	SPECIAL_SFX_ROTATE
112 },
113 {
114 	"ammo_slugs",
115 	"models/powerups/ammo/railgunam.md3",
116 	"",
117 	"sound/misc/am_pkup.wav",
118 	"icons/icona_railgun",
119 	"Slugs",
120 	10,
121 	AMMO,
122 	RAILGUN,
123 	SPECIAL_SFX_ROTATE
124 },
125 {
126 	"item_armor_body",
127 	"models/powerups/armor/armor_red.md3",
128 	"",
129 	"sound/misc/ar2_pkup.wav",
130 	"icons/iconr_red",
131 	"Heavy Armor",
132 	100,
133 	ARMOR,
134 	SUB_NONE,
135 	SPECIAL_SFX_ROTATE
136 },
137 {
138 	"item_armor_combat",
139 	"models/powerups/armor/armor_yel.md3",
140 	"",
141 	"sound/misc/ar2_pkup.wav",
142 	"icons/iconr_yellow",
143 	"Armor",
144 	50,
145 	ARMOR,
146 	SUB_NONE,
147 	SPECIAL_SFX_ROTATE
148 },
149 {
150 	"item_armor_shard",
151 	"models/powerups/armor/shard.md3",
152 	"",
153 	"sound/misc/ar1_pkup.wav",
154 	"icons/iconr_shard",
155 	"Armor Shared",
156 	5,
157 	ARMOR,
158 	SUB_NONE,
159 	SPECIAL_SFX_ROTATE
160 },
161 {
162 	"weapon_gauntlet",
163 	"models/weapons2/gauntlet/gauntlet.md3",
164 	"",
165 	"sound/misc/w_pkup.wav",
166 	"icons/iconw_gauntlet",
167 	"Gauntlet",
168 	0,
169 	WEAPON,
170 	GAUNTLET,
171 	SPECIAL_SFX_ROTATE
172 },
173 {
174 	"weapon_shotgun",
175 	"models/weapons2/shotgun/shotgun.md3",
176 	"",
177 	"sound/misc/w_pkup.wav",
178 	"icons/iconw_shotgun",
179 	"Shotgun",
180 	10,
181 	WEAPON,
182 	SHOTGUN,
183 	SPECIAL_SFX_ROTATE
184 },
185 {
186 	"weapon_machinegun",
187 	"models/weapons2/machinegun/machinegun.md3",
188 	"",
189 	"sound/misc/w_pkup.wav",
190 	"icons/iconw_machinegun",
191 	"Machinegun",
192 	40,
193 	WEAPON,
194 	MACHINEGUN,
195 	SPECIAL_SFX_ROTATE
196 },
197 {
198 	"weapon_grenadelauncher",
199 	"models/weapons2/grenadel/grenadel.md3",
200 	"",
201 	"sound/misc/w_pkup.wav",
202 	"icons/iconw_grenade",
203 	"Grenade Launcher",
204 	10,
205 	WEAPON,
206 	GRENADE_LAUNCHER,
207 	SPECIAL_SFX_ROTATE
208 },
209 {
210 	"weapon_rocketlauncher",
211 	"models/weapons2/rocketl/rocketl.md3",
212 	"",
213 	"sound/misc/w_pkup.wav",
214 	"icons/iconw_rocket",
215 	"Rocket Launcher",
216 	10,
217 	WEAPON,
218 	ROCKET_LAUNCHER,
219 	SPECIAL_SFX_ROTATE
220 },
221 {
222 	"weapon_lightning",
223 	"models/weapons2/lightning/lightning.md3",
224 	"",
225 	"sound/misc/w_pkup.wav",
226 	"icons/iconw_lightning",
227 	"Lightning Gun",
228 	100,
229 	WEAPON,
230 	LIGHTNING,
231 	SPECIAL_SFX_ROTATE
232 },
233 {
234 	"weapon_railgun",
235 	"models/weapons2/railgun/railgun.md3",
236 	"",
237 	"sound/misc/w_pkup.wav",
238 	"icons/iconw_railgun",
239 	"Railgun",
240 	10,
241 	WEAPON,
242 	RAILGUN,
243 	SPECIAL_SFX_ROTATE
244 },
245 {
246 	"weapon_plasmagun",
247 	"models/weapons2/plasma/plasma.md3",
248 	"",
249 	"sound/misc/w_pkup.wav",
250 	"icons/iconw_plasma",
251 	"Plasma Gun",
252 	50,
253 	WEAPON,
254 	PLASMAGUN,
255 	SPECIAL_SFX_ROTATE
256 },
257 {
258 	"weapon_bfg",
259 	"models/weapons2/bfg/bfg.md3",
260 	"",
261 	"sound/misc/w_pkup.wav",
262 	"icons/iconw_bfg",
263 	"BFG10K",
264 	20,
265 	WEAPON,
266 	BFG,
267 	SPECIAL_SFX_ROTATE
268 },
269 {
270 	"weapon_grapplinghook",
271 	"models/weapons2/grapple/grapple.md3",
272 	"",
273 	"sound/misc/w_pkup.wav",
274 	"icons/iconw_grapple",
275 	"Grappling Hook",
276 	0,
277 	WEAPON,
278 	GRAPPLING_HOOK,
279 	SPECIAL_SFX_ROTATE
280 },
281 {
282 	0
283 }
284 
285 };
286 
287 
288 /*!
289 */
getItemElement(const stringc & key)290 const SItemElement * getItemElement ( const stringc& key )
291 {
292 	const SItemElement *item = Quake3ItemElement;
293 
294 	while ( item->key )
295 	{
296 		if ( 0 == strcmp ( key.c_str(), item->key ) )
297 			return item;
298 		item += 1;
299 	}
300 	return 0;
301 }
302 
303 /*!
304 	Quake3 Model Factory.
305 	Takes the mesh buffers and creates scenenodes for their associated shaders
306 */
Q3ShaderFactory(Q3LevelLoadParameter & loadParam,IrrlichtDevice * device,IQ3LevelMesh * mesh,eQ3MeshIndex meshIndex,ISceneNode * parent,IMetaTriangleSelector * meta,bool showShaderName)307 void Q3ShaderFactory (	Q3LevelLoadParameter &loadParam,
308 						IrrlichtDevice *device,
309 						IQ3LevelMesh* mesh,
310 						eQ3MeshIndex meshIndex,
311 						ISceneNode *parent,
312 						IMetaTriangleSelector *meta,
313 						bool showShaderName )
314 {
315 	if ( 0 == mesh || 0 == device )
316 		return;
317 
318 	IMeshSceneNode* node = 0;
319 	ISceneManager* smgr = device->getSceneManager();
320 	ITriangleSelector * selector = 0;
321 
322 	// the additional mesh can be quite huge and is unoptimized
323 	// Save to cast to SMesh
324 	SMesh * additional_mesh = (SMesh*) mesh->getMesh ( meshIndex );
325 	if ( 0 == additional_mesh || additional_mesh->getMeshBufferCount() == 0)
326 		return;
327 
328 	char buf[128];
329 	if ( loadParam.verbose > 0 )
330 	{
331 		loadParam.startTime = device->getTimer()->getRealTime();
332 		if ( loadParam.verbose > 1 )
333 		{
334 			snprintf(buf, 128, "q3shaderfactory start" );
335 			device->getLogger()->log( buf, ELL_INFORMATION);
336 		}
337 	}
338 
339 	IGUIFont *font = 0;
340 	if ( showShaderName )
341 		font = device->getGUIEnvironment()->getFont("fontlucida.png");
342 
343 	IVideoDriver *driver = device->getVideoDriver();
344 
345 	// create helper textures
346 	if ( 1 )
347 	{
348 		tTexArray tex;
349 		u32 pos = 0;
350 		getTextures ( tex, "$redimage $blueimage $whiteimage $checkerimage", pos,
351 								device->getFileSystem(), driver );
352 	}
353 
354 	s32 sceneNodeID = 0;
355 	for ( u32 i = 0; i!= additional_mesh->getMeshBufferCount (); ++i )
356 	{
357 		IMeshBuffer *meshBuffer = additional_mesh->getMeshBuffer ( i );
358 		const SMaterial &material = meshBuffer->getMaterial();
359 
360 		//! The ShaderIndex is stored in the second material parameter
361 		s32 shaderIndex = (s32) material.MaterialTypeParam2;
362 
363 		// the meshbuffer can be rendered without additional support, or it has no shader
364 		IShader *shader = (IShader *) mesh->getShader ( shaderIndex );
365 
366 		// no shader, or mapped to existing material
367 		if ( 0 == shader )
368 		{
369 
370 #if 1
371 			// clone mesh
372 			SMesh * m = new SMesh ();
373 			m->addMeshBuffer ( meshBuffer );
374 			SMaterial &mat = m->getMeshBuffer( 0 )->getMaterial();
375 			if ( mat.getTexture( 0 ) == 0 )
376 				mat.setTexture ( 0, driver->getTexture ( "$blueimage" ) );
377 			if ( mat.getTexture( 1 ) == 0 )
378 				mat.setTexture ( 1, driver->getTexture ( "$redimage" ) );
379 
380 			IMesh * store = smgr->getMeshManipulator ()->createMeshWith2TCoords ( m );
381 			m->drop();
382 
383 			node = smgr->addMeshSceneNode ( store,  parent, sceneNodeID );
384 			node->setAutomaticCulling ( scene::EAC_OFF );
385 			store->drop ();
386 			sceneNodeID += 1;
387 #endif
388 		}
389 		else if ( 1 )
390 		{
391 /*
392 			stringc s;
393 			dumpShader ( s, shader );
394 			printf ( s.c_str () );
395 */
396 			// create sceneNode
397 			node = smgr->addQuake3SceneNode ( meshBuffer, shader, parent, sceneNodeID );
398 			node->setAutomaticCulling ( scene::EAC_FRUSTUM_BOX );
399 			sceneNodeID += 1;
400 		}
401 
402 		// show Debug Shader Name
403 		if ( showShaderName && node )
404 		{
405 			swprintf ( (wchar_t*) buf, 64, L"%hs:%d", node->getName(),node->getID() );
406 			smgr->addBillboardTextSceneNode(
407 					font,
408 					(wchar_t*) buf,
409 					node,
410 					dimension2d<f32>(80.0f, 8.0f),
411 					vector3df(0, 10, 0),
412 					sceneNodeID);
413 			sceneNodeID += 1;
414 		}
415 
416 		// create Portal Rendertargets
417 		if ( shader )
418 		{
419 			const SVarGroup *group = shader->getGroup(1);
420 			if ( group->isDefined( "surfaceparm", "portal" ) )
421 			{
422 			}
423 
424 		}
425 
426 
427 		// add collision
428 		// find out if shader is marked as nonsolid
429 		u8 doCreate = meta !=0  ;
430 
431 		if ( shader )
432 		{
433 			const SVarGroup *group = shader->getGroup(1);
434 			if (	group->isDefined( "surfaceparm", "trans" )
435 					// || group->isDefined( "surfaceparm", "sky" )
436 					// || group->isDefined( "surfaceparm", "nonsolid" )
437 				)
438 			{
439 				if ( !group->isDefined( "surfaceparm", "metalsteps" ) )
440 				{
441 					doCreate = 0;
442 				}
443 			}
444 		}
445 
446 		if ( doCreate )
447 		{
448 			IMesh *m = 0;
449 
450 			//! controls if triangles are modified by the scenenode during runtime
451 			bool takeOriginal = true;
452 
453 			if ( takeOriginal )
454 			{
455 				m = new SMesh ();
456 				((SMesh*) m )->addMeshBuffer (meshBuffer);
457 			}
458 			else
459 			{
460 				m = node->getMesh();
461 			}
462 
463 			//selector = smgr->createOctreeTriangleSelector ( m, 0, 128 );
464 			selector = smgr->createTriangleSelector ( m, 0 );
465 			meta->addTriangleSelector ( selector );
466 			selector->drop ();
467 
468 			if ( takeOriginal )
469 			{
470 				delete m;
471 			}
472 		}
473 
474 	}
475 
476 #if 0
477 	if ( meta )
478 	{
479 		selector = smgr->createOctreeTriangleSelector ( additional_mesh, 0 );
480 		meta->addTriangleSelector ( selector );
481 		selector->drop ();
482 	}
483 #endif
484 
485 	if ( loadParam.verbose > 0 )
486 	{
487 		loadParam.endTime = device->getTimer()->getRealTime ();
488 		snprintf(buf, 128, "q3shaderfactory needed %04d ms to create %d shader nodes",
489 			loadParam.endTime - loadParam.startTime,
490 			sceneNodeID
491 			);
492 		device->getLogger()->log(buf, ELL_INFORMATION);
493 	}
494 
495 }
496 
497 
498 /*!
499 	create Items from Entity
500 */
Q3ModelFactory(Q3LevelLoadParameter & loadParam,IrrlichtDevice * device,IQ3LevelMesh * masterMesh,ISceneNode * parent,bool showShaderName)501 void Q3ModelFactory (	Q3LevelLoadParameter &loadParam,
502 						IrrlichtDevice *device,
503 						IQ3LevelMesh* masterMesh,
504 						ISceneNode *parent,
505 						bool showShaderName
506 						)
507 {
508 	if ( 0 == masterMesh )
509 		return;
510 
511 	tQ3EntityList &entity = masterMesh->getEntityList ();
512 	ISceneManager* smgr = device->getSceneManager();
513 
514 
515 	char buf[128];
516 	const SVarGroup *group;
517 	IEntity search;
518 	s32 index;
519 	s32 lastIndex;
520 
521 /*
522 	stringc s;
523 	FILE *f = 0;
524 	f = fopen ( "entity.txt", "wb" );
525 	for ( index = 0; (u32) index < entityList.size (); ++index )
526 	{
527 		const IEntity *entity = &entityList[ index ];
528 		s = entity->name;
529 		dumpShader ( s, entity );
530 		fwrite ( s.c_str(), 1, s.size(), f );
531 	}
532 	fclose ( f );
533 */
534 	IAnimatedMeshMD3* model;
535 	SMD3Mesh * mesh;
536 	const SMD3MeshBuffer *meshBuffer;
537 	IMeshSceneNode* node;
538 	ISceneNodeAnimator* anim;
539 	const IShader *shader;
540 	u32 pos;
541 	vector3df p;
542 	u32 nodeCount = 0;
543 	tTexArray textureArray;
544 
545 	IGUIFont *font = 0;
546 	if ( showShaderName )
547 		font = device->getGUIEnvironment()->getFont("fontlucida.png");
548 
549 	const SItemElement *itemElement;
550 
551 	// walk list
552 	for ( index = 0; (u32) index < entity.size(); ++index )
553 	{
554 		itemElement = getItemElement ( entity[index].name );
555 		if ( 0 == itemElement )
556 			continue;
557 
558 		pos = 0;
559 		p = getAsVector3df ( entity[index].getGroup(1)->get ( "origin" ), pos );
560 
561 		nodeCount += 1;
562 		for ( u32 g = 0; g < 2; ++g )
563 		{
564 			if ( 0 == itemElement->model[g] || itemElement->model[g][0] == 0 )
565 				continue;
566 			model = (IAnimatedMeshMD3*) smgr->getMesh( itemElement->model[g] );
567 			if ( 0 == model )
568 				continue;
569 
570 			mesh = model->getOriginalMesh();
571 			for ( u32 j = 0; j != mesh->Buffer.size (); ++j )
572 			{
573 				meshBuffer = mesh->Buffer[j];
574 				if ( 0 == meshBuffer )
575 					continue;
576 
577 				shader = masterMesh->getShader ( meshBuffer->Shader.c_str(), false );
578 				IMeshBuffer *final = model->getMesh(0)->getMeshBuffer(j);
579 				if ( shader )
580 				{
581 					//!TODO: Hack don't modify the vertexbuffer. make it better;-)
582 					final->getMaterial().ColorMask = 0;
583 					node = smgr->addQuake3SceneNode ( final, shader, parent );
584 					final->getMaterial().ColorMask = 15;
585 				}
586 				else
587 				{
588 					// clone mesh
589 					SMesh * m = new SMesh ();
590 					m->addMeshBuffer ( final );
591 					node = smgr->addMeshSceneNode ( m,  parent );
592 					m->drop();
593 				}
594 
595 				if ( 0 == node )
596 				{
597 					snprintf ( buf, 128, "q3ModelFactory shader %s failed", meshBuffer->Shader.c_str() );
598 					device->getLogger()->log ( buf );
599 					continue;
600 				}
601 
602 				// node was maybe centered by shaderscenenode
603 				node->setPosition ( p );
604 				node->setName ( meshBuffer->Shader );
605 				node->setAutomaticCulling ( scene::EAC_BOX );
606 
607 				// add special effects to node
608 				if (	itemElement->special & SPECIAL_SFX_ROTATE ||
609 						(g == 0 && itemElement->special & SPECIAL_SFX_ROTATE_1)
610 					)
611 				{
612 					anim = smgr->createRotationAnimator ( vector3df ( 0.f,
613 						2.f, 0.f ) );
614 					node->addAnimator ( anim );
615 					anim->drop ();
616 				}
617 
618 				if ( itemElement->special & SPECIAL_SFX_BOUNCE )
619 				{
620 					//anim = smgr->createFlyStraightAnimator (
621 					//	p, p + vector3df ( 0.f, 60.f, 0.f ), 1000, true, true );
622 					anim = smgr->createFlyCircleAnimator (
623 						p + vector3df( 0.f, 20.f, 0.f ),
624 						20.f,
625 						0.005f,
626 						vector3df ( 1.f, 0.f, 0.f ),
627 						core::fract ( nodeCount * 0.05f ),
628 						1.f
629 						);
630 					node->addAnimator ( anim );
631 					anim->drop ();
632 				}
633 			}
634 		}
635 		// show name
636 		if ( showShaderName )
637 		{
638 			swprintf ( (wchar_t*) buf, sizeof(buf) / 2, L"%hs", itemElement->key );
639 			smgr->addBillboardTextSceneNode(
640 					font,
641 					(wchar_t*) buf,
642 					parent,
643 					dimension2d<f32>(80.0f, 8.0f),
644 					p + vector3df(0, 30, 0),
645 					0);
646 		}
647 	}
648 
649 	// music
650 	search.name = "worldspawn";
651 	index = entity.binary_search_multi ( search, lastIndex );
652 
653 	if ( index >= 0 )
654 	{
655 		group = entity[ index ].getGroup(1);
656 		background_music ( group->get ( "music" ).c_str () );
657 	}
658 
659 	// music
660 	search.name = "worldspawn";
661 	index = entity.binary_search_multi ( search, lastIndex );
662 
663 	if ( index >= 0 )
664 	{
665 		group = entity[ index ].getGroup(1);
666 		background_music ( group->get ( "music" ).c_str () );
667 	}
668 
669 	//IAnimatedMesh* mesh = smgr->getMesh("../../media/sydney.md2");
670 	//IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh );
671 
672 }
673 
674 /*!
675 	so we need a good starting Position in the level.
676 	we can ask the Quake3 Loader for all entities with class_name "info_player_deathmatch"
677 */
Q3StartPosition(IQ3LevelMesh * mesh,ICameraSceneNode * camera,s32 startposIndex,const vector3df & translation)678 s32 Q3StartPosition (	IQ3LevelMesh* mesh,
679 						ICameraSceneNode* camera,
680 						s32 startposIndex,
681 						const vector3df &translation
682 					)
683 {
684 	if ( 0 == mesh )
685 		return 0;
686 
687 	tQ3EntityList &entityList = mesh->getEntityList ();
688 
689 	IEntity search;
690 	search.name = "info_player_start";	// "info_player_deathmatch";
691 
692 	// find all entities in the multi-list
693 	s32 lastIndex;
694 	s32 index = entityList.binary_search_multi ( search, lastIndex );
695 
696 	if ( index < 0 )
697 	{
698 		search.name = "info_player_deathmatch";
699 		index = entityList.binary_search_multi ( search, lastIndex );
700 	}
701 
702 	if ( index < 0 )
703 		return 0;
704 
705 	index += core::clamp ( startposIndex, 0, lastIndex - index );
706 
707 	u32 parsepos;
708 
709 	const SVarGroup *group;
710 	group = entityList[ index ].getGroup(1);
711 
712 	parsepos = 0;
713 	vector3df pos = getAsVector3df ( group->get ( "origin" ), parsepos );
714 	pos += translation;
715 
716 	parsepos = 0;
717 	f32 angle = getAsFloat ( group->get ( "angle"), parsepos );
718 
719 	vector3df target ( 0.f, 0.f, 1.f );
720 	target.rotateXZBy ( angle - 90.f, vector3df () );
721 
722 	if ( camera )
723 	{
724 		camera->setPosition ( pos );
725 		camera->setTarget ( pos + target );
726 		//! New. FPSCamera and animators catches reset on animate 0
727 		camera->OnAnimate ( 0 );
728 	}
729 	return lastIndex - index + 1;
730 }
731 
732 
733 /*!
734 	gets a accumulated force on a given surface
735 */
getGravity(const c8 * surface)736 vector3df getGravity ( const c8 * surface )
737 {
738 	if ( 0 == strcmp ( surface, "earth" ) ) return vector3df ( 0.f, -90.f, 0.f );
739 	if ( 0 == strcmp ( surface, "moon" ) ) return vector3df ( 0.f, -6.f / 100.f, 0.f );
740 	if ( 0 == strcmp ( surface, "water" ) ) return vector3df ( 0.1f / 100.f, -2.f / 100.f, 0.f );
741 	if ( 0 == strcmp ( surface, "ice" ) ) return vector3df ( 0.2f / 100.f, -9.f / 100.f, 0.3f / 100.f );
742 
743 	return vector3df ( 0.f, 0.f, 0.f );
744 }
745 
746 
747 
748 /*
749 	Dynamically load the Irrlicht Library
750 */
751 
752 #if defined(_IRR_WINDOWS_API_)
753 #ifdef _MSC_VER
754 #pragma comment(lib, "Irrlicht.lib")
755 #endif
756 
757 #include <windows.h>
758 
load_createDevice(const c8 * filename)759 funcptr_createDevice load_createDevice ( const c8 * filename)
760 {
761 	return (funcptr_createDevice) GetProcAddress ( LoadLibrary ( filename ), "createDevice" );
762 }
763 
load_createDeviceEx(const c8 * filename)764 funcptr_createDeviceEx load_createDeviceEx ( const c8 * filename)
765 {
766 	return (funcptr_createDeviceEx) GetProcAddress ( LoadLibrary ( filename ), "createDeviceEx" );
767 }
768 
769 #else
770 
771 // TODO: Dynamic Loading for other os
load_createDevice(const c8 * filename)772 funcptr_createDevice load_createDevice ( const c8 * filename)
773 {
774 	return createDevice;
775 }
776 
load_createDeviceEx(const c8 * filename)777 funcptr_createDeviceEx load_createDeviceEx ( const c8 * filename)
778 {
779 	return createDeviceEx;
780 }
781 
782 #endif
783 
784 /*
785 	get the current collision response camera animator
786 */
camCollisionResponse(IrrlichtDevice * device)787 ISceneNodeAnimatorCollisionResponse* camCollisionResponse( IrrlichtDevice * device )
788 {
789 	ICameraSceneNode *camera = device->getSceneManager()->getActiveCamera();
790 	ISceneNodeAnimatorCollisionResponse *a = 0;
791 
792 	list<ISceneNodeAnimator*>::ConstIterator it = camera->getAnimators().begin();
793 	for (; it != camera->getAnimators().end(); ++it)
794 	{
795 		a = (ISceneNodeAnimatorCollisionResponse*) (*it);
796 		if ( a->getType() == ESNAT_COLLISION_RESPONSE )
797 			return a;
798 	}
799 
800 	return 0;
801 }
802 
803 
804 //! internal Animation
setTimeFire(TimeFire * t,u32 delta,u32 flags)805 void setTimeFire ( TimeFire *t, u32 delta, u32 flags )
806 {
807 	t->flags = flags;
808 	t->next = 0;
809 	t->delta = delta;
810 }
811 
812 
checkTimeFire(TimeFire * t,u32 listSize,u32 now)813 void checkTimeFire ( TimeFire *t, u32 listSize, u32 now )
814 {
815 	u32 i;
816 	for ( i = 0; i < listSize; ++i )
817 	{
818 		if ( now < t[i].next )
819 			continue;
820 
821 		t[i].next = core::max_ ( now + t[i].delta, t[i].next + t[i].delta );
822 		t[i].flags |= FIRED;
823 	}
824 }
825