You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
198 lines
6.7 KiB
198 lines
6.7 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: Mirrors the movement of a camera about a given point. |
|
// |
|
//=============================================================================// |
|
|
|
#include "cbase.h" |
|
#include "baseentity.h" |
|
#include "modelentities.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
////////////////////////////////////////////////////////////////////////// |
|
// CLogicMirrorMovement |
|
// This will record the vector offset of an entity's center from a given reference point |
|
// (most likely the center of a mirror or portal) and place an entity (most likely a point camera) |
|
// at a the same offset, mirrored about the reference point and orientation. |
|
////////////////////////////////////////////////////////////////////////// |
|
class CLogicMirrorMovement : public CLogicalEntity |
|
{ |
|
DECLARE_DATADESC(); |
|
DECLARE_CLASS( CLogicMirrorMovement, CLogicalEntity ); |
|
|
|
private: |
|
void SetMirrorTarget( const char *pName ); // Set entity to watch and mirror (ex. the player) |
|
void SetTarget( const char *pName ); // Set entity to move based on the Mirror Target entity (ex. a point_camera) |
|
void SetMirrorRelative( const char* pName ); // Set the point about which to measure an offset to orient based upon (ex. portal 1) |
|
void SetRemoteTarget ( const char *pName ); // Entity's orientation/location from which to offset the movement target (ex. portal 2) |
|
void SetDrawingSurface ( const char *pName ); |
|
|
|
void InputSetMirrorTarget( inputdata_t &inputdata ); |
|
void InputSetTarget( inputdata_t &inputdata ); |
|
void InputSetRemoteTarget ( inputdata_t &inputdata ); |
|
void InputSetMirrorRelative ( inputdata_t &inputdata ); |
|
|
|
void Think(); |
|
virtual void Activate(); |
|
|
|
string_t m_strMirrorTarget; |
|
string_t m_strRemoteTarget; |
|
string_t m_strMirrorRelative; |
|
|
|
EHANDLE m_hRemoteTarget; |
|
EHANDLE m_hMirrorTarget; |
|
EHANDLE m_hMovementTarget; |
|
EHANDLE m_hMirrorRelative; |
|
|
|
}; |
|
|
|
LINK_ENTITY_TO_CLASS( logic_mirror_movement, CLogicMirrorMovement ); |
|
|
|
|
|
BEGIN_DATADESC( CLogicMirrorMovement ) |
|
|
|
DEFINE_KEYFIELD( m_strMirrorTarget, FIELD_STRING, "MirrorTarget" ), |
|
DEFINE_KEYFIELD( m_strRemoteTarget, FIELD_STRING, "RemoteTarget" ), |
|
DEFINE_KEYFIELD( m_strMirrorRelative, FIELD_STRING, "MirrorRelative" ), |
|
|
|
DEFINE_FIELD( m_hMirrorTarget, FIELD_EHANDLE ), |
|
DEFINE_FIELD( m_hMovementTarget, FIELD_EHANDLE ), |
|
DEFINE_FIELD( m_hRemoteTarget, FIELD_EHANDLE ), |
|
DEFINE_FIELD( m_hMirrorRelative, FIELD_EHANDLE ), |
|
|
|
DEFINE_INPUTFUNC( FIELD_STRING, "SetMirrorTarget", InputSetMirrorTarget ), |
|
DEFINE_INPUTFUNC( FIELD_STRING, "SetTarget", InputSetTarget ), |
|
DEFINE_INPUTFUNC( FIELD_STRING, "SetRemoteTarget", InputSetRemoteTarget ), |
|
DEFINE_INPUTFUNC( FIELD_STRING, "SetMirrorRelative", InputSetMirrorRelative ), |
|
|
|
DEFINE_THINKFUNC( Think ), |
|
|
|
END_DATADESC() |
|
|
|
|
|
void CLogicMirrorMovement::Activate() |
|
{ |
|
BaseClass::Activate(); |
|
|
|
SetMirrorTarget( STRING(m_strMirrorTarget) ); |
|
SetTarget( STRING(m_target) ); |
|
SetRemoteTarget( STRING(m_strRemoteTarget ) ); |
|
SetMirrorRelative( STRING( m_strMirrorRelative) ); |
|
|
|
SetThink( &CLogicMirrorMovement::Think ); |
|
SetNextThink( gpGlobals->curtime + TICK_INTERVAL ); |
|
} |
|
|
|
|
|
void CLogicMirrorMovement::SetMirrorTarget( const char *pName ) |
|
{ |
|
m_hMirrorTarget = gEntList.FindEntityByName( NULL, pName ); |
|
if ( !m_hMirrorTarget ) |
|
{ |
|
if ( Q_strnicmp( STRING(m_strMirrorTarget), "!player", 8 ) ) |
|
{ |
|
Warning("logic_mirror_movement: Unable to find mirror target entity %s\n", pName ); |
|
} |
|
} |
|
} |
|
|
|
void CLogicMirrorMovement::SetTarget( const char *pName ) |
|
{ |
|
m_hMovementTarget = gEntList.FindEntityByName( NULL, pName ); |
|
if ( !m_hMovementTarget ) |
|
{ |
|
Warning("logic_mirror_movement: Unable to find movement target entity %s\n", pName ); |
|
} |
|
} |
|
|
|
void CLogicMirrorMovement::SetRemoteTarget(const char *pName ) |
|
{ |
|
m_hRemoteTarget = gEntList.FindEntityByName( NULL, pName ); |
|
if ( !m_hRemoteTarget ) |
|
{ |
|
Warning("logic_mirror_movement: Unable to find remote target entity %s\n", pName ); |
|
} |
|
} |
|
|
|
void CLogicMirrorMovement::SetMirrorRelative(const char* pName ) |
|
{ |
|
m_hMirrorRelative = gEntList.FindEntityByName( NULL, pName ); |
|
if ( !m_hMirrorRelative ) |
|
{ |
|
Warning("logic_mirror_movement: Unable to find mirror relative entity %s\n", pName ); |
|
} |
|
} |
|
|
|
void CLogicMirrorMovement::InputSetMirrorTarget( inputdata_t &inputdata ) |
|
{ |
|
m_strMirrorTarget = AllocPooledString( inputdata.value.String() ); |
|
SetMirrorTarget( inputdata.value.String() ); |
|
} |
|
|
|
void CLogicMirrorMovement::InputSetTarget( inputdata_t &inputdata ) |
|
{ |
|
m_target = AllocPooledString( inputdata.value.String() ); |
|
SetTarget( inputdata.value.String() ); |
|
} |
|
|
|
void CLogicMirrorMovement::InputSetRemoteTarget(inputdata_t &inputdata ) |
|
{ |
|
m_strRemoteTarget = AllocPooledString( inputdata.value.String() ); |
|
SetRemoteTarget( inputdata.value.String() ); |
|
} |
|
|
|
void CLogicMirrorMovement::InputSetMirrorRelative(inputdata_t &inputdata ) |
|
{ |
|
m_strMirrorRelative = AllocPooledString ( inputdata.value.String() ); |
|
SetMirrorRelative( inputdata.value.String() ); |
|
} |
|
|
|
|
|
void CLogicMirrorMovement::Think() |
|
{ |
|
// Attempt to get the player's handle because it didn't exist at Activate time |
|
if ( !m_hMirrorTarget.Get() ) |
|
{ |
|
// If we will never find a target, we don't have a use... shutdown |
|
if ( m_strMirrorTarget == NULL_STRING ) |
|
SetNextThink ( NULL ); |
|
|
|
//BUGBUG: If m_strSetMirrorTarget doesn't exist in ent list, we get per-think searches with no results ever... |
|
SetMirrorTarget ( STRING(m_strMirrorTarget) ); |
|
} |
|
|
|
// Make sure all entities are valid |
|
if ( m_hMirrorTarget.Get() && m_hMovementTarget.Get() && m_hRemoteTarget.Get() && m_hMirrorRelative.Get() ) |
|
{ |
|
// Get our two portal's world transforms transforms |
|
VMatrix matPortal1ToWorldInv, matPortal2ToWorld; |
|
MatrixInverseGeneral( m_hMirrorRelative->EntityToWorldTransform(), matPortal1ToWorldInv ); |
|
matPortal2ToWorld = m_hRemoteTarget->EntityToWorldTransform(); |
|
|
|
VMatrix matTransformToRemotePortal = matPortal1ToWorldInv * matPortal2ToWorld; |
|
|
|
// Get our scene camera's current orientation |
|
Vector ptCameraPosition, vCameraLook, vCameraRight, vCameraUp; |
|
ptCameraPosition = m_hMirrorTarget->EyePosition(); |
|
m_hMirrorTarget->GetVectors ( &vCameraLook, &vCameraRight, &vCameraUp ); |
|
|
|
// map this position and orientation to the remote portal, mirrored (invert the result) |
|
Vector ptNewPosition, vNewLook; |
|
ptNewPosition = matPortal1ToWorldInv * ptCameraPosition; |
|
ptNewPosition = matPortal2ToWorld*( Vector( -ptNewPosition.x, -ptNewPosition.y, ptNewPosition.z ) ); |
|
|
|
vNewLook = matPortal1ToWorldInv.ApplyRotation( vCameraLook ); |
|
vNewLook = matPortal2ToWorld.ApplyRotation( Vector( -vNewLook.x, -vNewLook.y, vNewLook.z) ); |
|
|
|
// Set the point camera to the new location/orientation |
|
QAngle qNewAngles; |
|
VectorAngles( vNewLook, qNewAngles ); |
|
m_hMovementTarget->Teleport( &ptNewPosition, &qNewAngles, NULL ); |
|
} |
|
|
|
SetNextThink( gpGlobals->curtime + TICK_INTERVAL ); |
|
} |
|
|
|
|
|
|