Move some track object classes to new files
git-svn-id: svn+ssh://svn.code.sf.net/p/supertuxkart/code/main/trunk@12602 178a84e3-b1eb-0310-8ba1-8eac791a3b58
This commit is contained in:
@@ -23,6 +23,7 @@
|
||||
#include <matrix4.h>
|
||||
#include <ISceneNode.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
namespace irr
|
||||
{
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2009 Joerg Henrichs
|
||||
// Copyright (C) 2013 Joerg Henrichs, Marianne Gagnon
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
@@ -45,599 +45,7 @@
|
||||
#include <ICameraSceneNode.h>
|
||||
#include <IBillboardSceneNode.h>
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
TrackObjectPresentation::TrackObjectPresentation(const XMLNode& xml_node)
|
||||
{
|
||||
m_init_xyz = core::vector3df(0,0,0);
|
||||
m_init_hpr = core::vector3df(0,0,0);
|
||||
m_init_scale = core::vector3df(1,1,1);
|
||||
|
||||
xml_node.get("xyz", &m_init_xyz );
|
||||
xml_node.get("hpr", &m_init_hpr );
|
||||
xml_node.get("scale", &m_init_scale);
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
const core::vector3df& TrackObjectPresentationSceneNode::getPosition() const
|
||||
{
|
||||
return m_node->getPosition();
|
||||
}
|
||||
|
||||
const core::vector3df& TrackObjectPresentationSceneNode::getRotation() const
|
||||
{
|
||||
return m_node->getRotation();
|
||||
}
|
||||
|
||||
const core::vector3df& TrackObjectPresentationSceneNode::getScale() const
|
||||
{
|
||||
return m_node->getScale();
|
||||
}
|
||||
|
||||
|
||||
void TrackObjectPresentationSceneNode::move(const core::vector3df& xyz, const core::vector3df& hpr,
|
||||
const core::vector3df& scale)
|
||||
{
|
||||
m_node->setPosition(xyz);
|
||||
m_node->setRotation(hpr);
|
||||
m_node->setScale(scale);
|
||||
|
||||
//if (dynamic_cast<TrackObjectPresentationMesh*>(this) != NULL)
|
||||
}
|
||||
|
||||
void TrackObjectPresentationSceneNode::setEnable(bool enabled)
|
||||
{
|
||||
m_node->setVisible(enabled);
|
||||
}
|
||||
|
||||
void TrackObjectPresentationSceneNode::reset()
|
||||
{
|
||||
m_node->setPosition(m_init_xyz);
|
||||
m_node->setRotation(m_init_hpr);
|
||||
m_node->setScale(m_init_scale);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
TrackObjectPresentationEmpty::TrackObjectPresentationEmpty(const XMLNode& xml_node) :
|
||||
TrackObjectPresentationSceneNode(xml_node)
|
||||
{
|
||||
m_node = irr_driver->getSceneManager()->addEmptySceneNode();
|
||||
m_node->setPosition(m_init_xyz);
|
||||
m_node->setRotation(m_init_hpr);
|
||||
m_node->setScale(m_init_scale);
|
||||
}
|
||||
|
||||
TrackObjectPresentationEmpty::~TrackObjectPresentationEmpty()
|
||||
{
|
||||
irr_driver->removeNode(m_node);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
TrackObjectPresentationMesh::TrackObjectPresentationMesh(const XMLNode& xml_node, bool enabled) :
|
||||
TrackObjectPresentationSceneNode(xml_node)
|
||||
{
|
||||
m_is_looped = false;
|
||||
m_mesh = NULL;
|
||||
m_node = NULL;
|
||||
|
||||
xml_node.get("looped", &m_is_looped );
|
||||
std::string model_name;
|
||||
xml_node.get("model", &model_name );
|
||||
|
||||
std::string full_path =
|
||||
World::getWorld()->getTrack()->getTrackFile(model_name);
|
||||
|
||||
bool animated = (UserConfigParams::m_graphical_effects ||
|
||||
World::getWorld()->getIdent() == IDENT_CUSTSCENE);
|
||||
|
||||
if (file_manager->fileExists(full_path))
|
||||
{
|
||||
if (animated)
|
||||
{
|
||||
m_mesh = irr_driver->getAnimatedMesh(full_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_mesh = irr_driver->getMesh(full_path);
|
||||
}
|
||||
}
|
||||
|
||||
if(!m_mesh)
|
||||
{
|
||||
// If the model isn't found in the track directory, look
|
||||
// in STK's model directory.
|
||||
full_path = file_manager->getModelFile(model_name);
|
||||
m_mesh = irr_driver->getAnimatedMesh(full_path);
|
||||
|
||||
if(!m_mesh)
|
||||
{
|
||||
throw std::runtime_error("Model '" + model_name + "' cannot be found");
|
||||
}
|
||||
}
|
||||
|
||||
m_mesh->grab();
|
||||
irr_driver->grabAllTextures(m_mesh);
|
||||
|
||||
if (animated)
|
||||
{
|
||||
scene::IAnimatedMeshSceneNode *node =
|
||||
irr_driver->addAnimatedMesh((scene::IAnimatedMesh*)m_mesh);
|
||||
m_node = node;
|
||||
|
||||
m_frame_start = node->getStartFrame();
|
||||
xml_node.get("frame-start", &m_frame_start);
|
||||
|
||||
m_frame_end = node->getEndFrame();
|
||||
xml_node.get("frame-end", &m_frame_end);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_node = irr_driver->addMesh(m_mesh);
|
||||
m_frame_start = 0;
|
||||
m_frame_end = 0;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
std::string debug_name = model_name+" (track-object)";
|
||||
m_node->setName(debug_name.c_str());
|
||||
#endif
|
||||
|
||||
if(!enabled)
|
||||
m_node->setVisible(false);
|
||||
|
||||
m_node->setPosition(m_init_xyz);
|
||||
m_node->setRotation(m_init_hpr);
|
||||
m_node->setScale(m_init_scale);
|
||||
}
|
||||
|
||||
TrackObjectPresentationMesh::~TrackObjectPresentationMesh()
|
||||
{
|
||||
if (m_node)
|
||||
irr_driver->removeNode(m_node);
|
||||
|
||||
if(m_mesh)
|
||||
{
|
||||
irr_driver->dropAllTextures(m_mesh);
|
||||
m_mesh->drop();
|
||||
if(m_mesh->getReferenceCount()==1)
|
||||
irr_driver->removeMeshFromCache(m_mesh);
|
||||
}
|
||||
}
|
||||
|
||||
void TrackObjectPresentationMesh::reset()
|
||||
{
|
||||
if (m_node->getType()==scene::ESNT_ANIMATED_MESH)
|
||||
{
|
||||
scene::IAnimatedMeshSceneNode *a_node =
|
||||
(scene::IAnimatedMeshSceneNode*)m_node;
|
||||
|
||||
a_node->setPosition(m_init_xyz);
|
||||
a_node->setRotation(m_init_hpr);
|
||||
a_node->setScale(m_init_scale);
|
||||
a_node->setLoopMode(m_is_looped);
|
||||
a_node->setCurrentFrame((float)(a_node->getStartFrame()));
|
||||
|
||||
// trick to reset the animation AND also the timer inside it
|
||||
a_node->OnAnimate(0);
|
||||
a_node->OnAnimate(0);
|
||||
|
||||
if(m_is_looped)
|
||||
{
|
||||
a_node->setFrameLoop(m_frame_start, m_frame_end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
TrackObjectPresentationSound::TrackObjectPresentationSound(const XMLNode& xml_node) :
|
||||
TrackObjectPresentation(xml_node)
|
||||
{
|
||||
m_sound = NULL;
|
||||
m_xyz = m_init_xyz;
|
||||
|
||||
std::string sound;
|
||||
xml_node.get("sound", &sound);
|
||||
|
||||
float rolloff = 0.5;
|
||||
xml_node.get("rolloff", &rolloff );
|
||||
float volume = 1.0;
|
||||
xml_node.get("volume", &volume );
|
||||
|
||||
bool trigger_when_near = false;
|
||||
xml_node.get("play-when-near", &trigger_when_near);
|
||||
|
||||
float trigger_distance = 1.0f;
|
||||
xml_node.get("distance", &trigger_distance);
|
||||
|
||||
xml_node.get("conditions", &m_trigger_condition);
|
||||
|
||||
float max_dist = 390.0f;
|
||||
xml_node.get("max_dist", &max_dist );
|
||||
|
||||
// first try track dir, then global dir
|
||||
std::string soundfile = file_manager->getModelFile(sound);
|
||||
if (!file_manager->fileExists(soundfile))
|
||||
{
|
||||
soundfile = file_manager->getSFXFile(sound);
|
||||
}
|
||||
|
||||
SFXBuffer* buffer = new SFXBuffer(soundfile,
|
||||
true /* positional */,
|
||||
rolloff,
|
||||
max_dist,
|
||||
volume);
|
||||
buffer->load();
|
||||
|
||||
m_sound = sfx_manager->createSoundSource(buffer, true, true);
|
||||
if (m_sound != NULL)
|
||||
{
|
||||
m_sound->position(m_init_xyz);
|
||||
if (!trigger_when_near && m_trigger_condition.empty())
|
||||
{
|
||||
m_sound->setLoop(true);
|
||||
m_sound->play();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,
|
||||
"[TrackObject] Sound emitter object could not be created\n");
|
||||
}
|
||||
|
||||
if (trigger_when_near)
|
||||
{
|
||||
ItemManager::get()->newItem(m_init_xyz, trigger_distance, this);
|
||||
}
|
||||
}
|
||||
|
||||
void TrackObjectPresentationSound::update(float dt)
|
||||
{
|
||||
if (m_sound != NULL)
|
||||
{
|
||||
// muting when too far is implemented manually since not supported by OpenAL
|
||||
// so need to call this every frame to update the muting state if listener
|
||||
// moved
|
||||
m_sound->position(m_xyz);
|
||||
}
|
||||
}
|
||||
|
||||
void TrackObjectPresentationSound::onTriggerItemApproached(Item* who)
|
||||
{
|
||||
if (m_sound != NULL && m_sound->getStatus() != SFXManager::SFX_PLAYING)
|
||||
{
|
||||
m_sound->play();
|
||||
}
|
||||
}
|
||||
|
||||
void TrackObjectPresentationSound::triggerSound(bool loop)
|
||||
{
|
||||
if (m_sound != NULL)
|
||||
{
|
||||
m_sound->setLoop(loop);
|
||||
m_sound->play();
|
||||
}
|
||||
}
|
||||
|
||||
void TrackObjectPresentationSound::stopSound()
|
||||
{
|
||||
if (m_sound != NULL) m_sound->stop();
|
||||
}
|
||||
|
||||
TrackObjectPresentationSound::~TrackObjectPresentationSound()
|
||||
{
|
||||
if (m_sound)
|
||||
{
|
||||
//delete m_sound->getBuffer();
|
||||
sfx_manager->deleteSFX(m_sound);
|
||||
}
|
||||
}
|
||||
|
||||
void TrackObjectPresentationSound::move(const core::vector3df& xyz, const core::vector3df& hpr,
|
||||
const core::vector3df& scale)
|
||||
{
|
||||
m_xyz = xyz;
|
||||
if (m_sound != NULL) m_sound->position(xyz);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
TrackObjectPresentationBillboard::TrackObjectPresentationBillboard(const XMLNode& xml_node) :
|
||||
TrackObjectPresentationSceneNode(xml_node)
|
||||
{
|
||||
std::string texture_name;
|
||||
float width, height;
|
||||
|
||||
m_fade_out_start = 50.0f;
|
||||
m_fade_out_end = 150.0f;
|
||||
|
||||
xml_node.get("texture", &texture_name);
|
||||
xml_node.get("width", &width );
|
||||
xml_node.get("height", &height );
|
||||
|
||||
m_fade_out_when_close = false;
|
||||
xml_node.get("fadeout", &m_fade_out_when_close);
|
||||
|
||||
if (m_fade_out_when_close)
|
||||
{
|
||||
xml_node.get("start", &m_fade_out_start);
|
||||
xml_node.get("end", &m_fade_out_end );
|
||||
}
|
||||
|
||||
video::ITexture *texture =
|
||||
irr_driver->getTexture(file_manager->getTextureFile(texture_name));
|
||||
m_node = irr_driver->addBillboard(core::dimension2df(width, height),
|
||||
texture);
|
||||
Material *stk_material = material_manager->getMaterial(texture_name);
|
||||
stk_material->setMaterialProperties(&(m_node->getMaterial(0)), NULL);
|
||||
|
||||
m_node->setPosition(m_init_xyz);
|
||||
}
|
||||
|
||||
void TrackObjectPresentationBillboard::update(float dt)
|
||||
{
|
||||
if (m_fade_out_when_close)
|
||||
{
|
||||
scene::ICameraSceneNode* curr_cam = irr_driver->getSceneManager()->getActiveCamera();
|
||||
const float dist = m_node->getPosition().getDistanceFrom( curr_cam->getPosition() );
|
||||
|
||||
scene::IBillboardSceneNode* node = (scene::IBillboardSceneNode*)m_node;
|
||||
|
||||
if (dist < m_fade_out_start)
|
||||
{
|
||||
node->setColor(video::SColor(0, 255, 255, 255));
|
||||
}
|
||||
else if (dist > m_fade_out_end)
|
||||
{
|
||||
node->setColor(video::SColor(255, 255, 255, 255));
|
||||
}
|
||||
else
|
||||
{
|
||||
int a = (int)(255*(dist - m_fade_out_start) / (m_fade_out_end - m_fade_out_start));
|
||||
node->setColor(video::SColor(a, 255, 255, 255));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TrackObjectPresentationBillboard::~TrackObjectPresentationBillboard()
|
||||
{
|
||||
if (m_node)
|
||||
irr_driver->removeNode(m_node);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
TrackObjectPresentationParticles::TrackObjectPresentationParticles(const XMLNode& xml_node) :
|
||||
TrackObjectPresentation(xml_node)
|
||||
{
|
||||
m_emitter = NULL;
|
||||
m_lod_emitter_node = NULL;
|
||||
|
||||
std::string path;
|
||||
irr::core::vector3df emitter_origin;
|
||||
xml_node.get("kind", &path);
|
||||
xml_node.getXYZ(&emitter_origin);
|
||||
|
||||
int clip_distance = -1;
|
||||
xml_node.get("clip_distance", &clip_distance);
|
||||
|
||||
xml_node.get("conditions", &m_trigger_condition);
|
||||
|
||||
try
|
||||
{
|
||||
ParticleKind* kind = ParticleKindManager::get()->getParticles( path.c_str() );
|
||||
if (kind == NULL)
|
||||
{
|
||||
throw std::runtime_error(path + " could not be loaded");
|
||||
}
|
||||
ParticleEmitter* emitter = new ParticleEmitter( kind, emitter_origin );
|
||||
|
||||
/*
|
||||
if (clip_distance > 0)
|
||||
{
|
||||
scene::ISceneManager* sm = irr_driver->getSceneManager();
|
||||
scene::ISceneNode* sroot = sm->getRootSceneNode();
|
||||
LODNode* lod = new LODNode("particles", sroot, sm);
|
||||
lod->add(clip_distance, (scene::ISceneNode*)emitter->getNode(), true);
|
||||
//m_all_emitters.push_back(emitter);
|
||||
m_node = lod;
|
||||
m_lod_emitter_node = lod;
|
||||
m_emitter = emitter;
|
||||
}*/
|
||||
//else
|
||||
//{
|
||||
//m_node = emitter->getNode(); // FIXME: this leaks
|
||||
m_emitter = emitter;
|
||||
//}
|
||||
|
||||
if (m_trigger_condition.size() > 0)
|
||||
{
|
||||
m_emitter->setCreationRateAbsolute(0.0f);
|
||||
}
|
||||
}
|
||||
catch (std::runtime_error& e)
|
||||
{
|
||||
fprintf(stderr, "[Track] WARNING: Could not load particles '%s'; cause :\n %s", path.c_str(), e.what());
|
||||
}
|
||||
}
|
||||
|
||||
TrackObjectPresentationParticles::~TrackObjectPresentationParticles()
|
||||
{
|
||||
if (m_emitter)
|
||||
{
|
||||
if (m_lod_emitter_node != NULL)
|
||||
{
|
||||
irr_driver->removeNode(m_lod_emitter_node);
|
||||
m_emitter->unsetNode();
|
||||
}
|
||||
delete m_emitter; // this will also delete m_node
|
||||
}
|
||||
}
|
||||
|
||||
void TrackObjectPresentationParticles::update(float dt)
|
||||
{
|
||||
if (m_emitter != NULL)
|
||||
{
|
||||
m_emitter->update(dt);
|
||||
}
|
||||
}
|
||||
|
||||
void TrackObjectPresentationParticles::triggerParticles()
|
||||
{
|
||||
if (m_emitter != NULL)
|
||||
{
|
||||
m_emitter->setCreationRateAbsolute(1.0f);
|
||||
m_emitter->setParticleType(m_emitter->getParticlesInfo());
|
||||
}
|
||||
}
|
||||
|
||||
void TrackObjectPresentationParticles::move(const core::vector3df& xyz, const core::vector3df& hpr,
|
||||
const core::vector3df& scale)
|
||||
{
|
||||
if (m_emitter != NULL) m_emitter->setPosition(xyz);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
TrackObjectPresentationActionTrigger::TrackObjectPresentationActionTrigger(const XMLNode& xml_node) :
|
||||
TrackObjectPresentation(xml_node)
|
||||
{
|
||||
float trigger_distance = 1.0f;
|
||||
xml_node.get("distance", &trigger_distance);
|
||||
|
||||
xml_node.get("action", &m_action);
|
||||
|
||||
if (m_action.size() == 0)
|
||||
{
|
||||
fprintf(stderr, "[TrackObject] WARNING: action-trigger has no action defined\n");
|
||||
}
|
||||
|
||||
ItemManager::get()->newItem(m_init_xyz, trigger_distance, this);
|
||||
}
|
||||
|
||||
void TrackObjectPresentationActionTrigger::onTriggerItemApproached(Item* who)
|
||||
{
|
||||
if (m_action == "garage")
|
||||
{
|
||||
new RacePausedDialog(0.8f, 0.6f);
|
||||
//dynamic_cast<OverWorld*>(World::getWorld())->scheduleSelectKart();
|
||||
}
|
||||
else if (m_action == "tutorial_drive")
|
||||
{
|
||||
//if (World::getWorld()->getPhase() == World::RACE_PHASE)
|
||||
{
|
||||
m_action = "__disabled__";
|
||||
//World::getWorld()->getRaceGUI()->clearAllMessages();
|
||||
|
||||
InputDevice* device = input_manager->getDeviceList()->getLatestUsedDevice();
|
||||
DeviceConfig* config = device->getConfiguration();
|
||||
irr::core::stringw accel = config->getBindingAsString(PA_ACCEL);
|
||||
irr::core::stringw left = config->getBindingAsString(PA_STEER_LEFT);
|
||||
irr::core::stringw right = config->getBindingAsString(PA_STEER_RIGHT);
|
||||
|
||||
new TutorialMessageDialog(_("Accelerate with <%s> and steer with <%s> and <%s>", accel, left, right),
|
||||
false);
|
||||
}
|
||||
}
|
||||
else if (m_action == "tutorial_bananas")
|
||||
{
|
||||
m_action = "__disabled__";
|
||||
|
||||
new TutorialMessageDialog(_("Avoid bananas!"), true);
|
||||
}
|
||||
else if (m_action == "tutorial_giftboxes")
|
||||
{
|
||||
m_action = "__disabled__";
|
||||
InputDevice* device = input_manager->getDeviceList()->getLatestUsedDevice();
|
||||
DeviceConfig* config = device->getConfiguration();
|
||||
irr::core::stringw fire = config->getBindingAsString(PA_FIRE);
|
||||
|
||||
new TutorialMessageDialog(_("Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!", fire),
|
||||
true);
|
||||
}
|
||||
else if (m_action == "tutorial_nitro_collect")
|
||||
{
|
||||
m_action = "__disabled__";
|
||||
|
||||
new TutorialMessageDialog(_("Collect nitro bottles (we will use them after the curve)"),
|
||||
true);
|
||||
}
|
||||
else if (m_action == "tutorial_nitro_use")
|
||||
{
|
||||
m_action = "__disabled__";
|
||||
InputDevice* device = input_manager->getDeviceList()->getLatestUsedDevice();
|
||||
DeviceConfig* config = device->getConfiguration();
|
||||
irr::core::stringw nitro = config->getBindingAsString(PA_NITRO);
|
||||
|
||||
new TutorialMessageDialog(_("Use the nitro you collected by pressing <%s>!", nitro),
|
||||
true);
|
||||
}
|
||||
else if (m_action == "tutorial_rescue")
|
||||
{
|
||||
m_action = "__disabled__";
|
||||
InputDevice* device = input_manager->getDeviceList()->getLatestUsedDevice();
|
||||
DeviceConfig* config = device->getConfiguration();
|
||||
irr::core::stringw rescue = config->getBindingAsString(PA_RESCUE);
|
||||
|
||||
new TutorialMessageDialog(_("Oops! When you're in trouble, press <%s> to be rescued", rescue),
|
||||
false);
|
||||
}
|
||||
else if (m_action == "tutorial_skidding")
|
||||
{
|
||||
m_action = "__disabled__";
|
||||
//World::getWorld()->getRaceGUI()->clearAllMessages();
|
||||
|
||||
InputDevice* device = input_manager->getDeviceList()->getLatestUsedDevice();
|
||||
DeviceConfig* config = device->getConfiguration();
|
||||
irr::core::stringw skid = config->getBindingAsString(PA_DRIFT);
|
||||
|
||||
|
||||
new TutorialMessageDialog(_("Accelerate and press the <%s> key while turning to skid. Skidding for a short while can help you turn faster to take sharp turns.", skid),
|
||||
true);
|
||||
}
|
||||
else if (m_action == "tutorial_skidding2")
|
||||
{
|
||||
m_action = "__disabled__";
|
||||
World::getWorld()->getRaceGUI()->clearAllMessages();
|
||||
|
||||
new TutorialMessageDialog(_("Note that if you manage to skid for several seconds, you will receive a bonus speedup as a reward!"),
|
||||
true);
|
||||
}
|
||||
else if (m_action == "tutorial_endmessage")
|
||||
{
|
||||
m_action = "__disabled__";
|
||||
World::getWorld()->getRaceGUI()->clearAllMessages();
|
||||
|
||||
new TutorialMessageDialog(_("You are now ready to race. Good luck!"),
|
||||
true);
|
||||
}
|
||||
else if (m_action == "tutorial_exit")
|
||||
{
|
||||
World::getWorld()->scheduleExitRace();
|
||||
return;
|
||||
}
|
||||
else if (m_action == "__disabled__")
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "[TrackObject] WARNING: unknown action <%s>\n",
|
||||
m_action.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
/** A track object: any additional object on the track. This object implements
|
||||
|
||||
@@ -28,11 +28,12 @@ namespace irr
|
||||
using namespace irr;
|
||||
|
||||
#include "items/item.hpp"
|
||||
#include "graphics/lod_node.hpp"
|
||||
#include "tracks/track_object_presentation.hpp"
|
||||
#include "utils/cpp2011.h"
|
||||
#include "utils/no_copy.hpp"
|
||||
#include "utils/vec3.hpp"
|
||||
#include <string>
|
||||
#include "graphics/lod_node.hpp"
|
||||
|
||||
class XMLNode;
|
||||
class SFXBase;
|
||||
@@ -40,199 +41,6 @@ class ParticleEmitter;
|
||||
class PhysicalObject;
|
||||
class ThreeDAnimation;
|
||||
|
||||
class TrackObjectPresentation
|
||||
{
|
||||
protected:
|
||||
/** The initial XYZ position of the object. */
|
||||
core::vector3df m_init_xyz;
|
||||
|
||||
/** The initial hpr of the object. */
|
||||
core::vector3df m_init_hpr;
|
||||
|
||||
/** The initial scale of the object. */
|
||||
core::vector3df m_init_scale;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
TrackObjectPresentation(const XMLNode& xml_node);
|
||||
virtual ~TrackObjectPresentation() {}
|
||||
|
||||
virtual void reset() {}
|
||||
virtual void setEnable(bool enabled) {}
|
||||
virtual void update(float dt) {}
|
||||
virtual void move(const core::vector3df& xyz, const core::vector3df& hpr,
|
||||
const core::vector3df& scale) {}
|
||||
|
||||
virtual const core::vector3df& getPosition() const { return m_init_xyz; }
|
||||
virtual const core::vector3df& getRotation() const { return m_init_hpr; }
|
||||
virtual const core::vector3df& getScale() const { return m_init_scale; }
|
||||
|
||||
LEAK_CHECK()
|
||||
};
|
||||
|
||||
class TrackObjectPresentationSceneNode : public TrackObjectPresentation
|
||||
{
|
||||
protected:
|
||||
scene::ISceneNode* m_node;
|
||||
public:
|
||||
|
||||
TrackObjectPresentationSceneNode(const XMLNode& xml_node) :
|
||||
TrackObjectPresentation(xml_node)
|
||||
{
|
||||
m_node = NULL;
|
||||
}
|
||||
|
||||
virtual const core::vector3df& getPosition() const OVERRIDE;
|
||||
virtual const core::vector3df& getRotation() const OVERRIDE;
|
||||
virtual const core::vector3df& getScale() const OVERRIDE;
|
||||
virtual void move(const core::vector3df& xyz, const core::vector3df& hpr,
|
||||
const core::vector3df& scale) OVERRIDE;
|
||||
virtual void setEnable(bool enabled) OVERRIDE;
|
||||
virtual void reset() OVERRIDE;
|
||||
|
||||
scene::ISceneNode* getNode() { return m_node; }
|
||||
const scene::ISceneNode* getNode() const { return m_node; }
|
||||
};
|
||||
|
||||
class TrackObjectPresentationEmpty : public TrackObjectPresentationSceneNode
|
||||
{
|
||||
public:
|
||||
|
||||
TrackObjectPresentationEmpty(const XMLNode& xml_node);
|
||||
virtual ~TrackObjectPresentationEmpty();
|
||||
};
|
||||
|
||||
class TrackObjectPresentationMesh : public TrackObjectPresentationSceneNode
|
||||
{
|
||||
private:
|
||||
/** The mesh used here. It needs to be stored so that it can be
|
||||
* removed from irrlicht's mesh cache when it is deleted. */
|
||||
scene::IMesh *m_mesh;
|
||||
|
||||
/** True if it is a looped animation. */
|
||||
bool m_is_looped;
|
||||
|
||||
/** Start frame of the animation to be played. */
|
||||
unsigned int m_frame_start;
|
||||
|
||||
/** End frame of the animation to be played. */
|
||||
unsigned int m_frame_end;
|
||||
|
||||
public:
|
||||
TrackObjectPresentationMesh(const XMLNode& xml_node, bool enabled);
|
||||
virtual ~TrackObjectPresentationMesh();
|
||||
|
||||
virtual void reset() OVERRIDE;
|
||||
|
||||
|
||||
/** 2-step construction */
|
||||
void setNode(scene::ISceneNode* node)
|
||||
{
|
||||
//assert(m_node == NULL);
|
||||
if (m_node != NULL)
|
||||
{
|
||||
m_node->remove();
|
||||
}
|
||||
|
||||
m_node = node;
|
||||
|
||||
if (m_node->getType() == irr::scene::ESNT_LOD_NODE)
|
||||
{
|
||||
((LODNode*)m_node)->setNodesPosition(m_init_xyz);
|
||||
((LODNode*)m_node)->setNodesRotation(m_init_hpr);
|
||||
((LODNode*)m_node)->setNodesScale(m_init_scale);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_node->setPosition(m_init_xyz);
|
||||
m_node->setRotation(m_init_hpr);
|
||||
m_node->setScale(m_init_scale);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
class TrackObjectPresentationSound : public TrackObjectPresentation,
|
||||
public TriggerItemListener
|
||||
{
|
||||
private:
|
||||
|
||||
/** If a sound is attached to this object and/or this is a sound emitter object */
|
||||
SFXBase* m_sound;
|
||||
|
||||
/** Currently used for sound effects only, in cutscenes only atm */
|
||||
std::string m_trigger_condition;
|
||||
|
||||
core::vector3df m_xyz;
|
||||
|
||||
public:
|
||||
|
||||
TrackObjectPresentationSound(const XMLNode& xml_node);
|
||||
virtual ~TrackObjectPresentationSound();
|
||||
virtual void onTriggerItemApproached(Item* who) OVERRIDE;
|
||||
virtual void update(float dt) OVERRIDE;
|
||||
void triggerSound(bool loop);
|
||||
void stopSound();
|
||||
|
||||
/** Currently used for sound effects only, in cutscenes only atm */
|
||||
const std::string& getTriggerCondition() const { return m_trigger_condition; }
|
||||
|
||||
virtual void move(const core::vector3df& xyz, const core::vector3df& hpr,
|
||||
const core::vector3df& scale) OVERRIDE;
|
||||
};
|
||||
|
||||
class TrackObjectPresentationBillboard : public TrackObjectPresentationSceneNode
|
||||
{
|
||||
/** To make the billboard disappear when close to the camera. Useful for light halos :
|
||||
* instead of "colliding" with the camera and suddenly disappearing when clipped by
|
||||
* frustum culling, it will gently fade out.
|
||||
*/
|
||||
bool m_fade_out_when_close;
|
||||
float m_fade_out_start;
|
||||
float m_fade_out_end;
|
||||
public:
|
||||
TrackObjectPresentationBillboard(const XMLNode& xml_node);
|
||||
virtual ~TrackObjectPresentationBillboard();
|
||||
virtual void update(float dt) OVERRIDE;
|
||||
};
|
||||
|
||||
|
||||
class TrackObjectPresentationParticles : public TrackObjectPresentation
|
||||
{
|
||||
private:
|
||||
ParticleEmitter* m_emitter;
|
||||
LODNode* m_lod_emitter_node;
|
||||
std::string m_trigger_condition;
|
||||
|
||||
public:
|
||||
TrackObjectPresentationParticles(const XMLNode& xml_node);
|
||||
virtual ~TrackObjectPresentationParticles();
|
||||
|
||||
virtual void update(float dt) OVERRIDE;
|
||||
virtual void move(const core::vector3df& xyz, const core::vector3df& hpr,
|
||||
const core::vector3df& scale) OVERRIDE;
|
||||
std::string& getTriggerCondition() { return m_trigger_condition; }
|
||||
|
||||
void triggerParticles();
|
||||
};
|
||||
|
||||
class TrackObjectPresentationActionTrigger : public TrackObjectPresentation,
|
||||
public TriggerItemListener
|
||||
{
|
||||
private:
|
||||
|
||||
/** For action trigger objects */
|
||||
std::string m_action;
|
||||
|
||||
public:
|
||||
|
||||
|
||||
TrackObjectPresentationActionTrigger(const XMLNode& xml_node);
|
||||
virtual ~TrackObjectPresentationActionTrigger() {}
|
||||
|
||||
virtual void onTriggerItemApproached(Item* who) OVERRIDE;
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup tracks
|
||||
|
||||
633
src/tracks/track_object_presentation.cpp
Normal file
633
src/tracks/track_object_presentation.cpp
Normal file
@@ -0,0 +1,633 @@
|
||||
//
|
||||
// SuperTuxKart - a fun racing game with go-kart
|
||||
// Copyright (C) 2013 Joerg Henrichs, Marianne Gagnon
|
||||
//
|
||||
// This program is free software; you can redistribute it and/or
|
||||
// modify it under the terms of the GNU General Public License
|
||||
// as published by the Free Software Foundation; either version 3
|
||||
// of the License, or (at your option) any later version.
|
||||
//
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program; if not, write to the Free Software
|
||||
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
|
||||
#include "tracks/track_object_presentation.hpp"
|
||||
|
||||
#include "audio/sfx_base.hpp"
|
||||
#include "audio/sfx_buffer.hpp"
|
||||
#include "graphics/material_manager.hpp"
|
||||
#include "graphics/particle_emitter.hpp"
|
||||
#include "graphics/particle_kind_manager.hpp"
|
||||
#include "io/file_manager.hpp"
|
||||
#include "io/xml_node.hpp"
|
||||
#include "input/device_manager.hpp"
|
||||
#include "input/input_manager.hpp"
|
||||
#include "items/item_manager.hpp"
|
||||
#include "modes/world.hpp"
|
||||
#include "states_screens/dialogs/race_paused_dialog.hpp"
|
||||
#include "states_screens/dialogs/tutorial_message_dialog.hpp"
|
||||
#include "tracks/track.hpp"
|
||||
|
||||
#include <ISceneManager.h>
|
||||
#include <IMeshSceneNode.h>
|
||||
#include <ICameraSceneNode.h>
|
||||
#include <IBillboardSceneNode.h>
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
TrackObjectPresentation::TrackObjectPresentation(const XMLNode& xml_node)
|
||||
{
|
||||
m_init_xyz = core::vector3df(0,0,0);
|
||||
m_init_hpr = core::vector3df(0,0,0);
|
||||
m_init_scale = core::vector3df(1,1,1);
|
||||
|
||||
xml_node.get("xyz", &m_init_xyz );
|
||||
xml_node.get("hpr", &m_init_hpr );
|
||||
xml_node.get("scale", &m_init_scale);
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
const core::vector3df& TrackObjectPresentationSceneNode::getPosition() const
|
||||
{
|
||||
return m_node->getPosition();
|
||||
}
|
||||
|
||||
const core::vector3df& TrackObjectPresentationSceneNode::getRotation() const
|
||||
{
|
||||
return m_node->getRotation();
|
||||
}
|
||||
|
||||
const core::vector3df& TrackObjectPresentationSceneNode::getScale() const
|
||||
{
|
||||
return m_node->getScale();
|
||||
}
|
||||
|
||||
|
||||
void TrackObjectPresentationSceneNode::move(const core::vector3df& xyz, const core::vector3df& hpr,
|
||||
const core::vector3df& scale)
|
||||
{
|
||||
m_node->setPosition(xyz);
|
||||
m_node->setRotation(hpr);
|
||||
m_node->setScale(scale);
|
||||
|
||||
//if (dynamic_cast<TrackObjectPresentationMesh*>(this) != NULL)
|
||||
}
|
||||
|
||||
void TrackObjectPresentationSceneNode::setEnable(bool enabled)
|
||||
{
|
||||
m_node->setVisible(enabled);
|
||||
}
|
||||
|
||||
void TrackObjectPresentationSceneNode::reset()
|
||||
{
|
||||
m_node->setPosition(m_init_xyz);
|
||||
m_node->setRotation(m_init_hpr);
|
||||
m_node->setScale(m_init_scale);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
TrackObjectPresentationEmpty::TrackObjectPresentationEmpty(const XMLNode& xml_node) :
|
||||
TrackObjectPresentationSceneNode(xml_node)
|
||||
{
|
||||
m_node = irr_driver->getSceneManager()->addEmptySceneNode();
|
||||
m_node->setPosition(m_init_xyz);
|
||||
m_node->setRotation(m_init_hpr);
|
||||
m_node->setScale(m_init_scale);
|
||||
}
|
||||
|
||||
TrackObjectPresentationEmpty::~TrackObjectPresentationEmpty()
|
||||
{
|
||||
irr_driver->removeNode(m_node);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
TrackObjectPresentationMesh::TrackObjectPresentationMesh(const XMLNode& xml_node, bool enabled) :
|
||||
TrackObjectPresentationSceneNode(xml_node)
|
||||
{
|
||||
m_is_looped = false;
|
||||
m_mesh = NULL;
|
||||
m_node = NULL;
|
||||
|
||||
xml_node.get("looped", &m_is_looped );
|
||||
std::string model_name;
|
||||
xml_node.get("model", &model_name );
|
||||
|
||||
std::string full_path =
|
||||
World::getWorld()->getTrack()->getTrackFile(model_name);
|
||||
|
||||
bool animated = (UserConfigParams::m_graphical_effects ||
|
||||
World::getWorld()->getIdent() == IDENT_CUSTSCENE);
|
||||
|
||||
if (file_manager->fileExists(full_path))
|
||||
{
|
||||
if (animated)
|
||||
{
|
||||
m_mesh = irr_driver->getAnimatedMesh(full_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_mesh = irr_driver->getMesh(full_path);
|
||||
}
|
||||
}
|
||||
|
||||
if(!m_mesh)
|
||||
{
|
||||
// If the model isn't found in the track directory, look
|
||||
// in STK's model directory.
|
||||
full_path = file_manager->getModelFile(model_name);
|
||||
m_mesh = irr_driver->getAnimatedMesh(full_path);
|
||||
|
||||
if(!m_mesh)
|
||||
{
|
||||
throw std::runtime_error("Model '" + model_name + "' cannot be found");
|
||||
}
|
||||
}
|
||||
|
||||
m_mesh->grab();
|
||||
irr_driver->grabAllTextures(m_mesh);
|
||||
|
||||
if (animated)
|
||||
{
|
||||
scene::IAnimatedMeshSceneNode *node =
|
||||
irr_driver->addAnimatedMesh((scene::IAnimatedMesh*)m_mesh);
|
||||
m_node = node;
|
||||
|
||||
m_frame_start = node->getStartFrame();
|
||||
xml_node.get("frame-start", &m_frame_start);
|
||||
|
||||
m_frame_end = node->getEndFrame();
|
||||
xml_node.get("frame-end", &m_frame_end);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_node = irr_driver->addMesh(m_mesh);
|
||||
m_frame_start = 0;
|
||||
m_frame_end = 0;
|
||||
}
|
||||
#ifdef DEBUG
|
||||
std::string debug_name = model_name+" (track-object)";
|
||||
m_node->setName(debug_name.c_str());
|
||||
#endif
|
||||
|
||||
if(!enabled)
|
||||
m_node->setVisible(false);
|
||||
|
||||
m_node->setPosition(m_init_xyz);
|
||||
m_node->setRotation(m_init_hpr);
|
||||
m_node->setScale(m_init_scale);
|
||||
}
|
||||
|
||||
TrackObjectPresentationMesh::~TrackObjectPresentationMesh()
|
||||
{
|
||||
if (m_node)
|
||||
irr_driver->removeNode(m_node);
|
||||
|
||||
if(m_mesh)
|
||||
{
|
||||
irr_driver->dropAllTextures(m_mesh);
|
||||
m_mesh->drop();
|
||||
if(m_mesh->getReferenceCount()==1)
|
||||
irr_driver->removeMeshFromCache(m_mesh);
|
||||
}
|
||||
}
|
||||
|
||||
void TrackObjectPresentationMesh::reset()
|
||||
{
|
||||
if (m_node->getType()==scene::ESNT_ANIMATED_MESH)
|
||||
{
|
||||
scene::IAnimatedMeshSceneNode *a_node =
|
||||
(scene::IAnimatedMeshSceneNode*)m_node;
|
||||
|
||||
a_node->setPosition(m_init_xyz);
|
||||
a_node->setRotation(m_init_hpr);
|
||||
a_node->setScale(m_init_scale);
|
||||
a_node->setLoopMode(m_is_looped);
|
||||
a_node->setCurrentFrame((float)(a_node->getStartFrame()));
|
||||
|
||||
// trick to reset the animation AND also the timer inside it
|
||||
a_node->OnAnimate(0);
|
||||
a_node->OnAnimate(0);
|
||||
|
||||
if(m_is_looped)
|
||||
{
|
||||
a_node->setFrameLoop(m_frame_start, m_frame_end);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
TrackObjectPresentationSound::TrackObjectPresentationSound(const XMLNode& xml_node) :
|
||||
TrackObjectPresentation(xml_node)
|
||||
{
|
||||
m_sound = NULL;
|
||||
m_xyz = m_init_xyz;
|
||||
|
||||
std::string sound;
|
||||
xml_node.get("sound", &sound);
|
||||
|
||||
float rolloff = 0.5;
|
||||
xml_node.get("rolloff", &rolloff );
|
||||
float volume = 1.0;
|
||||
xml_node.get("volume", &volume );
|
||||
|
||||
bool trigger_when_near = false;
|
||||
xml_node.get("play-when-near", &trigger_when_near);
|
||||
|
||||
float trigger_distance = 1.0f;
|
||||
xml_node.get("distance", &trigger_distance);
|
||||
|
||||
xml_node.get("conditions", &m_trigger_condition);
|
||||
|
||||
float max_dist = 390.0f;
|
||||
xml_node.get("max_dist", &max_dist );
|
||||
|
||||
// first try track dir, then global dir
|
||||
std::string soundfile = file_manager->getModelFile(sound);
|
||||
if (!file_manager->fileExists(soundfile))
|
||||
{
|
||||
soundfile = file_manager->getSFXFile(sound);
|
||||
}
|
||||
|
||||
SFXBuffer* buffer = new SFXBuffer(soundfile,
|
||||
true /* positional */,
|
||||
rolloff,
|
||||
max_dist,
|
||||
volume);
|
||||
buffer->load();
|
||||
|
||||
m_sound = sfx_manager->createSoundSource(buffer, true, true);
|
||||
if (m_sound != NULL)
|
||||
{
|
||||
m_sound->position(m_init_xyz);
|
||||
if (!trigger_when_near && m_trigger_condition.empty())
|
||||
{
|
||||
m_sound->setLoop(true);
|
||||
m_sound->play();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr,
|
||||
"[TrackObject] Sound emitter object could not be created\n");
|
||||
}
|
||||
|
||||
if (trigger_when_near)
|
||||
{
|
||||
ItemManager::get()->newItem(m_init_xyz, trigger_distance, this);
|
||||
}
|
||||
}
|
||||
|
||||
void TrackObjectPresentationSound::update(float dt)
|
||||
{
|
||||
if (m_sound != NULL)
|
||||
{
|
||||
// muting when too far is implemented manually since not supported by OpenAL
|
||||
// so need to call this every frame to update the muting state if listener
|
||||
// moved
|
||||
m_sound->position(m_xyz);
|
||||
}
|
||||
}
|
||||
|
||||
void TrackObjectPresentationSound::onTriggerItemApproached(Item* who)
|
||||
{
|
||||
if (m_sound != NULL && m_sound->getStatus() != SFXManager::SFX_PLAYING)
|
||||
{
|
||||
m_sound->play();
|
||||
}
|
||||
}
|
||||
|
||||
void TrackObjectPresentationSound::triggerSound(bool loop)
|
||||
{
|
||||
if (m_sound != NULL)
|
||||
{
|
||||
m_sound->setLoop(loop);
|
||||
m_sound->play();
|
||||
}
|
||||
}
|
||||
|
||||
void TrackObjectPresentationSound::stopSound()
|
||||
{
|
||||
if (m_sound != NULL) m_sound->stop();
|
||||
}
|
||||
|
||||
TrackObjectPresentationSound::~TrackObjectPresentationSound()
|
||||
{
|
||||
if (m_sound)
|
||||
{
|
||||
//delete m_sound->getBuffer();
|
||||
sfx_manager->deleteSFX(m_sound);
|
||||
}
|
||||
}
|
||||
|
||||
void TrackObjectPresentationSound::move(const core::vector3df& xyz, const core::vector3df& hpr,
|
||||
const core::vector3df& scale)
|
||||
{
|
||||
m_xyz = xyz;
|
||||
if (m_sound != NULL) m_sound->position(xyz);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
TrackObjectPresentationBillboard::TrackObjectPresentationBillboard(const XMLNode& xml_node) :
|
||||
TrackObjectPresentationSceneNode(xml_node)
|
||||
{
|
||||
std::string texture_name;
|
||||
float width, height;
|
||||
|
||||
m_fade_out_start = 50.0f;
|
||||
m_fade_out_end = 150.0f;
|
||||
|
||||
xml_node.get("texture", &texture_name);
|
||||
xml_node.get("width", &width );
|
||||
xml_node.get("height", &height );
|
||||
|
||||
m_fade_out_when_close = false;
|
||||
xml_node.get("fadeout", &m_fade_out_when_close);
|
||||
|
||||
if (m_fade_out_when_close)
|
||||
{
|
||||
xml_node.get("start", &m_fade_out_start);
|
||||
xml_node.get("end", &m_fade_out_end );
|
||||
}
|
||||
|
||||
video::ITexture *texture =
|
||||
irr_driver->getTexture(file_manager->getTextureFile(texture_name));
|
||||
m_node = irr_driver->addBillboard(core::dimension2df(width, height),
|
||||
texture);
|
||||
Material *stk_material = material_manager->getMaterial(texture_name);
|
||||
stk_material->setMaterialProperties(&(m_node->getMaterial(0)), NULL);
|
||||
|
||||
m_node->setPosition(m_init_xyz);
|
||||
}
|
||||
|
||||
void TrackObjectPresentationBillboard::update(float dt)
|
||||
{
|
||||
if (m_fade_out_when_close)
|
||||
{
|
||||
scene::ICameraSceneNode* curr_cam = irr_driver->getSceneManager()->getActiveCamera();
|
||||
const float dist = m_node->getPosition().getDistanceFrom( curr_cam->getPosition() );
|
||||
|
||||
scene::IBillboardSceneNode* node = (scene::IBillboardSceneNode*)m_node;
|
||||
|
||||
if (dist < m_fade_out_start)
|
||||
{
|
||||
node->setColor(video::SColor(0, 255, 255, 255));
|
||||
}
|
||||
else if (dist > m_fade_out_end)
|
||||
{
|
||||
node->setColor(video::SColor(255, 255, 255, 255));
|
||||
}
|
||||
else
|
||||
{
|
||||
int a = (int)(255*(dist - m_fade_out_start) / (m_fade_out_end - m_fade_out_start));
|
||||
node->setColor(video::SColor(a, 255, 255, 255));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TrackObjectPresentationBillboard::~TrackObjectPresentationBillboard()
|
||||
{
|
||||
if (m_node)
|
||||
irr_driver->removeNode(m_node);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
TrackObjectPresentationParticles::TrackObjectPresentationParticles(const XMLNode& xml_node) :
|
||||
TrackObjectPresentation(xml_node)
|
||||
{
|
||||
m_emitter = NULL;
|
||||
m_lod_emitter_node = NULL;
|
||||
|
||||
std::string path;
|
||||
irr::core::vector3df emitter_origin;
|
||||
xml_node.get("kind", &path);
|
||||
xml_node.getXYZ(&emitter_origin);
|
||||
|
||||
int clip_distance = -1;
|
||||
xml_node.get("clip_distance", &clip_distance);
|
||||
|
||||
xml_node.get("conditions", &m_trigger_condition);
|
||||
|
||||
try
|
||||
{
|
||||
ParticleKind* kind = ParticleKindManager::get()->getParticles( path.c_str() );
|
||||
if (kind == NULL)
|
||||
{
|
||||
throw std::runtime_error(path + " could not be loaded");
|
||||
}
|
||||
ParticleEmitter* emitter = new ParticleEmitter( kind, emitter_origin );
|
||||
|
||||
/*
|
||||
if (clip_distance > 0)
|
||||
{
|
||||
scene::ISceneManager* sm = irr_driver->getSceneManager();
|
||||
scene::ISceneNode* sroot = sm->getRootSceneNode();
|
||||
LODNode* lod = new LODNode("particles", sroot, sm);
|
||||
lod->add(clip_distance, (scene::ISceneNode*)emitter->getNode(), true);
|
||||
//m_all_emitters.push_back(emitter);
|
||||
m_node = lod;
|
||||
m_lod_emitter_node = lod;
|
||||
m_emitter = emitter;
|
||||
}*/
|
||||
//else
|
||||
//{
|
||||
//m_node = emitter->getNode(); // FIXME: this leaks
|
||||
m_emitter = emitter;
|
||||
//}
|
||||
|
||||
if (m_trigger_condition.size() > 0)
|
||||
{
|
||||
m_emitter->setCreationRateAbsolute(0.0f);
|
||||
}
|
||||
}
|
||||
catch (std::runtime_error& e)
|
||||
{
|
||||
fprintf(stderr, "[Track] WARNING: Could not load particles '%s'; cause :\n %s", path.c_str(), e.what());
|
||||
}
|
||||
}
|
||||
|
||||
TrackObjectPresentationParticles::~TrackObjectPresentationParticles()
|
||||
{
|
||||
if (m_emitter)
|
||||
{
|
||||
if (m_lod_emitter_node != NULL)
|
||||
{
|
||||
irr_driver->removeNode(m_lod_emitter_node);
|
||||
m_emitter->unsetNode();
|
||||
}
|
||||
delete m_emitter; // this will also delete m_node
|
||||
}
|
||||
}
|
||||
|
||||
void TrackObjectPresentationParticles::update(float dt)
|
||||
{
|
||||
if (m_emitter != NULL)
|
||||
{
|
||||
m_emitter->update(dt);
|
||||
}
|
||||
}
|
||||
|
||||
void TrackObjectPresentationParticles::triggerParticles()
|
||||
{
|
||||
if (m_emitter != NULL)
|
||||
{
|
||||
m_emitter->setCreationRateAbsolute(1.0f);
|
||||
m_emitter->setParticleType(m_emitter->getParticlesInfo());
|
||||
}
|
||||
}
|
||||
|
||||
void TrackObjectPresentationParticles::move(const core::vector3df& xyz, const core::vector3df& hpr,
|
||||
const core::vector3df& scale)
|
||||
{
|
||||
if (m_emitter != NULL) m_emitter->setPosition(xyz);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
|
||||
TrackObjectPresentationActionTrigger::TrackObjectPresentationActionTrigger(const XMLNode& xml_node) :
|
||||
TrackObjectPresentation(xml_node)
|
||||
{
|
||||
float trigger_distance = 1.0f;
|
||||
xml_node.get("distance", &trigger_distance);
|
||||
|
||||
xml_node.get("action", &m_action);
|
||||
|
||||
if (m_action.size() == 0)
|
||||
{
|
||||
fprintf(stderr, "[TrackObject] WARNING: action-trigger has no action defined\n");
|
||||
}
|
||||
|
||||
ItemManager::get()->newItem(m_init_xyz, trigger_distance, this);
|
||||
}
|
||||
|
||||
void TrackObjectPresentationActionTrigger::onTriggerItemApproached(Item* who)
|
||||
{
|
||||
if (m_action == "garage")
|
||||
{
|
||||
new RacePausedDialog(0.8f, 0.6f);
|
||||
//dynamic_cast<OverWorld*>(World::getWorld())->scheduleSelectKart();
|
||||
}
|
||||
else if (m_action == "tutorial_drive")
|
||||
{
|
||||
//if (World::getWorld()->getPhase() == World::RACE_PHASE)
|
||||
{
|
||||
m_action = "__disabled__";
|
||||
//World::getWorld()->getRaceGUI()->clearAllMessages();
|
||||
|
||||
InputDevice* device = input_manager->getDeviceList()->getLatestUsedDevice();
|
||||
DeviceConfig* config = device->getConfiguration();
|
||||
irr::core::stringw accel = config->getBindingAsString(PA_ACCEL);
|
||||
irr::core::stringw left = config->getBindingAsString(PA_STEER_LEFT);
|
||||
irr::core::stringw right = config->getBindingAsString(PA_STEER_RIGHT);
|
||||
|
||||
new TutorialMessageDialog(_("Accelerate with <%s> and steer with <%s> and <%s>", accel, left, right),
|
||||
false);
|
||||
}
|
||||
}
|
||||
else if (m_action == "tutorial_bananas")
|
||||
{
|
||||
m_action = "__disabled__";
|
||||
|
||||
new TutorialMessageDialog(_("Avoid bananas!"), true);
|
||||
}
|
||||
else if (m_action == "tutorial_giftboxes")
|
||||
{
|
||||
m_action = "__disabled__";
|
||||
InputDevice* device = input_manager->getDeviceList()->getLatestUsedDevice();
|
||||
DeviceConfig* config = device->getConfiguration();
|
||||
irr::core::stringw fire = config->getBindingAsString(PA_FIRE);
|
||||
|
||||
new TutorialMessageDialog(_("Collect gift boxes, and fire the weapon with <%s> to blow away these boxes!", fire),
|
||||
true);
|
||||
}
|
||||
else if (m_action == "tutorial_nitro_collect")
|
||||
{
|
||||
m_action = "__disabled__";
|
||||
|
||||
new TutorialMessageDialog(_("Collect nitro bottles (we will use them after the curve)"),
|
||||
true);
|
||||
}
|
||||
else if (m_action == "tutorial_nitro_use")
|
||||
{
|
||||
m_action = "__disabled__";
|
||||
InputDevice* device = input_manager->getDeviceList()->getLatestUsedDevice();
|
||||
DeviceConfig* config = device->getConfiguration();
|
||||
irr::core::stringw nitro = config->getBindingAsString(PA_NITRO);
|
||||
|
||||
new TutorialMessageDialog(_("Use the nitro you collected by pressing <%s>!", nitro),
|
||||
true);
|
||||
}
|
||||
else if (m_action == "tutorial_rescue")
|
||||
{
|
||||
m_action = "__disabled__";
|
||||
InputDevice* device = input_manager->getDeviceList()->getLatestUsedDevice();
|
||||
DeviceConfig* config = device->getConfiguration();
|
||||
irr::core::stringw rescue = config->getBindingAsString(PA_RESCUE);
|
||||
|
||||
new TutorialMessageDialog(_("Oops! When you're in trouble, press <%s> to be rescued", rescue),
|
||||
false);
|
||||
}
|
||||
else if (m_action == "tutorial_skidding")
|
||||
{
|
||||
m_action = "__disabled__";
|
||||
//World::getWorld()->getRaceGUI()->clearAllMessages();
|
||||
|
||||
InputDevice* device = input_manager->getDeviceList()->getLatestUsedDevice();
|
||||
DeviceConfig* config = device->getConfiguration();
|
||||
irr::core::stringw skid = config->getBindingAsString(PA_DRIFT);
|
||||
|
||||
|
||||
new TutorialMessageDialog(_("Accelerate and press the <%s> key while turning to skid. Skidding for a short while can help you turn faster to take sharp turns.", skid),
|
||||
true);
|
||||
}
|
||||
else if (m_action == "tutorial_skidding2")
|
||||
{
|
||||
m_action = "__disabled__";
|
||||
World::getWorld()->getRaceGUI()->clearAllMessages();
|
||||
|
||||
new TutorialMessageDialog(_("Note that if you manage to skid for several seconds, you will receive a bonus speedup as a reward!"),
|
||||
true);
|
||||
}
|
||||
else if (m_action == "tutorial_endmessage")
|
||||
{
|
||||
m_action = "__disabled__";
|
||||
World::getWorld()->getRaceGUI()->clearAllMessages();
|
||||
|
||||
new TutorialMessageDialog(_("You are now ready to race. Good luck!"),
|
||||
true);
|
||||
}
|
||||
else if (m_action == "tutorial_exit")
|
||||
{
|
||||
World::getWorld()->scheduleExitRace();
|
||||
return;
|
||||
}
|
||||
else if (m_action == "__disabled__")
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "[TrackObject] WARNING: unknown action <%s>\n",
|
||||
m_action.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
254
src/tracks/track_object_presentation.hpp
Normal file
254
src/tracks/track_object_presentation.hpp
Normal file
@@ -0,0 +1,254 @@
|
||||
#ifndef HEADER_TRACK_OBJECT_PRESENTATION_HPP
|
||||
#define HEADER_TRACK_OBJECT_PRESENTATION_HPP
|
||||
|
||||
#include <vector3d.h>
|
||||
#include <IAnimatedMeshSceneNode.h>
|
||||
namespace irr
|
||||
{
|
||||
namespace scene { class IAnimatedMesh; class ISceneNode; }
|
||||
}
|
||||
using namespace irr;
|
||||
|
||||
#include "graphics/lod_node.hpp"
|
||||
#include "items/item.hpp"
|
||||
#include "utils/cpp2011.h"
|
||||
#include "utils/no_copy.hpp"
|
||||
#include "utils/vec3.hpp"
|
||||
#include <string>
|
||||
|
||||
class XMLNode;
|
||||
class SFXBase;
|
||||
class ParticleEmitter;
|
||||
class PhysicalObject;
|
||||
class ThreeDAnimation;
|
||||
|
||||
/**
|
||||
* \ingroup tracks
|
||||
* Base class for all track object presentation classes
|
||||
*/
|
||||
class TrackObjectPresentation
|
||||
{
|
||||
protected:
|
||||
/** The initial XYZ position of the object. */
|
||||
core::vector3df m_init_xyz;
|
||||
|
||||
/** The initial hpr of the object. */
|
||||
core::vector3df m_init_hpr;
|
||||
|
||||
/** The initial scale of the object. */
|
||||
core::vector3df m_init_scale;
|
||||
|
||||
|
||||
public:
|
||||
|
||||
TrackObjectPresentation(const XMLNode& xml_node);
|
||||
virtual ~TrackObjectPresentation() {}
|
||||
|
||||
virtual void reset() {}
|
||||
virtual void setEnable(bool enabled) {}
|
||||
virtual void update(float dt) {}
|
||||
virtual void move(const core::vector3df& xyz, const core::vector3df& hpr,
|
||||
const core::vector3df& scale) {}
|
||||
|
||||
virtual const core::vector3df& getPosition() const { return m_init_xyz; }
|
||||
virtual const core::vector3df& getRotation() const { return m_init_hpr; }
|
||||
virtual const core::vector3df& getScale() const { return m_init_scale; }
|
||||
|
||||
LEAK_CHECK()
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup tracks
|
||||
* Base class for all track object presentation classes using a scene node
|
||||
* as presentation
|
||||
*/
|
||||
class TrackObjectPresentationSceneNode : public TrackObjectPresentation
|
||||
{
|
||||
protected:
|
||||
scene::ISceneNode* m_node;
|
||||
public:
|
||||
|
||||
TrackObjectPresentationSceneNode(const XMLNode& xml_node) :
|
||||
TrackObjectPresentation(xml_node)
|
||||
{
|
||||
m_node = NULL;
|
||||
}
|
||||
|
||||
virtual const core::vector3df& getPosition() const OVERRIDE;
|
||||
virtual const core::vector3df& getRotation() const OVERRIDE;
|
||||
virtual const core::vector3df& getScale() const OVERRIDE;
|
||||
virtual void move(const core::vector3df& xyz, const core::vector3df& hpr,
|
||||
const core::vector3df& scale) OVERRIDE;
|
||||
virtual void setEnable(bool enabled) OVERRIDE;
|
||||
virtual void reset() OVERRIDE;
|
||||
|
||||
scene::ISceneNode* getNode() { return m_node; }
|
||||
const scene::ISceneNode* getNode() const { return m_node; }
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup tracks
|
||||
* A track object representation that is invisible and only consists of a
|
||||
* location, rotation and scale.
|
||||
*/
|
||||
class TrackObjectPresentationEmpty : public TrackObjectPresentationSceneNode
|
||||
{
|
||||
public:
|
||||
|
||||
TrackObjectPresentationEmpty(const XMLNode& xml_node);
|
||||
virtual ~TrackObjectPresentationEmpty();
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup tracks
|
||||
* A track object representation that consists of a mesh scene node.
|
||||
*/
|
||||
class TrackObjectPresentationMesh : public TrackObjectPresentationSceneNode
|
||||
{
|
||||
private:
|
||||
/** The mesh used here. It needs to be stored so that it can be
|
||||
* removed from irrlicht's mesh cache when it is deleted. */
|
||||
scene::IMesh *m_mesh;
|
||||
|
||||
/** True if it is a looped animation. */
|
||||
bool m_is_looped;
|
||||
|
||||
/** Start frame of the animation to be played. */
|
||||
unsigned int m_frame_start;
|
||||
|
||||
/** End frame of the animation to be played. */
|
||||
unsigned int m_frame_end;
|
||||
|
||||
public:
|
||||
TrackObjectPresentationMesh(const XMLNode& xml_node, bool enabled);
|
||||
virtual ~TrackObjectPresentationMesh();
|
||||
|
||||
virtual void reset() OVERRIDE;
|
||||
|
||||
|
||||
/** 2-step construction */
|
||||
void setNode(scene::ISceneNode* node)
|
||||
{
|
||||
//assert(m_node == NULL);
|
||||
if (m_node != NULL)
|
||||
{
|
||||
m_node->remove();
|
||||
}
|
||||
|
||||
m_node = node;
|
||||
|
||||
if (m_node->getType() == irr::scene::ESNT_LOD_NODE)
|
||||
{
|
||||
((LODNode*)m_node)->setNodesPosition(m_init_xyz);
|
||||
((LODNode*)m_node)->setNodesRotation(m_init_hpr);
|
||||
((LODNode*)m_node)->setNodesScale(m_init_scale);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_node->setPosition(m_init_xyz);
|
||||
m_node->setRotation(m_init_hpr);
|
||||
m_node->setScale(m_init_scale);
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup tracks
|
||||
* A track object representation that consists of a sound emitter
|
||||
*/
|
||||
class TrackObjectPresentationSound : public TrackObjectPresentation,
|
||||
public TriggerItemListener
|
||||
{
|
||||
private:
|
||||
|
||||
/** If a sound is attached to this object and/or this is a sound emitter object */
|
||||
SFXBase* m_sound;
|
||||
|
||||
/** Currently used for sound effects only, in cutscenes only atm */
|
||||
std::string m_trigger_condition;
|
||||
|
||||
core::vector3df m_xyz;
|
||||
|
||||
public:
|
||||
|
||||
TrackObjectPresentationSound(const XMLNode& xml_node);
|
||||
virtual ~TrackObjectPresentationSound();
|
||||
virtual void onTriggerItemApproached(Item* who) OVERRIDE;
|
||||
virtual void update(float dt) OVERRIDE;
|
||||
void triggerSound(bool loop);
|
||||
void stopSound();
|
||||
|
||||
/** Currently used for sound effects only, in cutscenes only atm */
|
||||
const std::string& getTriggerCondition() const { return m_trigger_condition; }
|
||||
|
||||
virtual void move(const core::vector3df& xyz, const core::vector3df& hpr,
|
||||
const core::vector3df& scale) OVERRIDE;
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup tracks
|
||||
* A track object representation that consists of a billboard scene node.
|
||||
*/
|
||||
class TrackObjectPresentationBillboard : public TrackObjectPresentationSceneNode
|
||||
{
|
||||
/** To make the billboard disappear when close to the camera. Useful for light halos :
|
||||
* instead of "colliding" with the camera and suddenly disappearing when clipped by
|
||||
* frustum culling, it will gently fade out.
|
||||
*/
|
||||
bool m_fade_out_when_close;
|
||||
float m_fade_out_start;
|
||||
float m_fade_out_end;
|
||||
public:
|
||||
TrackObjectPresentationBillboard(const XMLNode& xml_node);
|
||||
virtual ~TrackObjectPresentationBillboard();
|
||||
virtual void update(float dt) OVERRIDE;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* \ingroup tracks
|
||||
* A track object representation that consists of a particle emitter
|
||||
*/
|
||||
class TrackObjectPresentationParticles : public TrackObjectPresentation
|
||||
{
|
||||
private:
|
||||
ParticleEmitter* m_emitter;
|
||||
LODNode* m_lod_emitter_node;
|
||||
std::string m_trigger_condition;
|
||||
|
||||
public:
|
||||
TrackObjectPresentationParticles(const XMLNode& xml_node);
|
||||
virtual ~TrackObjectPresentationParticles();
|
||||
|
||||
virtual void update(float dt) OVERRIDE;
|
||||
virtual void move(const core::vector3df& xyz, const core::vector3df& hpr,
|
||||
const core::vector3df& scale) OVERRIDE;
|
||||
std::string& getTriggerCondition() { return m_trigger_condition; }
|
||||
|
||||
void triggerParticles();
|
||||
};
|
||||
|
||||
/**
|
||||
* \ingroup tracks
|
||||
* A track object representation that consists of an action trigger
|
||||
*/
|
||||
class TrackObjectPresentationActionTrigger : public TrackObjectPresentation,
|
||||
public TriggerItemListener
|
||||
{
|
||||
private:
|
||||
|
||||
/** For action trigger objects */
|
||||
std::string m_action;
|
||||
|
||||
public:
|
||||
|
||||
|
||||
TrackObjectPresentationActionTrigger(const XMLNode& xml_node);
|
||||
virtual ~TrackObjectPresentationActionTrigger() {}
|
||||
|
||||
virtual void onTriggerItemApproached(Item* who) OVERRIDE;
|
||||
};
|
||||
|
||||
|
||||
#endif // TRACKOBJECTPRESENTATION_HPP
|
||||
Reference in New Issue
Block a user