Skip to content

Commit

Permalink
🎮 Added prop animation source dashboard
Browse files Browse the repository at this point in the history
This allows the modder to use any input source from the dashboard system (https://docs.rigsofrods.org/vehicle-creation/making-custom-hud/#input-sources) to be used as input source for prop animation (https://docs.rigsofrods.org/vehicle-creation/fileformat-truck/#add_animation).

The new source name is 'dashboard' and the data link is specified by 'link: ' argument.

Below is an example showing 2 ways to have parking-brake animation: the old direct source and the new method via dashboard:
```
; STANDARD:
7,3,6,   0.125, 0.68, -0.02,   -90,0,0    beacon.mesh
add_animation 180, 0, 0, source: parking , mode: x-rotation
; DASHBOARD:
7,3,6,   0.12, 0.15,  -0.02,     -90,0,0    redbeacon.mesh
add_animation 180, 0, 0, source: dashboard,  mode: x-rotation, link:parkingbrake
```
  • Loading branch information
ohlidalp committed Apr 14, 2024
1 parent 04fb5da commit 891aba2
Show file tree
Hide file tree
Showing 6 changed files with 128 additions and 93 deletions.
11 changes: 10 additions & 1 deletion source/main/gfx/GfxActor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "AirBrake.h"
#include "Actor.h"
#include "Collisions.h"
#include "DashBoardManager.h"
#include "DustPool.h" // General particle gfx
#include "EngineSim.h"
#include "GameContext.h"
Expand Down Expand Up @@ -2789,13 +2790,21 @@ void RoR::GfxActor::UpdatePropAnimations(float dt)
this->CalcPropAnimation(anim, cstate, div, dt);

// key triggered animations - state determined in simulation
if (anim.animFlags & ANIM_FLAG_EVENT)
if (anim.animFlags & PROP_ANIM_FLAG_EVENT)
{
ROR_ASSERT(prop_anim_key_index < (int)m_simbuf.simbuf_prop_anim_keys.size());
const bool anim_active = m_simbuf.simbuf_prop_anim_keys[prop_anim_key_index++].simbuf_anim_active;
cstate += (float)anim_active;
}

// dashboard animations - state determined in simulation
if (anim.animFlags & PROP_ANIM_FLAG_DASHBOARD)
{
int link_id = (int)anim.animOpt3;
ROR_ASSERT(link_id < DD_MAX);
cstate += m_actor->ar_dashboard->getNumeric(link_id);
}

//propanimation placed here to avoid interference with existing hydros(cstate) and permanent prop animation
//land vehicle steering
if (anim.animFlags & PROP_ANIM_FLAG_STEERING)
Expand Down
73 changes: 36 additions & 37 deletions source/main/gfx/GfxData.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,41 +39,40 @@ namespace RoR {
/// @addtogroup Gfx
/// @{

enum PropAnimFlag
{
PROP_ANIM_FLAG_AIRSPEED = BITMASK(1),
PROP_ANIM_FLAG_VVI = BITMASK(2),
PROP_ANIM_FLAG_ALTIMETER = BITMASK(3),
PROP_ANIM_FLAG_AOA = BITMASK(4),
PROP_ANIM_FLAG_FLAP = BITMASK(5),
PROP_ANIM_FLAG_AIRBRAKE = BITMASK(6),
PROP_ANIM_FLAG_ROLL = BITMASK(7),
PROP_ANIM_FLAG_PITCH = BITMASK(8),
PROP_ANIM_FLAG_THROTTLE = BITMASK(9),
PROP_ANIM_FLAG_RPM = BITMASK(10),
PROP_ANIM_FLAG_ACCEL = BITMASK(11),
PROP_ANIM_FLAG_BRAKE = BITMASK(12),
PROP_ANIM_FLAG_CLUTCH = BITMASK(13),
PROP_ANIM_FLAG_TACHO = BITMASK(14),
PROP_ANIM_FLAG_SPEEDO = BITMASK(15),
PROP_ANIM_FLAG_PBRAKE = BITMASK(16),
PROP_ANIM_FLAG_TURBO = BITMASK(17),
PROP_ANIM_FLAG_SHIFTER = BITMASK(18),
PROP_ANIM_FLAG_AETORQUE = BITMASK(19),
PROP_ANIM_FLAG_AEPITCH = BITMASK(20),
PROP_ANIM_FLAG_AESTATUS = BITMASK(21),
PROP_ANIM_FLAG_TORQUE = BITMASK(22),
PROP_ANIM_FLAG_HEADING = BITMASK(23),
PROP_ANIM_FLAG_DIFFLOCK = BITMASK(24),
PROP_ANIM_FLAG_STEERING = BITMASK(25),
PROP_ANIM_FLAG_EVENT = BITMASK(26),
PROP_ANIM_FLAG_AILERONS = BITMASK(27),
PROP_ANIM_FLAG_ARUDDER = BITMASK(28),
PROP_ANIM_FLAG_BRUDDER = BITMASK(29),
PROP_ANIM_FLAG_BTHROTTLE = BITMASK(30),
PROP_ANIM_FLAG_PERMANENT = BITMASK(31),
PROP_ANIM_FLAG_ELEVATORS = BITMASK(32),
};

static const BitMask64_t PROP_ANIM_FLAG_AIRSPEED = BITMASK64(1);
static const BitMask64_t PROP_ANIM_FLAG_VVI = BITMASK64(2);
static const BitMask64_t PROP_ANIM_FLAG_ALTIMETER = BITMASK64(3);
static const BitMask64_t PROP_ANIM_FLAG_AOA = BITMASK64(4);
static const BitMask64_t PROP_ANIM_FLAG_FLAP = BITMASK64(5);
static const BitMask64_t PROP_ANIM_FLAG_AIRBRAKE = BITMASK64(6);
static const BitMask64_t PROP_ANIM_FLAG_ROLL = BITMASK64(7);
static const BitMask64_t PROP_ANIM_FLAG_PITCH = BITMASK64(8);
static const BitMask64_t PROP_ANIM_FLAG_THROTTLE = BITMASK64(9);
static const BitMask64_t PROP_ANIM_FLAG_RPM = BITMASK64(10);
static const BitMask64_t PROP_ANIM_FLAG_ACCEL = BITMASK64(11);
static const BitMask64_t PROP_ANIM_FLAG_BRAKE = BITMASK64(12);
static const BitMask64_t PROP_ANIM_FLAG_CLUTCH = BITMASK64(13);
static const BitMask64_t PROP_ANIM_FLAG_TACHO = BITMASK64(14);
static const BitMask64_t PROP_ANIM_FLAG_SPEEDO = BITMASK64(15);
static const BitMask64_t PROP_ANIM_FLAG_PBRAKE = BITMASK64(16);
static const BitMask64_t PROP_ANIM_FLAG_TURBO = BITMASK64(17);
static const BitMask64_t PROP_ANIM_FLAG_SHIFTER = BITMASK64(18);
static const BitMask64_t PROP_ANIM_FLAG_AETORQUE = BITMASK64(19);
static const BitMask64_t PROP_ANIM_FLAG_AEPITCH = BITMASK64(20);
static const BitMask64_t PROP_ANIM_FLAG_AESTATUS = BITMASK64(21);
static const BitMask64_t PROP_ANIM_FLAG_TORQUE = BITMASK64(22);
static const BitMask64_t PROP_ANIM_FLAG_HEADING = BITMASK64(23);
static const BitMask64_t PROP_ANIM_FLAG_DIFFLOCK = BITMASK64(24);
static const BitMask64_t PROP_ANIM_FLAG_STEERING = BITMASK64(25);
static const BitMask64_t PROP_ANIM_FLAG_EVENT = BITMASK64(26);
static const BitMask64_t PROP_ANIM_FLAG_AILERONS = BITMASK64(27);
static const BitMask64_t PROP_ANIM_FLAG_ARUDDER = BITMASK64(28);
static const BitMask64_t PROP_ANIM_FLAG_BRUDDER = BITMASK64(29);
static const BitMask64_t PROP_ANIM_FLAG_BTHROTTLE = BITMASK64(30);
static const BitMask64_t PROP_ANIM_FLAG_PERMANENT = BITMASK64(31);
static const BitMask64_t PROP_ANIM_FLAG_ELEVATORS = BITMASK64(32);
static const BitMask64_t PROP_ANIM_FLAG_DASHBOARD = BITMASK64(33); //!< Used with dashboard system inputs, see `enum DashData` in file DashBoardManager.h

enum PropAnimMode
{
Expand All @@ -88,7 +87,6 @@ enum PropAnimMode
PROP_ANIM_MODE_BOUNCE = BITMASK(9),
};

inline PropAnimFlag operator|=(PropAnimFlag& dst, PropAnimFlag const& arg) { dst = static_cast<PropAnimFlag>(dst|arg); return dst; }
inline PropAnimMode operator|=(PropAnimMode& dst, PropAnimMode const& arg) { dst = static_cast<PropAnimMode>(dst|arg); return dst; }

enum class VideoCamState
Expand Down Expand Up @@ -137,13 +135,14 @@ enum ShifterPropAnim
struct PropAnim
{
float animratio = 0; //!< A coefficient for the animation, prop degree if used with mode: rotation and propoffset if used with mode: offset.
PropAnimFlag animFlags = {};
BitMask64_t animFlags = 0ull;
PropAnimMode animMode = {};

/// MULTIPURPOSE
/// * SHIFTER type `ShifterPropAnim` (1 = shifterman1, 2 = shifterman2, 3 = shifterseq, 4 = shifterlin)
/// * AEROENGINE number (starting from 1), applies to: rpm + throttle + torque ( turboprop ) + pitch ( turboprop ) + status + fire
/// * ALTIMETER type (1 = 100k limited, 2 = 10k oscillating, 3 = 1k oscillating)
/// * DASHBOARD input (see `enum DashData` in file DashBoardManager.h)
float animOpt3 = 0;
float animOpt5 = 0;
float lower_limit = 0; //!< The lower limit for the animation
Expand Down
59 changes: 38 additions & 21 deletions source/main/physics/ActorSpawner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1974,9 +1974,45 @@ void ActorSpawner::ProcessProp(RigDef::Prop & def)
anim.animOpt3 = static_cast<float>(source_itor->motor);
}
}

// Source 'event' - make sure there is parameter 'event:'
if (BITMASK_IS_1(anim_def.source, RigDef::Animation::SOURCE_EVENT) &&
anim_def.event_name != "")
{
int event_id = RoR::App::GetInputEngine()->resolveEventName(anim_def.event_name);
if (event_id == -1)
{
AddMessage(Message::TYPE_ERROR, "Unknown animation event: " + anim_def.event_name);
}
else
{
PropAnimKeyState state;
state.eventlock_present = BITMASK_IS_1(anim_def.mode, RigDef::Animation::MODE_EVENT_LOCK);
state.event_id = static_cast<events>(event_id);
m_actor->m_prop_anim_key_states.push_back(state);
BITMASK_SET_1(anim.animFlags, PROP_ANIM_FLAG_EVENT);
}
}

// Source 'dashboard' - make sure there is parameter 'link:'
if (BITMASK_IS_1(anim_def.source, RigDef::Animation::SOURCE_DASHBOARD) &&
anim_def.dash_link_name != "")
{
int link_id = m_actor->ar_dashboard->getLinkIDForName(anim_def.dash_link_name);
if (link_id == -1)
{
AddMessage(Message::TYPE_ERROR, "Unknown animation dashboard link: " + anim_def.dash_link_name);
}
else
{
BITMASK_SET_1(anim.animFlags, PROP_ANIM_FLAG_DASHBOARD);
anim.animOpt3 = static_cast<float>(link_id);
}
}

if (anim.animFlags == 0)
{
AddMessage(Message::TYPE_ERROR, "Failed to identify animation source");
AddMessage(Message::TYPE_ERROR, fmt::format("Prop (mesh: '{}') will not be animated, no valid `source` was set.", def.mesh_name));
}

/* Anim modes */
Expand All @@ -2000,7 +2036,7 @@ void ActorSpawner::ProcessProp(RigDef::Prop & def)
}
if (anim.animMode == 0)
{
AddMessage(Message::TYPE_ERROR, "Failed to identify animation mode");
AddMessage(Message::TYPE_ERROR, fmt::format("Prop (mesh: '{}') will not be animated, no valid `mode` was set.", def.mesh_name));
}

