mirror of
https://github.com/thug1src/thug.git
synced 2024-11-30 12:06:44 +00:00
570 lines
20 KiB
C++
570 lines
20 KiB
C++
//****************************************************************************
|
|
//* MODULE: Gel/Components
|
|
//* FILENAME: GunslingerWalkCameraComponent.cpp
|
|
//* OWNER: Dave
|
|
//* CREATION DATE: 5/13/03
|
|
//****************************************************************************
|
|
|
|
#include <gel/components/walkcameracomponent.h>
|
|
#include <core/math/slerp.h>
|
|
#include <gel/object/compositeobject.h>
|
|
#include <gel/object/compositeobjectmanager.h>
|
|
#include <gel/components/walkcomponent.h>
|
|
#include <gel/components/camerautil.h>
|
|
#include <gel/components/cameralookaroundcomponent.h>
|
|
#include <gel/components/cameracomponent.h>
|
|
#include <gel/components/pedlogiccomponent.h> // Messy, but for now used to obtain ped positions etc.
|
|
#include <gel/components/weaponcomponent.h>
|
|
#include <gel/scripting/checksum.h>
|
|
#include <gel/scripting/script.h>
|
|
#include <gel/scripting/struct.h>
|
|
#include <gfx/debuggfx.h>
|
|
|
|
// These should be members in the cameralookaroundcomponent.
|
|
extern float spin_modulator;
|
|
extern float tilt_modulator;
|
|
extern float last_heading_change;
|
|
extern float last_tilt_change;
|
|
extern bool gun_fired;
|
|
extern bool allow_strafe_locking;
|
|
|
|
int best_ped_timer = 0;
|
|
Obj::CCompositeObject* p_selected_target = NULL;
|
|
float target_selection_timer = 0.0f; // Times how long the selected target has been targeted for.
|
|
|
|
namespace Obj
|
|
{
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
static float s_get_gunslinger_param( uint32 checksum )
|
|
{
|
|
Script::CStruct* p_cam_params = Script::GetStructure( CRCD( 0xa13ff9ae,"GunslingerCameraParameters" ));
|
|
Dbg_Assert( p_cam_params );
|
|
|
|
float param;
|
|
p_cam_params->GetFloat( checksum, ¶m, Script::ASSERT );
|
|
return param;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
CBaseComponent* CWalkCameraComponent::s_create()
|
|
{
|
|
return static_cast< CBaseComponent* >( new CWalkCameraComponent );
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
CWalkCameraComponent::CWalkCameraComponent() : CBaseComponent()
|
|
{
|
|
SetType( CRC_WALKCAMERA );
|
|
|
|
m_last_actual_matrix.Ident();
|
|
m_last_tripod_pos.Set( 0.0f, 0.0f, 0.0f, 1.0f );
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
CWalkCameraComponent::~CWalkCameraComponent()
|
|
{
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void CWalkCameraComponent::InitFromStructure( Script::CStruct* pParams )
|
|
{
|
|
uint32 target_id = 0 ;
|
|
pParams->GetChecksum("CameraTarget", &target_id, Script::ASSERT);
|
|
|
|
CCompositeObject* p_target = static_cast< CCompositeObject* >(CCompositeObjectManager::Instance()->GetObjectByID(target_id));
|
|
Dbg_MsgAssert(p_target, ("Bad CameraTarget given to WalkCameraComponent"));
|
|
|
|
set_target(p_target);
|
|
|
|
m_last_dot = 1.0f;
|
|
m_current_zoom = 1.0f;
|
|
|
|
m_last_actual_matrix = GetObject()->GetMatrix();
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void CWalkCameraComponent::RefreshFromStructure( Script::CStruct* pParams )
|
|
{
|
|
InitFromStructure(pParams);
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void CWalkCameraComponent::Finalize()
|
|
{
|
|
mp_lookaround_component = GetCameraLookAroundComponentFromObject(GetObject());
|
|
mp_camera_component = GetCameraComponentFromObject(GetObject());
|
|
|
|
Dbg_Assert(mp_lookaround_component);
|
|
Dbg_Assert(mp_camera_component);
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void CWalkCameraComponent::Update()
|
|
{
|
|
// optimization KLUDGE
|
|
// if (Script::GetInteger(CRCD(0x1aa88b08, "vehicle_mode")))
|
|
// {
|
|
// GetObject()->Pause(true);
|
|
// return;
|
|
// }
|
|
|
|
if (mp_target->HasTeleported())
|
|
{
|
|
m_instant_count = 3;
|
|
}
|
|
|
|
bool instantly;
|
|
if (m_instant_count > 0)
|
|
{
|
|
--m_instant_count;
|
|
instantly = true;
|
|
}
|
|
else
|
|
{
|
|
instantly = false;
|
|
}
|
|
|
|
mp_camera_component->StoreOldPosition();
|
|
|
|
float frame_length = Tmr::FrameLength();
|
|
|
|
// get input
|
|
// float horiz_control = GetInputComponentFromObject( GetObject())->GetControlPad().m_scaled_rightX;
|
|
float horiz_control = mp_lookaround_component->mLookaroundHeading;
|
|
|
|
// Restore camera position from last frame, previous to refocusing, lookaround and collision detection.
|
|
GetObject()->GetMatrix() = m_last_actual_matrix;
|
|
|
|
Mth::Vector target_facing = -GetObject()->GetMatrix()[Z];
|
|
target_facing[Y] = 0.0f;
|
|
target_facing.Normalize();
|
|
|
|
Mth::Vector subject_facing = mp_target->GetMatrix()[Z];
|
|
subject_facing[Y] = 0.0f;
|
|
subject_facing.Normalize();
|
|
|
|
// two options; we either use our old facing as the target facing or use the subject's facing as the target facing
|
|
bool use_subject_facing = true;
|
|
|
|
// if in a flush request
|
|
if (m_flush_request_active)
|
|
{
|
|
// always use the subject's matrix
|
|
}
|
|
// if controlling camera
|
|
else if (horiz_control != 0.0f)
|
|
{
|
|
use_subject_facing = false;
|
|
}
|
|
// if the subject's facing is towards the camera
|
|
else if (Mth::DotProduct(target_facing, subject_facing) < cosf(Mth::DegToRad(s_get_gunslinger_param(CRCD(0xb8da8a73, "lock_angle")))))
|
|
{
|
|
use_subject_facing = false;
|
|
}
|
|
// if the subject is moving very slowly
|
|
else // if (!mp_target_walk_component->UseDPadCamera())
|
|
{
|
|
float full_slerp_speed;
|
|
float min_slerp_speed;
|
|
if (!mp_target_walk_component->UseDPadCamera())
|
|
{
|
|
full_slerp_speed = s_get_gunslinger_param(CRCD(0xbcef6dda, "full_slerp_speed"));
|
|
min_slerp_speed = s_get_gunslinger_param(CRCD(0x824349e5, "min_slerp_speed"));
|
|
}
|
|
else
|
|
{
|
|
full_slerp_speed = s_get_gunslinger_param(CRCD(0x73da1ec0, "dpad_full_slerp_speed"));
|
|
min_slerp_speed = s_get_gunslinger_param(CRCD(0xda5cad3, "dpad_min_slerp_speed"));
|
|
}
|
|
|
|
float target_vel = mp_target->GetVel().Length();
|
|
if (target_vel < full_slerp_speed)
|
|
{
|
|
use_subject_facing = false;
|
|
}
|
|
}
|
|
|
|
// Never want to use the subject facing camera.
|
|
use_subject_facing = false;
|
|
|
|
if (use_subject_facing)
|
|
{
|
|
target_facing = subject_facing;
|
|
}
|
|
|
|
// Build target matrix.
|
|
Mth::Matrix target_matrix;
|
|
target_matrix[W].Set( 0.0f, 0.0f, 0.0f, 1.0f );
|
|
target_matrix[Z] = target_facing;
|
|
target_matrix[Y].Set( 0.0f, 1.0f, 0.0f );
|
|
target_matrix[X].Set( target_facing[Z], 0.0f, -target_facing[X] );
|
|
|
|
// Dave note - testing default value for now.
|
|
float slerp = 0.06f;
|
|
|
|
target_matrix[X] = -target_matrix[X];
|
|
target_matrix[Z] = -target_matrix[Z];
|
|
|
|
// use later for camera position
|
|
Mth::Vector up = mp_target->GetMatrix()[Y];
|
|
|
|
if (!instantly)
|
|
{
|
|
if( Mth::DotProduct(target_matrix[X], GetObject()->GetMatrix()[X]) > CAMERA_SLERP_STOP &&
|
|
Mth::DotProduct(target_matrix[Y], GetObject()->GetMatrix()[Y]) > CAMERA_SLERP_STOP &&
|
|
Mth::DotProduct(target_matrix[Z], GetObject()->GetMatrix()[Z]) > CAMERA_SLERP_STOP )
|
|
{
|
|
// we're already at our target, so don't do anything
|
|
|
|
// turn off any flush request
|
|
if (m_flush_request_active)
|
|
{
|
|
m_flush_request_active = false;
|
|
mp_target_walk_component->SetForwardControlLock(false);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Slerp to the target matrix.
|
|
Mth::SlerpInterpolator slerper( &GetObject()->GetMatrix(), &target_matrix );
|
|
|
|
// Apply the slerping.
|
|
slerper.getMatrix( &GetObject()->GetMatrix(), GetTimeAdjustedSlerp( slerp, frame_length ));
|
|
|
|
// Calculate for the skater camera.
|
|
m_last_dot = Mth::DotProduct(m_last_actual_matrix[Z], GetObject()->GetMatrix()[Z]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
GetObject()->GetMatrix() = target_matrix;
|
|
}
|
|
|
|
// At this point, GetObject()->GetMatrix() is valid to store.
|
|
m_last_actual_matrix = GetObject()->GetMatrix();
|
|
|
|
// Now apply the lookaround adjustments to the matrix.
|
|
// Control over target facing.
|
|
if( horiz_control != 0.0f && !m_flush_request_active )
|
|
{
|
|
// The horiz_control value needs to be damped when there is an item of interest within the reticle area.
|
|
GetObject()->GetMatrix().RotateYLocal( horiz_control );
|
|
}
|
|
|
|
float tilt = s_get_gunslinger_param( CRCD( 0xe3c07609, "tilt" ));
|
|
GetObject()->GetMatrix().RotateXLocal( tilt + mp_lookaround_component->mLookaroundTilt );
|
|
|
|
Mth::Vector camera_pos = get_tripod_pos( instantly );
|
|
|
|
// Test the weapon component to generate the 'sticky' targetting behavior.
|
|
if( mp_target && p_selected_target )
|
|
{
|
|
CWeaponComponent* p_weapon = GetWeaponComponentFromObject( mp_target );
|
|
|
|
p_weapon->SetCurrentTarget( p_selected_target );
|
|
p_weapon->SetSightPos( camera_pos );
|
|
p_weapon->SetSightMatrix( GetObject()->GetMatrix());
|
|
|
|
float extra_heading_change, extra_tilt_change;
|
|
p_weapon->ProcessStickyTarget( last_heading_change, last_tilt_change, &extra_heading_change, &extra_tilt_change );
|
|
|
|
if(( extra_heading_change != 0.0f ) || ( extra_tilt_change != 0.0f ))
|
|
{
|
|
// Reset the matrix to what it was prior to the heading and tilt adjustments.
|
|
GetObject()->SetMatrix( m_last_actual_matrix );
|
|
|
|
mp_lookaround_component->mLookaroundHeading += extra_heading_change;
|
|
horiz_control += extra_heading_change;
|
|
GetObject()->GetMatrix().RotateYLocal( horiz_control );
|
|
|
|
mp_lookaround_component->mLookaroundTilt += extra_tilt_change;
|
|
GetObject()->GetMatrix().RotateXLocal( tilt + mp_lookaround_component->mLookaroundTilt );
|
|
}
|
|
}
|
|
|
|
// Calculate zoom
|
|
float above, behind;
|
|
calculate_zoom( above, behind );
|
|
|
|
camera_pos += GetObject()->GetMatrix()[Z] * behind + up * above;
|
|
|
|
Mth::Vector focus_pos = mp_target_walk_component->GetEffectivePos() + up * above;
|
|
|
|
// Focus the camera directly on the target object
|
|
target_matrix[Z] = focus_pos - camera_pos;
|
|
target_matrix[Z].Normalize();
|
|
|
|
// Read back the Y from the current matrix.
|
|
// target_matrix[Y] = GetObject()->GetMatrix()[Y];
|
|
target_matrix[Y] = Mth::Vector( 0.0f, 1.0f, 0.0f );
|
|
|
|
// Generate new orthonormal X and Y axes.
|
|
target_matrix[X] = Mth::CrossProduct(target_matrix[Y], target_matrix[Z]);
|
|
target_matrix[X].Normalize();
|
|
|
|
target_matrix[Y] = Mth::CrossProduct(target_matrix[Z], target_matrix[X]);
|
|
target_matrix[Y].Normalize();
|
|
|
|
// Write back into camera matrix.
|
|
// Since camera points in -Z, but player in +Z, we must negate the X and Z axes
|
|
GetObject()->GetMatrix()[X] = -target_matrix[X];
|
|
GetObject()->GetMatrix()[Y] = target_matrix[Y];
|
|
GetObject()->GetMatrix()[Z] = -target_matrix[Z];
|
|
|
|
// clean up matrix
|
|
GetObject()->GetMatrix()[X][W] = 0.0f;
|
|
GetObject()->GetMatrix()[Y][W] = 0.0f;
|
|
GetObject()->GetMatrix()[Z][W] = 0.0f;
|
|
GetObject()->GetMatrix()[W].Set(0.0f, 0.0f, 0.0f, 1.0f);
|
|
|
|
// Now do collision detection.
|
|
ApplyCameraCollisionDetection( camera_pos, GetObject()->GetMatrix(), camera_pos - GetObject()->GetMatrix()[Z] * behind, focus_pos );
|
|
|
|
#ifdef __USER_DAN__
|
|
if (Script::GetInteger(CRCD(0xaf90c5fd, "walking_debug_lines")))
|
|
{
|
|
Gfx::AddDebugStar(focus_pos, 24.0f, MAKE_RGB(255, 200, 0), 1);
|
|
}
|
|
#endif
|
|
|
|
camera_pos[W] = 1.0f;
|
|
GetObject()->SetPos( camera_pos );
|
|
|
|
// Do the target selection.
|
|
if( mp_target )
|
|
{
|
|
Mth::Vector reticle_min = camera_pos;
|
|
Mth::Vector reticle_max;
|
|
|
|
CWeaponComponent* p_weapon = GetWeaponComponentFromObject( mp_target );
|
|
|
|
p_weapon->SetSightMatrix( GetObject()->GetMatrix());
|
|
p_selected_target = p_weapon->GetCurrentTarget( reticle_min, &reticle_max );
|
|
|
|
if( gun_fired )
|
|
{
|
|
p_weapon->Fire();
|
|
}
|
|
|
|
spin_modulator = p_weapon->GetSpinModulator();
|
|
tilt_modulator = p_weapon->GetTiltModulator();
|
|
|
|
p_weapon->DrawReticle();
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
CBaseComponent::EMemberFunctionResult CWalkCameraComponent::CallMemberFunction( uint32 Checksum, Script::CStruct* pParams, Script::CScript* pScript )
|
|
{
|
|
switch ( Checksum )
|
|
{
|
|
// @script | WalkCamera_FlushRequest | Force the camera to lerp quickly to behind the walker
|
|
case CRCC(0x73febd0f, "WalkCamera_FlushRequest"):
|
|
FlushRequest();
|
|
break;
|
|
|
|
default:
|
|
return CBaseComponent::MF_NOT_EXECUTED;
|
|
}
|
|
return CBaseComponent::MF_TRUE;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void CWalkCameraComponent::GetDebugInfo(Script::CStruct *p_info)
|
|
{
|
|
Dbg_MsgAssert(p_info,("NULL p_info sent to CWalkCameraComponent::GetDebugInfo"));
|
|
|
|
CBaseComponent::GetDebugInfo(p_info);
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void CWalkCameraComponent::ReadyForActivation ( const SCameraState& state )
|
|
{
|
|
m_last_tripod_pos = state.lastTripodPos;
|
|
m_last_actual_matrix = state.lastActualMatrix;
|
|
m_last_dot = state.lastDot;
|
|
m_current_zoom = state.lastZoom;
|
|
m_flush_request_active = false;
|
|
|
|
mp_lookaround_component->mLookaroundTilt = 0.0f;
|
|
mp_lookaround_component->mLookaroundHeading = 0.0f;
|
|
mp_lookaround_component->mLookaroundZoom = 1.0f;
|
|
mp_lookaround_component->mLookaroundLock = false;
|
|
|
|
m_override_active = false;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void CWalkCameraComponent::GetCameraState ( SCameraState& state )
|
|
{
|
|
state.lastActualMatrix = m_last_actual_matrix;
|
|
state.lastTripodPos = m_last_tripod_pos;
|
|
state.lastDot = m_last_dot;
|
|
state.lastZoom = m_current_zoom;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void CWalkCameraComponent::FlushRequest ( )
|
|
{
|
|
m_flush_request_active = true;
|
|
mp_target_walk_component->SetForwardControlLock(true);
|
|
|
|
// flush requests zero skater cam lookaround
|
|
mp_lookaround_component->mLookaroundHeading = 0.0f;
|
|
mp_lookaround_component->mLookaroundTilt = 0.0f;
|
|
mp_lookaround_component->mLookaroundZoom = 1.0f;
|
|
mp_lookaround_component->mLookaroundLock = false;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void CWalkCameraComponent::set_target ( CCompositeObject* p_target )
|
|
{
|
|
mp_target = p_target;
|
|
Dbg_Assert(mp_target);
|
|
|
|
mp_target_walk_component = GetWalkComponentFromObject(mp_target);
|
|
Dbg_Assert(mp_target_walk_component);
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
Mth::Vector CWalkCameraComponent::get_tripod_pos( bool instantly )
|
|
{
|
|
if (instantly)
|
|
{
|
|
m_last_tripod_pos = mp_target_walk_component->GetEffectivePos();
|
|
}
|
|
else
|
|
{
|
|
float lerp_xz = GetTimeAdjustedSlerp(s_get_gunslinger_param(CRCD(0xae47899b, "lerp_xz")), Tmr::FrameLength());
|
|
float lerp_y = GetTimeAdjustedSlerp(s_get_gunslinger_param(CRCD(0xe1e4e104, "lerp_y")), Tmr::FrameLength());
|
|
|
|
const Mth::Vector& target_pos = mp_target_walk_component->GetEffectivePos();
|
|
|
|
m_last_tripod_pos.Set(
|
|
Mth::Lerp(m_last_tripod_pos[X], target_pos[X], lerp_xz),
|
|
Mth::Lerp(m_last_tripod_pos[Y], target_pos[Y], lerp_y),
|
|
Mth::Lerp(m_last_tripod_pos[Z], target_pos[Z], lerp_xz)
|
|
);
|
|
}
|
|
|
|
return m_last_tripod_pos;
|
|
}
|
|
|
|
/******************************************************************/
|
|
/* */
|
|
/* */
|
|
/******************************************************************/
|
|
|
|
void CWalkCameraComponent::calculate_zoom ( float& above, float& behind )
|
|
{
|
|
float target_zoom = 1.0f;
|
|
|
|
// If lookaround override is set, factor in the lookaround override zoom.
|
|
if (mp_lookaround_component->mLookaroundOverride && mp_lookaround_component->mLookaroundZoom != 1.0f)
|
|
{
|
|
target_zoom *= mp_lookaround_component->mLookaroundZoom;
|
|
}
|
|
|
|
// m_current_zoom += (( target_zoom - m_current_zoom ) * s_get_gunslinger_param( CRCD( 0x748743a7, "zoom_lerp" )));
|
|
m_current_zoom += (( target_zoom - m_current_zoom ) * s_get_gunslinger_param( CRCD( 0x748743a7, "zoom_lerp" )));
|
|
|
|
// behind = s_get_gunslinger_param(CRCD(0x52e6c41b, "behind")) * m_current_zoom;
|
|
behind = s_get_gunslinger_param(CRCD(0x52e6c41b, "behind")) * m_current_zoom;
|
|
|
|
// Behind is also shortened when the lookaround camera is tilting upwards.
|
|
if( mp_lookaround_component->mLookaroundTilt < 0.0f )
|
|
{
|
|
float max_tilt = -0.9f;
|
|
// behind = behind * (0.4f + (0.6f * ((max_tilt + mp_lookaround_component->mLookaroundTilt) / max_tilt)));
|
|
behind = behind * ( 0.0f + ( 1.0f * (( max_tilt - mp_lookaround_component->mLookaroundTilt ) / max_tilt )));
|
|
}
|
|
else if( mp_lookaround_component->mLookaroundTilt > 0.0f )
|
|
{
|
|
float max_tilt = 1.4f;
|
|
behind = behind * ( 0.0f + ( 1.0f * (( max_tilt - mp_lookaround_component->mLookaroundTilt ) / max_tilt )));
|
|
}
|
|
|
|
// Use lip_trick_above when doing a lip trick.
|
|
// float above_val = s_get_gunslinger_param(CRCD(0xb96ae2d, "above"));
|
|
float above_val = s_get_gunslinger_param( CRCD( 0xb96ae2d, "above" ));
|
|
|
|
// Figure above tending towards the perfect above, if zoom is < 1.0.
|
|
if( m_current_zoom < 1.0f )
|
|
{
|
|
above = SKATERCAMERACOMPONENT_PERFECT_ABOVE + ((above_val - SKATERCAMERACOMPONENT_PERFECT_ABOVE) * m_current_zoom);
|
|
}
|
|
else
|
|
{
|
|
above = above_val;
|
|
}
|
|
}
|
|
|
|
}
|