diff --git a/source/main/ForwardDeclarations.h b/source/main/ForwardDeclarations.h index 723f0ec84e..0750a3c42c 100644 --- a/source/main/ForwardDeclarations.h +++ b/source/main/ForwardDeclarations.h @@ -69,9 +69,12 @@ namespace RoR typedef int FlareID_t; //!< Index into `Actor::ar_flares`, use `RoR::FLAREID_INVALID` as empty value static const FlareID_t FLAREID_INVALID = -1; - typedef int ExhaustID_t; //!< Index into `Actor::exhausts`, use `RoR::EXHAUSTID_INVALID` as empty value + typedef int ExhaustID_t; //!< Index into `GfxActor::m_exhausts`, use `RoR::EXHAUSTID_INVALID` as empty value static const ExhaustID_t EXHAUSTID_INVALID = -1; + typedef int CParticleID_t; //!< Index into `GfxActor::m_cparticles`, use `RoR::CPARTICLEID_INVALID` as empty value + static const CParticleID_t CPARTICLEID_INVALID = -1; + typedef int CommandkeyID_t; //!< Index into `Actor::ar_commandkeys` (BEWARE: indexed 1-MAX_COMMANDKEYS, 0 is invalid value, negative subscript of any size is acceptable, see `class CmdKeyArray` ). static const CommandkeyID_t COMMANDKEYID_INVALID = 0; @@ -187,8 +190,8 @@ namespace RoR struct rotator_t; struct flare_t; struct rope_t; - struct exhaust_t; - struct cparticle_t; + struct Exhaust; + struct CParticle; struct collision_box_t; struct tie_t; struct hook_t; diff --git a/source/main/gfx/DustPool.cpp b/source/main/gfx/DustPool.cpp index 8664a25bf2..95520632c8 100644 --- a/source/main/gfx/DustPool.cpp +++ b/source/main/gfx/DustPool.cpp @@ -194,15 +194,9 @@ void DustPool::allocRipple(Vector3 pos, Vector3 vel) void DustPool::update() { - float speed_factor = 0.f; - if (App::sim_state->getEnum() == SimState::RUNNING && !App::GetGameContext()->GetActorManager()->IsSimulationPaused()) - { - speed_factor = App::GetGfxScene()->GetSimDataBuffer().simbuf_sim_speed; - } - for (int i = 0; i < allocated; i++) { - pss[i]->setSpeedFactor(speed_factor); + App::GetGfxScene()->AdjustParticleSystemTimeFactor(pss[i]); ParticleEmitter* emit = pss[i]->getEmitter(0); Vector3 ndir = velocities[i]; Real vel = ndir.length(); diff --git a/source/main/gfx/GfxActor.cpp b/source/main/gfx/GfxActor.cpp index 68bddb84cc..bbf88ec676 100644 --- a/source/main/gfx/GfxActor.cpp +++ b/source/main/gfx/GfxActor.cpp @@ -283,6 +283,54 @@ RoR::GfxActor::~GfxActor() HandleGenericException(WhereFrom(this, "destroying renderdash"), HANDLEGENERICEXCEPTION_LOGFILE); } } + + // delete exhausts + for (std::vector::iterator it = m_exhausts.begin(); it != m_exhausts.end(); it++) + { + try + { + if (it->smokeNode) + { + it->smokeNode->removeAndDestroyAllChildren(); + App::GetGfxScene()->GetSceneManager()->destroySceneNode(it->smokeNode); + } + if (it->smoker) + { + it->smoker->removeAllAffectors(); + it->smoker->removeAllEmitters(); + App::GetGfxScene()->GetSceneManager()->destroyParticleSystem(it->smoker); + } + } + catch (...) + { + HandleGenericException(fmt::format("GfxActor::~GfxActor(); instanceID:{}, streamID:{}, filename:{}; deleting exhaust {}/{}.", + m_actor->ar_instance_id, m_actor->ar_net_stream_id, m_actor->ar_filename, std::distance(m_exhausts.begin(), it), m_exhausts.size()), HANDLEGENERICEXCEPTION_LOGFILE); + } + } + + // delete custom particles + for (int i = 0; i < (int)m_cparticles.size(); i++) + { + try + { + if (m_cparticles[i].snode) + { + m_cparticles[i].snode->removeAndDestroyAllChildren(); + App::GetGfxScene()->GetSceneManager()->destroySceneNode(m_cparticles[i].snode); + } + if (m_cparticles[i].psys) + { + m_cparticles[i].psys->removeAllAffectors(); + m_cparticles[i].psys->removeAllEmitters(); + App::GetGfxScene()->GetSceneManager()->destroyParticleSystem(m_cparticles[i].psys); + } + } + catch (...) + { + HandleGenericException(fmt::format("Actor::dispose(); instanceID:{}, streamID:{}, filename:{}; deleting custom particle {}/{}.", + m_actor->ar_instance_id, m_actor->ar_net_stream_id, m_actor->ar_filename, i, m_cparticles.size()), HANDLEGENERICEXCEPTION_LOGFILE); + } + } } ActorPtr RoR::GfxActor::GetActor() @@ -1844,6 +1892,7 @@ void RoR::GfxActor::UpdateSimDataBuffer() m_simbuf.simbuf_clutch = m_actor->ar_engine->GetClutch(); m_simbuf.simbuf_num_gears = m_actor->ar_engine->getNumGears(); m_simbuf.simbuf_engine_max_rpm = m_actor->ar_engine->getMaxRPM(); + m_simbuf.simbuf_engine_smoke = m_actor->ar_engine->GetSmoke(); } if (m_actor->m_num_wheel_diffs > 0) { @@ -1858,6 +1907,7 @@ void RoR::GfxActor::UpdateSimDataBuffer() m_simbuf.simbuf_lightmask = m_actor->m_lightmask; m_simbuf.simbuf_smoke_enabled = m_actor->getSmokeEnabled(); m_simbuf.simbuf_parking_brake = m_actor->ar_parking_brake; + m_simbuf.simbuf_cparticles_active = m_actor->ar_cparticles_active; // Aerial m_simbuf.simbuf_hydro_aileron_state = m_actor->ar_hydro_aileron_state; @@ -1986,19 +2036,45 @@ void RoR::GfxActor::UpdateAirbrakes() } } -// TODO: Also move the data structure + setup code to GfxActor ~ only_a_ptr, 05/2018 void RoR::GfxActor::UpdateCParticles() { - //update custom particle systems - for (int i = 0; i < m_actor->ar_num_custom_particles; i++) + for (CParticle& cparticle: m_cparticles) { - Ogre::Vector3 pos = m_simbuf.simbuf_nodes[m_actor->ar_custom_particles[i].emitterNode].AbsPosition; - Ogre::Vector3 dir = pos - m_simbuf.simbuf_nodes[m_actor->ar_custom_particles[i].directionNode].AbsPosition; - dir = fast_normalise(dir); - m_actor->ar_custom_particles[i].snode->setPosition(pos); - for (int j = 0; j < m_actor->ar_custom_particles[i].psys->getNumEmitters(); j++) + App::GetGfxScene()->AdjustParticleSystemTimeFactor(cparticle.psys); + const Ogre::Vector3 pos = m_simbuf.simbuf_nodes[cparticle.emitterNode].AbsPosition; + const Ogre::Vector3 dir = fast_normalise(pos - m_simbuf.simbuf_nodes[cparticle.directionNode].AbsPosition); + cparticle.snode->setPosition(pos); + + for (unsigned short j = 0; j < cparticle.psys->getNumEmitters(); j++) + { + cparticle.psys->getEmitter(j)->setEnabled(m_simbuf.simbuf_cparticles_active); + cparticle.psys->getEmitter(j)->setDirection(dir); + } + } +} + +void RoR::GfxActor::UpdateExhausts() +{ + if (!m_simbuf.simbuf_has_engine) + return; + + for (Exhaust& exhaust: m_exhausts) + { + if (!exhaust.smoker) // This remains `nullptr` if removed via `addonpart_unwanted_exhaust` or Tuning UI. + continue; + + App::GetGfxScene()->AdjustParticleSystemTimeFactor(exhaust.smoker); + const Ogre::Vector3 pos = m_simbuf.simbuf_nodes[exhaust.emitterNode].AbsPosition; + const Ogre::Vector3 dir = pos - m_simbuf.simbuf_nodes[exhaust.directionNode].AbsPosition; + exhaust.smokeNode->setPosition(pos); + + const bool active = m_simbuf.simbuf_smoke_enabled && m_simbuf.simbuf_engine_smoke != -1.f; + exhaust.smoker->getEmitter(0)->setEnabled(active); + if (active) // `setTimeToLive()` assert()s that argument is not negative. { - m_actor->ar_custom_particles[i].psys->getEmitter(j)->setDirection(dir); + exhaust.smoker->getEmitter(0)->setColour(Ogre::ColourValue(0.0, 0.0, 0.0, 0.02 + m_simbuf.simbuf_engine_smoke * 0.06)); + exhaust.smoker->getEmitter(0)->setTimeToLive((0.02 + m_simbuf.simbuf_engine_smoke * 0.06) / 0.04); + exhaust.smoker->getEmitter(0)->setParticleVelocity(1.0 + m_simbuf.simbuf_engine_smoke * 2.0, 2.0 + m_simbuf.simbuf_engine_smoke * 3.0); } } } diff --git a/source/main/gfx/GfxActor.h b/source/main/gfx/GfxActor.h index 045f83956c..ac4c4a81b8 100644 --- a/source/main/gfx/GfxActor.h +++ b/source/main/gfx/GfxActor.h @@ -66,6 +66,13 @@ class GfxActor void RegisterCabMesh(Ogre::Entity* ent, Ogre::SceneNode* snode, FlexObj* flexobj); void SortFlexbodies(); + // Retrieving elements + + std::vector& GetFlexbodies() { return m_flexbodies; }; + std::vector& getProps() { return m_props; } + std::vector& getCParticles() { return m_cparticles; } + std::vector& getExhausts() { return m_exhausts; } + // Visual changes void SetMaterialFlareOn(int flare_index, bool state_on); @@ -108,6 +115,7 @@ class GfxActor void UpdatePropAnimations(float dt); void UpdateAirbrakes(); void UpdateCParticles(); + void UpdateExhausts(); void UpdateAeroEngines(); void UpdateNetLabels(float dt); void UpdateFlares(float dt, bool is_player); @@ -132,17 +140,15 @@ class GfxActor void CalculateDriverPos(Ogre::Vector3& out_pos, Ogre::Quaternion& out_rot); int GetActorId() const; int GetActorState() const; - std::vector& GetFlexbodies() { return m_flexbodies; }; - Ogre::MaterialPtr& GetCabTransMaterial() { return m_cab_mat_visual_trans; } VideoCamState GetVideoCamState() const { return m_vidcam_state; } DebugViewType GetDebugView() const { return m_debug_view; } Ogre::String GetResourceGroup() { return m_custom_resource_group; } ActorPtr GetActor(); // Watch out for multithreading with this! + Ogre::MaterialPtr& GetCabTransMaterial() { return m_cab_mat_visual_trans; } Ogre::TexturePtr GetHelpTex() { return m_help_tex; } Ogre::MaterialPtr GetHelpMat() { return m_help_mat; } bool HasDriverSeatProp() const { return m_driverseat_prop_index != -1; } void CalcPropAnimation(PropAnim& anim, float& cstate, int& div, float dt); - std::vector& getProps() { return m_props; } size_t getNumVideoCameras() const { return m_videocameras.size(); } SurveyMapEntity& getSurveyMapEntity() { return m_surveymap_entity; } WheelSide getWheelSide(WheelID_t wheel_id) { return (wheel_id >= 0 && (size_t)wheel_id < m_wheels.size()) ? m_wheels[wheel_id].wx_side : WheelSide::INVALID; } @@ -193,6 +199,8 @@ class GfxActor DustPool* m_particles_ripple = nullptr; DustPool* m_particles_sparks = nullptr; DustPool* m_particles_clump = nullptr; + std::vector m_cparticles; + std::vector m_exhausts; // Cab mesh ('submesh' in truck fileformat) FlexObj* m_cab_mesh = nullptr; diff --git a/source/main/gfx/GfxData.h b/source/main/gfx/GfxData.h index d548fa6d8d..ce779ef613 100644 --- a/source/main/gfx/GfxData.h +++ b/source/main/gfx/GfxData.h @@ -316,6 +316,23 @@ struct FlareMaterial // materialflares Ogre::ColourValue emissive_color; }; +struct Exhaust +{ + NodeNum_t emitterNode = NODENUM_INVALID; + NodeNum_t directionNode = NODENUM_INVALID; + Ogre::SceneNode *smokeNode = nullptr; + Ogre::ParticleSystem* smoker = nullptr; //!< This remains `nullptr` if removed via `addonpart_unwanted_exhaust` or Tuning UI. + std::string particleSystemName; //!< Name in .particle file ~ for display in Tuning UI. +}; + +struct CParticle +{ + NodeNum_t emitterNode = NODENUM_INVALID; + NodeNum_t directionNode = NODENUM_INVALID; + Ogre::SceneNode *snode = nullptr; + Ogre::ParticleSystem* psys = nullptr; +}; + /// @} // addtogroup Gfx } // namespace RoR diff --git a/source/main/gfx/GfxScene.cpp b/source/main/gfx/GfxScene.cpp index 93bad10de8..02f527dbb1 100644 --- a/source/main/gfx/GfxScene.cpp +++ b/source/main/gfx/GfxScene.cpp @@ -221,6 +221,7 @@ void GfxScene::UpdateScene(float dt) gfx_actor->UpdateWingMeshes(); gfx_actor->UpdateAirbrakes(); gfx_actor->UpdateCParticles(); + gfx_actor->UpdateExhausts(); gfx_actor->UpdateAeroEngines(); gfx_actor->UpdatePropAnimations(dt_actor); gfx_actor->UpdateRenderdashRTT(); @@ -403,3 +404,13 @@ void GfxScene::DrawNetLabel(Ogre::Vector3 scene_pos, float cam_dist, std::string #endif // USE_SOCKETW } +void GfxScene::AdjustParticleSystemTimeFactor(Ogre::ParticleSystem* psys) +{ + float speed_factor = 0.f; + if (App::sim_state->getEnum() == SimState::RUNNING && !App::GetGameContext()->GetActorManager()->IsSimulationPaused()) + { + speed_factor = m_simbuf.simbuf_sim_speed; + } + + psys->setSpeedFactor(speed_factor); +} \ No newline at end of file diff --git a/source/main/gfx/GfxScene.h b/source/main/gfx/GfxScene.h index b5157818ec..9912285442 100644 --- a/source/main/gfx/GfxScene.h +++ b/source/main/gfx/GfxScene.h @@ -47,8 +47,12 @@ class GfxScene public: void Init(); + + // Particles: void CreateDustPools(); DustPool* GetDustPool(const char* name); + void AdjustParticleSystemTimeFactor(Ogre::ParticleSystem* psys); + void SetParticlesVisible(bool visible); void DrawNetLabel(Ogre::Vector3 pos, float cam_dist, std::string const& nick, int colornum); void UpdateScene(float dt); diff --git a/source/main/gfx/SimBuffers.h b/source/main/gfx/SimBuffers.h index 45bb7b9f1b..ecbf64620c 100644 --- a/source/main/gfx/SimBuffers.h +++ b/source/main/gfx/SimBuffers.h @@ -155,6 +155,7 @@ struct ActorSB float simbuf_clutch = 0; int simbuf_num_gears = 0; //!< Gearbox float simbuf_engine_max_rpm = 0; + float simbuf_engine_smoke = 0; // Tyre pressure float simbuf_tyre_pressure = 0; @@ -164,6 +165,7 @@ struct ActorSB BitMask_t simbuf_lightmask = 0; bool simbuf_smoke_enabled = false; bool simbuf_parking_brake = false; + bool simbuf_cparticles_active = false; // Aerial float simbuf_hydro_aileron_state = 0; diff --git a/source/main/gui/panels/GUI_TopMenubar.cpp b/source/main/gui/panels/GUI_TopMenubar.cpp index 5548b1f1b0..100065a429 100644 --- a/source/main/gui/panels/GUI_TopMenubar.cpp +++ b/source/main/gui/panels/GUI_TopMenubar.cpp @@ -1858,12 +1858,12 @@ void TopMenubar::Draw(float dt) } // Draw exhausts - size_t total_exhausts = tuning_actor->exhausts.size(); + size_t total_exhausts = tuning_actor->GetGfxActor()->getExhausts().size(); std::string exhausts_title = fmt::format(_LC("Tuning", "Exhausts ({})"), total_exhausts); if (ImGui::CollapsingHeader(exhausts_title.c_str())) { // Draw all exhausts (those removed by addonparts are also present as placeholders) - for (ExhaustID_t exhaustid = 0; exhaustid < (int)tuning_actor->exhausts.size(); exhaustid++) + for (ExhaustID_t exhaustid = 0; exhaustid < (int)total_exhausts; exhaustid++) { ImGui::PushID(exhaustid); ImGui::AlignTextToFramePadding(); @@ -1872,7 +1872,7 @@ void TopMenubar::Draw(float dt) this->DrawTuningForceRemoveControls( exhaustid, - tuning_actor->exhausts[exhaustid].particleSystemName, + tuning_actor->GetGfxActor()->getExhausts()[exhaustid].particleSystemName, tuneup_def && tuneup_def->isExhaustUnwanted(exhaustid), tuneup_def && tuneup_def->isExhaustForceRemoved(exhaustid), ModifyProjectRequestType::TUNEUP_FORCEREMOVE_EXHAUST_SET, diff --git a/source/main/gui/panels/GUI_VehicleInfoTPanel.cpp b/source/main/gui/panels/GUI_VehicleInfoTPanel.cpp index 522f3d528d..3b8e7c9e33 100644 --- a/source/main/gui/panels/GUI_VehicleInfoTPanel.cpp +++ b/source/main/gui/panels/GUI_VehicleInfoTPanel.cpp @@ -770,7 +770,7 @@ void VehicleInfoTPanel::DrawVehicleBasicsUI(RoR::GfxActor* actorx) } } - const int num_cparticles = actorx->GetActor()->ar_num_custom_particles; + const int num_cparticles = (int)actorx->getCParticles().size(); const size_t num_videocams = actorx->getNumVideoCameras(); ImGui::TextDisabled("View:"); if (num_cparticles) diff --git a/source/main/physics/Actor.cpp b/source/main/physics/Actor.cpp index 01e54eb29b..b3cf3635a5 100644 --- a/source/main/physics/Actor.cpp +++ b/source/main/physics/Actor.cpp @@ -265,54 +265,6 @@ void Actor::dispose() } this->ar_flares.clear(); - // delete exhausts - for (std::vector::iterator it = exhausts.begin(); it != exhausts.end(); it++) - { - try - { - if (it->smokeNode) - { - it->smokeNode->removeAndDestroyAllChildren(); - App::GetGfxScene()->GetSceneManager()->destroySceneNode(it->smokeNode); - } - if (it->smoker) - { - it->smoker->removeAllAffectors(); - it->smoker->removeAllEmitters(); - App::GetGfxScene()->GetSceneManager()->destroyParticleSystem(it->smoker); - } - } - catch (...) - { - HandleGenericException(fmt::format("Actor::dispose(); instanceID:{}, streamID:{}, filename:{}; deleting exhaust {}/{}.", - ar_instance_id, ar_net_stream_id, ar_filename, std::distance(exhausts.begin(), it), exhausts.size()), HANDLEGENERICEXCEPTION_LOGFILE); - } - } - - // delete custom particles - for (int i = 0; i < ar_num_custom_particles; i++) - { - try - { - if (ar_custom_particles[i].snode) - { - ar_custom_particles[i].snode->removeAndDestroyAllChildren(); - App::GetGfxScene()->GetSceneManager()->destroySceneNode(ar_custom_particles[i].snode); - } - if (ar_custom_particles[i].psys) - { - ar_custom_particles[i].psys->removeAllAffectors(); - ar_custom_particles[i].psys->removeAllEmitters(); - App::GetGfxScene()->GetSceneManager()->destroyParticleSystem(ar_custom_particles[i].psys); - } - } - catch (...) - { - HandleGenericException(fmt::format("Actor::dispose(); instanceID:{}, streamID:{}, filename:{}; deleting custom particle {}/{}.", - ar_instance_id, ar_net_stream_id, ar_filename, i, ar_num_custom_particles), HANDLEGENERICEXCEPTION_LOGFILE); - } - } - // delete Rails for (std::vector::iterator it = m_railgroups.begin(); it != m_railgroups.end(); it++) { @@ -685,7 +637,7 @@ void Actor::calcNetwork() } // set particle cannon - if (((flagmask & NETMASK_PARTICLE) != 0) != m_custom_particles_enabled) + if (((flagmask & NETMASK_PARTICLE) != 0) != ar_cparticles_active) toggleCustomParticles(); m_antilockbrake = flagmask & NETMASK_ALB_ACTIVE; @@ -3191,15 +3143,7 @@ void Actor::toggleCustomParticles() if (ar_state == ActorState::DISPOSED) return; - m_custom_particles_enabled = !m_custom_particles_enabled; - for (int i = 0; i < ar_num_custom_particles; i++) - { - ar_custom_particles[i].active = !ar_custom_particles[i].active; - for (int j = 0; j < ar_custom_particles[i].psys->getNumEmitters(); j++) - { - ar_custom_particles[i].psys->getEmitter(j)->setEnabled(ar_custom_particles[i].active); - } - } + ar_cparticles_active = !ar_cparticles_active; //ScriptEvent - Particle Toggle TRIGGER_EVENT_ASYNC(SE_TRUCK_CPARTICLES_TOGGLE, ar_instance_id); @@ -3242,34 +3186,6 @@ void Actor::updateVisual(float dt) } #endif //openAL - // update exhausts - // TODO: Move to GfxActor, don't forget dt*m_simulation_speed - if (ar_engine && exhausts.size() > 0) - { - std::vector::iterator it; - for (it = exhausts.begin(); it != exhausts.end(); it++) - { - if (!it->smoker) - continue; - Vector3 dir = ar_nodes[it->emitterNode].AbsPosition - ar_nodes[it->directionNode].AbsPosition; - // dir.normalise(); - ParticleEmitter* emit = it->smoker->getEmitter(0); - it->smokeNode->setPosition(ar_nodes[it->emitterNode].AbsPosition); - emit->setDirection(dir); - if (!m_disable_smoke && ar_engine->GetSmoke() != -1.0) - { - emit->setEnabled(true); - emit->setColour(ColourValue(0.0, 0.0, 0.0, 0.02 + ar_engine->GetSmoke() * 0.06)); - emit->setTimeToLive((0.02 + ar_engine->GetSmoke() * 0.06) / 0.04); - } - else - { - emit->setEnabled(false); - } - emit->setParticleVelocity(1.0 + ar_engine->GetSmoke() * 2.0, 2.0 + ar_engine->GetSmoke() * 3.0); - } - } - // Wings (only physics, graphics are updated in GfxActor) float autoaileron = 0; float autorudder = 0; @@ -4456,7 +4372,7 @@ Actor::Actor( , m_water_contact(false) , m_water_contact_old(false) , m_has_command_beams(false) - , m_custom_particles_enabled(false) + , ar_cparticles_active(false) , m_beam_break_debug_enabled(false) , m_beam_deform_debug_enabled(false) , m_trigger_debug_enabled(false) @@ -4565,7 +4481,7 @@ BlinkType Actor::getBlinkType() bool Actor::getCustomParticleMode() { - return m_custom_particles_enabled; + return ar_cparticles_active; } Ogre::Real Actor::getMinimalCameraRadius() diff --git a/source/main/physics/Actor.h b/source/main/physics/Actor.h index f1e811eeef..e0d7195cd7 100644 --- a/source/main/physics/Actor.h +++ b/source/main/physics/Actor.h @@ -296,7 +296,6 @@ class Actor : public RefCountingObject wing_t* ar_wings = nullptr; int ar_num_wings = 0; std::vector authors; - std::vector exhausts; std::vector ar_ropes; std::vector ar_ropables; std::vector ar_ties; @@ -323,8 +322,6 @@ class Actor : public RefCountingObject int ar_num_contacters = 0; //!< Total number of nodes which can selfcontact cabs wheel_t ar_wheels[MAX_WHEELS] = {}; int ar_num_wheels = 0; - cparticle_t ar_custom_particles[MAX_CPARTICLES] = {}; - int ar_num_custom_particles = 0; soundsource_t ar_soundsources[MAX_SOUNDSCRIPTS_PER_TRUCK] = {}; int ar_num_soundsources = 0; AeroEngine* ar_aeroengines[MAX_AEROENGINES] = {}; @@ -483,6 +480,7 @@ class Actor : public RefCountingObject bool ar_toggle_ropes:1; //!< Sim state bool ar_toggle_ties:1; //!< Sim state bool ar_physics_paused:1; //!< Sim state + bool ar_cparticles_active:1;//!< Gfx state private: @@ -627,7 +625,6 @@ class Actor : public RefCountingObject bool m_water_contact:1; //!< Scripting state bool m_water_contact_old:1; //!< Scripting state bool m_has_command_beams:1; //!< Physics attr; - bool m_custom_particles_enabled:1; //!< Gfx state bool m_preloaded_with_terrain:1; //!< Spawn context (TODO: remove!) bool m_beam_break_debug_enabled:1; //!< Logging state bool m_beam_deform_debug_enabled:1; //!< Logging state diff --git a/source/main/physics/ActorSpawner.cpp b/source/main/physics/ActorSpawner.cpp index 46b410b730..30d351ab85 100644 --- a/source/main/physics/ActorSpawner.cpp +++ b/source/main/physics/ActorSpawner.cpp @@ -278,9 +278,6 @@ void ActorSpawner::InitializeRig() m_actor->ar_minimass.resize(req.num_nodes); - m_actor->exhausts.clear(); - memset(m_actor->ar_custom_particles, 0, sizeof(cparticle_t) * MAX_CPARTICLES); - m_actor->ar_num_custom_particles = 0; memset(m_actor->ar_soundsources, 0, sizeof(soundsource_t) * MAX_SOUNDSCRIPTS_PER_TRUCK); m_actor->ar_num_soundsources = 0; memset(m_actor->ar_collcabs, 0, sizeof(int) * MAX_CABS); @@ -1282,8 +1279,8 @@ void ActorSpawner::ProcessExhaust(RigDef::Exhaust & def) return; } - const ExhaustID_t exhaust_id = (ExhaustID_t)m_actor->exhausts.size(); - exhaust_t exhaust; + const ExhaustID_t exhaust_id = (ExhaustID_t)m_actor->m_gfx_actor->m_exhausts.size(); + Exhaust exhaust; exhaust.emitterNode = this->GetNodeIndexOrThrow(def.reference_node); exhaust.directionNode = this->GetNodeIndexOrThrow(def.direction_node); @@ -1296,7 +1293,7 @@ void ActorSpawner::ProcessExhaust(RigDef::Exhaust & def) if (!TuneupUtil::isExhaustAnyhowRemoved(m_actor->getWorkingTuneupDef(), exhaust_id)) { - std::string name = this->ComposeName(template_name.c_str(), (int)m_actor->exhausts.size()); + std::string name = this->ComposeName(template_name.c_str(), (int)m_actor->m_gfx_actor->m_exhausts.size()); exhaust.smoker = this->CreateParticleSystem(name, template_name); if (exhaust.smoker == nullptr) { @@ -1306,7 +1303,7 @@ void ActorSpawner::ProcessExhaust(RigDef::Exhaust & def) return; } - exhaust.smokeNode = m_particles_parent_scenenode->createChildSceneNode(this->ComposeName("exhaust", (int)m_actor->exhausts.size())); + exhaust.smokeNode = m_particles_parent_scenenode->createChildSceneNode(this->ComposeName("exhaust", (int)m_actor->m_gfx_actor->m_exhausts.size())); exhaust.smokeNode->attachObject(exhaust.smoker); exhaust.smokeNode->setPosition(m_actor->ar_nodes[exhaust.emitterNode].AbsPosition); @@ -1314,7 +1311,7 @@ void ActorSpawner::ProcessExhaust(RigDef::Exhaust & def) m_actor->m_gfx_actor->SetNodeHot(exhaust.directionNode, true); } - m_actor->exhausts.push_back(exhaust); + m_actor->m_gfx_actor->m_exhausts.push_back(exhaust); } std::string ActorSpawner::GetSubmeshGroundmodelName() @@ -2896,13 +2893,13 @@ void ActorSpawner::ProcessParticle(RigDef::Particle & def) return; } - int particle_index = m_actor->ar_num_custom_particles; - cparticle_t & particle = m_actor->ar_custom_particles[particle_index]; + CParticleID_t particle_id = static_cast(m_actor->m_gfx_actor->m_cparticles.size()); + CParticle particle; particle.emitterNode = GetNodeIndexOrThrow(def.emitter_node); particle.directionNode = GetNodeIndexOrThrow(def.reference_node); - std::string name = this->ComposeName(def.particle_system_name.c_str(), particle_index); + std::string name = this->ComposeName(def.particle_system_name.c_str(), particle_id); particle.psys = this->CreateParticleSystem(name, def.particle_system_name); if (particle.psys == nullptr) { @@ -2912,18 +2909,17 @@ void ActorSpawner::ProcessParticle(RigDef::Particle & def) return; } - particle.snode = m_particles_parent_scenenode->createChildSceneNode(this->ComposeName("cparticles", m_actor->ar_num_custom_particles)); + particle.snode = m_particles_parent_scenenode->createChildSceneNode(this->ComposeName("cparticles", particle_id)); particle.snode->attachObject(particle.psys); particle.snode->setPosition(m_actor->ar_nodes[particle.emitterNode].AbsPosition); /* Shut down the emitters */ - particle.active = false; for (unsigned int i = 0; i < particle.psys->getNumEmitters(); i++) { particle.psys->getEmitter(i)->setEnabled(false); } - ++m_actor->ar_num_custom_particles; + m_actor->m_gfx_actor->m_cparticles.push_back(particle); } void ActorSpawner::ProcessRopable(RigDef::Ropable & def) @@ -6055,12 +6051,13 @@ void ActorSpawner::AddExhaust( NodeNum_t direction_node_idx ) { - exhaust_t exhaust; + const ExhaustID_t exhaust_id = (ExhaustID_t)m_actor->m_gfx_actor->m_exhausts.size(); + Exhaust exhaust; exhaust.emitterNode = emitter_node_idx; exhaust.directionNode = direction_node_idx; exhaust.smoker = App::GetGfxScene()->GetSceneManager()->createParticleSystem( - this->ComposeName("exhaust", (int)m_actor->exhausts.size()), + this->ComposeName("exhaust", exhaust_id), /*quota=*/500, // Default value m_custom_resource_group); @@ -6074,14 +6071,14 @@ void ActorSpawner::AddExhaust( Ogre::MaterialPtr mat = this->FindOrCreateCustomizedMaterial("tracks/Smoke", m_custom_resource_group); exhaust.smoker->setMaterialName(mat->getName(), mat->getGroup()); - exhaust.smokeNode = m_particles_parent_scenenode->createChildSceneNode(this->ComposeName("exhaust", (int)m_actor->exhausts.size())); + exhaust.smokeNode = m_particles_parent_scenenode->createChildSceneNode(this->ComposeName("exhaust", exhaust_id)); exhaust.smokeNode->attachObject(exhaust.smoker); exhaust.smokeNode->setPosition(m_actor->ar_nodes[exhaust.emitterNode].AbsPosition); m_actor->m_gfx_actor->SetNodeHot(exhaust.emitterNode, true); m_actor->m_gfx_actor->SetNodeHot(exhaust.directionNode, true); - m_actor->exhausts.push_back(exhaust); + m_actor->m_gfx_actor->m_exhausts.push_back(exhaust); } void ActorSpawner::ProcessCinecam(RigDef::Cinecam & def) @@ -6161,18 +6158,6 @@ void ActorSpawner::ProcessGlobals(RigDef::Globals & def) // Limits. /* -------------------------------------------------------------------------- */ -bool ActorSpawner::CheckParticleLimit(unsigned int count) -{ - if ((m_actor->ar_num_custom_particles + count) > MAX_CPARTICLES) - { - std::stringstream msg; - msg << "Particle limit (" << MAX_CPARTICLES << ") exceeded"; - AddMessage(Message::TYPE_ERROR, msg.str()); - return false; - } - return true; -} - bool ActorSpawner::CheckAxleLimit(unsigned int count) { if ((m_actor->m_num_wheel_diffs + count) > MAX_WHEELS/2) diff --git a/source/main/physics/ActorSpawner.h b/source/main/physics/ActorSpawner.h index ecd9ecd2d9..1270bb66f7 100644 --- a/source/main/physics/ActorSpawner.h +++ b/source/main/physics/ActorSpawner.h @@ -362,7 +362,6 @@ class ActorSpawner /// @name Limit checks /// @{ - bool CheckParticleLimit(unsigned int count); bool CheckAxleLimit(unsigned int count); bool CheckSubmeshLimit(unsigned int count); bool CheckTexcoordLimit(unsigned int count); diff --git a/source/main/physics/Savegame.cpp b/source/main/physics/Savegame.cpp index 7baf958379..6a172d54e2 100644 --- a/source/main/physics/Savegame.cpp +++ b/source/main/physics/Savegame.cpp @@ -545,7 +545,7 @@ bool ActorManager::SaveScene(Ogre::String filename) j_entry.AddMember("wheel_speed", actor->ar_wheel_speed, j_doc.GetAllocator()); j_entry.AddMember("wheel_spin", actor->ar_wheel_spin, j_doc.GetAllocator()); - j_entry.AddMember("custom_particles", actor->m_custom_particles_enabled, j_doc.GetAllocator()); + j_entry.AddMember("custom_particles", actor->ar_cparticles_active, j_doc.GetAllocator()); // Flares j_entry.AddMember("lights", (int)actor->getHeadlightsVisible(), j_doc.GetAllocator()); @@ -831,7 +831,7 @@ void ActorManager::RestoreSavedState(ActorPtr actor, rapidjson::Value const& j_e actor->ar_wheel_speed = j_entry["wheel_speed"].GetFloat(); actor->ar_wheel_spin = j_entry["wheel_spin"].GetFloat(); - if (actor->m_custom_particles_enabled != j_entry["custom_particles"].GetBool()) + if (actor->ar_cparticles_active != j_entry["custom_particles"].GetBool()) { actor->toggleCustomParticles(); } diff --git a/source/main/physics/SimData.h b/source/main/physics/SimData.h index 07dde3705f..9fb671fe49 100644 --- a/source/main/physics/SimData.h +++ b/source/main/physics/SimData.h @@ -635,25 +635,6 @@ struct flare_t SimpleInertia inertia; //!< Only 'flares3' }; -struct exhaust_t -{ - NodeNum_t emitterNode = NODENUM_INVALID; - NodeNum_t directionNode = NODENUM_INVALID; - Ogre::SceneNode *smokeNode = nullptr; - Ogre::ParticleSystem* smoker = nullptr; //!< This remains `nullptr` if removed via `addonpart_unwanted_exhaust` or Tuning UI. - std::string particleSystemName; //!< Name in .particle file ~ for display in Tuning UI. -}; - - -struct cparticle_t -{ - NodeNum_t emitterNode = NODENUM_INVALID; - NodeNum_t directionNode = NODENUM_INVALID; - bool active; - Ogre::SceneNode *snode; - Ogre::ParticleSystem* psys; -}; - /// User input state for animated props with 'source:event'. struct PropAnimKeyState { diff --git a/source/main/physics/air/TurboJet.cpp b/source/main/physics/air/TurboJet.cpp index 07d0957f1e..925052b44d 100644 --- a/source/main/physics/air/TurboJet.cpp +++ b/source/main/physics/air/TurboJet.cpp @@ -183,6 +183,7 @@ void TurbojetVisual::UpdateVisuals(RoR::GfxActor* gfx_actor) if (m_smoke_particle && gfx_actor->GetSimDataBuffer().simbuf_smoke_enabled) { + App::GetGfxScene()->AdjustParticleSystemTimeFactor(m_smoke_particle); m_smoke_scenenode->setPosition(node_buf[m_node_back].AbsPosition); ParticleEmitter* emit = m_smoke_particle->getEmitter(0); emit->setDirection(-laxis); diff --git a/source/main/physics/air/TurboProp.cpp b/source/main/physics/air/TurboProp.cpp index 4b2f72b757..0ad08e4cde 100644 --- a/source/main/physics/air/TurboProp.cpp +++ b/source/main/physics/air/TurboProp.cpp @@ -175,6 +175,7 @@ void Turboprop::updateVisuals(RoR::GfxActor* gfx_m_actor) //smoke if (smokeNode) { + App::GetGfxScene()->AdjustParticleSystemTimeFactor(smokePS); smokeNode->setPosition(node_buf[nodeback].AbsPosition); ParticleEmitter* emit = smokePS->getEmitter(0); Vector3 dir = node_buf[nodeback].AbsPosition - node_buf[noderef].AbsPosition; diff --git a/source/main/terrain/TerrainObjectManager.cpp b/source/main/terrain/TerrainObjectManager.cpp index 20697d6533..8aab36208c 100644 --- a/source/main/terrain/TerrainObjectManager.cpp +++ b/source/main/terrain/TerrainObjectManager.cpp @@ -764,6 +764,11 @@ bool TerrainObjectManager::LoadTerrainObject(const Ogre::String& name, const Ogr SceneNode* sn = tenode->createChildSceneNode(); sn->attachObject(pParticleSys); sn->pitch(Degree(90)); + + ParticleEffectObject peo; + peo.node = sn; + peo.psys = pParticleSys; + m_particle_effect_objects.push_back(peo); } if (!odef->mat_name.empty()) @@ -953,10 +958,10 @@ bool TerrainObjectManager::LoadTerrainScript(const Ogre::String& filename) return result != SCRIPTUNITID_INVALID; } -bool TerrainObjectManager::UpdateAnimatedObjects(float dt) +void TerrainObjectManager::UpdateAnimatedObjects(float dt) { if (m_animated_objects.size() == 0) - return true; + return; std::vector::iterator it; @@ -968,7 +973,17 @@ bool TerrainObjectManager::UpdateAnimatedObjects(float dt) it->anim->addTime(time); } } - return true; +} + +void TerrainObjectManager::UpdateParticleEffectObjects() +{ + for (ParticleEffectObject& peo : m_particle_effect_objects) + { + if (peo.psys) + { + App::GetGfxScene()->AdjustParticleSystemTimeFactor(peo.psys); + } + } } void TerrainObjectManager::LoadTelepoints() @@ -1009,6 +1024,7 @@ bool TerrainObjectManager::UpdateTerrainObjects(float dt) } #endif //USE_PAGED this->UpdateAnimatedObjects(dt); + this->UpdateParticleEffectObjects(); return true; } diff --git a/source/main/terrain/TerrainObjectManager.h b/source/main/terrain/TerrainObjectManager.h index 8d6df52c1c..c6e589a66d 100644 --- a/source/main/terrain/TerrainObjectManager.h +++ b/source/main/terrain/TerrainObjectManager.h @@ -124,6 +124,12 @@ class TerrainObjectManager float speedfactor; }; + struct ParticleEffectObject + { + Ogre::ParticleSystem* psys = nullptr; + Ogre::SceneNode* node = nullptr; + }; + struct PredefinedActor { float px; @@ -149,9 +155,10 @@ class TerrainObjectManager RoR::ODefFile* FetchODef(std::string const & odef_name); void ProcessODefCollisionBoxes(StaticObject* obj, ODefFile* odef, const EditorObject& params, bool race_event); - // Misc functions + // Update functions - bool UpdateAnimatedObjects(float dt); + void UpdateAnimatedObjects(float dt); + void UpdateParticleEffectObjects(); // Variables @@ -161,6 +168,7 @@ class TerrainObjectManager std::vector m_editor_objects; std::vector m_predefined_actors; std::vector m_animated_objects; + std::vector m_particle_effect_objects; std::vector m_mesh_objects; SurveyMapEntityVec m_map_entities; Terrain* terrainManager;