3
create the additional scenenodes for ( bullets, health... )
5
Defines the Entities for Quake3
12
using namespace scene;
14
using namespace video;
16
using namespace quake3;
18
//! This list is based on the original quake3.
19
static const SItemElement Quake3ItemElement [] = {
21
{"models/powerups/health/medium_cross.md3",
22
"models/powerups/health/medium_sphere.md3"},
23
"sound/items/n_health.wav",
29
SPECIAL_SFX_BOUNCE | SPECIAL_SFX_ROTATE_1
31
{ "item_health_large",
32
"models/powerups/health/large_cross.md3",
33
"models/powerups/health/large_sphere.md3",
34
"sound/items/l_health.wav",
40
SPECIAL_SFX_BOUNCE | SPECIAL_SFX_ROTATE_1
44
"models/powerups/health/mega_cross.md3",
45
"models/powerups/health/mega_sphere.md3",
46
"sound/items/m_health.wav",
52
SPECIAL_SFX_BOUNCE | SPECIAL_SFX_ROTATE_1
56
"models/powerups/health/small_cross.md3",
57
"models/powerups/health/small_sphere.md3",
58
"sound/items/s_health.wav",
64
SPECIAL_SFX_BOUNCE | SPECIAL_SFX_ROTATE_1
67
"models/powerups/ammo/machinegunam.md3",
69
"sound/misc/am_pkup.wav",
70
"icons/icona_machinegun",
79
"models/powerups/ammo/plasmaam.md3",
81
"sound/misc/am_pkup.wav",
90
"models/powerups/ammo/rocketam.md3",
102
"models/powerups/ammo/shotgunam.md3",
104
"sound/misc/am_pkup.wav",
105
"icons/icona_shotgun",
114
"models/powerups/ammo/railgunam.md3",
116
"sound/misc/am_pkup.wav",
117
"icons/icona_railgun",
126
"models/powerups/armor/armor_red.md3",
128
"sound/misc/ar2_pkup.wav",
138
"models/powerups/armor/armor_yel.md3",
140
"sound/misc/ar2_pkup.wav",
141
"icons/iconr_yellow",
150
"models/powerups/armor/shard.md3",
152
"sound/misc/ar1_pkup.wav",
162
"models/weapons2/gauntlet/gauntlet.md3",
164
"sound/misc/w_pkup.wav",
165
"icons/iconw_gauntlet",
174
"models/weapons2/shotgun/shotgun.md3",
176
"sound/misc/w_pkup.wav",
177
"icons/iconw_shotgun",
186
"models/weapons2/machinegun/machinegun.md3",
188
"sound/misc/w_pkup.wav",
189
"icons/iconw_machinegun",
197
"weapon_grenadelauncher",
198
"models/weapons2/grenadel/grenadel.md3",
200
"sound/misc/w_pkup.wav",
201
"icons/iconw_grenade",
209
"weapon_rocketlauncher",
210
"models/weapons2/rocketl/rocketl.md3",
212
"sound/misc/w_pkup.wav",
213
"icons/iconw_rocket",
222
"models/weapons2/lightning/lightning.md3",
224
"sound/misc/w_pkup.wav",
225
"icons/iconw_lightning",
234
"models/weapons2/railgun/railgun.md3",
236
"sound/misc/w_pkup.wav",
237
"icons/iconw_railgun",
246
"models/weapons2/plasma/plasma.md3",
248
"sound/misc/w_pkup.wav",
249
"icons/iconw_plasma",
258
"models/weapons2/bfg/bfg.md3",
260
"sound/misc/w_pkup.wav",
269
"weapon_grapplinghook",
270
"models/weapons2/grapple/grapple.md3",
272
"sound/misc/w_pkup.wav",
273
"icons/iconw_grapple",
289
const SItemElement * getItemElement ( const stringc& key )
291
const SItemElement *item = Quake3ItemElement;
295
if ( 0 == strcmp ( key.c_str(), item->key ) )
303
Quake3 Model Factory.
304
Takes the mesh buffers and creates scenenodes for their associated shaders
306
void Q3ShaderFactory ( Q3LevelLoadParameter &loadParam,
307
IrrlichtDevice *device,
309
eQ3MeshIndex meshIndex,
311
IMetaTriangleSelector *meta,
312
bool showShaderName )
314
if ( 0 == mesh || 0 == device )
317
IMeshSceneNode* node = 0;
318
ISceneManager* smgr = device->getSceneManager();
319
ITriangleSelector * selector = 0;
321
// the additional mesh can be quite huge and is unoptimized
322
// Save to cast to SMesh
323
SMesh * additional_mesh = (SMesh*) mesh->getMesh ( meshIndex );
324
if ( 0 == additional_mesh || additional_mesh->getMeshBufferCount() == 0)
328
if ( loadParam.verbose > 0 )
330
loadParam.startTime = device->getTimer()->getRealTime();
331
if ( loadParam.verbose > 1 )
333
snprintf(buf, 128, "q3shaderfactory start" );
334
device->getLogger()->log( buf, ELL_INFORMATION);
339
if ( showShaderName )
340
font = device->getGUIEnvironment()->getFont("fontlucida.png");
342
IVideoDriver *driver = device->getVideoDriver();
344
// create helper textures
349
getTextures ( tex, "$redimage $blueimage $whiteimage $checkerimage", pos,
350
device->getFileSystem(), driver );
354
for ( u32 i = 0; i!= additional_mesh->getMeshBufferCount (); ++i )
356
IMeshBuffer *meshBuffer = additional_mesh->getMeshBuffer ( i );
357
const SMaterial &material = meshBuffer->getMaterial();
359
//! The ShaderIndex is stored in the second material parameter
360
s32 shaderIndex = (s32) material.MaterialTypeParam2;
362
// the meshbuffer can be rendered without additional support, or it has no shader
363
IShader *shader = (IShader *) mesh->getShader ( shaderIndex );
365
// no shader, or mapped to existing material
371
SMesh * m = new SMesh ();
372
m->addMeshBuffer ( meshBuffer );
373
SMaterial &mat = m->getMeshBuffer( 0 )->getMaterial();
374
if ( mat.getTexture( 0 ) == 0 )
375
mat.setTexture ( 0, driver->getTexture ( "$blueimage" ) );
376
if ( mat.getTexture( 1 ) == 0 )
377
mat.setTexture ( 1, driver->getTexture ( "$redimage" ) );
379
IMesh * store = smgr->getMeshManipulator ()->createMeshWith2TCoords ( m );
382
node = smgr->addMeshSceneNode ( store, parent, sceneNodeID );
383
node->setAutomaticCulling ( scene::EAC_OFF );
392
dumpShader ( s, shader );
393
printf ( s.c_str () );
396
node = smgr->addQuake3SceneNode ( meshBuffer, shader, parent, sceneNodeID );
397
node->setAutomaticCulling ( scene::EAC_FRUSTUM_BOX );
401
// show Debug Shader Name
402
if ( showShaderName && node )
404
IBillboardTextSceneNode* node2 = 0;
405
swprintf ( (wchar_t*) buf, 64, L"%hs:%d", node->getName(),node->getID() );
406
node2 = smgr->addBillboardTextSceneNode(
410
dimension2d<f32>(80.0f, 8.0f),
414
snprintf ( buf, 64, "%s:%d", node->getName(),node->getID() );
415
//node2->setName ( buf );
419
// create Portal Rendertargets
422
const SVarGroup *group = shader->getGroup(1);
423
if ( group->isDefined( "surfaceparm", "portal" ) )
431
// find out if shader is marked als nonsolid
432
u8 doCreate = meta !=0 ;
436
const SVarGroup *group = shader->getGroup(1);
437
if ( group->isDefined( "surfaceparm", "trans" )
438
// || group->isDefined( "surfaceparm", "sky" )
439
// || group->isDefined( "surfaceparm", "nonsolid" )
442
if ( !group->isDefined( "surfaceparm", "metalsteps" ) )
453
//! controls if triangles are modified by the scenenode during runtime
454
bool takeOriginal = true;
459
((SMesh*) m )->addMeshBuffer (meshBuffer);
466
//selector = smgr->createOctreeTriangleSelector ( m, 0, 128 );
467
selector = smgr->createTriangleSelector ( m, 0 );
468
meta->addTriangleSelector ( selector );
482
selector = smgr->createOctreeTriangleSelector ( additional_mesh, 0 );
483
meta->addTriangleSelector ( selector );
488
if ( loadParam.verbose > 0 )
490
loadParam.endTime = device->getTimer()->getRealTime ();
491
snprintf(buf, 128, "q3shaderfactory needed %04d ms to create %d shader nodes",
492
loadParam.endTime - loadParam.startTime,
495
device->getLogger()->log(buf, ELL_INFORMATION);
502
create Items from Entity
504
void Q3ModelFactory ( Q3LevelLoadParameter &loadParam,
505
IrrlichtDevice *device,
506
IQ3LevelMesh* masterMesh,
511
if ( 0 == masterMesh )
514
tQ3EntityList &entity = masterMesh->getEntityList ();
515
ISceneManager* smgr = device->getSceneManager();
519
const SVarGroup *group;
527
f = fopen ( "entity.txt", "wb" );
528
for ( index = 0; (u32) index < entityList.size (); ++index )
530
const IEntity *entity = &entityList[ index ];
532
dumpShader ( s, entity );
533
fwrite ( s.c_str(), 1, s.size(), f );
537
IAnimatedMeshMD3* model;
539
const SMD3MeshBuffer *meshBuffer;
540
IMeshSceneNode* node;
541
ISceneNodeAnimator* anim;
542
const IShader *shader;
546
tTexArray textureArray;
549
if ( showShaderName )
550
font = device->getGUIEnvironment()->getFont("fontlucida.png");
552
const SItemElement *itemElement;
555
for ( index = 0; (u32) index < entity.size(); ++index )
557
itemElement = getItemElement ( entity[index].name );
558
if ( 0 == itemElement )
562
p = getAsVector3df ( entity[index].getGroup(1)->get ( "origin" ), pos );
565
for ( u32 g = 0; g < 2; ++g )
567
if ( 0 == itemElement->model[g] || itemElement->model[g][0] == 0 )
569
model = (IAnimatedMeshMD3*) smgr->getMesh( itemElement->model[g] );
573
mesh = model->getOriginalMesh();
574
for ( u32 j = 0; j != mesh->Buffer.size (); ++j )
576
meshBuffer = mesh->Buffer[j];
577
if ( 0 == meshBuffer )
580
shader = masterMesh->getShader ( meshBuffer->Shader.c_str(), false );
581
IMeshBuffer *final = model->getMesh(0)->getMeshBuffer(j);
584
//!TODO: Hack don't modify the vertexbuffer. make it better;-)
585
final->getMaterial().ColorMask = 0;
586
node = smgr->addQuake3SceneNode ( final, shader, parent );
587
final->getMaterial().ColorMask = 15;
592
SMesh * m = new SMesh ();
593
m->addMeshBuffer ( final );
594
node = smgr->addMeshSceneNode ( m, parent );
600
snprintf ( buf, 128, "q3ModelFactory shader %s failed", meshBuffer->Shader.c_str() );
601
device->getLogger()->log ( buf );
605
// node was maybe centered by shaderscenenode
606
node->setPosition ( p );
607
node->setName ( meshBuffer->Shader );
608
node->setAutomaticCulling ( scene::EAC_BOX );
610
// add special effects to node
611
if ( itemElement->special & SPECIAL_SFX_ROTATE ||
612
(g == 0 && itemElement->special & SPECIAL_SFX_ROTATE_1)
615
anim = smgr->createRotationAnimator ( vector3df ( 0.f,
617
node->addAnimator ( anim );
621
if ( itemElement->special & SPECIAL_SFX_BOUNCE )
623
//anim = smgr->createFlyStraightAnimator (
624
// p, p + vector3df ( 0.f, 60.f, 0.f ), 1000, true, true );
625
anim = smgr->createFlyCircleAnimator (
626
p + vector3df( 0.f, 20.f, 0.f ),
629
vector3df ( 1.f, 0.f, 0.f ),
630
core::fract ( nodeCount * 0.05f ),
633
node->addAnimator ( anim );
639
if ( showShaderName )
641
IBillboardTextSceneNode* node2 = 0;
642
swprintf ( (wchar_t*) buf, sizeof(buf) / 2, L"%hs", itemElement->key );
643
node2 = smgr->addBillboardTextSceneNode(
647
dimension2d<f32>(80.0f, 8.0f),
648
p + vector3df(0, 30, 0),
656
search.name = "worldspawn";
657
index = entity.binary_search_multi ( search, lastIndex );
661
group = entity[ index ].getGroup(1);
662
background_music ( group->get ( "music" ).c_str () );
666
search.name = "worldspawn";
667
index = entity.binary_search_multi ( search, lastIndex );
671
group = entity[ index ].getGroup(1);
672
background_music ( group->get ( "music" ).c_str () );
675
//IAnimatedMesh* mesh = smgr->getMesh("../../media/sydney.md2");
676
//IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh );
681
so we need a good starting Position in the level.
682
we can ask the Quake3 Loader for all entities with class_name "info_player_deathmatch"
684
s32 Q3StartPosition ( IQ3LevelMesh* mesh,
685
ICameraSceneNode* camera,
687
const vector3df &translation
693
tQ3EntityList &entityList = mesh->getEntityList ();
696
search.name = "info_player_start"; // "info_player_deathmatch";
698
// find all entities in the multi-list
700
s32 index = entityList.binary_search_multi ( search, lastIndex );
704
search.name = "info_player_deathmatch";
705
index = entityList.binary_search_multi ( search, lastIndex );
711
index += core::clamp ( startposIndex, 0, lastIndex - index );
715
const SVarGroup *group;
716
group = entityList[ index ].getGroup(1);
719
vector3df pos = getAsVector3df ( group->get ( "origin" ), parsepos );
723
f32 angle = getAsFloat ( group->get ( "angle"), parsepos );
725
vector3df target ( 0.f, 0.f, 1.f );
726
target.rotateXZBy ( angle - 90.f, vector3df () );
730
camera->setPosition ( pos );
731
camera->setTarget ( pos + target );
732
//! New. FPSCamera and animators catches reset on animate 0
733
camera->OnAnimate ( 0 );
735
return lastIndex - index + 1;
740
gets a accumulated force on a given surface
742
vector3df getGravity ( const c8 * surface )
744
if ( 0 == strcmp ( surface, "earth" ) ) return vector3df ( 0.f, -90.f, 0.f );
745
if ( 0 == strcmp ( surface, "moon" ) ) return vector3df ( 0.f, -6.f / 100.f, 0.f );
746
if ( 0 == strcmp ( surface, "water" ) ) return vector3df ( 0.1f / 100.f, -2.f / 100.f, 0.f );
747
if ( 0 == strcmp ( surface, "ice" ) ) return vector3df ( 0.2f / 100.f, -9.f / 100.f, 0.3f / 100.f );
749
return vector3df ( 0.f, 0.f, 0.f );
755
Dynamically load the Irrlicht Library
758
#if defined(_IRR_WINDOWS_API_)
760
#pragma comment(lib, "Irrlicht.lib")
765
funcptr_createDevice load_createDevice ( const c8 * filename)
767
return (funcptr_createDevice) GetProcAddress ( LoadLibrary ( filename ), "createDevice" );
770
funcptr_createDeviceEx load_createDeviceEx ( const c8 * filename)
772
return (funcptr_createDeviceEx) GetProcAddress ( LoadLibrary ( filename ), "createDeviceEx" );
777
// TODO: Dynamic Loading for other os
778
funcptr_createDevice load_createDevice ( const c8 * filename)
783
funcptr_createDeviceEx load_createDeviceEx ( const c8 * filename)
785
return createDeviceEx;
791
get the current collision respone camera animator
793
ISceneNodeAnimatorCollisionResponse* camCollisionResponse( IrrlichtDevice * device )
795
ICameraSceneNode *camera = device->getSceneManager()->getActiveCamera();
796
ISceneNodeAnimatorCollisionResponse *a = 0;
798
list<ISceneNodeAnimator*>::ConstIterator it = camera->getAnimators().begin();
799
for (; it != camera->getAnimators().end(); ++it)
801
a = (ISceneNodeAnimatorCollisionResponse*) (*it);
802
if ( a->getType() == ESNAT_COLLISION_RESPONSE )
810
//! internal Animation
811
void setTimeFire ( TimeFire *t, u32 delta, u32 flags )
819
void checkTimeFire ( TimeFire *t, u32 listSize, u32 now )
822
for ( i = 0; i < listSize; ++i )
824
if ( now < t[i].next )
827
t[i].next = core::max_ ( now + t[i].delta, t[i].next + t[i].delta );