16
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-07-18 00:49:19 +02:00
Files
maszyna/vehicle/Camera.cpp
Sebastian Krzyszkowiak 15c666a7ef Allow to speed up external camera movement with Ctrl key
Shift isn't used as that would affect joystick controls and we
probably should discourage the user from roaming around in external
cam mode too much, so they won't forget that they're not in regular
free fly out of the cab.
2026-06-29 23:12:52 +02:00

235 lines
7.7 KiB
C++

/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
#include "stdafx.h"
#include "vehicle/Camera.h"
#include "utilities/Globals.h"
#include "utilities/utilities.h"
#include "utilities/glmHelpers.h"
#include "Console.h"
#include "utilities/Timer.h"
#include "vehicle/Driver.h"
#include "vehicle/DynObj.h"
#include "MOVER.h"
//---------------------------------------------------------------------------
void TCamera::Init(glm::dvec3 const &NPos, glm::dvec3 const &NAngle /*, TCameraType const NType*/, TDynamicObject *Owner)
{
vUp = { 0, 1, 0 };
Velocity = { 0, 0, 0 };
Angle = NAngle;
Pos = NPos;
m_owner = Owner;
};
void TCamera::Reset() {
Angle = {};
m_rotationoffsets = {};
};
void TCamera::OnCursorMove(double x, double y) {
m_rotationoffsets.x += y;
m_rotationoffsets.y += x;
}
static double ComputeAxisSpeed(double param, double walkspeed, double maxspeed, double threshold) {
double absval = std::abs(param);
// 2/3rd of the stick range lerps walk speed, past that we lerp between max walk and run speed
double walk = walkspeed * std::min(absval / threshold, 1.0);
double run = (std::max(0.0, absval - threshold) / (1.0 - threshold)) * std::max(0.0, maxspeed - walkspeed);
return (param >= 0.0 ? 1.0 : -1.0) * (walk + run);
}
bool
TCamera::OnCommand( command_data const &Command ) {
auto const walkspeed { 1.0 };
auto const runspeed { 10.0 };
// threshold position on stick between walk lerp and walk/run lerp
auto const stickthreshold = 2.0 / 3.0;
bool iscameracommand { true };
switch( Command.command ) {
case user_command::viewturn: {
OnCursorMove(
Command.param1 * 0.005 * Global.fMouseXScale / Global.ZoomFactor,
Command.param2 * 0.01 * Global.fMouseYScale / Global.ZoomFactor );
break;
}
case user_command::movehorizontal:
case user_command::movehorizontalfast: {
auto const movespeed = (
m_owner == nullptr ? runspeed : // free roam
false == FreeFlyModeFlag ? walkspeed : // vehicle cab
0.0 ); // vehicle external
// if( movespeed == 0.0 ) { break; } // enable to fix external cameras in place
auto const speedmultiplier = (
( ( true == FreeFlyModeFlag ) && ( Command.command == user_command::movehorizontalfast ) ) ?
( m_owner == nullptr ) ? 30.0 : 5.0 :
1.0 );
// left-right
m_moverate.x = ComputeAxisSpeed(Command.param1, walkspeed, movespeed, stickthreshold) * speedmultiplier;
// forward-back
m_moverate.z = -ComputeAxisSpeed(Command.param2, walkspeed, movespeed, stickthreshold) * speedmultiplier;
break;
}
case user_command::movevertical:
case user_command::moveverticalfast: {
auto const movespeed = (
m_owner == nullptr ? runspeed * 0.5 : // free roam
false == FreeFlyModeFlag ? walkspeed : // vehicle cab
0.0 ); // vehicle external
// if( movespeed == 0.0 ) { break; } // enable to fix external cameras in place
auto const speedmultiplier = (
( ( true == FreeFlyModeFlag ) && ( Command.command == user_command::moveverticalfast ) ) ?
( m_owner == nullptr ) ? 10.0 : 3.0 :
1.0 );
// up-down
m_moverate.y = ComputeAxisSpeed(Command.param1, walkspeed, movespeed, stickthreshold) * speedmultiplier;
break;
}
default: {
iscameracommand = false;
break;
}
} // switch
return iscameracommand;
}
static void UpdateVelocityAxis(double& velocity, double moverate, double deltatime)
{
velocity = std::clamp(velocity + moverate * 10.0 * deltatime, -std::abs(moverate), std::abs(moverate));
}
void TCamera::Update()
{
// check for sent user commands
// NOTE: this is a temporary arrangement, for the transition period from old command setup to the new one
// ultimately we'll need to track position of camera/driver for all human entities present in the scenario
command_data command;
// NOTE: currently we're only storing commands for local entity and there's no id system in place,
// so we're supplying 'default' entity id of 0
while( simulation::Commands.pop( command, static_cast<std::size_t>( command_target::entity ) | 0 ) ) {
OnCommand( command );
}
auto const deltatime { Timer::GetDeltaRenderTime() }; // czas bez pauzy
// update rotation
auto const rotationfactor { std::min( 1.0, 20 * deltatime ) };
Angle.y -= m_rotationoffsets.y * rotationfactor;
m_rotationoffsets.y *= ( 1.0 - rotationfactor );
Angle.y = std::remainder(Angle.y, 2.0 * M_PI);
// Limit the camera pitch to +/- 90°.
Angle.x = std::clamp(Angle.x - (m_rotationoffsets.x * rotationfactor), -M_PI_2, M_PI_2);
m_rotationoffsets.x *= ( 1.0 - rotationfactor );
// update position
if( ( m_owner == nullptr )
|| ( true == FreeFlyModeFlag )
|| ( false == Global.ctrlState )
|| ( true == DebugCameraFlag ) ) {
// ctrl is used for mirror view, so we ignore the controls when in vehicle if ctrl is pressed
// McZapkie-170402: poruszanie i rozgladanie we free takie samo jak w follow
UpdateVelocityAxis(Velocity.x, m_moverate.x, deltatime);
UpdateVelocityAxis(Velocity.y, m_moverate.y, deltatime);
UpdateVelocityAxis(Velocity.z, m_moverate.z, deltatime);
}
if( ( m_owner == nullptr )
|| ( true == DebugCameraFlag ) ) {
// free movement position update
auto movement { Velocity };
movement = RotateY(movement, (double)Angle.y);
Pos += movement * 5.0 * deltatime;
}
else {
// attached movement position update
auto movement { Velocity * -2.0 };
movement.y = -movement.y;
auto const *owner { (
m_owner->Mechanik ?
m_owner->Mechanik :
m_owner->ctOwner ) };
if( ( owner && owner->Occupied() )
&& ( owner->Occupied()->CabOccupied < 0 ) ) {
movement *= -1.f;
movement.y = -movement.y;
}
/*
if( ( m_owner->ctOwner )
&& ( m_owner->ctOwner->Vehicle()->DirectionGet() != m_owner->DirectionGet() ) ) {
movement *= -1.f;
movement.y = -movement.y;
}
*/
movement = RotateY(movement, (double)Angle.y);
m_owneroffset += movement * deltatime;
}
}
bool TCamera::SetMatrix( glm::dmat4 &Matrix ) {
Matrix = glm::rotate(Matrix, -(double)Angle.x, glm::dvec3(1, 0, 0));
Matrix = glm::rotate(Matrix, -(double)Angle.y, glm::dvec3(0, 1, 0)); // w zewnętrznym widoku: kierunek patrzenia
Matrix = glm::rotate(Matrix, -(double)Angle.z, glm::dvec3(0, 0, 1)); // po wyłączeniu tego kręci się pojazd, a sceneria nie
if( ( m_owner != nullptr ) && ( false == DebugCameraFlag ) ) {
Matrix *= glm::lookAt(Pos, LookAt, glm::dvec3{ vUp } );
}
else {
Matrix = glm::translate( Matrix, -Pos ); // nie zmienia kierunku patrzenia
}
return true;
}
void TCamera::RaLook()
{ // zmiana kierunku patrzenia - przelicza Yaw
auto where = LookAt - Pos /*+ Math3D::vector3(0, 3, 0)*/; // trochę w górę od szyn
if( ( where.x != 0.0 ) || ( where.z != 0.0 ) ) {
Angle.y = atan2( -where.x, -where.z ); // kąt horyzontalny
m_rotationoffsets.y = 0.0;
}
double l = glm::length(where);
if( l > 0.0 ) {
Angle.x = asin( where.y / l ); // kąt w pionie
m_rotationoffsets.x = 0.0;
}
};