Skip to content

Commit

Permalink
NBUtil/export: added cinecam + override node masses
Browse files Browse the repository at this point in the history
FEATURE CHANGES:
* There's a new checkbox in the NBUtil: "Override all node masses?" - if unchecked, the TotalMass slider doesn't affec the export. If checked, all nodes will get the 'l' flag and weight override parameter. This is the only way to propagate the slider setting to the truck file.
    !KNOWN BUG! The total mass inflates every time the checkbox is used - probably because the dry_mass/load_mass globals are unchanged and wheel nodes still abide it.
* The cinecam was added to the export.

CODE CHANGES:
* Actor.h: some fields/funcs renamed and moved around.
* Actor.cpp - the export function moved to new file 'ActorExport.cpp'
  • Loading branch information
ohlidalp committed Oct 9, 2024
1 parent 3a60698 commit dbe6ca3
Show file tree
Hide file tree
Showing 6 changed files with 273 additions and 183 deletions.
1 change: 1 addition & 0 deletions source/main/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ set(SOURCE_FILES
network/RoRnet.h
physics/Actor.{h,cpp}
physics/ApproxMath.h
physics/ActorExport.cpp
physics/ActorForcesEuler.cpp
physics/ActorManager.{h,cpp}
physics/ActorSlideNode.cpp
Expand Down
2 changes: 2 additions & 0 deletions source/main/gui/panels/GUI_NodeBeamUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ void NodeBeamUtils::Draw()
req->mpr_target_actor = actor;
App::GetGameContext()->PushMessage(Message(MSG_EDI_MODIFY_PROJECT_REQUESTED, req));
}
ImGui::Checkbox(_LC("NodeBeamUtils", "Override all node masses"), &actor->ar_nb_export_override_all_node_masses);
ImGui::Dummy(ImVec2(5, 5));
}

ImGui::PushItemWidth(500.f); // Width includes [+/-] buttons
Expand Down
186 changes: 10 additions & 176 deletions source/main/physics/Actor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -715,8 +715,11 @@ void Actor::calcNetwork()
m_net_initialized = true;
}

