mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-18 00:49:19 +02:00
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.
235 lines
7.7 KiB
C++
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;
|
|
}
|
|
};
|