Skip to content

Commit

Permalink
Synced all particles to simulation time.
Browse files Browse the repository at this point in the history
Particles fixed: exhausts, cparticles, turboprops, turbojets, terrain object particles.

Known issue: Particle time to live still runs on real time - this appears to be a bug in OGRE.

Overview of changes:
* Created helper `GfxScene::AdjustParticleSystemTimeFactor()`, applied to all particle systems in game.
* Exhausts and CParticles moved from Actor (actor.h + simdata.h) to GfxActor (gfxactor.h + gfxdata.h).
* Terrain object particle systems are now stored in vector<> in order to update their pace.
  • Loading branch information
ohlidalp committed Jul 31, 2024
1 parent 9843b20 commit b6812a6
Show file tree
Hide file tree
Showing 20 changed files with 195 additions and 176 deletions.
9 changes: 6 additions & 3 deletions source/main/ForwardDeclarations.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,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;

Expand Down Expand Up @@ -180,8 +183,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;
Expand Down
8 changes: 1 addition & 7 deletions source/main/gfx/DustPool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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>() == 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();
Expand Down
94 changes: 85 additions & 9 deletions source/main/gfx/GfxActor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,6 +283,54 @@ RoR::GfxActor::~GfxActor()
HandleGenericException(WhereFrom(this, "destroying renderdash"), HANDLEGENERICEXCEPTION_LOGFILE);
}
}

// delete exhausts
for (std::vector<Exhaust>::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()
Expand Down Expand Up @@ -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)
{
Expand All @@ -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;
Expand Down Expand Up @@ -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);
}
}
}
Expand Down
14 changes: 11 additions & 3 deletions source/main/gfx/GfxActor.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,13 @@ class GfxActor
void RegisterCabMesh(Ogre::Entity* ent, Ogre::SceneNode* snode, FlexObj* flexobj);
void SortFlexbodies();

// Retrieving elements

std::vector<FlexBody*>& GetFlexbodies() { return m_flexbodies; };
std::vector<Prop>& getProps() { return m_props; }
std::vector<CParticle>& getCParticles() { return m_cparticles; }
std::vector<Exhaust>& getExhausts() { return m_exhausts; }

// Visual changes

void SetMaterialFlareOn(int flare_index, bool state_on);
Expand Down Expand Up @@ -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);
Expand All @@ -132,20 +140,18 @@ class GfxActor
void CalculateDriverPos(Ogre::Vector3& out_pos, Ogre::Quaternion& out_rot);
int GetActorId() const;
int GetActorState() const;
std::vector<FlexBody*>& 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; }
int FetchNumBeams() const ;
int FetchNumNodes() const ;
int FetchNumWheelNodes() const ;
bool HasDriverSeatProp() const { return m_driverseat_prop_index != -1; }
void CalcPropAnimation(PropAnim& anim, float& cstate, int& div, float dt);
std::vector<Prop>& getProps() { return m_props; }
bool hasCamera() { return m_videocameras.size() > 0; }
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; }
Expand Down Expand Up @@ -195,6 +201,8 @@ class GfxActor
DustPool* m_particles_ripple = nullptr;
DustPool* m_particles_sparks = nullptr;
DustPool* m_particles_clump = nullptr;
std::vector<CParticle> m_cparticles;
std::vector<Exhaust> m_exhausts;

// Cab mesh ('submesh' in truck fileformat)
FlexObj* m_cab_mesh = nullptr;
Expand Down
17 changes: 17 additions & 0 deletions source/main/gfx/GfxData.h
Original file line number Diff line number Diff line change
Expand Up @@ -314,6 +314,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
11 changes: 11 additions & 0 deletions source/main/gfx/GfxScene.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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>() == SimState::RUNNING && !App::GetGameContext()->GetActorManager()->IsSimulationPaused())
{
speed_factor = m_simbuf.simbuf_sim_speed;
}

psys->setSpeedFactor(speed_factor);
}
4 changes: 4 additions & 0 deletions source/main/gfx/GfxScene.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions source/main/gfx/SimBuffers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
6 changes: 3 additions & 3 deletions source/main/gui/panels/GUI_TopMenubar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1888,12 +1888,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();
Expand All @@ -1902,7 +1902,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,
Expand Down
4 changes: 2 additions & 2 deletions source/main/gui/panels/GUI_VehicleButtons.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -810,7 +810,7 @@ void VehicleButtons::DrawTransferCaseGearRatioButton(RoR::GfxActor* actorx)

void VehicleButtons::DrawParticlesButton(RoR::GfxActor* actorx)
{
if (actorx->GetActor()->ar_num_custom_particles == 0)
if (actorx->getCParticles().size() == 0)
{
ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true);
ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f);
Expand All @@ -829,7 +829,7 @@ void VehicleButtons::DrawParticlesButton(RoR::GfxActor* actorx)
actorx->GetActor()->toggleCustomParticles();
}

if (actorx->GetActor()->ar_num_custom_particles == 0)
if (actorx->getCParticles().size() == 0)
{
ImGui::PopItemFlag();
ImGui::PopStyleVar();
Expand Down
Loading

0 comments on commit b6812a6

Please sign in to comment.