summaryrefslogtreecommitdiff
path: root/vphysics/physics_object.h
blob: a1c6f5e134bcccfeebb6b556b5a34177d35f6b86 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose: 
//
// $NoKeywords: $
//=============================================================================//

#ifndef PHYSICS_OBJECT_H
#define PHYSICS_OBJECT_H

#ifdef _WIN32
#pragma once
#endif

#include "vphysics_interface.h"

class IVP_Real_Object;
class IVP_Environment;
class IVP_U_Float_Point;
class IVP_SurfaceManager;
class IVP_Controller;
class CPhysicsEnvironment;
struct vphysics_save_cphysicsobject_t
{
	const CPhysCollide *pCollide;
	const char *pName;
	float	sphereRadius;

	bool	isStatic;
	bool	collisionEnabled;
	bool	gravityEnabled;
	bool	dragEnabled;
	bool	motionEnabled;
	bool	isAsleep;
	bool	isTrigger;
	bool	asleepSinceCreation;		// has this been asleep since creation?
	bool	hasTouchedDynamic;
	bool	hasShadowController;
	short	collideType;
	unsigned short	gameIndex;
	int		hingeAxis;
	int		materialIndex;
	float	mass;
	Vector	rotInertia;
	float	speedDamping;
	float	rotSpeedDamping;
	Vector	massCenterOverride;

	unsigned int	callbacks;
	unsigned int	gameFlags;

	unsigned int	contentsMask;

	float			volume;
	float			dragCoefficient;
	float			angDragCoefficient;
	IPhysicsShadowController	*pShadow;
	//bool			m_shadowTempGravityDisable;

	Vector			origin;
	QAngle			angles;
	Vector			velocity;
	AngularImpulse	angVelocity;

	DECLARE_SIMPLE_DATADESC();
};

enum
{
	OBJ_AWAKE = 0,			// awake, simulating
	OBJ_STARTSLEEP = 1,		// going to sleep, but not queried yet
	OBJ_SLEEP = 2,			// sleeping, no state changes since last query
};


class CPhysicsObject : public IPhysicsObject
{
public:
	CPhysicsObject( void );
	virtual ~CPhysicsObject( void );

	void			Init( const CPhysCollide *pCollisionModel, IVP_Real_Object *pObject, int materialIndex, float volume, float drag, float angDrag );

	// IPhysicsObject functions
	bool			IsStatic() const;
	bool			IsAsleep() const;
	bool			IsTrigger() const;
	bool			IsFluid() const;
	bool			IsHinged() const { return (m_hingedAxis != 0) ? true : false; }
	bool			IsCollisionEnabled() const;
	bool			IsGravityEnabled() const;
	bool			IsDragEnabled() const;
	bool			IsMotionEnabled() const;
	bool			IsMoveable() const;
	bool			IsAttachedToConstraint( bool bExternalOnly ) const;


	void			EnableCollisions( bool enable );
	// Enable / disable gravity for this object
	void			EnableGravity( bool enable );
	// Enable / disable air friction / drag for this object
	void			EnableDrag( bool enable );
	void			EnableMotion( bool enable );

	void			SetGameData( void *pAppData );
	void			*GetGameData( void ) const;
	void			SetCallbackFlags( unsigned short callbackflags );
	unsigned short	GetCallbackFlags( void ) const;
	void			SetGameFlags( unsigned short userFlags );
	unsigned short	GetGameFlags( void ) const;
	void			SetGameIndex( unsigned short gameIndex );
	unsigned short	GetGameIndex( void ) const;

	void			Wake();
	void			Sleep();
	void			RecheckCollisionFilter();
	void			RecheckContactPoints();

	void			SetMass( float mass );
	float			GetMass( void ) const;
	float			GetInvMass( void ) const;
	void			SetInertia( const Vector &inertia );
	Vector			GetInertia( void ) const;
	Vector			GetInvInertia( void ) const;

	void			GetDamping( float *speed, float *rot ) const;
	void			SetDamping( const float *speed, const float *rot );
	void			SetDragCoefficient( float *pDrag, float *pAngularDrag );
	void			SetBuoyancyRatio( float ratio );
	int				GetMaterialIndex() const { return GetMaterialIndexInternal(); }
	void			SetMaterialIndex( int materialIndex );
	inline int		GetMaterialIndexInternal( void ) const { return m_materialIndex; }