if (BITMASK_IS_1(anim_def.mode, RigDef::Animation::MODE_AUTO_ANIMATE))
Expand Down Expand Up @@ -2046,25 +2082,6 @@ void ActorSpawner::ProcessProp(RigDef::Prop & def)
anim.animOpt5 = 1.f;
}

// Parameter 'event:'
if (BITMASK_IS_1(anim_def.source, RigDef::Animation::SOURCE_EVENT) &&
anim_def.event_name != "")
{
int event_id = RoR::App::GetInputEngine()->resolveEventName(anim_def.event_name);
if (event_id == -1)
{
AddMessage(Message::TYPE_ERROR, "Unknown animation event: " + anim_def.event_name);
}
else
{
PropAnimKeyState state;
state.eventlock_present = BITMASK_IS_1(anim_def.mode, RigDef::Animation::MODE_EVENT_LOCK);
state.event_id = static_cast<events>(event_id);
m_actor->m_prop_anim_key_states.push_back(state);
BITMASK_SET_1(anim.animFlags, PROP_ANIM_FLAG_EVENT);
}
}

prop.pp_animations.push_back(anim);
}

Expand Down
68 changes: 35 additions & 33 deletions source/main/resources/rig_def_fileformat/RigDef_File.h
Original file line number Diff line number Diff line change
Expand Up @@ -488,38 +488,39 @@ struct Animation
};

