// 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 #include #include #include #include #include #include // ---------------------------------------------------------------------------- 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 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 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(m_node); if (ln) { for (scene::ISceneNode* node : ln->getAllNodes()) { scene::IAnimatedMeshSceneNode* a_node = dynamic_cast(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 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 frames_start; if (xml_node) xml_node->get("frame-start", &frames_start); std::vector 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(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