stk-code_catmod/src/tracks/track_object_presentation.cpp

1174 lines
40 KiB
C++

// SuperTuxKart - a fun racing game with go-kart
//
// Copyright (C) 2013-2015 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 "challenges/unlock_manager.hpp"
#include "config/user_config.hpp"
#include "graphics/camera.hpp"
#include "graphics/central_settings.hpp"
#include "graphics/irr_driver.hpp"
#include "graphics/light.hpp"
#include "graphics/material_manager.hpp"
#include "graphics/particle_emitter.hpp"
#include "graphics/particle_kind_manager.hpp"
#include "graphics/stk_particle.hpp"
#include "graphics/sp/sp_shader_manager.hpp"
#include "io/file_manager.hpp"
#include "io/xml_node.hpp"
#include "input/device_manager.hpp"
#include "input/input_device.hpp"
#include "input/input_manager.hpp"
#include "items/item_manager.hpp"
#include "karts/abstract_kart.hpp"
#include "modes/world.hpp"
#include "scriptengine/script_engine.hpp"
#include "states_screens/dialogs/tutorial_message_dialog.hpp"
#include "tracks/check_cylinder.hpp"
#include "tracks/check_manager.hpp"
#include "tracks/check_trigger.hpp"
#include "tracks/model_definition_loader.hpp"
#include "tracks/track.hpp"
#include "tracks/track_manager.hpp"
#include "tracks/track_object_manager.hpp"
#include "utils/stk_process.hpp"
#include "utils/string_utils.hpp"
#include <IBillboardSceneNode.h>
#include <ICameraSceneNode.h>
#include <ILightSceneNode.h>
#include <IMeshManipulator.h>
#include <IMeshSceneNode.h>
#include <IParticleSystemSceneNode.h>
#include <ISceneManager.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);
if (!xml_node.get("xyz", &m_init_xyz ))
{
// support for old deprecated syntax
xml_node.getXYZ(&m_init_xyz);
}
xml_node.get("hpr", &m_init_hpr );
xml_node.get("scale", &m_init_scale);
} // TrackObjectPresentation
// ----------------------------------------------------------------------------
const core::vector3df& TrackObjectPresentationSceneNode::getPosition() const
{
if (m_node == NULL) return m_init_xyz;
return m_node->getPosition();
} // getPosition
// ----------------------------------------------------------------------------
const core::vector3df TrackObjectPresentationSceneNode::getAbsolutePosition() const
{
if (m_node == NULL) return m_init_xyz;
m_node->updateAbsolutePosition();
return m_node->getAbsolutePosition();
} // getAbsolutePosition
// ----------------------------------------------------------------------------
const core::vector3df TrackObjectPresentationSceneNode::getAbsoluteCenterPosition() const
{
if (m_node == NULL) return m_init_xyz;
m_node->updateAbsolutePosition();
core::aabbox3d<f32> bounds = m_node->getTransformedBoundingBox();
return bounds.getCenter();
}
// ----------------------------------------------------------------------------
const core::vector3df& TrackObjectPresentationSceneNode::getRotation() const
{
if (m_node == NULL) return m_init_hpr;
return m_node->getRotation();
} // getRotation
// ----------------------------------------------------------------------------
const core::vector3df& TrackObjectPresentationSceneNode::getScale() const
{
if (m_node == NULL) return m_init_scale;
return m_node->getScale();
} // getScale
// ----------------------------------------------------------------------------
void TrackObjectPresentationSceneNode::move(const core::vector3df& xyz,
const core::vector3df& hpr,
const core::vector3df& scale,
bool isAbsoluteCoord)
{
if (m_node == NULL) return;
if (m_node->getParent() != NULL && isAbsoluteCoord)
{
scene::ISceneNode* parent = m_node->getParent();
m_node->setPosition((xyz - parent->getAbsolutePosition())
/ parent->getScale());
}
else
{
m_node->setPosition(xyz);
}
m_node->setRotation(hpr);
m_node->setScale(scale);
m_node->updateAbsolutePosition();
} // move
// ----------------------------------------------------------------------------
void TrackObjectPresentationSceneNode::setEnable(bool enabled)
{
if (m_node != NULL && (!enabled || !m_force_always_hidden))
m_node->setVisible(enabled);
} // setEnable
// ----------------------------------------------------------------------------
void TrackObjectPresentationSceneNode::reset()
{
if (m_node == NULL) return;
m_node->setPosition(m_init_xyz);
m_node->setRotation(m_init_hpr);
m_node->setScale(m_init_scale);
} // reset
// ----------------------------------------------------------------------------
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::~TrackObjectPresentationEmpty()
{
irr_driver->removeNode(m_node);
} // ~TrackObjectPresentationEmpty
// ----------------------------------------------------------------------------
TrackObjectPresentationLibraryNode::TrackObjectPresentationLibraryNode(
TrackObject* parent,
const XMLNode& xml_node,
ModelDefinitionLoader& model_def_loader)
: TrackObjectPresentationSceneNode(xml_node)
{
m_parent = NULL;
m_start_executed = false;
m_reset_executed = false;
std::string name;
xml_node.get("name", &name);
m_name = name;
m_node = irr_driver->getSceneManager()->addEmptySceneNode();
#ifdef DEBUG
m_node->setName(("libnode_" + name).c_str());
#endif
XMLNode* libroot;
std::string lib_path =
file_manager->getAsset(FileManager::LIBRARY, name) + "/";
bool create_lod_definitions = true;
if (!model_def_loader.containsLibraryNode(name))
{
Track* track = Track::getCurrentTrack();
std::string local_lib_node_path;
std::string local_script_file_path;
if (track != NULL)
{
local_lib_node_path = track->getTrackFile("library/" + name + "/node.xml");
local_script_file_path = track->getTrackFile("library/" + name + "/scripting.as");
}
std::string lib_node_path = lib_path + "node.xml";
std::string lib_script_file_path = lib_path + "scripting.as";
if (local_lib_node_path.size() > 0 && file_manager->fileExists(local_lib_node_path))
{
lib_path = track->getTrackFile("library/" + name);
libroot = file_manager->createXMLTree(local_lib_node_path);
if (track != NULL)
{
Scripting::ScriptEngine::getInstance()->loadScript(local_script_file_path, false);
}
}
else if (file_manager->fileExists(lib_node_path))
{
libroot = file_manager->createXMLTree(lib_node_path);
if (track != NULL)
{
Scripting::ScriptEngine::getInstance()->loadScript(lib_script_file_path, false);
}
}
else
{
Log::error("TrackObjectPresentationLibraryNode",
"Cannot find library '%s'", lib_node_path.c_str());
return;
}
if (libroot == NULL)
{
Log::error("TrackObjectPresentationLibraryNode",
"Cannot find library '%s'", lib_node_path.c_str());
return;
}
std::string unique_id = StringUtils::insertValues("library/%s", name.c_str());
file_manager->pushTextureSearchPath(lib_path + "/", unique_id);
file_manager->pushModelSearchPath(lib_path);
material_manager->pushTempMaterial(lib_path + "/materials.xml");
#ifndef SERVER_ONLY
if (CVS->isGLSL())
{
SP::SPShaderManager::get()->loadSPShaders(lib_path);
}
#endif
model_def_loader.addToLibrary(name, libroot);
// Load LOD groups
const XMLNode *lod_xml_node = libroot->getNode("lod");
if (lod_xml_node != NULL)
{
for (unsigned int i = 0; i < lod_xml_node->getNumNodes(); i++)
{
const XMLNode* lod_group_xml = lod_xml_node->getNode(i);
for (unsigned int j = 0; j < lod_group_xml->getNumNodes(); j++)
{
model_def_loader.addModelDefinition(lod_group_xml->getNode(j));
}
}
}
}
else
{
libroot = model_def_loader.getLibraryNodes()[name];
assert(libroot != NULL);
// LOD definitions are already created, don't create them again
create_lod_definitions = false;
}
m_node->setPosition(m_init_xyz);
m_node->setRotation(m_init_hpr);
m_node->setScale(m_init_scale);
m_node->updateAbsolutePosition();
assert(libroot != NULL);
Track::getCurrentTrack()->loadObjects(libroot, lib_path, model_def_loader,
create_lod_definitions, m_node,
parent);
m_parent = parent;
} // TrackObjectPresentationLibraryNode
// ----------------------------------------------------------------------------
void TrackObjectPresentationLibraryNode::update(float dt)
{
// Child process currently has no scripting engine
if (STKProcess::getType() == PT_CHILD)
return;
if (!m_start_executed)
{
m_start_executed = true;
std::string fn_name = StringUtils::insertValues("void %s::onStart(const string)", m_name.c_str());
if (m_parent != NULL)
{
std::string lib_id = m_parent->getID();
std::string* lib_id_ptr = &lib_id;
Scripting::ScriptEngine::getInstance()->runFunction(false, fn_name,
[&](asIScriptContext* ctx) {
ctx->SetArgObject(0, lib_id_ptr);
});
}
}
if (!m_reset_executed)
{
m_reset_executed = true;
std::string fn_name = StringUtils::insertValues("void %s::onReset(const string)", m_name.c_str());
if (m_parent != NULL)
{
std::string lib_id = m_parent->getID();
std::string* lib_id_ptr = &lib_id;
Scripting::ScriptEngine::getInstance()->runFunction(false, fn_name,
[&](asIScriptContext* ctx) {
ctx->SetArgObject(0, lib_id_ptr);
});
}
}
}
// ----------------------------------------------------------------------------
TrackObjectPresentationLibraryNode::~TrackObjectPresentationLibraryNode()
{
irr_driver->removeNode(m_node);
} // TrackObjectPresentationLibraryNode
// ----------------------------------------------------------------------------
void TrackObjectPresentationLibraryNode::move(const core::vector3df& xyz, const core::vector3df& hpr,
const core::vector3df& scale, bool isAbsoluteCoord)
{
TrackObjectPresentationSceneNode::move(xyz, hpr, scale, isAbsoluteCoord);
for (TrackObject* obj : m_parent->getChildren())
{
if (obj->getPhysicalObject() != NULL)
{
obj->movePhysicalBodyToGraphicalNode(obj->getAbsolutePosition(), obj->getRotation());
}
}
}
// ----------------------------------------------------------------------------
TrackObjectPresentationLOD::TrackObjectPresentationLOD(const XMLNode& xml_node,
scene::ISceneNode* parent,
ModelDefinitionLoader& model_def_loader,
std::shared_ptr<RenderInfo> ri)
: TrackObjectPresentationSceneNode(xml_node)
{
m_node = model_def_loader.instanciateAsLOD(&xml_node, parent, ri);
if (m_node == NULL) throw std::runtime_error("Cannot load LOD node");
m_node->setPosition(m_init_xyz);
m_node->setRotation(m_init_hpr);
m_node->setScale(m_init_scale);
} // TrackObjectPresentationLOD
// ----------------------------------------------------------------------------
TrackObjectPresentationLOD::~TrackObjectPresentationLOD()
{
if (m_node)
irr_driver->removeNode(m_node);
} // TrackObjectPresentationLOD
// ----------------------------------------------------------------------------
void TrackObjectPresentationLOD::reset()
{
LODNode* ln = dynamic_cast<LODNode*>(m_node);
if (ln)
{
for (scene::ISceneNode* node : ln->getAllNodes())
{
scene::IAnimatedMeshSceneNode* a_node =
dynamic_cast<scene::IAnimatedMeshSceneNode*>(node);
if (a_node)
{
a_node->setLoopMode(true);
a_node->setAnimationEndCallback(NULL);
RandomGenerator rg;
int animation_set = 0;
if (a_node->getAnimationSetNum() > 0)
animation_set = rg.get(a_node->getAnimationSetNum());
a_node->useAnimationSet(animation_set);
}
}
}
} // reset
// ----------------------------------------------------------------------------
TrackObjectPresentationMesh::TrackObjectPresentationMesh(
const XMLNode& xml_node,
bool enabled,
scene::ISceneNode* parent,
std::shared_ptr<RenderInfo> render_info)
: 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 );
m_render_info = render_info;
m_model_file = model_name;
m_is_in_skybox = false;
std::string render_pass;
xml_node.get("renderpass", &render_pass);
// for backwards compatibility, if unspecified assume there is
bool skeletal_animation = true;
xml_node.get("skeletal-animation", &skeletal_animation);
if (render_pass == "skybox")
{
m_is_in_skybox = true;
}
bool animated = skeletal_animation && (UserConfigParams::m_animated_characters ||
World::getWorld()->getIdent() == IDENT_CUTSCENE);
bool displacing = false;
xml_node.get("displacing", &displacing);
animated &= !displacing;
if (animated)
m_mesh = irr_driver->getAnimatedMesh(model_name);
else
m_mesh = irr_driver->getMesh(model_name);
if (!m_mesh)
{
throw std::runtime_error("Model '" + model_name + "' cannot be found");
}
init(&xml_node, parent, enabled);
} // TrackObjectPresentationMesh
// ----------------------------------------------------------------------------
TrackObjectPresentationMesh::TrackObjectPresentationMesh(
scene::IAnimatedMesh* model,
const core::vector3df& xyz,
const core::vector3df& hpr,
const core::vector3df& scale)
: TrackObjectPresentationSceneNode(xyz, hpr, scale)
{
m_is_looped = false;
m_is_in_skybox = false;
m_mesh = NULL;
m_node = NULL;
m_mesh = model;
m_render_info = NULL;
init(NULL, NULL, true);
} // TrackObjectPresentationMesh
// ----------------------------------------------------------------------------
TrackObjectPresentationMesh::TrackObjectPresentationMesh(
const std::string& model_file,
const core::vector3df& xyz,
const core::vector3df& hpr,
const core::vector3df& scale)
: TrackObjectPresentationSceneNode(xyz, hpr, scale)
{
m_is_looped = false;
m_mesh = NULL;
m_node = NULL;
m_is_in_skybox = false;
m_render_info = NULL;
bool animated = (UserConfigParams::m_particles_effects > 1 ||
World::getWorld()->getIdent() == IDENT_CUTSCENE);
m_model_file = model_file;
file_manager->pushTextureSearchPath(StringUtils::getPath(model_file), "");
#ifndef SERVER_ONLY
if (file_manager->fileExists(model_file))
{
if (animated)
{
m_mesh = irr_driver->getAnimatedMesh(model_file);
}
else
{
m_mesh = irr_driver->getMesh(model_file);
}
}
#endif
if (!m_mesh)
{
throw std::runtime_error("Model '" + model_file + "' cannot be found");
}
file_manager->popTextureSearchPath();
init(NULL, NULL, true);
} // TrackObjectPresentationMesh
// ----------------------------------------------------------------------------
void TrackObjectPresentationMesh::init(const XMLNode* xml_node,
scene::ISceneNode* parent, bool enabled)
{
// for backwards compatibility, if unspecified assume there is
bool skeletal_animation = true;
if(xml_node)
xml_node->get("skeletal-animation", &skeletal_animation);
bool animated = skeletal_animation && (UserConfigParams::m_particles_effects > 1 ||
World::getWorld()->getIdent() == IDENT_CUTSCENE);
bool displacing = false;
std::string interaction;
if (xml_node)
{
xml_node->get("displacing", &displacing);
xml_node->get("interaction", &interaction);
}
animated &= !displacing;
m_mesh->grab();
irr_driver->grabAllTextures(m_mesh);
if (interaction == "physicsonly")
{
std::string type;
xml_node->get("type", &type);
if (type == "animation" || xml_node->hasChildNamed("curve"))
{
// Animated
//m_node = irr_driver->getSceneManager()->addEmptySceneNode();
m_node = irr_driver->addMesh(m_mesh, m_model_file, parent, m_render_info);
enabled = false;
m_force_always_hidden = true;
}
else
{
// Static
m_node = irr_driver->addMesh(m_mesh, m_model_file, parent, m_render_info);
enabled = false;
m_force_always_hidden = true;
Track *track = Track::getCurrentTrack();
if (track && track && xml_node)
track->addPhysicsOnlyNode(m_node);
}
}
else if (m_is_in_skybox)
{
// Tell the driver that this mesh is a part of the background
scene::IMeshSceneNode * const node =
irr_driver->getSceneManager()->addMeshSceneNode(m_mesh);
node->grab();
node->setParent(NULL);
irr_driver->addBackgroundNode(node);
m_node = node;
}
else if (animated)
{
scene::IAnimatedMeshSceneNode *node =
irr_driver->addAnimatedMesh((scene::IAnimatedMesh*)m_mesh,
m_model_file, parent, m_render_info);
m_node = node;
std::vector<int> frames_start;
if (xml_node)
xml_node->get("frame-start", &frames_start);
std::vector<int> frames_end;
if (xml_node)
xml_node->get("frame-end", &frames_end);
if (frames_start.empty() && frames_end.empty())
{
frames_start.push_back(node->getStartFrame());
frames_end.push_back(node->getEndFrame());
}
assert(frames_start.size() == frames_end.size());
for (unsigned int i = 0 ; i < frames_start.size() ; i++)
node->addAnimationSet(frames_start[i], frames_end[i]);
node->useAnimationSet(0);
Track *track = Track::getCurrentTrack();
if (track && track && xml_node)
track->handleAnimatedTextures(m_node, *xml_node);
Track::uploadNodeVertexBuffer(node);
}
else
{
m_node = irr_driver->addMesh(m_mesh, m_model_file, parent, m_render_info);
Track *track = Track::getCurrentTrack();
if (track && xml_node)
track->handleAnimatedTextures(m_node, *xml_node);
Track::uploadNodeVertexBuffer(m_node);
}
if(!enabled)
m_node->setVisible(false);
m_node->setPosition(m_init_xyz);
m_node->setRotation(m_init_hpr);
m_node->setScale(m_init_scale);
} // init
// ----------------------------------------------------------------------------
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);
}
} // ~TrackObjectPresentationMesh
// ----------------------------------------------------------------------------
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->setAnimationEndCallback(NULL);
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);
// irrlicht's "setFrameLoop" is a misnomer, it just sets the first and
// last frame, even if looping is disabled
RandomGenerator rg;
int animation_set = 0;
if (a_node->getAnimationSetNum() > 0)
animation_set = rg.get(a_node->getAnimationSetNum());
a_node->useAnimationSet(animation_set);
}
} // reset
// ----------------------------------------------------------------------------
TrackObjectPresentationSound::TrackObjectPresentationSound(
const XMLNode& xml_node,
scene::ISceneNode* parent,
bool disable_for_multiplayer)
: TrackObjectPresentation(xml_node)
{
// TODO: respect 'parent' if any
m_enabled = true;
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 );
if (trigger_when_near)
{
Track::getCurrentTrack()->getCheckManager()->add(
new CheckTrigger(m_init_xyz, trigger_distance, std::bind(
&TrackObjectPresentationSound::onTriggerItemApproached,
this, std::placeholders::_1)));
}
if (disable_for_multiplayer)
return;
// first try track dir, then global dir
std::string soundfile = Track::getCurrentTrack()->getTrackFile(sound);
//std::string soundfile = file_manager->getAsset(FileManager::MODEL,sound);
if (!file_manager->fileExists(soundfile))
{
soundfile = file_manager->getAsset(FileManager::SFX, sound);
}
SFXBuffer* buffer = new SFXBuffer(soundfile,
true /* positional */,
rolloff,
max_dist,
volume);
buffer->load();
m_sound = SFXManager::get()->createSoundSource(buffer, true, true);
if (m_sound != NULL)
{
m_sound->setPosition(m_init_xyz);
if (!trigger_when_near && m_trigger_condition.empty())
{
m_sound->setLoop(true);
m_sound->play();
}
}
else
Log::error("TrackObject", "Sound emitter object could not be created.");
} // TrackObjectPresentationSound
// ----------------------------------------------------------------------------
void TrackObjectPresentationSound::updateGraphics(float dt)
{
if (m_sound != NULL && m_enabled)
{
// 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->setPosition(m_xyz);
}
} // update
// ----------------------------------------------------------------------------
void TrackObjectPresentationSound::onTriggerItemApproached(int kart_id)
{
if (m_sound != NULL && m_sound->getStatus() != SFXBase::SFX_PLAYING && m_enabled)
{
m_sound->play();
}
} // onTriggerItemApproached
// ----------------------------------------------------------------------------
void TrackObjectPresentationSound::triggerSound(bool loop)
{
if (m_sound != NULL && m_enabled)
{
m_sound->setLoop(loop);
m_sound->play();
}
} // triggerSound
// ----------------------------------------------------------------------------
void TrackObjectPresentationSound::stopSound()
{
if (m_sound != NULL)
m_sound->stop();
} // stopSound
// ----------------------------------------------------------------------------
TrackObjectPresentationSound::~TrackObjectPresentationSound()
{
if (m_sound)
{
m_sound->deleteSFX();
}
} // ~TrackObjectPresentationSound
// ----------------------------------------------------------------------------
void TrackObjectPresentationSound::move(const core::vector3df& xyz,
const core::vector3df& hpr,
const core::vector3df& scale,
bool isAbsoluteCoord)
{
m_xyz = xyz;
if (m_sound != NULL && m_enabled)
m_sound->setPosition(xyz);
} // move
// ----------------------------------------------------------------------------
void TrackObjectPresentationSound::setEnable(bool enabled)
{
if (enabled != m_enabled)
{
m_enabled = enabled;
if (enabled)
triggerSound(true);
else
stopSound();
}
}
// ----------------------------------------------------------------------------
TrackObjectPresentationBillboard::TrackObjectPresentationBillboard(
const XMLNode& xml_node,
scene::ISceneNode* parent)
: 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 );
}
m_node = irr_driver->addBillboard(core::dimension2df(width, height),
texture_name, parent);
m_node->setPosition(m_init_xyz);
} // TrackObjectPresentationBillboard
// ----------------------------------------------------------------------------
void TrackObjectPresentationBillboard::updateGraphics(float dt)
{
if (GUIEngine::isNoGraphics()) return;
#ifndef SERVER_ONLY
if (m_fade_out_when_close)
{
scene::ICameraSceneNode* curr_cam = irr_driver->getSceneManager()
->getActiveCamera();
const float dist = m_node->getAbsolutePosition()
.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));
}
} // m_fade_out_when_close
#endif
} // update
// ----------------------------------------------------------------------------
TrackObjectPresentationBillboard::~TrackObjectPresentationBillboard()
{
if (m_node)
irr_driver->removeNode(m_node);
} // ~TrackObjectPresentationBillboard
// ----------------------------------------------------------------------------
TrackObjectPresentationParticles::TrackObjectPresentationParticles(
const XMLNode& xml_node,
scene::ISceneNode* parent)
: TrackObjectPresentationSceneNode(xml_node)
{
m_emitter = NULL;
m_lod_emitter_node = NULL;
std::string path;
xml_node.get("kind", &path);
int clip_distance = -1;
xml_node.get("clip_distance", &clip_distance);
xml_node.get("conditions", &m_trigger_condition);
bool auto_emit = true;
xml_node.get("auto_emit", &auto_emit);
m_delayed_stop = false;
m_delayed_stop_time = 0.0;
#ifndef SERVER_ONLY
try
{
ParticleKind* kind = ParticleKindManager::get()->getParticles(path);
if (kind == NULL)
{
throw std::runtime_error(path + " could not be loaded");
}
ParticleEmitter* emitter = new ParticleEmitter(kind, m_init_xyz, parent);
if (clip_distance > 0)
{
scene::ISceneManager* sm = irr_driver->getSceneManager();
scene::ISceneNode* sroot = sm->getRootSceneNode();
LODNode* lod = new LODNode("particles", !parent ? sroot : parent, sm);
lod->add(clip_distance, (scene::ISceneNode*)emitter->getNode(), true);
m_node = lod;
m_lod_emitter_node = lod;
m_emitter = emitter;
}
else
{
m_node = emitter->getNode();
m_emitter = emitter;
}
if (m_trigger_condition.size() > 0 || !auto_emit)
{
m_emitter->setCreationRateAbsolute(0.0f);
}
}
catch (std::runtime_error& e)
{
Log::warn ("Track", "Could not load particles '%s'; cause :\n %s",
path.c_str(), e.what());
}
#endif
} // TrackObjectPresentationParticles
// ----------------------------------------------------------------------------
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
}
} // ~TrackObjectPresentationParticles
// ----------------------------------------------------------------------------
void TrackObjectPresentationParticles::updateGraphics(float dt)
{
if (m_emitter != NULL)
{
m_emitter->update(dt);
}
if (m_delayed_stop)
{
if (m_delayed_stop_time < 0.0f)
{
m_delayed_stop = false;
stop();
}
m_delayed_stop_time -= dt;
}
} // update
// ----------------------------------------------------------------------------
void TrackObjectPresentationParticles::triggerParticles()
{
#ifndef SERVER_ONLY
if (m_emitter != NULL)
{
m_emitter->setCreationRateAbsolute(1.0f);
m_emitter->setParticleType(m_emitter->getParticlesInfo());
}
#endif
} // triggerParticles
// ----------------------------------------------------------------------------
void TrackObjectPresentationParticles::stop()
{
#ifndef SERVER_ONLY
if (m_emitter != NULL)
{
m_emitter->setCreationRateAbsolute(0.0f);
}
#endif
}
// ----------------------------------------------------------------------------
void TrackObjectPresentationParticles::stopIn(double delay)
{
m_delayed_stop = true;
m_delayed_stop_time = delay;
}
// ----------------------------------------------------------------------------
void TrackObjectPresentationParticles::setRate(float rate)
{
#ifndef SERVER_ONLY
if (m_emitter != NULL)
{
m_emitter->setCreationRateAbsolute(rate);
m_emitter->setParticleType(m_emitter->getParticlesInfo());
}
#endif
} // setRate
// ----------------------------------------------------------------------------
TrackObjectPresentationLight::TrackObjectPresentationLight(
const XMLNode& xml_node,
scene::ISceneNode* parent)
: TrackObjectPresentationSceneNode(xml_node)
{
m_color.set(0);
xml_node.get("color", &m_color);
const video::SColorf colorf(m_color);
m_energy = 1.0f;
xml_node.get("energy", &m_energy);
m_distance = 20.f * m_energy;
xml_node.get("distance", &m_distance);
#ifndef SERVER_ONLY
if (CVS->isGLSL())
{
m_node = irr_driver->addLight(m_init_xyz, m_energy, m_distance,
colorf.r, colorf.g, colorf.b, false,
parent);
}
else
#endif
{
m_node = NULL; // lights require shaders to work
}
} // TrackObjectPresentationLight
// ----------------------------------------------------------------------------
TrackObjectPresentationLight::~TrackObjectPresentationLight()
{
} // ~TrackObjectPresentationLight
// ----------------------------------------------------------------------------
void TrackObjectPresentationLight::setEnergy(float energy)
{
m_energy = energy;
LightNode* lnode = dynamic_cast<LightNode*>(m_node);
if (lnode != NULL)
{
lnode->setEnergy(energy);
}
}
// ----------------------------------------------------------------------------
void TrackObjectPresentationLight::setEnable(bool enabled)
{
if (m_node != NULL)
m_node->setVisible(enabled);
} // setEnable
// ----------------------------------------------------------------------------
TrackObjectPresentationActionTrigger::TrackObjectPresentationActionTrigger(
const XMLNode& xml_node,
TrackObject* parent)
: TrackObjectPresentation(xml_node)
{
float trigger_distance = 1.0f;
xml_node.get("distance", &trigger_distance);
xml_node.get("action", &m_action );
std::string trigger_type;
xml_node.get("trigger-type", &trigger_type);
if (trigger_type == "point" || trigger_type.empty())
{
m_type = TRIGGER_TYPE_POINT;
}
else if (trigger_type == "cylinder")
{
m_type = TRIGGER_TYPE_CYLINDER;
}
else
{
assert(false);
}
m_xml_reenable_timeout = 999999.9f;
xml_node.get("reenable-timeout", &m_xml_reenable_timeout);
setReenableTimeout(0.0f);
if (m_action.empty())
{
Log::warn("TrackObject", "Action-trigger has no action defined.");
return;
}
if (parent != NULL)
{
core::vector3df parent_xyz = parent->getInitXYZ();
core::vector3df parent_rot = parent->getInitRotation();
core::vector3df parent_scale = parent->getInitScale();
core::matrix4 lm, sm, rm;
lm.setTranslation(parent_xyz);
sm.setScale(parent_scale);
rm.setRotationDegrees(parent_rot);
core::matrix4 abs_trans = lm * rm * sm;
m_library_id = parent->getID();
m_library_name = parent->getName();
xml_node.get("triggered-object", &m_triggered_object);
if (!m_library_id.empty() && !m_triggered_object.empty() &&
!m_library_name.empty())
{
abs_trans.transformVect(m_init_xyz);
}
}
if (m_type == TRIGGER_TYPE_POINT)
{
Track::getCurrentTrack()->getCheckManager()->add(
new CheckTrigger(m_init_xyz, trigger_distance, std::bind(
&TrackObjectPresentationActionTrigger::onTriggerItemApproached,
this, std::placeholders::_1)));
}
else if (m_type == TRIGGER_TYPE_CYLINDER)
{
Track::getCurrentTrack()->getCheckManager()->add(new CheckCylinder(xml_node, std::bind(
&TrackObjectPresentationActionTrigger::onTriggerItemApproached,
this, std::placeholders::_1)));
}
else
{
assert(false);
}
} // TrackObjectPresentationActionTrigger
// ----------------------------------------------------------------------------
TrackObjectPresentationActionTrigger::TrackObjectPresentationActionTrigger(
const core::vector3df& xyz,
const std::string& script_name,
float distance)
: TrackObjectPresentation(xyz)
{
m_init_xyz = xyz;
m_init_hpr = core::vector3df(0, 0, 0);
m_init_scale = core::vector3df(1, 1, 1);
float trigger_distance = distance;
m_action = script_name;
m_xml_reenable_timeout = 999999.9f;
setReenableTimeout(0.0f);
m_type = TRIGGER_TYPE_POINT;
Track::getCurrentTrack()->getCheckManager()->add(
new CheckTrigger(m_init_xyz, trigger_distance, std::bind(
&TrackObjectPresentationActionTrigger::onTriggerItemApproached,
this, std::placeholders::_1)));
} // TrackObjectPresentationActionTrigger
// ----------------------------------------------------------------------------
void TrackObjectPresentationActionTrigger::onTriggerItemApproached(int kart_id)
{
if (m_reenable_timeout > StkTime::getMonoTimeMs() ||
STKProcess::getType() == PT_CHILD)
{
return;
}
setReenableTimeout(m_xml_reenable_timeout);
if (!m_library_id.empty() && !m_triggered_object.empty() &&
!m_library_name.empty())
{
Scripting::ScriptEngine::getInstance()->runFunction(true, "void "
+ m_library_name + "::" + m_action +
"(int, const string, const string)", [=](asIScriptContext* ctx)
{
ctx->SetArgDWord(0, kart_id);
ctx->SetArgObject(1, &m_library_id);
ctx->SetArgObject(2, &m_triggered_object);
});
}
else
{
Scripting::ScriptEngine::getInstance()->runFunction(true,
"void " + m_action + "(int)", [=](asIScriptContext* ctx)
{
ctx->SetArgDWord(0, kart_id);
});
}
} // onTriggerItemApproached