Skip to content

Commit

Permalink
🎮 Added videocamera flipping to Tuning UI
Browse files Browse the repository at this point in the history
The full `addonpart_tweak_videocamera` mechanism wasn't implemented, only the UI override.
  • Loading branch information
ohlidalp committed Mar 9, 2025
1 parent 9d78fec commit 2417275
Show file tree
Hide file tree
Showing 8 changed files with 154 additions and 8 deletions.
3 changes: 3 additions & 0 deletions source/main/ForwardDeclarations.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ namespace RoR
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;

typedef int VideoCameraID_t; //!< Index into `GfxActor::m_videocameras`, use `RoR::VIDEOCAMERAID_INVALID` as empty value
static const VideoCameraID_t VIDEOCAMERAID_INVALID = -1;

typedef int ScriptRetCode_t; //!< see enum `RoR::ScriptRetCode` - combines AngelScript codes and RoR internal codes.

typedef int TerrainEditorObjectID_t; //!< Offset into `RoR::TerrainObjectManager::m_editor_objects`, use `RoR::TERRAINEDITOROBJECTID_INVALID` as empty value.
Expand Down
4 changes: 3 additions & 1 deletion source/main/gfx/GfxData.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,14 +220,16 @@ struct Prop
/// either in-scene texture or external window.
struct VideoCamera
{
VideoCamRole vcam_role = VCAM_ROLE_INVALID;
VideoCamRole vcam_role = VCAM_ROLE_INVALID; //!< Active role assigned at spawn (i.e. TRACKING if tracking node was set)
VideoCamRole vcam_role_orig = VCAM_ROLE_INVALID; //!< User-defined role from rig-def file, may be different from final active role.
NodeNum_t vcam_node_center = NODENUM_INVALID;
NodeNum_t vcam_node_dir_y = NODENUM_INVALID;
NodeNum_t vcam_node_dir_z = NODENUM_INVALID;
NodeNum_t vcam_node_alt_pos = NODENUM_INVALID;
NodeNum_t vcam_node_lookat = NODENUM_INVALID; //!< Only for VCAM_ROLE_TRACK_CAM
Ogre::Quaternion vcam_rotation;
Ogre::Vector3 vcam_pos_offset = Ogre::Vector3::ZERO;
std::string vcam_mat_name_orig; //!< For display in Tuning UI: Original material name from rig-def file, without per-actor stamping
Ogre::MaterialPtr vcam_material;
std::string vcam_off_tex_name; //!< Used when videocamera is offline
Ogre::Camera* vcam_ogre_camera = nullptr;
Expand Down
82 changes: 82 additions & 0 deletions source/main/gui/panels/GUI_TopMenubar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1939,6 +1939,88 @@ void TopMenubar::Draw(float dt)
ImGui::PopID(); // material_name.c_str()
}
}