// Source flags
static const BitMask_t SOURCE_AIRSPEED = BITMASK( 1);
static const BitMask_t SOURCE_VERTICAL_VELOCITY = BITMASK( 2);
static const BitMask_t SOURCE_ALTIMETER_100K = BITMASK( 3);
static const BitMask_t SOURCE_ALTIMETER_10K = BITMASK( 4);
static const BitMask_t SOURCE_ALTIMETER_1K = BITMASK( 5);
static const BitMask_t SOURCE_ANGLE_OF_ATTACK = BITMASK( 6);
static const BitMask_t SOURCE_FLAP = BITMASK( 7);
static const BitMask_t SOURCE_AIR_BRAKE = BITMASK( 8);
static const BitMask_t SOURCE_ROLL = BITMASK( 9);
static const BitMask_t SOURCE_PITCH = BITMASK(10);
static const BitMask_t SOURCE_BRAKES = BITMASK(11);
static const BitMask_t SOURCE_ACCEL = BITMASK(12);
static const BitMask_t SOURCE_CLUTCH = BITMASK(13);
static const BitMask_t SOURCE_SPEEDO = BITMASK(14);
static const BitMask_t SOURCE_TACHO = BITMASK(15);
static const BitMask_t SOURCE_TURBO = BITMASK(16);
static const BitMask_t SOURCE_PARKING = BITMASK(17);
static const BitMask_t SOURCE_SHIFT_LEFT_RIGHT = BITMASK(18);
static const BitMask_t SOURCE_SHIFT_BACK_FORTH = BITMASK(19);
static const BitMask_t SOURCE_SEQUENTIAL_SHIFT = BITMASK(20);
static const BitMask_t SOURCE_SHIFTERLIN = BITMASK(21);
static const BitMask_t SOURCE_TORQUE = BITMASK(22);
static const BitMask_t SOURCE_HEADING = BITMASK(23);
static const BitMask_t SOURCE_DIFFLOCK = BITMASK(24);
static const BitMask_t SOURCE_BOAT_RUDDER = BITMASK(25);
static const BitMask_t SOURCE_BOAT_THROTTLE = BITMASK(26);
static const BitMask_t SOURCE_STEERING_WHEEL = BITMASK(27);
static const BitMask_t SOURCE_AILERON = BITMASK(28);
static const BitMask_t SOURCE_ELEVATOR = BITMASK(29);
static const BitMask_t SOURCE_AIR_RUDDER = BITMASK(30);
static const BitMask_t SOURCE_PERMANENT = BITMASK(31);
static const BitMask_t SOURCE_EVENT = BITMASK(32);
static const BitMask64_t SOURCE_AIRSPEED = BITMASK64( 1);
static const BitMask64_t SOURCE_VERTICAL_VELOCITY = BITMASK64( 2);
static const BitMask64_t SOURCE_ALTIMETER_100K = BITMASK64( 3);
static const BitMask64_t SOURCE_ALTIMETER_10K = BITMASK64( 4);
static const BitMask64_t SOURCE_ALTIMETER_1K = BITMASK64( 5);
static const BitMask64_t SOURCE_ANGLE_OF_ATTACK = BITMASK64( 6);
static const BitMask64_t SOURCE_FLAP = BITMASK64( 7);
static const BitMask64_t SOURCE_AIR_BRAKE = BITMASK64( 8);
static const BitMask64_t SOURCE_ROLL = BITMASK64( 9);
static const BitMask64_t SOURCE_PITCH = BITMASK64(10);
static const BitMask64_t SOURCE_BRAKES = BITMASK64(11);
static const BitMask64_t SOURCE_ACCEL = BITMASK64(12);
static const BitMask64_t SOURCE_CLUTCH = BITMASK64(13);
static const BitMask64_t SOURCE_SPEEDO = BITMASK64(14);
static const BitMask64_t SOURCE_TACHO = BITMASK64(15);
static const BitMask64_t SOURCE_TURBO = BITMASK64(16);
static const BitMask64_t SOURCE_PARKING = BITMASK64(17);
static const BitMask64_t SOURCE_SHIFT_LEFT_RIGHT = BITMASK64(18);
static const BitMask64_t SOURCE_SHIFT_BACK_FORTH = BITMASK64(19);
static const BitMask64_t SOURCE_SEQUENTIAL_SHIFT = BITMASK64(20);
static const BitMask64_t SOURCE_SHIFTERLIN = BITMASK64(21);
static const BitMask64_t SOURCE_TORQUE = BITMASK64(22);
static const BitMask64_t SOURCE_HEADING = BITMASK64(23);
static const BitMask64_t SOURCE_DIFFLOCK = BITMASK64(24);
static const BitMask64_t SOURCE_BOAT_RUDDER = BITMASK64(25);
static const BitMask64_t SOURCE_BOAT_THROTTLE = BITMASK64(26);
static const BitMask64_t SOURCE_STEERING_WHEEL = BITMASK64(27);
static const BitMask64_t SOURCE_AILERON = BITMASK64(28);
static const BitMask64_t SOURCE_ELEVATOR = BITMASK64(29);
static const BitMask64_t SOURCE_AIR_RUDDER = BITMASK64(30);
static const BitMask64_t SOURCE_PERMANENT = BITMASK64(31);
static const BitMask64_t SOURCE_EVENT = BITMASK64(32);
static const BitMask64_t SOURCE_DASHBOARD = BITMASK64(33);

