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 );
|
|
}
|
|
|
|
|