// Draw videocameras
size_t total_videocameras = tuning_actor->GetGfxActor()->getVideoCameras().size();
std::string videocameras_title = fmt::format(_LC("Tuning", "Videocameras ({})"), total_videocameras);
if (ImGui::CollapsingHeader(videocameras_title.c_str()))
{
// Draw all videocameras (those removed by addonparts are also present as placeholders)
for (VideoCameraID_t videocameraid = 0; videocameraid < (int)total_videocameras; videocameraid++)
{
ImGui::PushID(videocameraid);
ImGui::AlignTextToFramePadding();

this->DrawTuningBoxedSubjectIdInline(videocameraid);

VideoCamRole current_role_def = tuning_actor->GetGfxActor()->getVideoCameras()[videocameraid].vcam_role_orig;
if (current_role_def != VCAM_ROLE_MIRROR && current_role_def != VCAM_ROLE_MIRROR_NOFLIP)
{
// Tuning menu is limited to only switch MIRROR/MIRROR_NOFLIP, so not-mirrors can be ignored.
ImGui::TextDisabled("(Not a mirror)");
}
else
{
// Draw RTT material name
ImGui::SameLine();
ImGui::Dummy(ImVec2(3, 3));
ImGui::SameLine();
ImGui::Text("%s", tuning_actor->GetGfxActor()->getVideoCameras()[videocameraid].vcam_mat_name_orig.c_str());

// Setup the 'forced' state orange styling

VideoCamRole forced_role_def = VCAM_ROLE_INVALID;
if (tuneup_def && tuneup_def->isVideoCameraRoleForced(videocameraid, /*[out]*/forced_role_def))
{
ImGui::PushStyleColor(ImGuiCol_Border, ORANGE_TEXT);
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1.f);
}

// Draw the 'flipped' checkbox
ImGui::SameLine();
const bool current_flipped = current_role_def == VCAM_ROLE_MIRROR;
bool requested_flipped = current_flipped;
ImGui::Checkbox("Flipped", &requested_flipped);

// Draw reset button and reset the orange styling

bool resetPressed = false;
if (tuneup_def && tuneup_def->isVideoCameraRoleForced(videocameraid, /*[out]*/forced_role_def))
{
ImGui::SameLine();
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Text, GRAY_HINT_TEXT);
resetPressed = ImGui::SmallButton(_LC("Tuning", "Reset"));
ImGui::PopStyleColor(); //ImGuiCol_Text, GRAY_HINT_TEXT
ImGui::PopStyleVar(); //ImGuiStyleVar_FrameBorderSize, 1.f
ImGui::PopStyleColor(); //ImGuiCol_Border, ORANGE_TEXT
}

// modify project if needed
if (current_flipped != requested_flipped)
{
const VideoCamRole desired_role = (requested_flipped) ? VCAM_ROLE_MIRROR : VCAM_ROLE_MIRROR_NOFLIP;

ModifyProjectRequest* req = new ModifyProjectRequest();
req->mpr_type = ModifyProjectRequestType::TUNEUP_FORCED_VCAM_ROLE_SET;
req->mpr_subject_id = videocameraid;
req->mpr_value_int = (int)desired_role;
req->mpr_target_actor = tuning_actor;
App::GetGameContext()->PushMessage(Message(MSG_EDI_MODIFY_PROJECT_REQUESTED, req));
}
else if (resetPressed)
{
ModifyProjectRequest* req = new ModifyProjectRequest();
req->mpr_type = ModifyProjectRequestType::TUNEUP_FORCED_VCAM_ROLE_RESET;
req->mpr_subject_id = videocameraid;
req->mpr_target_actor = tuning_actor;
App::GetGameContext()->PushMessage(Message(MSG_EDI_MODIFY_PROJECT_REQUESTED, req));
}
}

ImGui::PopID(); // videocameraid
}
}
}