void Actor::RecalculateNodeMasses(Real total)
void Actor::recalculateNodeMasses()
{
// Originally `calc_masses2(Real total, bool reCalc)`, where `total` was always the dry mass.
// ------------------------------------------------------------------------------------------

//reset
for (int i = 0; i < ar_num_nodes; i++)
{
Expand Down Expand Up @@ -750,7 +753,7 @@ void Actor::RecalculateNodeMasses(Real total)
{
if (ar_beams[i].bm_type != BEAM_VIRTUAL)
{
Real half_mass = ar_beams[i].L * total / len / 2.0f;
Real half_mass = ar_beams[i].L * m_dry_mass / len / 2.0f;
if (!ar_beams[i].p1->nd_tyre_node)
ar_beams[i].p1->mass += half_mass;
if (!ar_beams[i].p2->nd_tyre_node)
Expand Down Expand Up @@ -4470,6 +4473,11 @@ void Actor::setMass(float m)
m_dry_mass = m;
}

void Actor::setLoadedMass(float m)
{
m_load_mass = m;
}

bool Actor::getCustomLightVisible(int number)
{
if (number < 0 || number >= MAX_CLIGHTS)
Expand Down Expand Up @@ -4779,177 +4787,3 @@ int Actor::getShockNode2(int shock_number)
}
return -1.f;
}

void Actor::propagateNodeBeamChangesToDef()
{
// PROOF OF CONCEPT:
// * assumes 'section/end_section' is not used (=only root module exists)
// * uses dummy 'set_beam_defaults' and 'detacher_group' for the hookbeams (nodes with 'h' option)
// * doesn't separate out 'set_beam_defaults_scale' from 'set_beam_defaults'
// * uses only 'set_default_minimass', ignores global 'minimass'
// * ignores 'detacher_group' for the hookbeams (nodes with 'h' option)
// -------------------------------------------------------------------------

using namespace RigDef;

// Purge old data
m_used_actor_entry->actor_def->root_module->nodes.clear();
m_used_actor_entry->actor_def->root_module->beams.clear();

// Prepare 'set_node_defaults' with builtin values.
auto node_defaults = std::shared_ptr<NodeDefaults>(new NodeDefaults); // comes pre-filled

// Prepare 'set_default_minimass' with builtin values.
auto default_minimass = std::shared_ptr<DefaultMinimass>(new DefaultMinimass());
default_minimass->min_mass_Kg = DEFAULT_MINIMASS;

// Prepare 'set_beam_defaults' with builtin values.
auto beam_defaults = std::shared_ptr<BeamDefaults>(new BeamDefaults);
beam_defaults->springiness = DEFAULT_SPRING;
beam_defaults->damping_constant = DEFAULT_DAMP;
beam_defaults->deformation_threshold = BEAM_DEFORM;
beam_defaults->breaking_threshold = BEAM_BREAK;
beam_defaults->visual_beam_diameter = DEFAULT_BEAM_DIAMETER;

// Prepare 'detacher_group' with builtin values.
int detacher_group = DEFAULT_DETACHER_GROUP;

// ~~~ Nodes ~~~

Vector3 pivot = this->getRotationCenter();
pivot.y = App::GetGameContext()->GetTerrain()->GetHeightAt(pivot.x, pivot.z);
for (NodeNum_t i = 0; i < ar_num_nodes; i++)
{
if (ar_nodes[i].nd_rim_node || ar_nodes[i].nd_tyre_node || ar_nodes[i].nd_cinecam_node)
{
// Skip wheel nodes and cinecam nodes
continue;
}

// Check if 'set_node_defaults' must be updated.
float n_loadweight = ar_nodes_default_loadweights[i];
float n_friction = ar_nodes[i].friction_coef;
float n_volume = ar_nodes[i].volume_coef;
float n_surface = ar_nodes[i].surface_coef;
if (node_defaults->load_weight != n_loadweight
|| node_defaults->friction != n_friction
|| node_defaults->surface != n_surface
|| node_defaults->volume != n_volume)
{
node_defaults = std::shared_ptr<NodeDefaults>(new NodeDefaults);
node_defaults->load_weight = n_loadweight;
node_defaults->friction = n_friction;
node_defaults->surface = n_surface;
node_defaults->volume = n_volume;
}

// Check if 'set_default_minimass' needs update.
if (default_minimass->min_mass_Kg != ar_minimass[i])
{
default_minimass = std::shared_ptr<DefaultMinimass>(new DefaultMinimass());
default_minimass->min_mass_Kg = ar_minimass[i];
}

// Build the node
RigDef::Node node;
node.node_defaults = node_defaults;
node.default_minimass = default_minimass;
node.beam_defaults = beam_defaults; // Needed for hookbeams (nodes with 'h' option)
node.detacher_group = detacher_group; // Needed for hookbeams (nodes with 'h' option)
if (ar_nodes_name[i] != "")
{
node.id = RigDef::Node::Id(ar_nodes_name[i]);
}
else
{
node.id = RigDef::Node::Id(ar_nodes_id[i]);
}
node.position = ar_initial_node_positions[i] - pivot;
node.load_weight_override = ar_nodes_override_loadweights[i];
node._has_load_weight_override = (node.load_weight_override >= 0.0f);
node.options = ar_nodes_options[i];

// Submit the node
m_used_actor_entry->actor_def->root_module->nodes.push_back(node);
}

// ~~~ Beams ~~~

for (int i = 0; i < ar_num_beams; i++)
{
if (!ar_beams_user_defined[i])
{
// Skip everything not from 'beams' (wheels/cinecam/hooknode/wings/rotators etc...)
continue;
}

// Check if 'set_beam_defaults' must be updated.
float b_spring = ar_beams[i].k;
float b_damp = ar_beams[i].d;
float b_deform = ar_beams[i].default_beam_deform;
float b_break = ar_beams[i].strength;
if (beam_defaults->springiness != b_spring
|| beam_defaults->damping_constant != b_damp
|| beam_defaults->deformation_threshold != b_deform
|| beam_defaults->breaking_threshold != b_break)
{
beam_defaults = std::shared_ptr<BeamDefaults>(new BeamDefaults);
beam_defaults->springiness = b_spring;
beam_defaults->damping_constant = b_damp;
beam_defaults->deformation_threshold = b_deform;
beam_defaults->breaking_threshold = b_break;
}

// Check if 'detacher_group' needs update.
if (detacher_group != ar_beams[i].detacher_group)
{
detacher_group = ar_beams[i].detacher_group;
}

// Build the beam
RigDef::Beam beam;
beam.defaults = beam_defaults;
beam.detacher_group = detacher_group;
beam.extension_break_limit = ar_beams[i].longbound;

if (ar_beams[i].bounded == SUPPORTBEAM)
{
beam._has_extension_break_limit = true;
beam.options |= RigDef::Beam::OPTION_s_SUPPORT;
}
else if (ar_beams[i].bounded == ROPE)
{
beam.options |= RigDef::Beam::OPTION_r_ROPE;
}

if (ar_beams_invisible[i])
{
beam.options |= RigDef::Beam::OPTION_i_INVISIBLE;
}

// Build refs to the nodes
const BitMask_t nodeflags = RigDef::Node::Ref::REGULAR_STATE_IS_VALID;
NodeNum_t n1 = ar_beams[i].p1->pos;
if (ar_nodes_name[n1] != "")
{
beam.nodes[0] = RigDef::Node::Ref(ar_nodes_name[n1], 0, nodeflags, 0);
}
else
{
beam.nodes[0] = RigDef::Node::Ref(fmt::format("{}", ar_nodes_id[n1]), ar_nodes_id[n1], nodeflags, 0);
}

NodeNum_t n2 = ar_beams[i].p2->pos;
if (ar_nodes_name[n2] != "")
{
beam.nodes[1] = RigDef::Node::Ref(ar_nodes_name[n2], 0, nodeflags, 0);
}
else
{
beam.nodes[1] = RigDef::Node::Ref(fmt::format("{}", ar_nodes_id[n2]), ar_nodes_id[n2], nodeflags, 0);
}

// Submit the beam
m_used_actor_entry->actor_def->root_module->beams.push_back(beam);
}
}
19 changes: 13 additions & 6 deletions source/main/physics/Actor.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,13 @@ class Actor : public RefCountingObject<Actor>
// PLEASE maintain the same order as in 'scripting/bindings/ActorAngelscript.cpp' and 'doc/angelscript/.../BeamClass.h'
void scaleTruck(float value);
void setMass(float m);
void setLoadedMass(float m);
// not exported to scripting:
void applyNodeBeamScales(); //!< For GUI::NodeBeamUtils
void searchBeamDefaults(); //!< Searches for more stable beam defaults
void updateInitPosition();
void propagateNodeBeamChangesToDef(); //!< Back-propagates changes done by N/B-utils UI to the def-document.
void recalculateNodeMasses();
/// @}

/// @name User interaction
Expand Down Expand Up @@ -276,6 +278,15 @@ class Actor : public RefCountingObject<Actor>

// -------------------- Public data -------------------- //

/// @name Mass
/// @{
float m_dry_mass = 0.f; //!< User-defined; from 'globals' arg#1 - default for all nodes
float m_load_mass = 0.f; //!< User-defined; from 'globals' arg#2 - only applies to nodes with 'l' flag
int m_masscount = 0; //!< Calculated; Number of nodes loaded with l option
float m_total_mass = 0.f; //!< Calculated; total mass in Kg
float ar_initial_total_mass = 0.f; //!< Calculated; total mass in Kg (snapshot at spawn)
/// @}

// Node data (split to layers)
node_t* ar_nodes = nullptr;
int* ar_nodes_id = nullptr; //!< Number in truck file, -1 for nodes generated by wheels/cinecam
Expand Down Expand Up @@ -319,7 +330,7 @@ class Actor : public RefCountingObject<Actor>
Ogre::AxisAlignedBox ar_bounding_box; //!< standard bounding box (surrounds all nodes of an actor)
Ogre::AxisAlignedBox ar_evboxes_bounding_box; //!< bounding box around nodes eligible for eventbox triggering
Ogre::AxisAlignedBox ar_predicted_bounding_box;
float ar_initial_total_mass = 0.f;



std::vector<wheeldetacher_t> ar_wheeldetachers;
Expand Down Expand Up @@ -466,6 +477,7 @@ class Actor : public RefCountingObject<Actor>

// Realtime node/beam structure editing helpers
bool ar_nb_initialized = false;
bool ar_nb_export_override_all_node_masses = false;
std::vector<float> ar_nb_optimum; //!< Temporary storage of the optimum search result
std::vector<float> ar_nb_reference; //!< Temporary storage of the reference search result
int ar_nb_skip_steps = 0; //!< Amount of physics steps to be skipped before measuring
Expand Down Expand Up @@ -525,7 +537,6 @@ class Actor : public RefCountingObject<Actor>
void CalcWheels(bool doUpdate, int num_steps);

void DetermineLinkedActors();
void RecalculateNodeMasses(Ogre::Real total); //!< Previously 'calc_masses2()'
void calcNodeConnectivityGraph();
void AddInterActorBeam(beam_t* beam, ActorPtr other, ActorLinkingRequestType type); //!< Do not call directly - use `MSG_SIM_ACTOR_LINKING_REQUESTED`
void RemoveInterActorBeam(beam_t* beam, ActorLinkingRequestType type); //!< Do not call directly - use `MSG_SIM_ACTOR_LINKING_REQUESTED`
Expand Down Expand Up @@ -566,7 +577,6 @@ class Actor : public RefCountingObject<Actor>
Ogre::Vector3 m_avg_node_velocity = Ogre::Vector3::ZERO; //!< average node velocity (compared to the previous frame step)
float m_stabilizer_shock_sleep = 0.f; //!< Sim state
Replay* m_replay_handler = nullptr;
float m_total_mass = 0.f; //!< Physics state; total mass in Kg
NodeNum_t m_mouse_grab_node = NODENUM_INVALID; //!< Sim state; node currently being dragged by user
Ogre::Vector3 m_mouse_grab_pos = Ogre::Vector3::ZERO;
float m_mouse_grab_move_force = 0.f;
Expand All @@ -593,9 +603,6 @@ class Actor : public RefCountingObject<Actor>
float m_odometer_total = 0.f; //!< GUI state
float m_odometer_user = 0.f; //!< GUI state
int m_num_command_beams = 0; //!< TODO: Remove! Spawner context only; likely unused feature
float m_load_mass = 0.f; //!< Physics attr; predefined load mass in Kg
int m_masscount = 0; //!< Physics attr; Number of nodes loaded with l option
float m_dry_mass = 0.f; //!< Physics attr;
std::unique_ptr<Buoyance> m_buoyance; //!< Physics
CacheEntryPtr m_used_actor_entry;
CacheEntryPtr m_used_skin_entry; //!< Graphics
Expand Down
Loading

0 comments on commit dbe6ca3

Please sign in to comment.