	unsigned int	GetContents() const { return m_contentsMask; }
	void			SetContents( unsigned int contents );

	float			GetSphereRadius() const;
	Vector			GetMassCenterLocalSpace() const;
	float			GetEnergy() const;

	void			SetPosition( const Vector &worldPosition, const QAngle &angles, bool isTeleport = false );
	void			SetPositionMatrix( const matrix3x4_t& matrix, bool isTeleport = false  );
	void			GetPosition( Vector *worldPosition, QAngle *angles ) const;
	void			GetPositionMatrix( matrix3x4_t *positionMatrix ) const;

	void			SetVelocity( const Vector *velocity, const AngularImpulse *angularVelocity );
	void			SetVelocityInstantaneous( const Vector *velocity, const AngularImpulse *angularVelocity );
	void			AddVelocity( const Vector *velocity, const AngularImpulse *angularVelocity );
	void			GetVelocity( Vector *velocity, AngularImpulse *angularVelocity ) const;
	void			GetImplicitVelocity( Vector *velocity, AngularImpulse *angularVelocity ) const;
	void			GetVelocityAtPoint( const Vector &worldPosition, Vector *pVelocity ) const;

	void			LocalToWorld( Vector *worldPosition, const Vector &localPosition ) const;
	void			WorldToLocal( Vector *localPosition, const Vector &worldPosition ) const;
	void			LocalToWorldVector( Vector *worldVector, const Vector &localVector ) const;
	void			WorldToLocalVector( Vector *localVector, const Vector &worldVector ) const;

	void			ApplyForceCenter( const Vector &forceVector );
	void			ApplyForceOffset( const Vector &forceVector, const Vector &worldPosition );
	void			ApplyTorqueCenter( const AngularImpulse & );
	void			CalculateForceOffset( const Vector &forceVector, const Vector &worldPosition, Vector *centerForce, AngularImpulse *centerTorque ) const;
	void			CalculateVelocityOffset( const Vector &forceVector, const Vector &worldPosition, Vector *centerVelocity, AngularImpulse *centerAngularVelocity ) const;
	float			CalculateLinearDrag( const Vector &unitDirection ) const;
	float			CalculateAngularDrag( const Vector &objectSpaceRotationAxis ) const;

	bool			GetContactPoint( Vector *contactPoint, IPhysicsObject **contactObject ) const;
	void			SetShadow( float maxSpeed, float maxAngularSpeed, bool allowPhysicsMovement, bool allowPhysicsRotation );
	void			UpdateShadow( const Vector &targetPosition, const QAngle &targetAngles, bool tempDisableGravity, float timeOffset );
	void			RemoveShadowController();
	int				GetShadowPosition( Vector *position, QAngle *angles ) const;
	IPhysicsShadowController *GetShadowController( void ) const;
	float			ComputeShadowControl( const hlshadowcontrol_params_t &params, float secondsToArrival, float dt );

	const CPhysCollide	*GetCollide( void ) const;
	char const		*GetName() const;

	float			GetDragInDirection( const IVP_U_Float_Point &dir ) const;
	float			GetAngularDragInDirection( const IVP_U_Float_Point &angVelocity ) const;
	void			BecomeTrigger();
	void			RemoveTrigger();
	void			BecomeHinged( int localAxis );
	void			RemoveHinged();

	IPhysicsFrictionSnapshot *CreateFrictionSnapshot();
	void			DestroyFrictionSnapshot( IPhysicsFrictionSnapshot *pSnapshot );

	void			OutputDebugInfo() const;

	// local functions
	inline	IVP_Real_Object *GetObject( void ) const { return m_pObject; }
	inline int		CallbackFlags( void ) const { return m_callbacks; }
	inline void		AddCallbackFlags( unsigned short flags ) { m_callbacks |= flags; }
	inline void		RemoveCallbackFlags( unsigned short flags ) { m_callbacks &= ~flags; }
	inline bool		HasTouchedDynamic();
	inline void		SetTouchedDynamic();
	void			NotifySleep( void );
	void			NotifyWake( void );
	int				GetSleepState( void ) const { return m_sleepState; }
	inline void		ForceSilentDelete() { m_forceSilentDelete = true; }