m_open_menu_hoverbox_min = menu_pos - MENU_HOVERBOX_PADDING;
Expand Down
12 changes: 8 additions & 4 deletions source/main/physics/ActorSpawner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6979,15 +6979,19 @@ void ActorSpawner::CreateVideoCamera(RigDef::VideoCamera* def)
{
try
{
auto videocameraid = (VideoCameraID_t)m_actor->m_gfx_actor->m_videocameras.size();
RoR::VideoCamera vcam;

vcam.vcam_role = def->camera_role;
const VideoCamRole tweaked_role = TuneupUtil::getTweakedVideoCameraRole(m_actor->getWorkingTuneupDef(), videocameraid, def->camera_role);
vcam.vcam_role_orig = tweaked_role;
vcam.vcam_role = vcam.vcam_role_orig;
if (vcam.vcam_role == VCAM_ROLE_INVALID)
{
this->AddMessage(Message::TYPE_ERROR, "VideoCamera (mat: " + def->material_name + ") has invalid 'role': " + TOSTRING(def->camera_role));
this->AddMessage(Message::TYPE_ERROR, fmt::format("Skipping VideoCamera (mat: {}) with invalid 'role' ({})", def->material_name, (int)vcam.vcam_role_orig));
return;
}

vcam.vcam_mat_name_orig = def->material_name;
vcam.vcam_material = this->FindOrCreateCustomizedMaterial(def->material_name, m_custom_resource_group);
if (vcam.vcam_material.isNull())
{
Expand All @@ -7002,7 +7006,7 @@ void ActorSpawner::CreateVideoCamera(RigDef::VideoCamera* def)

//rotate camera picture 180 degrees, skip for mirrors
float rotation_z = def->rotation.z + 180;
if (def->camera_role == VCAM_ROLE_MIRROR || def->camera_role == VCAM_ROLE_MIRROR_NOFLIP)
if (tweaked_role == VCAM_ROLE_MIRROR || tweaked_role == VCAM_ROLE_MIRROR_NOFLIP)
{
rotation_z += 180.0f;
}
Expand Down Expand Up @@ -7075,7 +7079,7 @@ void ActorSpawner::CreateVideoCamera(RigDef::VideoCamera* def)
vcam.vcam_material->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureName(vcam.vcam_render_tex->getName());

// this is a mirror, flip the image left<>right to have a mirror and not a cameraimage
if (def->camera_role == VCAM_ROLE_MIRROR)
if (tweaked_role == VCAM_ROLE_MIRROR)
vcam.vcam_material->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureUScale(-1);
}

Expand Down
10 changes: 10 additions & 0 deletions source/main/resources/CacheSystem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2117,6 +2117,16 @@ void CacheSystem::ModifyProject(ModifyProjectRequest* request)
request->mpr_target_actor->getWorkingTuneupDef()->protected_managedmats.erase(request->mpr_subject);
break;

case ModifyProjectRequestType::TUNEUP_FORCED_VCAM_ROLE_SET:
request->mpr_target_actor->ensureWorkingTuneupDef();
request->mpr_target_actor->getWorkingTuneupDef()->force_video_cam_roles[request->mpr_subject_id] = (VideoCamRole)request->mpr_value_int;
break;

case ModifyProjectRequestType::TUNEUP_FORCED_VCAM_ROLE_RESET:
request->mpr_target_actor->ensureWorkingTuneupDef();
request->mpr_target_actor->getWorkingTuneupDef()->force_video_cam_roles.erase(request->mpr_subject_id);
break;

case ModifyProjectRequestType::PROJECT_LOAD_TUNEUP:
{
// Instead of loading with the saved tuneup directly, keep the autogenerated and sync it with the save.
Expand Down
4 changes: 3 additions & 1 deletion source/main/resources/CacheSystem.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ enum class ModifyProjectRequestType
TUNEUP_FORCEREMOVE_PROP_RESET, //!< 'subject_id' is prop ID.
TUNEUP_FORCEREMOVE_FLEXBODY_SET, //!< 'subject_id' is flexbody ID.
TUNEUP_FORCEREMOVE_FLEXBODY_RESET, //!< 'subject_id' is flexbody ID.
TUNEUP_FORCED_WHEEL_SIDE_SET, //!< 'subject_id' is wheel ID, 'value_int' is RoR::WheelSide
TUNEUP_FORCED_WHEEL_SIDE_SET, //!< 'subject_id' is wheel ID, 'value_int' is `RoR::WheelSide`
TUNEUP_FORCED_WHEEL_SIDE_RESET, //!< 'subject_id' is wheel ID.
TUNEUP_FORCEREMOVE_FLARE_SET, //!< 'subject_id' is flare ID.
TUNEUP_FORCEREMOVE_FLARE_RESET, //!< 'subject_id' is flare ID.
Expand All @@ -243,6 +243,8 @@ enum class ModifyProjectRequestType
TUNEUP_PROTECTED_EXHAUST_RESET, //!< 'subject_id' is exhaust ID.
TUNEUP_PROTECTED_MANAGEDMAT_SET, //!< 'subject' is managed material name.
TUNEUP_PROTECTED_MANAGEDMAT_RESET, //!< 'subject' is managed material name.
TUNEUP_FORCED_VCAM_ROLE_SET, //!< 'subject_id' is video camera ID, 'value_int' is `RoR::VideoCamRole`
TUNEUP_FORCED_VCAM_ROLE_RESET, //!< 'subject_id' is video camera ID.
PROJECT_LOAD_TUNEUP, //!< 'subject' is tuneup filename. This overwrites the auto-generated tuneup with the save.
PROJECT_RESET_TUNEUP, //!< 'subject' is empty. This resets the auto-generated tuneup to orig. values.
};
Expand Down
40 changes: 38 additions & 2 deletions source/main/resources/tuneup_fileformat/TuneupFileFormat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,10 @@ TuneupDefPtr TuneupDef::clone()
// nodes
ret->protected_nodes = this->protected_nodes;
ret->node_tweaks = this->node_tweaks;


// video cameras
ret->force_video_cam_roles = this->force_video_cam_roles;

// flares
ret->protected_flares = this->protected_flares;

Expand Down Expand Up @@ -110,7 +113,10 @@ void TuneupDef::reset()
// nodes
this->protected_nodes.clear();
this->node_tweaks.clear();


// video cameras
this->force_video_cam_roles.clear();

// flares
this->protected_flares.clear();

Expand All @@ -135,6 +141,20 @@ bool TuneupDef::isWheelSideForced(WheelID_t wheelid, WheelSide& out_val) const
}
}