// Mode flags
static const BitMask_t MODE_ROTATION_X = BITMASK(1);
Expand All @@ -536,10 +537,11 @@ struct Animation
float ratio = 0.f;
float lower_limit = -1.f;
float upper_limit = -1.f;
BitMask_t source = 0;
BitMask64_t source = 0ull;
std::list<MotorSource> motor_sources;
BitMask_t mode = 0;
Ogre::String event_name;
Ogre::String dash_link_name;

void AddMotorSource(BitMask_t source, unsigned int motor);
};
Expand Down
8 changes: 7 additions & 1 deletion source/main/resources/rig_def_fileformat/RigDef_Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1125,7 +1125,7 @@ void Parser::ParseDirectiveAddAnimation()

else { snprintf(warn_msg, WARN_LEN, "Invalid keyword: %s", entry[0].c_str()); }
}
else if (entry.size() == 2 && (entry[0] == "mode" || entry[0] == "event" || entry[0] == "source"))
else if (entry.size() == 2 && (entry[0] == "mode" || entry[0] == "event" || entry[0] == "source" || entry[0] == "link"))
{
Ogre::StringVector values = Ogre::StringUtil::split(entry[1], "|");
if (entry[0] == "mode")
Expand All @@ -1151,6 +1151,11 @@ void Parser::ParseDirectiveAddAnimation()
Ogre::StringUtil::trim(animation.event_name);
Ogre::StringUtil::toUpperCase(animation.event_name);
}
else if (entry[0] == "link")
{
animation.dash_link_name = entry[1];
Ogre::StringUtil::trim(animation.dash_link_name);
}
else if (entry[0] == "source")
{
for (auto itor = values.begin(); itor != values.end(); ++itor)
Expand Down Expand Up @@ -1190,6 +1195,7 @@ void Parser::ParseDirectiveAddAnimation()
else if (value == "rudderair") { animation.source |= Animation::SOURCE_AIR_RUDDER; }
else if (value == "permanent") { animation.source |= Animation::SOURCE_PERMANENT; }
else if (value == "event") { animation.source |= Animation::SOURCE_EVENT; }
else if (value == "dashboard") { animation.source |= Animation::SOURCE_DASHBOARD; }

else
{
Expand Down
2 changes: 2 additions & 0 deletions source/main/utils/BitFlags.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
/// @file
/// @brief Bit operations
typedef uint32_t BitMask_t;
typedef uint64_t BitMask64_t;

#define BITMASK( OFFSET ) ( 1 << ((OFFSET) - 1) )
#define BITMASK64( OFFSET ) ( 1ull << ((OFFSET) - 1ull) )

#define BITMASK_IS_0( VAR, FLAGS ) ( ((VAR) & (FLAGS)) == 0 )
#define BITMASK_IS_1( VAR, FLAGS ) ( ((VAR) & (FLAGS)) == (FLAGS) )
Expand Down

0 comments on commit 891aba2

Please sign in to comment.