From 7028cbe09c688437910a25623098762bf0fa592d Mon Sep 17 00:00:00 2001 From: David Walter Seikel Date: Mon, 28 Mar 2016 22:28:34 +1000 Subject: Move Irrlicht to src/others. --- .../examples/21.Quake3Explorer/q3factory.cpp | 824 +++++++++++++++++++++ 1 file changed, 824 insertions(+) create mode 100644 src/others/irrlicht-1.8.1/examples/21.Quake3Explorer/q3factory.cpp (limited to 'src/others/irrlicht-1.8.1/examples/21.Quake3Explorer/q3factory.cpp') diff --git a/src/others/irrlicht-1.8.1/examples/21.Quake3Explorer/q3factory.cpp b/src/others/irrlicht-1.8.1/examples/21.Quake3Explorer/q3factory.cpp new file mode 100644 index 0000000..d0f09b2 --- /dev/null +++ b/src/others/irrlicht-1.8.1/examples/21.Quake3Explorer/q3factory.cpp @@ -0,0 +1,824 @@ +/*! + Model Factory. + create the additional scenenodes for ( bullets, health... ) + + Defines the Entities for Quake3 +*/ + +#include +#include "q3factory.h" +#include "sound.h" + +using namespace irr; +using namespace scene; +using namespace gui; +using namespace video; +using namespace core; +using namespace quake3; + +//! This list is based on the original quake3. +static const SItemElement Quake3ItemElement [] = { +{ "item_health", + {"models/powerups/health/medium_cross.md3", + "models/powerups/health/medium_sphere.md3"}, + "sound/items/n_health.wav", + "icons/iconh_yellow", + "25 Health", + 25, + HEALTH, + SUB_NONE, + SPECIAL_SFX_BOUNCE | SPECIAL_SFX_ROTATE_1 +}, +{ "item_health_large", + "models/powerups/health/large_cross.md3", + "models/powerups/health/large_sphere.md3", + "sound/items/l_health.wav", + "icons/iconh_red", + "50 Health", + 50, + HEALTH, + SUB_NONE, + SPECIAL_SFX_BOUNCE | SPECIAL_SFX_ROTATE_1 +}, +{ + "item_health_mega", + "models/powerups/health/mega_cross.md3", + "models/powerups/health/mega_sphere.md3", + "sound/items/m_health.wav", + "icons/iconh_mega", + "Mega Health", + 100, + HEALTH, + SUB_NONE, + SPECIAL_SFX_BOUNCE | SPECIAL_SFX_ROTATE_1 +}, +{ + "item_health_small", + "models/powerups/health/small_cross.md3", + "models/powerups/health/small_sphere.md3", + "sound/items/s_health.wav", + "icons/iconh_green", + "5 Health", + 5, + HEALTH, + SUB_NONE, + SPECIAL_SFX_BOUNCE | SPECIAL_SFX_ROTATE_1 +}, +{ "ammo_bullets", + "models/powerups/ammo/machinegunam.md3", + "", + "sound/misc/am_pkup.wav", + "icons/icona_machinegun", + "Bullets", + 50, + AMMO, + MACHINEGUN, + SPECIAL_SFX_BOUNCE, +}, +{ + "ammo_cells", + "models/powerups/ammo/plasmaam.md3", + "", + "sound/misc/am_pkup.wav", + "icons/icona_plasma", + "Cells", + 30, + AMMO, + PLASMAGUN, + SPECIAL_SFX_BOUNCE +}, +{ "ammo_rockets", + "models/powerups/ammo/rocketam.md3", + "", + "", + "icons/icona_rocket", + "Rockets", + 5, + AMMO, + ROCKET_LAUNCHER, + SPECIAL_SFX_ROTATE +}, +{ + "ammo_shells", + "models/powerups/ammo/shotgunam.md3", + "", + "sound/misc/am_pkup.wav", + "icons/icona_shotgun", + "Shells", + 10, + AMMO, + SHOTGUN, + SPECIAL_SFX_ROTATE +}, +{ + "ammo_slugs", + "models/powerups/ammo/railgunam.md3", + "", + "sound/misc/am_pkup.wav", + "icons/icona_railgun", + "Slugs", + 10, + AMMO, + RAILGUN, + SPECIAL_SFX_ROTATE +}, +{ + "item_armor_body", + "models/powerups/armor/armor_red.md3", + "", + "sound/misc/ar2_pkup.wav", + "icons/iconr_red", + "Heavy Armor", + 100, + ARMOR, + SUB_NONE, + SPECIAL_SFX_ROTATE +}, +{ + "item_armor_combat", + "models/powerups/armor/armor_yel.md3", + "", + "sound/misc/ar2_pkup.wav", + "icons/iconr_yellow", + "Armor", + 50, + ARMOR, + SUB_NONE, + SPECIAL_SFX_ROTATE +}, +{ + "item_armor_shard", + "models/powerups/armor/shard.md3", + "", + "sound/misc/ar1_pkup.wav", + "icons/iconr_shard", + "Armor Shared", + 5, + ARMOR, + SUB_NONE, + SPECIAL_SFX_ROTATE +}, +{ + "weapon_gauntlet", + "models/weapons2/gauntlet/gauntlet.md3", + "", + "sound/misc/w_pkup.wav", + "icons/iconw_gauntlet", + "Gauntlet", + 0, + WEAPON, + GAUNTLET, + SPECIAL_SFX_ROTATE +}, +{ + "weapon_shotgun", + "models/weapons2/shotgun/shotgun.md3", + "", + "sound/misc/w_pkup.wav", + "icons/iconw_shotgun", + "Shotgun", + 10, + WEAPON, + SHOTGUN, + SPECIAL_SFX_ROTATE +}, +{ + "weapon_machinegun", + "models/weapons2/machinegun/machinegun.md3", + "", + "sound/misc/w_pkup.wav", + "icons/iconw_machinegun", + "Machinegun", + 40, + WEAPON, + MACHINEGUN, + SPECIAL_SFX_ROTATE +}, +{ + "weapon_grenadelauncher", + "models/weapons2/grenadel/grenadel.md3", + "", + "sound/misc/w_pkup.wav", + "icons/iconw_grenade", + "Grenade Launcher", + 10, + WEAPON, + GRENADE_LAUNCHER, + SPECIAL_SFX_ROTATE +}, +{ + "weapon_rocketlauncher", + "models/weapons2/rocketl/rocketl.md3", + "", + "sound/misc/w_pkup.wav", + "icons/iconw_rocket", + "Rocket Launcher", + 10, + WEAPON, + ROCKET_LAUNCHER, + SPECIAL_SFX_ROTATE +}, +{ + "weapon_lightning", + "models/weapons2/lightning/lightning.md3", + "", + "sound/misc/w_pkup.wav", + "icons/iconw_lightning", + "Lightning Gun", + 100, + WEAPON, + LIGHTNING, + SPECIAL_SFX_ROTATE +}, +{ + "weapon_railgun", + "models/weapons2/railgun/railgun.md3", + "", + "sound/misc/w_pkup.wav", + "icons/iconw_railgun", + "Railgun", + 10, + WEAPON, + RAILGUN, + SPECIAL_SFX_ROTATE +}, +{ + "weapon_plasmagun", + "models/weapons2/plasma/plasma.md3", + "", + "sound/misc/w_pkup.wav", + "icons/iconw_plasma", + "Plasma Gun", + 50, + WEAPON, + PLASMAGUN, + SPECIAL_SFX_ROTATE +}, +{ + "weapon_bfg", + "models/weapons2/bfg/bfg.md3", + "", + "sound/misc/w_pkup.wav", + "icons/iconw_bfg", + "BFG10K", + 20, + WEAPON, + BFG, + SPECIAL_SFX_ROTATE +}, +{ + "weapon_grapplinghook", + "models/weapons2/grapple/grapple.md3", + "", + "sound/misc/w_pkup.wav", + "icons/iconw_grapple", + "Grappling Hook", + 0, + WEAPON, + GRAPPLING_HOOK, + SPECIAL_SFX_ROTATE +}, +{ + 0 +} + +}; + + +/*! +*/ +const SItemElement * getItemElement ( const stringc& key ) +{ + const SItemElement *item = Quake3ItemElement; + + while ( item->key ) + { + if ( 0 == strcmp ( key.c_str(), item->key ) ) + return item; + item += 1; + } + return 0; +} + +/*! + Quake3 Model Factory. + Takes the mesh buffers and creates scenenodes for their associated shaders +*/ +void Q3ShaderFactory ( Q3LevelLoadParameter &loadParam, + IrrlichtDevice *device, + IQ3LevelMesh* mesh, + eQ3MeshIndex meshIndex, + ISceneNode *parent, + IMetaTriangleSelector *meta, + bool showShaderName ) +{ + if ( 0 == mesh || 0 == device ) + return; + + IMeshSceneNode* node = 0; + ISceneManager* smgr = device->getSceneManager(); + ITriangleSelector * selector = 0; + + // the additional mesh can be quite huge and is unoptimized + // Save to cast to SMesh + SMesh * additional_mesh = (SMesh*) mesh->getMesh ( meshIndex ); + if ( 0 == additional_mesh || additional_mesh->getMeshBufferCount() == 0) + return; + + char buf[128]; + if ( loadParam.verbose > 0 ) + { + loadParam.startTime = device->getTimer()->getRealTime(); + if ( loadParam.verbose > 1 ) + { + snprintf(buf, 128, "q3shaderfactory start" ); + device->getLogger()->log( buf, ELL_INFORMATION); + } + } + + IGUIFont *font = 0; + if ( showShaderName ) + font = device->getGUIEnvironment()->getFont("fontlucida.png"); + + IVideoDriver *driver = device->getVideoDriver(); + + // create helper textures + if ( 1 ) + { + tTexArray tex; + u32 pos = 0; + getTextures ( tex, "$redimage $blueimage $whiteimage $checkerimage", pos, + device->getFileSystem(), driver ); + } + + s32 sceneNodeID = 0; + for ( u32 i = 0; i!= additional_mesh->getMeshBufferCount (); ++i ) + { + IMeshBuffer *meshBuffer = additional_mesh->getMeshBuffer ( i ); + const SMaterial &material = meshBuffer->getMaterial(); + + //! The ShaderIndex is stored in the second material parameter + s32 shaderIndex = (s32) material.MaterialTypeParam2; + + // the meshbuffer can be rendered without additional support, or it has no shader + IShader *shader = (IShader *) mesh->getShader ( shaderIndex ); + + // no shader, or mapped to existing material + if ( 0 == shader ) + { + +#if 1 + // clone mesh + SMesh * m = new SMesh (); + m->addMeshBuffer ( meshBuffer ); + SMaterial &mat = m->getMeshBuffer( 0 )->getMaterial(); + if ( mat.getTexture( 0 ) == 0 ) + mat.setTexture ( 0, driver->getTexture ( "$blueimage" ) ); + if ( mat.getTexture( 1 ) == 0 ) + mat.setTexture ( 1, driver->getTexture ( "$redimage" ) ); + + IMesh * store = smgr->getMeshManipulator ()->createMeshWith2TCoords ( m ); + m->drop(); + + node = smgr->addMeshSceneNode ( store, parent, sceneNodeID ); + node->setAutomaticCulling ( scene::EAC_OFF ); + store->drop (); + sceneNodeID += 1; +#endif + } + else if ( 1 ) + { +/* + stringc s; + dumpShader ( s, shader ); + printf ( s.c_str () ); +*/ + // create sceneNode + node = smgr->addQuake3SceneNode ( meshBuffer, shader, parent, sceneNodeID ); + node->setAutomaticCulling ( scene::EAC_FRUSTUM_BOX ); + sceneNodeID += 1; + } + + // show Debug Shader Name + if ( showShaderName && node ) + { + swprintf ( (wchar_t*) buf, 64, L"%hs:%d", node->getName(),node->getID() ); + smgr->addBillboardTextSceneNode( + font, + (wchar_t*) buf, + node, + dimension2d(80.0f, 8.0f), + vector3df(0, 10, 0), + sceneNodeID); + sceneNodeID += 1; + } + + // create Portal Rendertargets + if ( shader ) + { + const SVarGroup *group = shader->getGroup(1); + if ( group->isDefined( "surfaceparm", "portal" ) ) + { + } + + } + + + // add collision + // find out if shader is marked as nonsolid + u8 doCreate = meta !=0 ; + + if ( shader ) + { + const SVarGroup *group = shader->getGroup(1); + if ( group->isDefined( "surfaceparm", "trans" ) + // || group->isDefined( "surfaceparm", "sky" ) + // || group->isDefined( "surfaceparm", "nonsolid" ) + ) + { + if ( !group->isDefined( "surfaceparm", "metalsteps" ) ) + { + doCreate = 0; + } + } + } + + if ( doCreate ) + { + IMesh *m = 0; + + //! controls if triangles are modified by the scenenode during runtime + bool takeOriginal = true; + + if ( takeOriginal ) + { + m = new SMesh (); + ((SMesh*) m )->addMeshBuffer (meshBuffer); + } + else + { + m = node->getMesh(); + } + + //selector = smgr->createOctreeTriangleSelector ( m, 0, 128 ); + selector = smgr->createTriangleSelector ( m, 0 ); + meta->addTriangleSelector ( selector ); + selector->drop (); + + if ( takeOriginal ) + { + delete m; + } + } + + } + +#if 0 + if ( meta ) + { + selector = smgr->createOctreeTriangleSelector ( additional_mesh, 0 ); + meta->addTriangleSelector ( selector ); + selector->drop (); + } +#endif + + if ( loadParam.verbose > 0 ) + { + loadParam.endTime = device->getTimer()->getRealTime (); + snprintf(buf, 128, "q3shaderfactory needed %04d ms to create %d shader nodes", + loadParam.endTime - loadParam.startTime, + sceneNodeID + ); + device->getLogger()->log(buf, ELL_INFORMATION); + } + +} + + +/*! + create Items from Entity +*/ +void Q3ModelFactory ( Q3LevelLoadParameter &loadParam, + IrrlichtDevice *device, + IQ3LevelMesh* masterMesh, + ISceneNode *parent, + bool showShaderName + ) +{ + if ( 0 == masterMesh ) + return; + + tQ3EntityList &entity = masterMesh->getEntityList (); + ISceneManager* smgr = device->getSceneManager(); + + + char buf[128]; + const SVarGroup *group; + IEntity search; + s32 index; + s32 lastIndex; + +/* + stringc s; + FILE *f = 0; + f = fopen ( "entity.txt", "wb" ); + for ( index = 0; (u32) index < entityList.size (); ++index ) + { + const IEntity *entity = &entityList[ index ]; + s = entity->name; + dumpShader ( s, entity ); + fwrite ( s.c_str(), 1, s.size(), f ); + } + fclose ( f ); +*/ + IAnimatedMeshMD3* model; + SMD3Mesh * mesh; + const SMD3MeshBuffer *meshBuffer; + IMeshSceneNode* node; + ISceneNodeAnimator* anim; + const IShader *shader; + u32 pos; + vector3df p; + u32 nodeCount = 0; + tTexArray textureArray; + + IGUIFont *font = 0; + if ( showShaderName ) + font = device->getGUIEnvironment()->getFont("fontlucida.png"); + + const SItemElement *itemElement; + + // walk list + for ( index = 0; (u32) index < entity.size(); ++index ) + { + itemElement = getItemElement ( entity[index].name ); + if ( 0 == itemElement ) + continue; + + pos = 0; + p = getAsVector3df ( entity[index].getGroup(1)->get ( "origin" ), pos ); + + nodeCount += 1; + for ( u32 g = 0; g < 2; ++g ) + { + if ( 0 == itemElement->model[g] || itemElement->model[g][0] == 0 ) + continue; + model = (IAnimatedMeshMD3*) smgr->getMesh( itemElement->model[g] ); + if ( 0 == model ) + continue; + + mesh = model->getOriginalMesh(); + for ( u32 j = 0; j != mesh->Buffer.size (); ++j ) + { + meshBuffer = mesh->Buffer[j]; + if ( 0 == meshBuffer ) + continue; + + shader = masterMesh->getShader ( meshBuffer->Shader.c_str(), false ); + IMeshBuffer *final = model->getMesh(0)->getMeshBuffer(j); + if ( shader ) + { + //!TODO: Hack don't modify the vertexbuffer. make it better;-) + final->getMaterial().ColorMask = 0; + node = smgr->addQuake3SceneNode ( final, shader, parent ); + final->getMaterial().ColorMask = 15; + } + else + { + // clone mesh + SMesh * m = new SMesh (); + m->addMeshBuffer ( final ); + node = smgr->addMeshSceneNode ( m, parent ); + m->drop(); + } + + if ( 0 == node ) + { + snprintf ( buf, 128, "q3ModelFactory shader %s failed", meshBuffer->Shader.c_str() ); + device->getLogger()->log ( buf ); + continue; + } + + // node was maybe centered by shaderscenenode + node->setPosition ( p ); + node->setName ( meshBuffer->Shader ); + node->setAutomaticCulling ( scene::EAC_BOX ); + + // add special effects to node + if ( itemElement->special & SPECIAL_SFX_ROTATE || + (g == 0 && itemElement->special & SPECIAL_SFX_ROTATE_1) + ) + { + anim = smgr->createRotationAnimator ( vector3df ( 0.f, + 2.f, 0.f ) ); + node->addAnimator ( anim ); + anim->drop (); + } + + if ( itemElement->special & SPECIAL_SFX_BOUNCE ) + { + //anim = smgr->createFlyStraightAnimator ( + // p, p + vector3df ( 0.f, 60.f, 0.f ), 1000, true, true ); + anim = smgr->createFlyCircleAnimator ( + p + vector3df( 0.f, 20.f, 0.f ), + 20.f, + 0.005f, + vector3df ( 1.f, 0.f, 0.f ), + core::fract ( nodeCount * 0.05f ), + 1.f + ); + node->addAnimator ( anim ); + anim->drop (); + } + } + } + // show name + if ( showShaderName ) + { + swprintf ( (wchar_t*) buf, sizeof(buf) / 2, L"%hs", itemElement->key ); + smgr->addBillboardTextSceneNode( + font, + (wchar_t*) buf, + parent, + dimension2d(80.0f, 8.0f), + p + vector3df(0, 30, 0), + 0); + } + } + + // music + search.name = "worldspawn"; + index = entity.binary_search_multi ( search, lastIndex ); + + if ( index >= 0 ) + { + group = entity[ index ].getGroup(1); + background_music ( group->get ( "music" ).c_str () ); + } + + // music + search.name = "worldspawn"; + index = entity.binary_search_multi ( search, lastIndex ); + + if ( index >= 0 ) + { + group = entity[ index ].getGroup(1); + background_music ( group->get ( "music" ).c_str () ); + } + + //IAnimatedMesh* mesh = smgr->getMesh("../../media/sydney.md2"); + //IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode( mesh ); + +} + +/*! + so we need a good starting Position in the level. + we can ask the Quake3 Loader for all entities with class_name "info_player_deathmatch" +*/ +s32 Q3StartPosition ( IQ3LevelMesh* mesh, + ICameraSceneNode* camera, + s32 startposIndex, + const vector3df &translation + ) +{ + if ( 0 == mesh ) + return 0; + + tQ3EntityList &entityList = mesh->getEntityList (); + + IEntity search; + search.name = "info_player_start"; // "info_player_deathmatch"; + + // find all entities in the multi-list + s32 lastIndex; + s32 index = entityList.binary_search_multi ( search, lastIndex ); + + if ( index < 0 ) + { + search.name = "info_player_deathmatch"; + index = entityList.binary_search_multi ( search, lastIndex ); + } + + if ( index < 0 ) + return 0; + + index += core::clamp ( startposIndex, 0, lastIndex - index ); + + u32 parsepos; + + const SVarGroup *group; + group = entityList[ index ].getGroup(1); + + parsepos = 0; + vector3df pos = getAsVector3df ( group->get ( "origin" ), parsepos ); + pos += translation; + + parsepos = 0; + f32 angle = getAsFloat ( group->get ( "angle"), parsepos ); + + vector3df target ( 0.f, 0.f, 1.f ); + target.rotateXZBy ( angle - 90.f, vector3df () ); + + if ( camera ) + { + camera->setPosition ( pos ); + camera->setTarget ( pos + target ); + //! New. FPSCamera and animators catches reset on animate 0 + camera->OnAnimate ( 0 ); + } + return lastIndex - index + 1; +} + + +/*! + gets a accumulated force on a given surface +*/ +vector3df getGravity ( const c8 * surface ) +{ + if ( 0 == strcmp ( surface, "earth" ) ) return vector3df ( 0.f, -90.f, 0.f ); + if ( 0 == strcmp ( surface, "moon" ) ) return vector3df ( 0.f, -6.f / 100.f, 0.f ); + if ( 0 == strcmp ( surface, "water" ) ) return vector3df ( 0.1f / 100.f, -2.f / 100.f, 0.f ); + if ( 0 == strcmp ( surface, "ice" ) ) return vector3df ( 0.2f / 100.f, -9.f / 100.f, 0.3f / 100.f ); + + return vector3df ( 0.f, 0.f, 0.f ); +} + + + +/* + Dynamically load the Irrlicht Library +*/ + +#if defined(_IRR_WINDOWS_API_) +#ifdef _MSC_VER +#pragma comment(lib, "Irrlicht.lib") +#endif + +#include + +funcptr_createDevice load_createDevice ( const c8 * filename) +{ + return (funcptr_createDevice) GetProcAddress ( LoadLibrary ( filename ), "createDevice" ); +} + +funcptr_createDeviceEx load_createDeviceEx ( const c8 * filename) +{ + return (funcptr_createDeviceEx) GetProcAddress ( LoadLibrary ( filename ), "createDeviceEx" ); +} + +#else + +// TODO: Dynamic Loading for other os +funcptr_createDevice load_createDevice ( const c8 * filename) +{ + return createDevice; +} + +funcptr_createDeviceEx load_createDeviceEx ( const c8 * filename) +{ + return createDeviceEx; +} + +#endif + +/* + get the current collision response camera animator +*/ +ISceneNodeAnimatorCollisionResponse* camCollisionResponse( IrrlichtDevice * device ) +{ + ICameraSceneNode *camera = device->getSceneManager()->getActiveCamera(); + ISceneNodeAnimatorCollisionResponse *a = 0; + + list::ConstIterator it = camera->getAnimators().begin(); + for (; it != camera->getAnimators().end(); ++it) + { + a = (ISceneNodeAnimatorCollisionResponse*) (*it); + if ( a->getType() == ESNAT_COLLISION_RESPONSE ) + return a; + } + + return 0; +} + + +//! internal Animation +void setTimeFire ( TimeFire *t, u32 delta, u32 flags ) +{ + t->flags = flags; + t->next = 0; + t->delta = delta; +} + + +void checkTimeFire ( TimeFire *t, u32 listSize, u32 now ) +{ + u32 i; + for ( i = 0; i < listSize; ++i ) + { + if ( now < t[i].next ) + continue; + + t[i].next = core::max_ ( now + t[i].delta, t[i].next + t[i].delta ); + t[i].flags |= FIRED; + } +} -- cgit v1.1