Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🚚 Added videocamera role MIRROR_NOFLIP (2) #3235

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions source/main/Application.h
Original file line number Diff line number Diff line change
Expand Up @@ -370,6 +370,21 @@ enum class TObjSpecialObject
};
const char* TObjSpecialObjectToString(TObjSpecialObject val);

enum VideoCamRole
{
// DO NOT CHANGE NUMBERS, they match 'videocamera/camera_role' parameter in the .truck file

VCAM_ROLE_VIDEOCAM = -1,
VCAM_ROLE_TRACKING_VIDEOCAM = 0,
VCAM_ROLE_MIRROR = 1, //!< Flips the video output and when not in driver cam, acts like a natural mirror, not a screen.
VCAM_ROLE_MIRROR_NOFLIP = 2, //!< Same as VCAM_ROLE_MIRROR, but without flipping the texture horizontally (expects texcoords to be already flipped in the mesh)

// Internal types
VCAM_ROLE_MIRROR_PROP_LEFT = -1001, //!< The classic 'special prop/rear view mirror'
VCAM_ROLE_MIRROR_PROP_RIGHT = -1002, //!< The classic 'special prop/rear view mirror'
VCAM_ROLE_INVALID = -9999,
};

// ------------------------------------------------------------------------------------------------
// Global variables
// ------------------------------------------------------------------------------------------------
Expand Down
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
12 changes: 6 additions & 6 deletions source/main/gfx/GfxActor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -483,13 +483,13 @@ void RoR::GfxActor::UpdateVideoCameras(float dt)
}
#endif // USE_CAELUM

if ((vidcam.vcam_type == VCTYPE_MIRROR_PROP_LEFT)
|| (vidcam.vcam_type == VCTYPE_MIRROR_PROP_RIGHT))
if ((vidcam.vcam_role == VCAM_ROLE_MIRROR_PROP_LEFT)
|| (vidcam.vcam_role == VCAM_ROLE_MIRROR_PROP_RIGHT))
{
// Mirror prop - special processing.
float mirror_angle = 0.f;
Ogre::Vector3 offset(Ogre::Vector3::ZERO);
if (vidcam.vcam_type == VCTYPE_MIRROR_PROP_LEFT)
if (vidcam.vcam_role == VCAM_ROLE_MIRROR_PROP_LEFT)
{
mirror_angle = m_actor->ar_left_mirror_angle;
offset = Ogre::Vector3(0.07f, -0.22f, 0);
Expand Down Expand Up @@ -545,14 +545,14 @@ void RoR::GfxActor::UpdateVideoCameras(float dt)
frustumUP.normalise();
vidcam.vcam_ogre_camera->setFixedYawAxis(true, frustumUP);

if (vidcam.vcam_type == VCTYPE_MIRROR)
if (vidcam.vcam_role == VCAM_ROLE_MIRROR)
{
//rotate the normal of the mirror by user rotation setting so it reflects correct
normal = vidcam.vcam_rotation * normal;
// merge camera direction and reflect it on our plane
vidcam.vcam_ogre_camera->setDirection((pos - App::GetCameraManager()->GetCameraNode()->getPosition()).reflect(normal));
}
else if (vidcam.vcam_type == VCTYPE_VIDEOCAM)
else if (vidcam.vcam_role == VCAM_ROLE_VIDEOCAM)
{
// rotate the camera according to the nodes orientation and user rotation
Ogre::Vector3 refx = abs_pos_z - abs_pos_center;
Expand All @@ -562,7 +562,7 @@ void RoR::GfxActor::UpdateVideoCameras(float dt)
Ogre::Quaternion rot = Ogre::Quaternion(-refx, -refy, -normal);
vidcam.vcam_ogre_camera->setOrientation(rot * vidcam.vcam_rotation); // rotate the camera orientation towards the calculated cam direction plus user rotation
}
else if (vidcam.vcam_type == VCTYPE_TRACKING_VIDEOCAM)
else if (vidcam.vcam_role == VCAM_ROLE_TRACKING_VIDEOCAM)
{
normal = m_simbuf.simbuf_nodes[vidcam.vcam_node_lookat].AbsPosition - pos;
normal.normalise();
Expand Down
6 changes: 3 additions & 3 deletions source/main/gfx/GfxActor.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class GfxActor
std::vector<Prop>& getProps() { return m_props; }
std::vector<CParticle>& getCParticles() { return m_cparticles; }
std::vector<Exhaust>& getExhausts() { return m_exhausts; }
std::vector<VideoCamera>& getVideoCameras() { return m_videocameras; }

// Visual changes

Expand Down Expand Up @@ -149,7 +150,6 @@ class GfxActor
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);
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; }
std::string getWheelRimMeshName(WheelID_t wheel_id) { return (wheel_id >= 0 && (size_t)wheel_id < m_wheels.size()) ? m_wheels[wheel_id].wx_rim_mesh_name : ""; }
Expand Down Expand Up @@ -191,6 +191,8 @@ class GfxActor
std::vector<VideoCamera> m_videocameras;
std::vector<FlareMaterial> m_flare_materials;
RoR::Renderdash* m_renderdash = nullptr;
std::vector<CParticle> m_cparticles;
std::vector<Exhaust> m_exhausts;

// Particles
DustPool* m_particles_drip = nullptr;
Expand All @@ -199,8 +201,6 @@ 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
18 changes: 5 additions & 13 deletions source/main/gfx/GfxData.h
Original file line number Diff line number Diff line change
Expand Up @@ -216,36 +216,28 @@ struct Prop
}
};