bool TuneupDef::isVideoCameraRoleForced(VideoCameraID_t camera_id, VideoCamRole& out_val) const
{
auto itor = force_video_cam_roles.find(camera_id);
if (itor != force_video_cam_roles.end())
{
out_val = itor->second;
return true;
}
else
{
return false;
}
}

// Tweaking helpers

float RoR::TuneupUtil::getTweakedWheelTireRadius(TuneupDefPtr& tuneup_def, WheelID_t wheel_id, float orig_val)
Expand Down Expand Up @@ -233,6 +253,22 @@ WheelSide RoR::TuneupUtil::getTweakedWheelSide(TuneupDefPtr& tuneup_def, WheelID
return orig_val;
}

VideoCamRole RoR::TuneupUtil::getTweakedVideoCameraRole(TuneupDefPtr& tuneup_def, VideoCameraID_t camera_id, VideoCamRole orig_val)
{
if (tuneup_def)
{
VideoCamRole forced_role = VCAM_ROLE_INVALID;
if (tuneup_def->isVideoCameraRoleForced(camera_id, forced_role))
{
return forced_role;
}

// STUB: actual tweaking isn't implemented yet
}

return orig_val;
}

bool RoR::TuneupUtil::isWheelTweaked(TuneupDefPtr& tuneup_def, WheelID_t wheel_id, TuneupWheelTweak*& out_tweak)
{

Expand Down
7 changes: 7 additions & 0 deletions source/main/resources/tuneup_fileformat/TuneupFileFormat.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ struct TuneupDef: public RefCountingObject<TuneupDef>
std::set<PropID_t> force_remove_props; //!< UI overrides
std::set<FlexbodyID_t> force_remove_flexbodies; //!< UI overrides
std::map<WheelID_t, WheelSide> force_wheel_sides; //!< UI overrides
std::map<VideoCameraID_t, VideoCamRole> force_video_cam_roles; //!< UI overrides
std::set<FlareID_t> force_remove_flares; //!< User unticked an UI checkbox in Tuning menu, section Flares.
std::set<ExhaustID_t> force_remove_exhausts; //!< User unticked an UI checkbox in Tuning menu, section Exhausts.
std::set<std::string> force_remove_managedmats;//!< User unticked an UI checkbox in Tuning menu, section Managed Materials.
Expand Down Expand Up @@ -172,6 +173,7 @@ struct TuneupDef: public RefCountingObject<TuneupDef>
bool isFlareForceRemoved(FlareID_t flareid) { return force_remove_flares.find(flareid) != force_remove_flares.end(); }
bool isExhaustForceRemoved(ExhaustID_t exhaustid) { return force_remove_exhausts.find(exhaustid) != force_remove_exhausts.end(); }
bool isManagedMatForceRemoved(const std::string& matname) { return force_remove_managedmats.find(matname) != force_remove_managedmats.end(); }
bool isVideoCameraRoleForced(VideoCameraID_t camera_id, VideoCamRole& out_val) const;
/// @}
};

Expand Down Expand Up @@ -242,6 +244,11 @@ class TuneupUtil
static bool isManagedMatTweaked(TuneupDefPtr& tuneup_def, const std::string& matname, TuneupManagedMatTweak*& out_tweak);
/// @}

/// @name VideoCamera helpers
/// @{
static VideoCamRole getTweakedVideoCameraRole(TuneupDefPtr& tuneup_def, VideoCameraID_t camera_id, VideoCamRole orig_val);
/// @}

private:

static void ParseTuneupAttribute(const std::string& line, TuneupDefPtr& tuneup_def);
Expand Down

0 comments on commit 2417275

Please sign in to comment.