	inline int		GetActiveIndex( void ) const { return m_activeIndex; }
	inline void		SetActiveIndex( int index ) { m_activeIndex = index; }
	inline float	GetBuoyancyRatio( void ) const { return m_buoyancyRatio; }
	// returns true if the mass center is set to the default for the collision model
	bool			IsMassCenterAtDefault() const;

	// is this object simulated, or controlled by game logic?
	bool			IsControlledByGame() const;

	IVP_SurfaceManager *GetSurfaceManager( void ) const;

	void			WriteToTemplate( vphysics_save_cphysicsobject_t &objectTemplate );
	void			InitFromTemplate( CPhysicsEnvironment *pEnvironment, void *pGameData, const vphysics_save_cphysicsobject_t &objectTemplate );

	CPhysicsEnvironment	*GetVPhysicsEnvironment();
	const CPhysicsEnvironment	*GetVPhysicsEnvironment() const;

private:
	// NOTE: Local to vphysics, used to save/restore shadow controller
	void			RestoreShadowController( IPhysicsShadowController *pShadowController );
	friend bool		RestorePhysicsObject( const physrestoreparams_t &params, CPhysicsObject **ppObject );

	bool			IsControlling( const IVP_Controller *pController ) const;
	float			GetVolume() const;
	void			SetVolume( float volume );
	
	// the mass has changed, recompute the drag information
	void			RecomputeDragBases();

	void			ClampVelocity();

	// NOTE: If m_pGameData is not the first member, the constructor debug code must be modified
	void			*m_pGameData;
	IVP_Real_Object	*m_pObject;
	const CPhysCollide *m_pCollide;
	IPhysicsShadowController	*m_pShadow;

	Vector			m_dragBasis;
	Vector			m_angDragBasis;

	// these 5 should pack into a short
	// pack new bools here
	bool			m_shadowTempGravityDisable : 5;
	bool			m_hasTouchedDynamic : 1;
	bool			m_asleepSinceCreation : 1;
	bool			m_forceSilentDelete : 1;
	unsigned char	m_sleepState : 2;
	unsigned char	m_hingedAxis : 3;
	unsigned char	m_collideType : 3;
	unsigned short	m_gameIndex;

private:
	unsigned short	m_materialIndex;
	unsigned short	m_activeIndex;

	unsigned short	m_callbacks;
	unsigned short	m_gameFlags;
	unsigned int	m_contentsMask;
	
	float			m_volume;
	float			m_buoyancyRatio;
	float			m_dragCoefficient;
	float			m_angDragCoefficient;

	friend CPhysicsObject *CreatePhysicsObject( CPhysicsEnvironment *pEnvironment, const CPhysCollide *pCollisionModel, int materialIndex, const Vector &position, const QAngle& angles, objectparams_t *pParams, bool isStatic );
	friend bool CPhysicsEnvironment::TransferObject( IPhysicsObject *pObject, IPhysicsEnvironment *pDestinationEnvironment ); //need direct access to m_pShadow for Portal mod's physics object transfer system
};

// If you haven't ever touched a dynamic object, there's no need to search for contacting objects to 
// wakeup when you are deleted.  So cache a bit here when contacts are generated
inline bool CPhysicsObject::HasTouchedDynamic()
{
	return m_hasTouchedDynamic;
}

inline void CPhysicsObject::SetTouchedDynamic()
{
	m_hasTouchedDynamic = true;
}

extern CPhysicsObject *CreatePhysicsObject( CPhysicsEnvironment *pEnvironment, const CPhysCollide *pCollisionModel, int materialIndex, const Vector &position, const QAngle &angles, objectparams_t *pParams, bool isStatic );
extern CPhysicsObject *CreatePhysicsSphere( CPhysicsEnvironment *pEnvironment, float radius, int materialIndex, const Vector &position, const QAngle &angles, objectparams_t *pParams, bool isStatic );
extern void PostRestorePhysicsObject();
extern IPhysicsObject *CreateObjectFromBuffer( CPhysicsEnvironment *pEnvironment, void *pGameData, unsigned char *pBuffer, unsigned int bufferSize, bool enableCollisions );
extern IPhysicsObject *CreateObjectFromBuffer_UseExistingMemory( CPhysicsEnvironment *pEnvironment, void *pGameData, unsigned char *pBuffer, unsigned int bufferSize, CPhysicsObject *pExistingMemory );

#endif // PHYSICS_OBJECT_H