enum VideoCamType
{
VCTYPE_INVALID,
VCTYPE_VIDEOCAM,
VCTYPE_TRACKING_VIDEOCAM,
VCTYPE_MIRROR,
VCTYPE_MIRROR_PROP_LEFT, //!< The classic 'special prop/rear view mirror'
VCTYPE_MIRROR_PROP_RIGHT, //!< The classic 'special prop/rear view mirror'
};

/// An Ogre::Camera mounted on the actor and rendering into
/// either in-scene texture or external window.
struct VideoCamera
{
VideoCamType vcam_type = VCTYPE_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 VCTYPE_TRACK_CAM
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;
Ogre::RenderTexture* vcam_render_target = nullptr;
Ogre::TexturePtr vcam_render_tex;
Ogre::SceneNode* vcam_debug_node = nullptr;
Ogre::RenderWindow* vcam_render_window = nullptr;
Ogre::SceneNode* vcam_prop_scenenode = nullptr; //!< Only for VCTYPE_MIRROR_PROP_*
Ogre::SceneNode* vcam_prop_scenenode = nullptr; //!< Only for VCAM_ROLE_MIRROR_PROP_*
};

/// Gfx attributes/state of a softbody node
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
4 changes: 2 additions & 2 deletions source/main/gui/panels/GUI_VehicleInfoTPanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -821,8 +821,8 @@ void VehicleInfoTPanel::DrawVehicleBasicsUI(RoR::GfxActor* actorx)
}
}

const int num_cparticles = (int)actorx->getCParticles().size();
const size_t num_videocams = actorx->getNumVideoCameras();
const size_t num_cparticles = actorx->getCParticles().size();
const size_t num_videocams = actorx->getVideoCameras().size();
ImGui::TextDisabled("View:");
if (num_cparticles)
{
Expand Down
34 changes: 19 additions & 15 deletions source/main/physics/ActorSpawner.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6979,22 +6979,23 @@ void ActorSpawner::CreateVideoCamera(RigDef::VideoCamera* def)
{
try
{
auto videocameraid = (VideoCameraID_t)m_actor->m_gfx_actor->m_videocameras.size();
RoR::VideoCamera vcam;

vcam.vcam_material = this->FindOrCreateCustomizedMaterial(def->material_name, m_custom_resource_group);
if (vcam.vcam_material.isNull())
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, "Failed to create VideoCamera with material: " + def->material_name);
this->AddMessage(Message::TYPE_ERROR, fmt::format("Skipping VideoCamera (mat: {}) with invalid 'role' ({})", def->material_name, (int)vcam.vcam_role_orig));
return;
}

switch (def->camera_role)
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())
{
case -1: vcam.vcam_type = VCTYPE_VIDEOCAM; break;
case 0: vcam.vcam_type = VCTYPE_TRACKING_VIDEOCAM; break;
case 1: vcam.vcam_type = VCTYPE_MIRROR; break;
default:
this->AddMessage(Message::TYPE_ERROR, "VideoCamera (mat: " + def->material_name + ") has invalid 'role': " + TOSTRING(def->camera_role));
this->AddMessage(Message::TYPE_ERROR, "Failed to create VideoCamera with material: " + def->material_name);
return;
}

Expand All @@ -7004,7 +7005,11 @@ void ActorSpawner::CreateVideoCamera(RigDef::VideoCamera* def)
vcam.vcam_pos_offset = def->offset;

//rotate camera picture 180 degrees, skip for mirrors
float rotation_z = (def->camera_role != 1) ? def->rotation.z + 180 : def->rotation.z;
float rotation_z = def->rotation.z + 180;
if (tweaked_role == VCAM_ROLE_MIRROR || tweaked_role == VCAM_ROLE_MIRROR_NOFLIP)
{
rotation_z += 180.0f;
}
vcam.vcam_rotation
= Ogre::Quaternion(Ogre::Degree(rotation_z), Ogre::Vector3::UNIT_Z)
* Ogre::Quaternion(Ogre::Degree(def->rotation.y), Ogre::Vector3::UNIT_Y)
Expand All @@ -7024,11 +7029,10 @@ void ActorSpawner::CreateVideoCamera(RigDef::VideoCamera* def)
if (def->alt_orientation_node.IsValidAnyState())
{
// This is a tracker camera
vcam.vcam_type = VCTYPE_TRACKING_VIDEOCAM;
vcam.vcam_role = VCAM_ROLE_TRACKING_VIDEOCAM;
vcam.vcam_node_lookat = this->GetNodeIndexOrThrow(def->alt_orientation_node);
}

// TODO: Eliminate gEnv
vcam.vcam_ogre_camera = App::GetGfxScene()->GetSceneManager()->createCamera(vcam.vcam_material->getName() + "_camera");

if (!App::gfx_window_videocams->getBool())
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 == 1)
if (tweaked_role == VCAM_ROLE_MIRROR)
vcam.vcam_material->getTechnique(0)->getPass(0)->getTextureUnitState(0)->setTextureUScale(-1);
}

Expand Down Expand Up @@ -7123,11 +7127,11 @@ void ActorSpawner::CreateMirrorPropVideoCam(
switch (type)
{
case CustomMaterial::MirrorPropType::MPROP_LEFT:
vcam.vcam_type = VCTYPE_MIRROR_PROP_LEFT;
vcam.vcam_role = VCAM_ROLE_MIRROR_PROP_LEFT;
break;

case CustomMaterial::MirrorPropType::MPROP_RIGHT:
vcam.vcam_type = VCTYPE_MIRROR_PROP_RIGHT;
vcam.vcam_role = VCAM_ROLE_MIRROR_PROP_RIGHT;
break;

default:
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
Loading