idTech 5 physics code.

This commit is contained in:
Justin Marshall
2026-08-09 05:16:51 -07:00
parent 47c4709db7
commit 1531f9b628
18 changed files with 7995 additions and 1251 deletions
File diff suppressed because it is too large Load Diff
+379 -278
View File
@@ -1,321 +1,422 @@
#pragma once
// Reconstructed C++ declarations from IDA Local Types and PDB/DIA metadata.
// Original PDB header: w:\tech5\engine\gamelib\physics\afconstraint.h
// Recovered logical types: 14
// Signatures retain Xbox 360 ABI evidence and may still require manual review.
#include "gamelib/physics/afbody.h"
#include "gamelib/physics/clip.h"
#include "idlib/text/atomicstring.h"
#include <cstdint>
#include <cstddef>
// IDA Local Type ordinal 2471; PDB kind: enum.
enum declAFConstraintType_t : __int32
{
DECLAF_CONSTRAINT_INVALID = 0x0,
DECLAF_CONSTRAINT_FIXED = 0x1,
DECLAF_CONSTRAINT_BALLANDSOCKETJOINT = 0x2,
DECLAF_CONSTRAINT_UNIVERSALJOINT = 0x3,
DECLAF_CONSTRAINT_HINGE = 0x4,
DECLAF_CONSTRAINT_SLIDER = 0x5,
DECLAF_CONSTRAINT_SPRING = 0x6,
class idDeclTable;
class idPhysics_AF;
class idRotation;
class idSerializer;
enum constraintType_t : int {
CONSTRAINT_INVALID = 0,
CONSTRAINT_FIXED = 1,
CONSTRAINT_BALLANDSOCKETJOINT = 2,
CONSTRAINT_UNIVERSALJOINT = 3,
CONSTRAINT_HINGE = 4,
CONSTRAINT_HINGESTEERING = 5,
CONSTRAINT_SLIDER = 6,
CONSTRAINT_CYLINDRICALJOINT = 7,
CONSTRAINT_PLANE = 9,
CONSTRAINT_SPRING = 10,
CONSTRAINT_CONTACT = 11,
CONSTRAINT_FRICTION = 12,
CONSTRAINT_CONELIMIT = 13,
CONSTRAINT_PYRAMIDLIMIT = 14,
CONSTRAINT_SUSPENSION = 15,
CONSTRAINT_WEEBLE = 16
};
// IDA Local Type ordinal 2940; PDB kind: enum.
enum idDeclAF_Constraint::afConstraintLimit_t : __int32
{
LIMIT_NONE = 0xFFFFFFFF,
LIMIT_CONE = 0x0,
LIMIT_PYRAMID = 0x1,
};
// IDA Local Type ordinal 14601; PDB kind: class.
class idAFConstraint
{
class alignas(16) idAFConstraint {
public:
// Recovered virtual interface; IDA vtable ordinal 14624.
virtual ~idAFConstraint();
virtual void SetBody1(idAFBody *);
virtual void SetBody2(idAFBody *);
virtual void DebugDraw();
virtual void Translate(const idVec3 *);
virtual void Rotate(const idRotation *);
virtual void GetCenter(idVec3 *);
virtual void IssueCollisionQueries();
virtual void CancelCollisionQueries();
virtual void Serialize(idSerializer *);
virtual void Evaluate(const idPhysics_AF *, float);
virtual void ApplyFriction(float);
struct constraintFlags_s {
std::uint8_t reserved : 3;
std::uint8_t isZero : 1;
std::uint8_t isPrimary : 1;
std::uint8_t noCollision : 1;
std::uint8_t frameConstraint : 1;
std::uint8_t allowPrimary : 1;
};
__declspec(align(16)) constraintType_t type;
idAtomicString name;
idAFBody *body1;
idAFBody *body2;
idPhysics_AF *physics;
idStaticSpatialVec lm;
idSpatialMat J1;
idSpatialMat J2;
idStaticSpatialVec c1;
idStaticSpatialVec c2;
idStaticSpatialVec lo;
idStaticSpatialVec hi;
idStaticSpatialVec e;
idAFConstraint *boxConstraint;
int boxIndex[6];
float boxScale[6];
idSpatialMat invI;
idSpatialMat J;
int firstIndex;
idAFConstraint::constraintFlags_s fl;
idAFConstraint(const char* name = nullptr,
constraintType_t type = CONSTRAINT_INVALID,
idAFBody* body1 = nullptr, idAFBody* body2 = nullptr);
virtual ~idAFConstraint();
static void* operator new(std::size_t size);
static void operator delete(void* pointer) noexcept;
virtual void SetBody1(idAFBody*);
virtual void SetBody2(idAFBody*);
virtual void DebugDraw();
virtual void Translate(const idVec3&);
virtual void Rotate(const idRotation&);
virtual void GetCenter(idVec3&) const;
virtual void IssueCollisionQueries();
virtual void CancelCollisionQueries();
virtual void Serialize(idSerializer*);
virtual void Evaluate(const idPhysics_AF*, float);
virtual void ApplyFriction(float);
void InitSize(int size);
alignas(16) constraintType_t type;
idAtomicString name;
idAFBody* body1;
idAFBody* body2;
idPhysics_AF* physics;
idStaticSpatialVec lm;
idSpatialMat J1;
idSpatialMat J2;
idStaticSpatialVec c1;
idStaticSpatialVec c2;
idStaticSpatialVec lo;
idStaticSpatialVec hi;
idStaticSpatialVec e;
idAFConstraint* boxConstraint;
int boxIndex[6];
float boxScale[6];
idSpatialMat invI;
idSpatialMat J;
int firstIndex;
constraintFlags_s fl;
};
// IDA Local Type ordinal 14615; PDB kind: class.
class __declspec(align(16)) idAFConstraint_Contact : public idAFConstraint
{
class alignas(16) idAFConstraint_Fixed : public idAFConstraint {
public:
// Recovered virtual interface; IDA vtable ordinal 33731.
virtual ~idAFConstraint_Contact();
virtual void SetBody1(idAFBody *);
virtual void SetBody2(idAFBody *);
virtual void DebugDraw();
virtual void Translate(const idVec3 *);
virtual void Rotate(const idRotation *);
virtual void GetCenter(idVec3 *);
virtual void IssueCollisionQueries();
virtual void CancelCollisionQueries();
virtual void Serialize(idSerializer *);
virtual void Evaluate(const idPhysics_AF *, float);
virtual void ApplyFriction(float);
idAFConstraint_Fixed(const char* name = nullptr,
idAFBody* body1 = nullptr, idAFBody* body2 = nullptr);
void SetBody1(idAFBody*) override;
void SetBody2(idAFBody*) override;
void Rotate(const idRotation&) override;
void GetCenter(idVec3&) const override;
void DebugDraw() override;
void Evaluate(const idPhysics_AF*, float) override;
void InitOffset();
contactInfo_t contact;
float separation;
idAFConstraint_ContactFriction *fc;
idVec3 offset;
idMat3 relAxis;
bool shouldClamp;
};
// IDA Local Type ordinal 14625; PDB kind: struct.
struct idAFConstraint::constraintFlags_s
{
unsigned __int8 : 3;
__int8 isZero : 1;
__int8 isPrimary : 1;
__int8 noCollision : 1;
__int8 frameConstraint : 1;
__int8 allowPrimary : 1;
};
class idAFConstraint_ConeLimit;
class idAFConstraint_PyramidLimit;
class idAFConstraint_BallAndSocketJointFriction;
// IDA Local Type ordinal 14656; PDB kind: class.
class __declspec(align(4)) idDeclAF_Constraint
{
class alignas(16) idAFConstraint_BallAndSocketJoint
: public idAFConstraint {
public:
idAtomicString name;
idAtomicString body1;
idAtomicString body2;
declAFConstraintType_t type;
float friction;
float stretch;
float compress;
float damping;
float restLength;
float minLength;
float maxLength;
idAFVector anchor;
idAFVector anchor2;
idAFVector shaft[2];
idAFVector axis;
idDeclAF_Constraint::afConstraintLimit_t limit;
idAFVector limitAxis;
float limitAngles[3];
bool syncConstraint;
idAFConstraint_BallAndSocketJoint(const char* name = nullptr,
idAFBody* body1 = nullptr, idAFBody* body2 = nullptr);
~idAFConstraint_BallAndSocketJoint() override;
void Translate(const idVec3&) override;
void Rotate(const idRotation&) override;
void GetCenter(idVec3&) const override;
void DebugDraw() override;
void Evaluate(const idPhysics_AF*, float) override;
void ApplyFriction(float) override;
void SetAnchor(const idVec3& worldPosition);
void SetWorldPosition(const idVec3& worldPosition);
float GetFriction() const;
void SetNoLimit();
void SetConeLimit(const idVec3& coneAxis, float coneAngle,
const idVec3& body1Axis);
void SetPyramidLimit(const idVec3& pyramidAxis,
const idVec3& baseAxis, float angle1, float angle2,
const idVec3& body1Axis);
idVec3 anchor1;
idVec3 anchor2;
float friction;
idAFConstraint_ConeLimit* coneLimit;
idAFConstraint_PyramidLimit* pyramidLimit;
idAFConstraint_BallAndSocketJointFriction* fc;
};
// IDA Local Type ordinal 21669; PDB kind: class.
class __declspec(align(16)) idAFConstraint_ConeLimit : public idAFConstraint
{
class alignas(16) idAFConstraint_BallAndSocketJointFriction
: public idAFConstraint {
public:
// Recovered virtual interface; IDA vtable ordinal 21670.
virtual ~idAFConstraint_ConeLimit();
virtual void SetBody1(idAFBody *);
virtual void SetBody2(idAFBody *);
virtual void DebugDraw();
virtual void Translate(const idVec3 *);
virtual void Rotate(const idRotation *);
virtual void GetCenter(idVec3 *);
virtual void IssueCollisionQueries();
virtual void CancelCollisionQueries();
virtual void Serialize(idSerializer *);
virtual void Evaluate(const idPhysics_AF *, float);
virtual void ApplyFriction(float);
idVec3 coneAnchor;
idVec3 coneAxis;
idVec3 body1Axis;
float cosAngle;
float sinHalfAngle;
float cosHalfAngle;
float epsilon;
explicit idAFConstraint_BallAndSocketJointFriction(
idAFConstraint_BallAndSocketJoint* joint = nullptr);
bool Add(idPhysics_AF*, float invTimeStep);
idAFConstraint_BallAndSocketJoint* joint;
};
// IDA Local Type ordinal 21688; PDB kind: class.
class __declspec(align(16)) idAFConstraint_Fixed : public idAFConstraint
{
class idAFConstraint_UniversalJointFriction;
class alignas(16) idAFConstraint_UniversalJoint : public idAFConstraint {
public:
// Recovered virtual interface; IDA vtable ordinal 21689.
virtual ~idAFConstraint_Fixed();
virtual void SetBody1(idAFBody *);
virtual void SetBody2(idAFBody *);
virtual void DebugDraw();
virtual void Translate(const idVec3 *);
virtual void Rotate(const idRotation *);
virtual void GetCenter(idVec3 *);
virtual void IssueCollisionQueries();
virtual void CancelCollisionQueries();
virtual void Serialize(idSerializer *);
virtual void Evaluate(const idPhysics_AF *, float);
virtual void ApplyFriction(float);
idAFConstraint_UniversalJoint(const char* name = nullptr,
idAFBody* body1 = nullptr, idAFBody* body2 = nullptr);
~idAFConstraint_UniversalJoint() override;
void Translate(const idVec3&) override;
void Rotate(const idRotation&) override;
void GetCenter(idVec3&) const override;
void DebugDraw() override;
void Evaluate(const idPhysics_AF*, float) override;
void ApplyFriction(float) override;
void SetAnchor(const idVec3& worldPosition);
void SetShafts(const idVec3& cardanShaft1,
const idVec3& cardanShaft2);
float GetFriction() const;
void SetNoLimit();
void SetConeLimit(const idVec3& coneAxis, float coneAngle,
const idVec3& body1Axis);
void SetPyramidLimit(const idVec3& pyramidAxis,
const idVec3& baseAxis, float angle1, float angle2,
const idVec3& body1Axis);
idVec3 offset;
idMat3 relAxis;
bool shouldClamp;
idVec3 anchor1;
idVec3 anchor2;
idVec3 shaft1;
idVec3 shaft2;
idVec3 axis1;
idVec3 axis2;
float friction;
idAFConstraint_ConeLimit* coneLimit;
idAFConstraint_PyramidLimit* pyramidLimit;
idAFConstraint_UniversalJointFriction* fc;
};
// IDA Local Type ordinal 21764; PDB kind: class.
class idAFConstraint_Line : public idAFConstraint
{
class alignas(16) idAFConstraint_UniversalJointFriction
: public idAFConstraint {
public:
// Recovered virtual interface; IDA vtable ordinal 21765.
virtual ~idAFConstraint_Line();
virtual void SetBody1(idAFBody *);
virtual void SetBody2(idAFBody *);
virtual void DebugDraw();
virtual void Translate(const idVec3 *);
virtual void Rotate(const idRotation *);
virtual void GetCenter(idVec3 *);
virtual void IssueCollisionQueries();
virtual void CancelCollisionQueries();
virtual void Serialize(idSerializer *);
virtual void Evaluate(const idPhysics_AF *, float);
virtual void ApplyFriction(float);
explicit idAFConstraint_UniversalJointFriction(
idAFConstraint_UniversalJoint* joint = nullptr);
bool Add(idPhysics_AF*, float invTimeStep);
void Evaluate(const idPhysics_AF*, float) override;
idAFConstraint_UniversalJoint* joint;
};
// IDA Local Type ordinal 21844; PDB kind: class.
class __declspec(align(4)) idAFConstraint_Weeble : public idAFConstraint
{
class idAFConstraint_HingeFriction;
class idAFConstraint_HingeSteering;
class alignas(16) idAFConstraint_Hinge : public idAFConstraint {
public:
// Recovered virtual interface; IDA vtable ordinal 21845.
virtual ~idAFConstraint_Weeble();
virtual void SetBody1(idAFBody *);
virtual void SetBody2(idAFBody *);
virtual void DebugDraw();
virtual void Translate(const idVec3 *);
virtual void Rotate(const idRotation *);
virtual void GetCenter(idVec3 *);
virtual void IssueCollisionQueries();
virtual void CancelCollisionQueries();
virtual void Serialize(idSerializer *);
virtual void Evaluate(const idPhysics_AF *, float);
virtual void ApplyFriction(float);
idAFConstraint_Hinge(const char* name = nullptr,
idAFBody* body1 = nullptr, idAFBody* body2 = nullptr);
~idAFConstraint_Hinge() override;
void Translate(const idVec3&) override;
void Rotate(const idRotation&) override;
void GetCenter(idVec3&) const override;
void DebugDraw() override;
void Evaluate(const idPhysics_AF*, float) override;
void ApplyFriction(float) override;
void SetAnchor(const idVec3& worldPosition);
void SetAxis(const idVec3& axis);
float GetFriction() const;
float GetAngle() const;
void SetNoLimit();
void SetLimit(float angle1, float angle2, float epsilon);
idVec3 up;
bool enabled;
idVec3 anchor1;
idVec3 anchor2;
idVec3 axis1;
idVec3 axis2;
idMat3 initialAxis;
float friction;
idAFConstraint_ConeLimit* coneLimit;
idAFConstraint_HingeSteering* steering;
idAFConstraint_HingeFriction* fc;
};
// IDA Local Type ordinal 21871; PDB kind: class.
class __declspec(align(16)) idAFConstraint_Hinge : public idAFConstraint
{
class alignas(16) idAFConstraint_HingeFriction : public idAFConstraint {
public:
// Recovered virtual interface; IDA vtable ordinal 21875.
virtual ~idAFConstraint_Hinge();
virtual void SetBody1(idAFBody *);
virtual void SetBody2(idAFBody *);
virtual void DebugDraw();
virtual void Translate(const idVec3 *);
virtual void Rotate(const idRotation *);
virtual void GetCenter(idVec3 *);
virtual void IssueCollisionQueries();
virtual void CancelCollisionQueries();
virtual void Serialize(idSerializer *);
virtual void Evaluate(const idPhysics_AF *, float);
virtual void ApplyFriction(float);
idVec3 anchor1;
idVec3 anchor2;
idVec3 axis1;
idVec3 axis2;
idMat3 initialAxis;
float friction;
idAFConstraint_ConeLimit *coneLimit;
idAFConstraint_HingeSteering *steering;
idAFConstraint_HingeFriction *fc;
explicit idAFConstraint_HingeFriction(
idAFConstraint_Hinge* hinge = nullptr);
bool Add(idPhysics_AF*, float invTimeStep);
idAFConstraint_Hinge* hinge;
};
// IDA Local Type ordinal 21970; PDB kind: class.
class __declspec(align(16)) idAFConstraint_Plane : public idAFConstraint
{
class idAFConstraint_HingeSteering : public idAFConstraint {
public:
// Recovered virtual interface; IDA vtable ordinal 21971.
virtual ~idAFConstraint_Plane();
virtual void SetBody1(idAFBody *);
virtual void SetBody2(idAFBody *);
virtual void DebugDraw();
virtual void Translate(const idVec3 *);
virtual void Rotate(const idRotation *);
virtual void GetCenter(idVec3 *);
virtual void IssueCollisionQueries();
virtual void CancelCollisionQueries();
virtual void Serialize(idSerializer *);
virtual void Evaluate(const idPhysics_AF *, float);
virtual void ApplyFriction(float);
idVec3 anchor1;
idVec3 anchor2;
idVec3 planeNormal;
explicit idAFConstraint_HingeSteering(
idAFConstraint_Hinge* hinge = nullptr);
bool Add(idPhysics_AF*, float invTimeStep);
idAFConstraint_Hinge* hinge;
float steerAngle;
float steerSpeed;
float epsilon;
};
// IDA Local Type ordinal 22048; PDB kind: class.
class idAFConstraint_Spring : public idAFConstraint
{
class alignas(16) idAFConstraint_Slider : public idAFConstraint {
public:
// Recovered virtual interface; IDA vtable ordinal 22049.
virtual ~idAFConstraint_Spring();
virtual void SetBody1(idAFBody *);
virtual void SetBody2(idAFBody *);
virtual void DebugDraw();
virtual void Translate(const idVec3 *);
virtual void Rotate(const idRotation *);
virtual void GetCenter(idVec3 *);
virtual void IssueCollisionQueries();
virtual void CancelCollisionQueries();
virtual void Serialize(idSerializer *);
virtual void Evaluate(const idPhysics_AF *, float);
virtual void ApplyFriction(float);
idVec3 anchor1;
idVec3 anchor2;
float kstretch;
float kcompress;
float damping;
float restLength;
float minLength;
float maxLength;
idAFConstraint_Slider(const char* name = nullptr,
idAFBody* body1 = nullptr, idAFBody* body2 = nullptr);
void SetAxis(const idVec3&);
void GetCenter(idVec3&) const override;
void DebugDraw() override;
void Evaluate(const idPhysics_AF*, float) override;
idVec3 axis;
idVec3 offset;
idMat3 relAxis;
};
// IDA Local Type ordinal 22279; PDB kind: class.
class __declspec(align(8)) idAFConstraint_Slider : public idAFConstraint
{
class idAFConstraint_Spring : public idAFConstraint {
public:
// Recovered virtual interface; IDA vtable ordinal 22280.
virtual ~idAFConstraint_Slider();
virtual void SetBody1(idAFBody *);
virtual void SetBody2(idAFBody *);
virtual void DebugDraw();
virtual void Translate(const idVec3 *);
virtual void Rotate(const idRotation *);
virtual void GetCenter(idVec3 *);
virtual void IssueCollisionQueries();
virtual void CancelCollisionQueries();
virtual void Serialize(idSerializer *);
virtual void Evaluate(const idPhysics_AF *, float);
virtual void ApplyFriction(float);
idVec3 axis;
idVec3 offset;
idMat3 relAxis;
idAFConstraint_Spring(const char* name = nullptr,
idAFBody* body1 = nullptr, idAFBody* body2 = nullptr);
void Translate(const idVec3&) override;
void Rotate(const idRotation&) override;
void GetCenter(idVec3&) const override;
void DebugDraw() override;
void Evaluate(const idPhysics_AF*, float) override;
void SetAnchor(const idVec3& anchor1, const idVec3& anchor2);
void SetSpring(float stretch, float compress, float damping,
float restLength);
void SetLimit(float minLength, float maxLength);
idVec3 anchor1;
idVec3 anchor2;
float kstretch;
float kcompress;
float damping;
float restLength;
float minLength;
float maxLength;
};
class idAFConstraint_ContactFriction;
class alignas(16) idAFConstraint_Contact : public idAFConstraint {
public:
idAFConstraint_Contact();
~idAFConstraint_Contact() override;
void GetCenter(idVec3&) const override;
void DebugDraw() override;
void ApplyFriction(float) override;
void Setup(idAFBody* body1, idAFBody* body2,
const contactInfo_t&, float separation, float invTimeStep);
contactInfo_t contact;
float separation;
idAFConstraint_ContactFriction* fc;
};
class alignas(16) idAFConstraint_ContactFriction
: public idAFConstraint {
public:
explicit idAFConstraint_ContactFriction(
idAFConstraint_Contact* contact = nullptr);
bool Add(idPhysics_AF*, float invTimeStep);
idAFConstraint_Contact* cc;
};
class alignas(16) idAFConstraint_ConeLimit : public idAFConstraint {
public:
idAFConstraint_ConeLimit();
void Setup(idAFBody*, idAFBody*, const idVec3& coneAnchor,
const idVec3& coneAxis, float coneAngle,
const idVec3& body1Axis);
bool Add(idPhysics_AF*, float invTimeStep);
void Translate(const idVec3&) override;
void Rotate(const idRotation&) override;
void DebugDraw() override;
idVec3 coneAnchor;
idVec3 coneAxis;
idVec3 body1Axis;
float cosAngle;
float sinHalfAngle;
float cosHalfAngle;
float epsilon;
};
class alignas(16) idAFConstraint_PyramidLimit : public idAFConstraint {
public:
idAFConstraint_PyramidLimit();
void Setup(idAFBody*, idAFBody*, const idVec3& pyramidAnchor,
const idVec3& pyramidAxis, const idVec3& baseAxis,
float angle1, float angle2, const idVec3& body1Axis);
bool Add(idPhysics_AF*, float invTimeStep);
void Translate(const idVec3&) override;
void Rotate(const idRotation&) override;
void DebugDraw() override;
idVec3 pyramidAnchor;
idMat3 pyramidBasis;
idVec3 body1Axis;
float cosAngle[2];
float sinHalfAngle[2];
float cosHalfAngle[2];
float epsilon;
};
class alignas(16) idAFConstraint_Suspension : public idAFConstraint {
public:
idAFConstraint_Suspension();
void Setup(const char* name, idAFBody*, const idVec3& localOrigin,
idClip*, idClipModel*, int clipMask, float radius);
void SetSuspension(float up, float down, float compress,
float damping);
int GetContactEntity() const;
void Translate(const idVec3&) override;
void IssueCollisionQueries() override;
void CancelCollisionQueries() override;
void DebugDraw() override;
void Evaluate(const idPhysics_AF*, float) override;
void Serialize(idSerializer*) override;
idVec3 localOrigin;
float suspensionUp;
float suspensionDown;
float suspensionCompress;
float suspensionDamping;
const idDeclTable* friction_longitudinal;
const idDeclTable* friction_lateral;
float frictionLatMultiplier;
float frictionLongMultiplier;
idClip* clip;
idClipModel* wheelModel;
float wheelRadius;
int clipMask;
idVec3 cgLocation;
float steerAngle;
bool motorEnabled;
float motorForce;
float motorVelocity;
idClipQuery traceQuery;
float traceFraction;
idVec3 traceEndPos;
idVec3 traceNormal;
idVec3 tracePoint;
int traceSurfaceFlags;
int traceEntityNum;
float wheelVelocity;
float wheelAngle;
float lastWheelHeight;
float lastMotorVelocity;
float lastTorque;
float lastGrip;
bool lastOnGround;
bool limitLateralGrip;
float lateralSlip;
float longitudinalSlip;
float debugSpringForce;
idVec3 debugv1;
idVec3 debugv2;
idVec3 debugv3;
float debugf1;
float debugf2;
float debugf3;
float debugf4;
};
class idAFConstraint_Line : public idAFConstraint {};
class idAFConstraint_CylindricalJoint : public idAFConstraint {};
class alignas(16) idAFConstraint_Plane : public idAFConstraint {
public:
idVec3 anchor1;
idVec3 anchor2;
idVec3 planeNormal;
};
class alignas(16) idAFConstraint_Weeble : public idAFConstraint {
public:
idVec3 up;
bool enabled;
};
static_assert(sizeof(idAFConstraint::constraintFlags_s) == 1,
"Recovered AF constraint flags ABI changed");
@@ -40,9 +40,10 @@ public:
void LinkClip() override;
bool EvaluateContacts() override;
void DisableClip(actorClipModel_t clipType);
void EnableClip(actorClipModel_t clipType);
void LinkClip(const idVec3& origin, const idMat3& axis);
virtual const idMat3* GetGravityAxis() { return &clipModelAxis; }
virtual void DisableClip(actorClipModel_t clipType);
virtual void EnableClip(actorClipModel_t clipType);
virtual void LinkClip(const idVec3& origin, const idMat3& axis);
void SetClipModelAxis();
float GetMasterDeltaYaw() const;
void RememberHistorySample();
File diff suppressed because it is too large Load Diff
+215 -157
View File
@@ -1,165 +1,223 @@
#pragma once
// Reconstructed C++ declarations from IDA Local Types and PDB/DIA metadata.
// Original PDB header: w:\tech5\engine\gamelib\physics\physics_af.h
// Recovered logical types: 2
// Signatures retain Xbox 360 ABI evidence and may still require manual review.
#include "gamelib/physics/afconstraint.h"
#include "gamelib/physics/aftree.h"
#include "gamelib/physics/physics_dynamicbase.h"
#include "idlib/containers/staticlist.h"
#include "idlib/math/fader.h"
#include "idlib/math/lcp.h"
class idSerializer;
// IDA Local Type ordinal 14613; PDB kind: class.
class idPhysics_AF : public idPhysics_DynamicBase
{
struct AFPState_t {
bool atRest;
float noMoveTime;
float activateTime;
idVec6 pushVelocity;
idVec6 auxVelocity;
};
class idPhysics_AF : public idPhysics_DynamicBase {
public:
// Recovered virtual interface; IDA vtable ordinal 14623.
virtual ~idPhysics_AF();
virtual void SetClipModel(idClipModel *, float, int, bool);
virtual idClipModel *GetClipModel(int);
virtual int GetNumClipModels();
virtual void SetMass(float, int);
virtual float GetMass(int);
virtual void SetContents(int, int);
virtual int GetContents(int);
virtual void SetClipMask(int, int);
virtual int GetClipMask(int);
virtual const idBounds *GetBounds(int);
virtual const idBounds *GetAbsBounds(int);
virtual void SetOrigin(const idVec3 *, int);
virtual void SetAxis(const idMat3 *, int);
virtual void Translate(const idVec3 *, int);
virtual void Rotate(const idRotation *, int);
virtual const idVec3 *GetOrigin(int);
virtual const idMat3 *GetAxis(int);
virtual const idVec3 *GetLocalOrigin(int);
virtual const idMat3 *GetLocalAxis(int);
virtual void SetLinearVelocity(const idVec3 *, int);
virtual void SetAngularVelocity(const idVec3 *, int);
virtual idVec3 *GetLinearVelocity(idVec3 *result, int);
virtual idVec3 *GetAngularVelocity(idVec3 *result, int);
virtual void SetGravity(const idVec3 *);
virtual const idVec3 *GetGravity();
virtual const idVec3 *GetGravityNormal();
virtual void SetWaterLevel(float, int);
virtual float GetWaterLevel(int);
virtual void SetWaterViscosity(float, int);
virtual float GetWaterViscosity(int);
virtual void SetWaterEntNum(int);
virtual int GetWaterEntNum();
virtual void SetWaterSurfaceWrldHeight(float);
virtual float GetWaterSurfaceWrldHeight();
virtual void GetImpactInfo(const int, const idVec3 *, impactInfo_t *);
virtual void ApplyImpulse(const int, const idVec3 *, const idVec3 *);
virtual void ApplyForce(const int, const idVec3 *, const idVec3 *);
virtual void Activate();
virtual void PutToRest();
virtual bool IsAtRest();
virtual bool IsPushable(int);
virtual void SaveState();
virtual void RestoreState();
virtual bool Evaluate(int, int);
virtual void UpdateTime(int);
virtual void ClipTranslation(trace_t *, const idVec3 *, const idClipModel *);
virtual void ClipRotation(trace_t *, const idRotation *, const idClipModel *);
virtual int ClipContents(const idClipModel *, int);
virtual void DisableClip();
virtual void EnableClip();
virtual void UnlinkClip();
virtual void LinkClip();
virtual bool EvaluateContacts();
virtual int GetNumContacts();
virtual const contactInfo_t *GetContact(int);
virtual void ClearContacts();
virtual void AddContactPhysics(idPhysics *);
virtual void RemoveContactPhysics(idPhysics *);
virtual int GetNumContactPhysics();
virtual idPhysics *GetContactPhysics(int);
virtual void ActivateContactPhysics();
virtual bool HasGroundContacts();
virtual bool IsGroundEntity(int);
virtual bool IsGroundClipModel(int, int);
virtual void SetPushed(int);
virtual idVec3 *GetPushedLinearVelocity(idVec3 *result, const int);
virtual idVec3 *GetPushedAngularVelocity(idVec3 *result, const int);
virtual void SetMaster(bool, const idVec3 *, const idMat3 *, const bindFlags_t);
virtual void SetLocalOrigin(const idVec3 *, int);
virtual void SetLocalAxis(const idMat3 *, int);
virtual int GetBlockingEntityNum();
virtual int GetLinearEndTime();
virtual int GetAngularEndTime();
virtual bool IsInNonResidentCollisionArea(bool);
virtual bool IsOutsideWorld();
virtual void Serialize(idSerializer *);
struct noclipBodyInfo_t {
int bodyId;
int originalClipMask;
idClipQuery query;
};
idList<idAFTree *,71> trees;
idList<idAFBody *,71> bodies;
idList<idAFConstraint *,71> constraints;
idList<idAFConstraint *,71> primaryConstraints;
idList<idAFConstraint *,71> auxiliaryConstraints;
idList<idAFConstraint *,71> frameConstraints;
idList<idAFConstraint_Contact *,71> contactConstraints;
idList<int,71> contactBodies;
idStaticList<idPhysics_AF::noclipBodyInfo_t,8> noclipBodies;
bool changedAF;
float linearFriction;
float angularFriction;
float contactFriction;
float bouncyness;
float totalMass;
idVec2 suspendVelocity;
idVec2 suspendAcceleration;
float noMoveTime;
float noMoveTranslation;
float noMoveRotation;
float minMoveTime;
float maxMoveTime;
float impulseThreshold;
float timeScale;
float timeScaleRampStart;
float timeScaleRampEnd;
float jointFrictionScale;
float jointFrictionDent;
float jointFrictionDentStart;
float jointFrictionDentEnd;
float jointFrictionDentScale;
float contactFrictionScale;
float contactFrictionDent;
float contactFrictionDentStart;
float contactFrictionDentEnd;
float contactFrictionDentScale;
idFader errorReduction;
idFader errorReductionMax;
idFader lcpEpsilon;
idFader limitErrorReduction;
idFader limitErrorReductionMax;
idFader limitLcpEpsilon;
idFader contactErrorReduction;
idFader contactErrorReductionMax;
idFader contactLcpEpsilon;
idFader universalErrorReduction;
idFader universalErrorReductionMax;
idFader universalTorsionLcpEpsilon;
int passEntityNum;
bool selfCollision;
bool comeToRest;
bool linearTime;
bool noImpact;
bool worldConstraintsLocked;
bool forcePushable;
bool addContactConstraints;
bool addGravity;
idAFBody *masterBody;
AFPState_t current;
AFPState_t saved;
float lastTimeStep;
int endTime;
float timeStep;
idVec3 lastImpulse;
idLCP *lcp;
idPhysics_AF();
~idPhysics_AF() override;
void SetClipModel(idClipModel*, float, int, bool) override;
idClipModel* GetClipModel(int) override;
int GetNumClipModels() override;
void SetMass(float, int) override;
float GetMass(int) override;
void SetContents(int, int) override;
int GetContents(int) override;
void SetClipMask(int, int) override;
int GetClipMask(int) override;
const idBounds* GetBounds(int) override;
const idBounds* GetAbsBounds(int) override;
void SetOrigin(const idVec3*, int) override;
void SetAxis(const idMat3*, int) override;
void Translate(const idVec3*, int) override;
void Rotate(const idRotation*, int) override;
const idVec3* GetOrigin(int) override;
const idMat3* GetAxis(int) override;
const idVec3* GetLocalOrigin(int) override;
const idMat3* GetLocalAxis(int) override;
void SetLinearVelocity(const idVec3*, int) override;
void SetAngularVelocity(const idVec3*, int) override;
idVec3* GetLinearVelocity(idVec3*, int) override;
idVec3* GetAngularVelocity(idVec3*, int) override;
void SetWaterEntNum(int) override;
int GetWaterEntNum() override;
void SetWaterSurfaceWrldHeight(float) override;
float GetWaterSurfaceWrldHeight() override;
void GetImpactInfo(int, const idVec3*, impactInfo_t*) override;
void ApplyImpulse(int, const idVec3*, const idVec3*) override;
void ApplyForce(int, const idVec3*, const idVec3*) override;
void Activate() override;
void PutToRest() override;
bool IsAtRest() override;
bool IsPushable(int) override;
void SaveState() override;
void RestoreState() override;
bool Evaluate(int, int) override;
void UpdateTime(int) override;
void ClipTranslation(trace_t*, const idVec3*,
const idClipModel*) override;
void ClipRotation(trace_t*, const idRotation*,
const idClipModel*) override;
int ClipContents(const idClipModel*, int) override;
void DisableClip() override;
void EnableClip() override;
void UnlinkClip() override;
void LinkClip() override;
bool EvaluateContacts() override;
void SetPushed(int) override;
idVec3* GetPushedLinearVelocity(idVec3*, int) override;
idVec3* GetPushedAngularVelocity(idVec3*, int) override;
void SetMaster(bool, const idVec3*, const idMat3*,
bindFlags_t) override;
void SetLocalOrigin(const idVec3*, int) override;
void SetLocalAxis(const idMat3*, int) override;
int GetBlockingEntityNum() override;
int GetLinearEndTime() override;
int GetAngularEndTime() override;
void Serialize(idSerializer*);
void Shutdown();
void SetSuspendTime(float minTime, float maxTime);
void SetSuspendTolerance(float translation, float rotation,
float noMoveTime_);
void SetSuspendSpeed(const idVec2& velocity,
const idVec2& acceleration);
void SetTimeScaleRamp(float start, float end);
void SetJointFrictionDent(float dent, float start, float end);
void SetContactFrictionDent(float dent, float start, float end);
void SetDefaultFriction(float linear, float angular, float contact);
float GetJointFrictionScale() const;
float GetContactFrictionScale() const;
void SetAuxAngularVelocity(const idVec3&);
void ForceBodyId(idAFBody*, int newId);
int GetBodyId(const idAFBody*) const;
idAFBody* GetBody(const char* name) const;
idAFBody* GetBody(int id) const;
idAFConstraint* GetConstraint(const char* name) const;
idAFConstraint* GetConstraint(int id) const;
int AddBody(idAFBody*);
void DeleteBody(int);
void AddConstraint(idAFConstraint*);
void DeleteConstraint(int);
void DeleteConstraint(const char* name);
void AddFrameConstraint(idAFConstraint*);
int AddNoclipBody(int bodyId);
void ApplyFriction(float timeStep, float endTimeMSec);
void PrimaryFactor();
void PrimaryForces(float timeStep);
void AuxiliaryForces(float timeStep);
void AddGravity();
void UpdateClipModels();
bool TestIfAtRest(float timeStep);
void EvaluateBodies(float timeStep);
void EvaluateConstraints(float timeStep);
void CollisionImpulse(idAFBody*, const trace_t&, float timeStep);
void IssueCollisionQueries();
void ResolveCollisions(float timeStep);
void AddFrameConstraints();
void RemoveFrameConstraints();
void SetupContactConstraints(float timeStep);
void AddContacts(idAFBody*, const contactsResult_t&);
void TestNoclipBodies();
void Evolve(float timeStep);
void BuildTrees();
void DebugDraw();
float GetLcpEpsilon(float timeStep) const;
float GetErrorReduction(float timeStep) const;
float GetErrorReductionMax(float timeStep) const;
float GetLimitErrorReduction(float timeStep) const;
float GetLimitErrorReductionMax(float timeStep) const;
float GetLimitLcpEpsilon(float timeStep) const;
float GetContactErrorReduction(float timeStep) const;
float GetContactErrorReductionMax(float timeStep) const;
float GetContactLcpEpsilon(float timeStep) const;
float GetUniversalErrorReduction(float timeStep) const;
float GetUniversalTorsionLcpEpsilon(float timeStep) const;
idList<idAFTree*, 71> trees;
idList<idAFBody*, 71> bodies;
idList<idAFConstraint*, 71> constraints;
idList<idAFConstraint*, 71> primaryConstraints;
idList<idAFConstraint*, 71> auxiliaryConstraints;
idList<idAFConstraint*, 71> frameConstraints;
idList<idAFConstraint_Contact*, 71> contactConstraints;
idList<int, 71> contactBodies;
idStaticList<noclipBodyInfo_t, 8> noclipBodies;
bool changedAF;
float linearFriction;
float angularFriction;
float contactFriction;
float bouncyness;
float totalMass;
idVec2 suspendVelocity;
idVec2 suspendAcceleration;
float noMoveTime;
float noMoveTranslation;
float noMoveRotation;
float minMoveTime;
float maxMoveTime;
float impulseThreshold;
float timeScale;
float timeScaleRampStart;
float timeScaleRampEnd;
float jointFrictionScale;
float jointFrictionDent;
float jointFrictionDentStart;
float jointFrictionDentEnd;
float jointFrictionDentScale;
float contactFrictionScale;
float contactFrictionDent;
float contactFrictionDentStart;
float contactFrictionDentEnd;
float contactFrictionDentScale;
idFader errorReduction;
idFader errorReductionMax;
idFader lcpEpsilon;
idFader limitErrorReduction;
idFader limitErrorReductionMax;
idFader limitLcpEpsilon;
idFader contactErrorReduction;
idFader contactErrorReductionMax;
idFader contactLcpEpsilon;
idFader universalErrorReduction;
idFader universalErrorReductionMax;
idFader universalTorsionLcpEpsilon;
int passEntityNum;
bool selfCollision;
bool comeToRest;
bool linearTime;
bool noImpact;
bool worldConstraintsLocked;
bool forcePushable;
bool addContactConstraints;
bool addGravity;
idAFBody* masterBody;
AFPState_t current;
AFPState_t saved;
float lastTimeStep;
int endTime;
float timeStep;
idVec3 lastImpulse;
idLCP* lcp;
};
// IDA Local Type ordinal 14619; PDB kind: struct.
struct idPhysics_AF::noclipBodyInfo_t
{
int bodyId;
int originalClipMask;
idClipQuery query;
};
static_assert(sizeof(AFPState_t) == 60,
"Recovered articulated-figure physics state ABI changed");
#if defined(_WIN32) && !defined(_WIN64)
static_assert(sizeof(idPhysics_AF) == 912,
"Recovered idPhysics_AF ABI changed");
#endif
@@ -0,0 +1,449 @@
#include "gamelib/physics/physics_ai.h"
#include "gamelib/physics/clipmodel.h"
#include "idlib/geometry/tracemodel.h"
#include "idlib/math/rotation.h"
#include <algorithm>
#include <cmath>
#include <cstring>
bool GameLib_GetMasterPhysicsTransform(idPhysicsCallbacks* callbacks,
idVec3& origin, idMat3& axis);
void GameLib_NotifyPhysicsActivated(idPhysicsCallbacks* callbacks,
int physicsId);
void GameLib_NotifyPhysicsDeactivated(idPhysicsCallbacks* callbacks,
int physicsId);
void GameLib_NotifyPhysicsCollision(idPhysicsCallbacks* callbacks,
int physicsId, const trace_t& collision, const idVec3& velocity);
namespace {
const idVec3 kAIZeroVector(0.0f, 0.0f, 0.0f);
const idMat3 kAIIdentityAxis(1.0f);
float AxisYaw(const idMat3& axis) {
return std::atan2(axis[0].y, axis[0].x) * 57.29577951308232f;
}
void ProjectOntoPlane(idVec3& vector, const idVec3& normal,
const float overBounce = 1.0f) {
if (normal.LengthSqr() <= 1.0e-12f) return;
vector = vector - normal * (vector.Dot(normal) * overBounce);
}
} // namespace
idPhysics_AI::idPhysics_AI()
: idPhysics_Actor()
, current{}
, saved{}
, stepMoveQuery{0}
, contactsQuery{0}
, lastCollisionNormal(0.0f, 0.0f, 0.0f)
, lastCollisionPoint(0.0f, 0.0f, 0.0f)
, stuckCollisionNormal(0.0f, 0.0f, 0.0f)
, stuckCollisionPoint(0.0f, 0.0f, 0.0f)
, clipModel_standing(nullptr)
, clipModel_crouched(nullptr)
, maxStepHeight(18.0f)
, minFloorCosine(0.70710677f)
, maxDropVelocity(-500.0f)
, heightCrouched(48.0f)
, movementType(AI_MOVE_WALKING)
, noImpact(false)
, masterControlledVelocity(false)
, swimmer(false)
, crouched(false)
, canSetCrouchedPhysics(false) {
type = PHYSICS_AI;
current.atRest = -1;
saved = current;
}
idPhysics_AI::~idPhysics_AI() {
UnlinkClip();
if (clipModel_crouched != nullptr
&& clipModel_crouched != clipModel_standing)
clipModel_crouched->Delete();
if (clipModel_standing != nullptr) clipModel_standing->Delete();
clipModel_standing = nullptr;
clipModel_crouched = nullptr;
clipModels[0] = nullptr;
}
void idPhysics_AI::SetClipModel(idClipModel* const model,
const float density, const int id, const bool freeOld) {
if (id != 0) {
idPhysics_Actor::SetClipModel(model, density, id, freeOld);
return;
}
if (freeOld) {
if (clipModel_crouched != nullptr
&& clipModel_crouched != clipModel_standing)
clipModel_crouched->Delete();
if (clipModel_standing != nullptr && clipModel_standing != model)
clipModel_standing->Delete();
}
clipModel_standing = model;
clipModel_crouched = nullptr;
clipModels[0] = nullptr;
if (model != nullptr && clip != nullptr) {
idBounds crouchedBounds = model->GetBounds();
crouchedBounds[1].z = heightCrouched;
if (crouchedBounds[1].z < crouchedBounds[0].z)
crouchedBounds[1].z = crouchedBounds[0].z;
idTraceModel crouchedTrace{};
crouchedTrace.SetupBox(crouchedBounds);
clipModel_crouched = new idClipModel(clip, &crouchedTrace, -1,
nullptr);
clipModel_crouched->SetContents(model->GetContents());
}
idPhysics_Actor::SetClipModel(model, density, 0, false);
current.worldOrigin = model != nullptr ? model->GetOrigin()
: kAIZeroVector;
current.localOrigin = current.worldOrigin;
LinkClip(current.worldOrigin, model != nullptr ? model->GetAxis()
: kAIIdentityAxis);
}
void idPhysics_AI::SetContents(const int contents, const int id) {
if (id <= 0) {
if (clipModel_standing != nullptr)
clipModel_standing->SetContents(contents);
if (clipModel_crouched != nullptr)
clipModel_crouched->SetContents(contents);
} else {
idPhysics_Actor::SetContents(contents, id);
}
}
void idPhysics_AI::SetOrigin(const idVec3* const newOrigin, int) {
if (newOrigin == nullptr) return;
stepMoveQuery.index = 0;
const idMat3 axis = clipModels[0] != nullptr
? clipModels[0]->GetAxis() : clipModelAxis;
LinkClip(*newOrigin, axis);
if (hasMaster && callbacks != nullptr) {
idVec3 masterOrigin;
idMat3 masterAxis;
if (GameLib_GetMasterPhysicsTransform(callbacks, masterOrigin,
masterAxis))
current.localOrigin = masterAxis.Transpose()
* (*newOrigin - masterOrigin);
} else {
current.localOrigin = *newOrigin;
}
Activate();
}
void idPhysics_AI::SetAxis(const idMat3* const newAxis, int) {
if (newAxis == nullptr) return;
stepMoveQuery.index = 0;
LinkClip(current.worldOrigin, *newAxis);
Activate();
}
void idPhysics_AI::Translate(const idVec3* const translation, int) {
if (translation == nullptr) return;
ResolveCollisions();
SetOrigin(&(current.worldOrigin = current.worldOrigin + *translation), 0);
}
void idPhysics_AI::Rotate(const idRotation* const rotation, int) {
if (rotation == nullptr) return;
ResolveCollisions();
current.worldOrigin = *rotation * current.worldOrigin;
const idMat3 axis = (clipModels[0] != nullptr
? clipModels[0]->GetAxis() : clipModelAxis) * rotation->ToMat3();
LinkClip(current.worldOrigin, axis);
current.localOrigin = *rotation * current.localOrigin;
Activate();
}
const idVec3* idPhysics_AI::GetLocalOrigin(int) {
return &current.localOrigin;
}
const idMat3* idPhysics_AI::GetLocalAxis(int) {
return clipModels[0] != nullptr ? &clipModels[0]->GetAxis()
: &kAIIdentityAxis;
}
void idPhysics_AI::SetLinearVelocity(const idVec3* const velocity, int) {
if (velocity == nullptr) return;
current.velocity = *velocity;
Activate();
}
void idPhysics_AI::SetAngularVelocity(const idVec3*, int) {}
idVec3* idPhysics_AI::GetLinearVelocity(idVec3* const result, int) {
if (result != nullptr) *result = current.velocity;
return result;
}
idVec3* idPhysics_AI::GetAngularVelocity(idVec3* const result, int) {
if (result != nullptr) result->Zero();
return result;
}
void idPhysics_AI::SetWaterEntNum(int) {}
int idPhysics_AI::GetWaterEntNum() { return -1; }
void idPhysics_AI::SetWaterSurfaceWrldHeight(float) {}
float idPhysics_AI::GetWaterSurfaceWrldHeight() { return 0.0f; }
void idPhysics_AI::GetImpactInfo(int, const idVec3*,
impactInfo_t* const info) {
if (info == nullptr) return;
info->Zero();
info->invMass = invMass;
info->velocity = current.velocity;
}
void idPhysics_AI::ApplyImpulse(int, const idVec3*,
const idVec3* const impulse) {
if (noImpact || impulse == nullptr) return;
if (swimmer && std::fabs(impulse->z) >= impulse->Length() - 1.0e-5f)
current.velocity.z += impulse->z * invMass * 1000.0f;
else
current.velocity = current.velocity + *impulse * invMass;
const float speed = current.velocity.Length();
if (speed > 2000.0f) current.velocity = current.velocity
* (2000.0f / speed);
Activate();
}
void idPhysics_AI::ApplyForce(int id, const idVec3* point,
const idVec3* force) {
ApplyImpulse(id, point, force);
}
void idPhysics_AI::Activate() {
current.atRest = -1;
if (callbacks != nullptr)
GameLib_NotifyPhysicsActivated(callbacks, GetPhysicsId());
}
void idPhysics_AI::PutToRest() {
current.atRest = 1;
current.velocity.Zero();
}
bool idPhysics_AI::IsAtRest() { return current.atRest >= 0; }
void idPhysics_AI::SaveState() {
saved = current;
if (clipModels[0] != nullptr) saved.worldOrigin = clipModels[0]->GetOrigin();
}
void idPhysics_AI::RestoreState() {
current = saved;
const idMat3 axis = clipModels[0] != nullptr
? clipModels[0]->GetAxis() : clipModelAxis;
LinkClip(current.worldOrigin, axis);
}
void idPhysics_AI::ResolveCollisions() {
lastCollisionNormal.Zero();
lastCollisionPoint.Zero();
ClearContacts();
current.onGround = false;
idClipModel* const model = clipModels[0];
if (model == nullptr) return;
AddGroundContacts(model, 12);
if (contacts.Num() == 0) return;
idVec3 normal;
normal.Zero();
for (int index = 0; index < contacts.Num(); ++index) {
normal = normal + contacts[index].normal;
UpdateCollisionResidency(contacts[index]);
if (contacts[index].normal.Dot(gravityNormal) < -minFloorCosine)
current.onGround = true;
}
normal.NormalizeFast();
lastCollisionNormal = normal;
lastCollisionPoint = contacts[0].point;
if (normal.LengthSqr() > 0.0f
&& std::fabs(normal.Dot(gravityNormal)) < 0.9999f) {
stuckCollisionNormal = normal;
stuckCollisionPoint = lastCollisionPoint;
}
}
void idPhysics_AI::Evolve(const float timeStep) {
idClipModel* const model = clipModels[0];
if (model == nullptr || clip == nullptr || timeStep <= 0.0f) return;
float stepDown = 0.0f;
if (movementType == AI_MOVE_FLYING) {
stepDown = maxStepHeight;
} else if (movementType == AI_MOVE_DROPPING) {
current.velocity = current.velocity + gravityVector * timeStep;
if (current.velocity.z < maxDropVelocity)
current.velocity.z = maxDropVelocity;
stepDown = maxStepHeight;
} else if (current.onGround
&& (!swimmer || GetWaterLevel(0) <= 0.0f)) {
ProjectOntoPlane(current.velocity, gravityNormal);
stepDown = maxStepHeight * 2.0f;
} else {
current.velocity = current.velocity + gravityVector * timeStep;
stepDown = maxStepHeight * 2.0f;
}
if (swimmer && GetWaterLevel(0) > 0.0f) {
const float damping = (std::max)(0.0f, 1.0f
- GetWaterViscosity(0) * GetWaterLevel(0) * timeStep);
current.velocity = current.velocity * damping;
}
ProjectOntoPlane(current.velocity, lastCollisionNormal, 1.001f);
const idVec3 start = model->GetOrigin();
const idVec3 end = start + current.velocity * timeStep;
trace_t collision{};
collision.fraction = 1.0f;
collision.endpos = end;
collision.endAxis = model->GetAxis();
contactsResult_t contactResults{};
stepMoveQuery = clip->StepMoveContacts(&collision, &contactResults,
start, end, gravityNormal, maxStepHeight, stepDown, model,
model->GetAxis(), clipMasks[0], GetEntityNumber(), false,
"idPhysics_AI::Evolve");
current.worldOrigin = collision.endpos;
LinkClip(current.worldOrigin, collision.endAxis);
ClearContacts();
const int count = (std::min)(contactResults.numContacts, 12);
for (int index = 0; index < count; ++index) {
contacts.Append(contactResults.contacts[index]);
UpdateCollisionResidency(contactResults.contacts[index]);
}
AddContactPhysicsForContacts();
lastCollisionNormal = collision.c.normal;
lastCollisionPoint = collision.c.point;
current.onGround = false;
for (int index = 0; index < contacts.Num(); ++index)
if (contacts[index].normal.Dot(gravityNormal) < -minFloorCosine)
current.onGround = true;
if (collision.fraction < 1.0f) {
ProjectOntoPlane(current.velocity, collision.c.normal, 1.001f);
if (callbacks != nullptr)
GameLib_NotifyPhysicsCollision(callbacks, GetPhysicsId(),
collision, current.velocity);
}
}
bool idPhysics_AI::Evaluate(const int timeStepMSec, int) {
RememberHistorySample();
idClipModel* desired = crouched && canSetCrouchedPhysics
? clipModel_crouched : clipModel_standing;
if (desired != nullptr && desired != clipModels[0]) {
const idVec3 origin = current.worldOrigin;
const idMat3 axis = clipModels[0] != nullptr
? clipModels[0]->GetAxis() : clipModelAxis;
if (clipModels[0] != nullptr) clipModels[0]->Unlink();
clipModels[0] = desired;
LinkClip(origin, axis);
}
if (hasMaster && callbacks != nullptr) {
idVec3 masterOrigin;
idMat3 masterAxis;
if (!GameLib_GetMasterPhysicsTransform(callbacks, masterOrigin,
masterAxis)) return false;
const idVec3 oldOrigin = current.worldOrigin;
current.worldOrigin = masterOrigin + masterAxis * current.localOrigin;
const idMat3 axis = clipModels[0] != nullptr
? clipModels[0]->GetAxis() : clipModelAxis;
LinkClip(current.worldOrigin, axis);
const float seconds = timeStepMSec * 0.001f;
if (seconds > 0.0f && masterControlledVelocity)
current.velocity = (current.worldOrigin - oldOrigin)
* (1.0f / seconds);
masterDeltaYaw = AxisYaw(masterAxis) - masterYaw;
masterYaw += masterDeltaYaw;
return (current.worldOrigin - oldOrigin).LengthSqr() != 0.0f;
}
if (IsAtRest()) return false;
ResolveCollisions();
Evolve(timeStepMSec * 0.001f);
if (IsOutsideWorld() && callbacks != nullptr)
GameLib_NotifyPhysicsDeactivated(callbacks, GetPhysicsId());
return true;
}
void idPhysics_AI::UpdateTime(int) {}
void idPhysics_AI::SetPushed(const int deltaTime) {
if (deltaTime <= 0) {
current.pushVelocity.Zero();
return;
}
current.pushVelocity = (current.worldOrigin - saved.worldOrigin)
* (1000.0f / static_cast<float>(deltaTime));
}
idVec3* idPhysics_AI::GetPushedLinearVelocity(idVec3* const result, int) {
if (result != nullptr) *result = current.pushVelocity;
return result;
}
idVec3* idPhysics_AI::GetPushedAngularVelocity(idVec3* const result, int) {
if (result != nullptr) result->Zero();
return result;
}
void idPhysics_AI::SetMaster(const bool enable,
const idVec3* const masterOrigin, const idMat3* const masterAxis,
bindFlags_t) {
stepMoveQuery.index = 0;
if (enable && masterOrigin != nullptr && masterAxis != nullptr) {
if (!hasMaster) {
current.localOrigin = masterAxis->Transpose()
* (current.worldOrigin - *masterOrigin);
masterYaw = AxisYaw(*masterAxis);
}
hasMaster = true;
ClearContacts();
} else if (hasMaster) {
hasMaster = false;
Activate();
}
}
void idPhysics_AI::SetLocalOrigin(const idVec3* const newOrigin, int) {
if (newOrigin == nullptr) return;
stepMoveQuery.index = 0;
current.localOrigin = *newOrigin;
if (hasMaster && callbacks != nullptr) {
idVec3 masterOrigin;
idMat3 masterAxis;
if (GameLib_GetMasterPhysicsTransform(callbacks, masterOrigin,
masterAxis))
LinkClip(masterOrigin + masterAxis * *newOrigin,
clipModels[0] != nullptr ? clipModels[0]->GetAxis()
: clipModelAxis);
} else {
LinkClip(*newOrigin, clipModels[0] != nullptr
? clipModels[0]->GetAxis() : clipModelAxis);
}
Activate();
}
void idPhysics_AI::SetLocalAxis(const idMat3* const newAxis, int) {
if (newAxis == nullptr) return;
idMat3 worldAxis = *newAxis;
if (hasMaster && callbacks != nullptr) {
idVec3 masterOrigin;
idMat3 masterAxis;
if (GameLib_GetMasterPhysicsTransform(callbacks, masterOrigin,
masterAxis)) worldAxis *= masterAxis;
}
LinkClip(current.worldOrigin, worldAxis);
Activate();
}
int idPhysics_AI::GetBlockingEntityNum() {
return contacts.Num() != 0 ? contacts[0].entityNum : 0x1FFF;
}
int idPhysics_AI::GetLinearEndTime() { return 0; }
int idPhysics_AI::GetAngularEndTime() { return 0; }
bool idPhysics_AI::IsOutsideWorld() {
return idPhysics_DynamicBase::IsOutsideWorld();
}
const idMat3* idPhysics_AI::GetGravityAxis() { return &clipModelAxis; }
void idPhysics_AI::DisableClip(const actorClipModel_t type_) {
idPhysics_Actor::DisableClip(type_);
}
void idPhysics_AI::EnableClip(const actorClipModel_t type_) {
idPhysics_Actor::EnableClip(type_);
}
void idPhysics_AI::LinkClip(const idVec3& origin, const idMat3& axis) {
current.worldOrigin = origin;
idPhysics_Actor::LinkClip(origin, axis);
}
+93 -115
View File
@@ -1,124 +1,102 @@
#pragma once
// Reconstructed C++ declarations from IDA Local Types and PDB/DIA metadata.
// Original PDB header: w:\tech5\engine\gamelib\physics\physics_ai.h
// Recovered logical types: 2
// Signatures retain Xbox 360 ABI evidence and may still require manual review.
#include "gamelib/physics/clip.h"
#include "gamelib/physics/physics_actor.h"
#include <cstdint>
// IDA Local Type ordinal 2324; PDB kind: enum.
enum idPhysics_AI::aiMovement_t : __int32
{
AI_MOVE_WALKING = 0x0,
AI_MOVE_FLYING = 0x1,
AI_MOVE_DROPPING = 0x2,
AI_MOVE_MAX = 0x3,
struct aiPState_t {
std::int16_t atRest;
bool onGround;
char pad;
idVec3 localOrigin;
idVec3 worldOrigin;
idVec3 velocity;
idVec3 pushVelocity;
};
// IDA Local Type ordinal 16704; PDB kind: class.
class __declspec(align(8)) idPhysics_AI : public idPhysics_Actor
{
class idPhysics_AI : public idPhysics_Actor {
public:
// Recovered virtual interface; IDA vtable ordinal 16705.
virtual ~idPhysics_AI();
virtual void SetClipModel(idClipModel *, float, int, bool);
virtual idClipModel *GetClipModel(int);
virtual int GetNumClipModels();
virtual void SetMass(float, int);
virtual float GetMass(int);
virtual void SetContents(int, int);
virtual int GetContents(int);
virtual void SetClipMask(int, int);
virtual int GetClipMask(int);
virtual const idBounds *GetBounds(int);
virtual const idBounds *GetAbsBounds(int);
virtual void SetOrigin(const idVec3 *, int);
virtual void SetAxis(const idMat3 *, int);
virtual void Translate(const idVec3 *, int);
virtual void Rotate(const idRotation *, int);
virtual const idVec3 *GetOrigin(int);
virtual const idMat3 *GetAxis(int);
virtual const idVec3 *GetLocalOrigin(int);
virtual const idMat3 *GetLocalAxis(int);
virtual void SetLinearVelocity(const idVec3 *, int);
virtual void SetAngularVelocity(const idVec3 *, int);
virtual idVec3 *GetLinearVelocity(idVec3 *result, int);
virtual idVec3 *GetAngularVelocity(idVec3 *result, int);
virtual void SetGravity(const idVec3 *);
virtual const idVec3 *GetGravity();
virtual const idVec3 *GetGravityNormal();
virtual void SetWaterLevel(float, int);
virtual float GetWaterLevel(int);
virtual void SetWaterViscosity(float, int);
virtual float GetWaterViscosity(int);
virtual void SetWaterEntNum(int);
virtual int GetWaterEntNum();
virtual void SetWaterSurfaceWrldHeight(float);
virtual float GetWaterSurfaceWrldHeight();
virtual void GetImpactInfo(const int, const idVec3 *, impactInfo_t *);
virtual void ApplyImpulse(const int, const idVec3 *, const idVec3 *);
virtual void ApplyForce(const int, const idVec3 *, const idVec3 *);
virtual void Activate();
virtual void PutToRest();
virtual bool IsAtRest();
virtual bool IsPushable(int);
virtual void SaveState();
virtual void RestoreState();
virtual bool Evaluate(int, int);
virtual void UpdateTime(int);
virtual void ClipTranslation(trace_t *, const idVec3 *, const idClipModel *);
virtual void ClipRotation(trace_t *, const idRotation *, const idClipModel *);
virtual int ClipContents(const idClipModel *, int);
virtual void DisableClip();
virtual void EnableClip();
virtual void UnlinkClip();
virtual void LinkClip();
virtual bool EvaluateContacts();
virtual int GetNumContacts();
virtual const contactInfo_t *GetContact(int);
virtual void ClearContacts();
virtual void AddContactPhysics(idPhysics *);
virtual void RemoveContactPhysics(idPhysics *);
virtual int GetNumContactPhysics();
virtual idPhysics *GetContactPhysics(int);
virtual void ActivateContactPhysics();
virtual bool HasGroundContacts();
virtual bool IsGroundEntity(int);
virtual bool IsGroundClipModel(int, int);
virtual void SetPushed(int);
virtual idVec3 *GetPushedLinearVelocity(idVec3 *result, const int);
virtual idVec3 *GetPushedAngularVelocity(idVec3 *result, const int);
virtual void SetMaster(bool, const idVec3 *, const idMat3 *, const bindFlags_t);
virtual void SetLocalOrigin(const idVec3 *, int);
virtual void SetLocalAxis(const idMat3 *, int);
virtual int GetBlockingEntityNum();
virtual int GetLinearEndTime();
virtual int GetAngularEndTime();
virtual bool IsInNonResidentCollisionArea(bool);
virtual bool IsOutsideWorld();
virtual const idMat3 *GetGravityAxis();
virtual void DisableClip_2(const idPhysics_Actor::actorClipModel_t);
virtual void EnableClip_2(const idPhysics_Actor::actorClipModel_t);
virtual void LinkClip_2(const idVec3 *, const idMat3 *);
enum aiMovement_t : int {
AI_MOVE_WALKING = 0,
AI_MOVE_FLYING = 1,
AI_MOVE_DROPPING = 2,
AI_MOVE_MAX = 3
};
aiPState_t current;
aiPState_t saved;
idClipQuery stepMoveQuery;
idClipQuery contactsQuery;
idVec3 lastCollisionNormal;
idVec3 lastCollisionPoint;
idVec3 stuckCollisionNormal;
idVec3 stuckCollisionPoint;
idClipModel *clipModel_standing;
idClipModel *clipModel_crouched;
float maxStepHeight;
float minFloorCosine;
float maxDropVelocity;
float heightCrouched;
idPhysics_AI::aiMovement_t movementType;
bool noImpact;
bool masterControlledVelocity;
bool swimmer;
bool crouched;
bool canSetCrouchedPhysics;
idPhysics_AI();
~idPhysics_AI() override;
void SetClipModel(idClipModel*, float, int, bool) override;
void SetContents(int, int) override;
void SetOrigin(const idVec3*, int) override;
void SetAxis(const idMat3*, int) override;
void Translate(const idVec3*, int) override;
void Rotate(const idRotation*, int) override;
const idVec3* GetLocalOrigin(int) override;
const idMat3* GetLocalAxis(int) override;
void SetLinearVelocity(const idVec3*, int) override;
void SetAngularVelocity(const idVec3*, int) override;
idVec3* GetLinearVelocity(idVec3*, int) override;
idVec3* GetAngularVelocity(idVec3*, int) override;
void SetWaterEntNum(int) override;
int GetWaterEntNum() override;
void SetWaterSurfaceWrldHeight(float) override;
float GetWaterSurfaceWrldHeight() override;
void GetImpactInfo(int, const idVec3*, impactInfo_t*) override;
void ApplyImpulse(int, const idVec3*, const idVec3*) override;
void ApplyForce(int, const idVec3*, const idVec3*) override;
void Activate() override;
void PutToRest() override;
bool IsAtRest() override;
void SaveState() override;
void RestoreState() override;
bool Evaluate(int, int) override;
void UpdateTime(int) override;
void SetPushed(int) override;
idVec3* GetPushedLinearVelocity(idVec3*, int) override;
idVec3* GetPushedAngularVelocity(idVec3*, int) override;
void SetMaster(bool, const idVec3*, const idMat3*, bindFlags_t) override;
void SetLocalOrigin(const idVec3*, int) override;
void SetLocalAxis(const idMat3*, int) override;
int GetBlockingEntityNum() override;
int GetLinearEndTime() override;
int GetAngularEndTime() override;
bool IsOutsideWorld() override;
const idMat3* GetGravityAxis() override;
void DisableClip(actorClipModel_t) override;
void EnableClip(actorClipModel_t) override;
void LinkClip(const idVec3&, const idMat3&) override;
void Evolve(float timeStep);
void ResolveCollisions();
aiPState_t current;
aiPState_t saved;
idClipQuery stepMoveQuery;
idClipQuery contactsQuery;
idVec3 lastCollisionNormal;
idVec3 lastCollisionPoint;
idVec3 stuckCollisionNormal;
idVec3 stuckCollisionPoint;
idClipModel* clipModel_standing;
idClipModel* clipModel_crouched;
float maxStepHeight;
float minFloorCosine;
float maxDropVelocity;
float heightCrouched;
aiMovement_t movementType;
bool noImpact;
bool masterControlledVelocity;
bool swimmer;
bool crouched;
bool canSetCrouchedPhysics;
};
static_assert(sizeof(aiPState_t) == 52,
"Recovered AI physics state ABI changed");
#if defined(_WIN32) && !defined(_WIN64)
static_assert(sizeof(idPhysics_AI) == 664,
"Recovered idPhysics_AI ABI changed");
#endif
@@ -32,7 +32,7 @@ public:
bool HasGroundContacts() override;
bool IsGroundEntity(int entityNumber) override;
bool IsGroundClipModel(int entityNumber, int bodyId) override;
bool IsOutsideWorld();
virtual bool IsOutsideWorld();
protected:
void AddContactPhysicsForContacts();
@@ -0,0 +1,923 @@
#include "gamelib/physics/physics_parametric.h"
#include "gamelib/physics/clip.h"
#include "gamelib/physics/clipmodel.h"
#include "gamelib/physics/push.h"
#include "idlib/math/rotation.h"
#include <algorithm>
#include <cmath>
#include <cstring>
bool GameLib_GetMasterPhysicsTransform(idPhysicsCallbacks* callbacks,
idVec3& origin, idMat3& axis);
void GameLib_NotifyPhysicsActivated(idPhysicsCallbacks* callbacks,
int physicsId);
namespace {
const idBounds kParametricZeroBounds{{idVec3(0.0f, 0.0f, 0.0f),
idVec3(0.0f, 0.0f, 0.0f)}};
const idVec3 kParametricZeroVector(0.0f, 0.0f, 0.0f);
const idMat3 kParametricIdentityAxis(1.0f);
void ZeroSpatial(idVec6& value) {
for (int index = 0; index < 6; ++index) value[index] = 0.0f;
}
void SetSpatial(idVec6& value, const idVec3& linear,
const idVec3& angular) {
value[0] = linear.x; value[1] = linear.y; value[2] = linear.z;
value[3] = angular.x; value[4] = angular.y; value[5] = angular.z;
}
idVec3 SpatialLinear(const idVec6& value) {
return idVec3(value[0], value[1], value[2]);
}
idVec3 SpatialAngular(const idVec6& value) {
return idVec3(value[3], value[4], value[5]);
}
idAngles Mat3ToAngles(const idMat3& axis) {
idAngles angles;
const float forwardLength = std::sqrt(axis[0].x * axis[0].x
+ axis[0].y * axis[0].y);
angles.pitch = std::atan2(-axis[0].z, forwardLength)
* 57.29577951308232f;
angles.yaw = std::atan2(axis[0].y, axis[0].x)
* 57.29577951308232f;
angles.roll = std::atan2(-axis[1].z, axis[2].z)
* 57.29577951308232f;
return angles;
}
idQuat Mat3ToQuat(const idMat3& matrix) {
idQuat result;
const float trace = matrix[0].x + matrix[1].y + matrix[2].z;
if (trace > 0.0f) {
const float scale = std::sqrt(trace + 1.0f) * 2.0f;
result.w = 0.25f * scale;
result.x = (matrix[2].y - matrix[1].z) / scale;
result.y = (matrix[0].z - matrix[2].x) / scale;
result.z = (matrix[1].x - matrix[0].y) / scale;
} else if (matrix[0].x > matrix[1].y
&& matrix[0].x > matrix[2].z) {
const float scale = std::sqrt(1.0f + matrix[0].x
- matrix[1].y - matrix[2].z) * 2.0f;
result.w = (matrix[2].y - matrix[1].z) / scale;
result.x = 0.25f * scale;
result.y = (matrix[0].y + matrix[1].x) / scale;
result.z = (matrix[0].z + matrix[2].x) / scale;
} else if (matrix[1].y > matrix[2].z) {
const float scale = std::sqrt(1.0f + matrix[1].y
- matrix[0].x - matrix[2].z) * 2.0f;
result.w = (matrix[0].z - matrix[2].x) / scale;
result.x = (matrix[0].y + matrix[1].x) / scale;
result.y = 0.25f * scale;
result.z = (matrix[1].z + matrix[2].y) / scale;
} else {
const float scale = std::sqrt(1.0f + matrix[2].z
- matrix[0].x - matrix[1].y) * 2.0f;
result.w = (matrix[1].x - matrix[0].y) / scale;
result.x = (matrix[0].z + matrix[2].x) / scale;
result.y = (matrix[1].z + matrix[2].y) / scale;
result.z = 0.25f * scale;
}
result.Normalize();
return result;
}
idMat3 QuatToMat3(idQuat quat) {
quat.Normalize();
const float xx = quat.x * quat.x;
const float yy = quat.y * quat.y;
const float zz = quat.z * quat.z;
const float xy = quat.x * quat.y;
const float xz = quat.x * quat.z;
const float yz = quat.y * quat.z;
const float wx = quat.w * quat.x;
const float wy = quat.w * quat.y;
const float wz = quat.w * quat.z;
return idMat3(
1.0f - 2.0f * (yy + zz), 2.0f * (xy - wz),
2.0f * (xz + wy), 2.0f * (xy + wz),
1.0f - 2.0f * (xx + zz), 2.0f * (yz - wx),
2.0f * (xz - wy), 2.0f * (yz + wx),
1.0f - 2.0f * (xx + yy));
}
bool MatrixChanged(const idMat3& first, const idMat3& second) {
return (first[0] - second[0]).LengthSqr() != 0.0f
|| (first[1] - second[1]).LengthSqr() != 0.0f
|| (first[2] - second[2]).LengthSqr() != 0.0f;
}
} // namespace
parametricPState_t::parametricPState_t()
: time(0)
, atRest(-1)
, worldOrigin(0.0f, 0.0f, 0.0f)
, worldAngles(0.0f, 0.0f, 0.0f)
, worldAxis(1.0f)
, localOrigin(0.0f, 0.0f, 0.0f)
, localAngles(0.0f, 0.0f, 0.0f)
, linearExtrapolation()
, angularExtrapolation()
, linearInterpolation()
, angularInterpolation()
, spline(nullptr)
, angularSpline(nullptr)
, splineInterpolate()
, useSplineAngles(false) {
linearInterpolation.Init(0.0f, 0.0f, 0.0f, 0.0f,
kParametricZeroVector, kParametricZeroVector);
angularInterpolation.Init(0.0f, 0.0f, 0.0f, 0.0f,
idAngles(0.0f, 0.0f, 0.0f), idAngles(0.0f, 0.0f, 0.0f));
splineInterpolate.Init(0.0f, 1.0f, 1.0f, 2.0f, 0.0f, 0.0f);
}
idPhysics_Parametric::idPhysics_Parametric()
: idPhysics_DynamicBase()
, current()
, saved(current)
, spatialVelocity{}
, blockingPhysicsId(-1)
, absBounds(kParametricZeroBounds)
, pusher(nullptr)
, isPusher(false)
, clipModel(nullptr)
, pushFlags(0)
, hasMaster(false)
, isOrientated(false)
, hasWorldOrientation(false)
, worldAxis(1.0f)
, worldOrigin(0.0f, 0.0f, 0.0f) {
type = PHYSICS_PARAMETRIC;
ZeroSpatial(spatialVelocity);
}
idPhysics_Parametric::~idPhysics_Parametric() {
if (clipModel != nullptr) clipModel->Unlink();
clipModel = nullptr;
}
void idPhysics_Parametric::SetPusher(idPush* const push, const int flags) {
pusher = push;
isPusher = push != nullptr;
pushFlags = flags;
}
bool idPhysics_Parametric::IsPusher() const { return isPusher; }
idCurve_Spline<idVec3>* idPhysics_Parametric::GetSpline() {
return current.spline;
}
const idAngles* idPhysics_Parametric::GetLocalAngles() const {
return &current.localAngles;
}
void idPhysics_Parametric::SetClipModel(idClipModel* const model, float,
int, const bool freeOld) {
if (clipModel != nullptr && clipModel != model && freeOld)
clipModel->Delete();
clipModel = model;
LinkClip();
}
idClipModel* idPhysics_Parametric::GetClipModel(int) { return clipModel; }
int idPhysics_Parametric::GetNumClipModels() { return clipModel != nullptr; }
void idPhysics_Parametric::SetMass(float, int) {}
float idPhysics_Parametric::GetMass(int) { return 0.0f; }
void idPhysics_Parametric::SetContents(const int contents, int) {
if (clipModel != nullptr) clipModel->SetContents(contents);
}
int idPhysics_Parametric::GetContents(int) {
return clipModel != nullptr ? clipModel->GetContents() : 0;
}
const idBounds* idPhysics_Parametric::GetBounds(int) {
return clipModel != nullptr ? &clipModel->GetBounds()
: &kParametricZeroBounds;
}
const idBounds* idPhysics_Parametric::GetAbsBounds(int) {
if (clipModel != nullptr) return &clipModel->GetAbsBounds();
absBounds[0] = current.worldOrigin;
absBounds[1] = current.worldOrigin;
return &absBounds;
}
void idPhysics_Parametric::SetLinearExtrapolation(
const extrapolation_t extrapolation, const int currentTime,
const int startTime, const int duration, const idVec3& base,
const idVec3& baseSpeed, const idVec3& speed) {
current.time = currentTime;
current.linearExtrapolation.Init(static_cast<float>(startTime),
static_cast<float>(duration), base, baseSpeed, speed, extrapolation);
current.localOrigin = base;
Activate();
}
void idPhysics_Parametric::SetAngularExtrapolation(
const extrapolation_t extrapolation, const int currentTime,
const int startTime, const int duration, const idAngles& base,
const idAngles& baseSpeed, const idAngles& speed) {
current.time = currentTime;
current.angularExtrapolation.Init(static_cast<float>(startTime),
static_cast<float>(duration), base, baseSpeed, speed, extrapolation);
current.localAngles = base;
Activate();
}
idAngles idPhysics_Parametric::GetCurrentAngularExtrapolationAngles(
const int time) const {
return current.angularExtrapolation.GetCurrentValue(
static_cast<float>(time));
}
void idPhysics_Parametric::SetLinearInterpolation(const int currentTime,
const int startTime, const int accelTime, const int decelTime,
const int duration, const idVec3& start, const idVec3& end) {
current.time = currentTime;
current.linearInterpolation.Init(static_cast<float>(startTime),
static_cast<float>(accelTime), static_cast<float>(decelTime),
static_cast<float>(duration), start, end);
current.localOrigin = start;
Activate();
}
void idPhysics_Parametric::SetAngularInterpolation(const int currentTime,
const int startTime, const int accelTime, const int decelTime,
const int duration, const idAngles& start, const idAngles& end) {
current.time = currentTime;
current.angularInterpolation.Init(static_cast<float>(startTime),
static_cast<float>(accelTime), static_cast<float>(decelTime),
static_cast<float>(duration), start, end);
current.localAngles = start;
Activate();
}
void idPhysics_Parametric::SetSpline(idCurve_Spline<idVec3>* const spline,
const int accelTime, const int decelTime,
const bool useAngles,
idCurve_Spline<idAngles>* const angularSpline) {
current.spline = spline;
current.angularSpline = angularSpline;
current.useSplineAngles = useAngles;
if (spline != nullptr && spline->GetNumValues() > 0) {
const float start = spline->GetTime(0);
const float end = spline->GetTime(spline->GetNumValues() - 1);
const float length = spline->GetLengthForTime(end);
current.splineInterpolate.Init(start,
static_cast<float>(accelTime), static_cast<float>(decelTime),
end - start, 0.0f, length);
}
Activate();
}
void idPhysics_Parametric::SetOrigin(const idVec3* const origin, int) {
if (origin == nullptr) return;
current.localOrigin = *origin;
current.worldOrigin = *origin;
current.linearExtrapolation.SetStartValue(*origin);
current.linearInterpolation.SetStartValue(*origin);
current.linearInterpolation.SetEndValue(*origin);
if (hasMaster && callbacks != nullptr) {
idVec3 masterOrigin;
idMat3 masterAxis;
if (GameLib_GetMasterPhysicsTransform(callbacks, masterOrigin,
masterAxis)) {
current.localOrigin = masterAxis.Transpose()
* (*origin - masterOrigin);
current.worldOrigin = *origin;
}
}
LinkClip();
Activate();
}
void idPhysics_Parametric::SetAxis(const idMat3* const axis, int) {
if (axis == nullptr) return;
current.worldAxis = *axis;
current.worldAngles = Mat3ToAngles(*axis);
current.localAngles = current.worldAngles;
current.angularExtrapolation.SetStartValue(current.localAngles);
current.angularInterpolation.SetStartValue(current.localAngles);
current.angularInterpolation.SetEndValue(current.localAngles);
LinkClip();
Activate();
}
void idPhysics_Parametric::Translate(const idVec3* const translation, int) {
if (translation == nullptr) return;
const idVec3 target = current.worldOrigin + *translation;
SetOrigin(&target, 0);
}
void idPhysics_Parametric::Rotate(const idRotation* const rotation, int) {
if (rotation == nullptr) return;
current.worldOrigin = *rotation * current.worldOrigin;
current.worldAxis *= rotation->ToMat3();
current.worldAngles = Mat3ToAngles(current.worldAxis);
current.localAngles = current.worldAngles;
LinkClip();
Activate();
}
const idVec3* idPhysics_Parametric::GetOrigin(int) {
return &current.worldOrigin;
}
const idMat3* idPhysics_Parametric::GetAxis(int) {
return &current.worldAxis;
}
const idVec3* idPhysics_Parametric::GetLocalOrigin(int) {
return &current.localOrigin;
}
const idMat3* idPhysics_Parametric::GetLocalAxis(int) {
static idMat3 localAxis;
localAxis = current.localAngles.ToMat3();
return &localAxis;
}
void idPhysics_Parametric::SetLinearVelocity(const idVec3* const velocity,
int) {
if (velocity == nullptr) return;
SetLinearExtrapolation(static_cast<extrapolation_t>(
EXTRAPOLATION_LINEAR | EXTRAPOLATION_NOSTOP),
current.time, current.time, 0, current.localOrigin,
kParametricZeroVector, *velocity);
}
void idPhysics_Parametric::SetAngularVelocity(const idVec3* const velocity,
int) {
if (velocity == nullptr) return;
const idAngles angularSpeed(velocity->x, velocity->y, velocity->z);
SetAngularExtrapolation(static_cast<extrapolation_t>(
EXTRAPOLATION_LINEAR | EXTRAPOLATION_NOSTOP),
current.time, current.time, 0, current.localAngles,
idAngles(0.0f, 0.0f, 0.0f), angularSpeed);
}
idVec3* idPhysics_Parametric::GetLinearVelocity(idVec3* const result, int) {
if (result != nullptr) *result = SpatialLinear(spatialVelocity);
return result;
}
idVec3* idPhysics_Parametric::GetAngularVelocity(idVec3* const result, int) {
if (result != nullptr) *result = SpatialAngular(spatialVelocity);
return result;
}
void idPhysics_Parametric::SetWaterEntNum(int) {}
int idPhysics_Parametric::GetWaterEntNum() { return -1; }
void idPhysics_Parametric::SetWaterSurfaceWrldHeight(float) {}
float idPhysics_Parametric::GetWaterSurfaceWrldHeight() { return 0.0f; }
void idPhysics_Parametric::GetImpactInfo(int, const idVec3*,
impactInfo_t* const info) {
if (info == nullptr) return;
info->Zero();
info->velocity = SpatialLinear(spatialVelocity);
}
void idPhysics_Parametric::ApplyImpulse(int, const idVec3*, const idVec3*) {}
void idPhysics_Parametric::ApplyForce(int, const idVec3*, const idVec3*) {}
void idPhysics_Parametric::Activate() {
current.atRest = -1;
if (callbacks != nullptr)
GameLib_NotifyPhysicsActivated(callbacks, GetPhysicsId());
}
void idPhysics_Parametric::PutToRest() {
current.atRest = current.time;
ZeroSpatial(spatialVelocity);
}
bool idPhysics_Parametric::IsAtRest() { return current.atRest >= 0; }
bool idPhysics_Parametric::IsPushable(int) { return false; }
void idPhysics_Parametric::SaveState() { saved = current; }
void idPhysics_Parametric::RestoreState() {
current = saved;
LinkClip();
}
void idPhysics_Parametric::ForceUpdateSpatialVelocity(
const int timeStepMSec) {
if (timeStepMSec <= 0) return;
const float inverseSeconds = 1000.0f / static_cast<float>(timeStepMSec);
const idVec3 oldOrigin = current.worldOrigin;
const idAngles oldAngles = current.worldAngles;
const float sampleTime = static_cast<float>(current.time + timeStepMSec);
idVec3 newOrigin = current.linearExtrapolation.GetCurrentValue(sampleTime);
if (current.linearInterpolation.GetDuration() > 0.0f)
newOrigin = current.linearInterpolation.GetCurrentValue(sampleTime);
idAngles newAngles = current.angularExtrapolation.GetCurrentValue(sampleTime);
if (current.angularInterpolation.GetDuration() > 0.0f)
newAngles = current.angularInterpolation.GetCurrentValue(sampleTime);
SetSpatial(spatialVelocity, (newOrigin - oldOrigin) * inverseSeconds,
idVec3(newAngles.pitch - oldAngles.pitch,
newAngles.yaw - oldAngles.yaw,
newAngles.roll - oldAngles.roll) * inverseSeconds);
}
bool idPhysics_Parametric::Evaluate(int timeStepMSec,
const int endTimeMSec) {
const idVec3 oldOrigin = current.worldOrigin;
const idMat3 oldAxis = current.worldAxis;
current.time = endTimeMSec;
idVec3 localOrigin = current.linearExtrapolation.GetCurrentValue(
static_cast<float>(endTimeMSec));
if (current.linearInterpolation.GetDuration() > 0.0f)
localOrigin = current.linearInterpolation.GetCurrentValue(
static_cast<float>(endTimeMSec));
idAngles localAngles = current.angularExtrapolation.GetCurrentValue(
static_cast<float>(endTimeMSec));
if (current.angularInterpolation.GetDuration() > 0.0f)
localAngles = current.angularInterpolation.GetCurrentValue(
static_cast<float>(endTimeMSec));
if (current.spline != nullptr && current.spline->GetNumValues() > 0) {
const float length = current.splineInterpolate.GetCurrentValue(
static_cast<float>(endTimeMSec));
const float splineTime = current.spline->GetTimeForLength(length);
localOrigin = current.spline->GetCurrentValue(splineTime);
if (current.angularSpline != nullptr)
localAngles = current.angularSpline->GetCurrentValue(splineTime);
}
current.localOrigin = localOrigin;
current.localAngles = localAngles;
idVec3 desiredOrigin = localOrigin;
idMat3 desiredAxis = localAngles.ToMat3();
if (hasMaster && callbacks != nullptr) {
idVec3 masterOrigin;
idMat3 masterAxis;
if (GameLib_GetMasterPhysicsTransform(callbacks, masterOrigin,
masterAxis)) {
desiredOrigin = masterOrigin + masterAxis * localOrigin;
if (isOrientated) desiredAxis *= masterAxis;
}
}
if (hasWorldOrientation) {
desiredOrigin = worldOrigin + worldAxis * desiredOrigin;
desiredAxis *= worldAxis;
}
blockingPhysicsId = -1;
if (isPusher && pusher != nullptr) {
trace_t pushTrace{};
pusher->ClipPush(pushTrace, this, pushFlags, oldOrigin, oldAxis,
desiredOrigin, desiredAxis);
if (pushTrace.fraction < 1.0f)
blockingPhysicsId = pushTrace.c.physicsId;
}
current.worldOrigin = desiredOrigin;
current.worldAngles = Mat3ToAngles(desiredAxis);
current.worldAxis = desiredAxis;
if (timeStepMSec > 0)
SetSpatial(spatialVelocity,
(current.worldOrigin - oldOrigin)
* (1000.0f / static_cast<float>(timeStepMSec)),
idVec3(current.worldAngles.pitch - Mat3ToAngles(oldAxis).pitch,
current.worldAngles.yaw - Mat3ToAngles(oldAxis).yaw,
current.worldAngles.roll - Mat3ToAngles(oldAxis).roll)
* (1000.0f / static_cast<float>(timeStepMSec)));
LinkClip();
const bool linearDone = current.linearInterpolation.GetDuration() > 0.0f
? current.linearInterpolation.IsDone(static_cast<float>(endTimeMSec))
: current.linearExtrapolation.IsDone(static_cast<float>(endTimeMSec));
const bool angularDone = current.angularInterpolation.GetDuration() > 0.0f
? current.angularInterpolation.IsDone(static_cast<float>(endTimeMSec))
: current.angularExtrapolation.IsDone(static_cast<float>(endTimeMSec));
const bool splineDone = current.spline == nullptr
|| current.splineInterpolate.IsDone(static_cast<float>(endTimeMSec));
if (linearDone && angularDone && splineDone) PutToRest();
return (current.worldOrigin - oldOrigin).LengthSqr() != 0.0f
|| MatrixChanged(current.worldAxis, oldAxis);
}
void idPhysics_Parametric::UpdateTime(const int endTimeMSec) {
const float delta = static_cast<float>(endTimeMSec - current.time);
current.time = endTimeMSec;
current.linearExtrapolation.SetStartTime(
current.linearExtrapolation.GetStartTime() + delta);
current.angularExtrapolation.SetStartTime(
current.angularExtrapolation.GetStartTime() + delta);
current.linearInterpolation.SetStartTime(
current.linearInterpolation.GetStartTime() + delta);
current.angularInterpolation.SetStartTime(
current.angularInterpolation.GetStartTime() + delta);
current.splineInterpolate.SetStartTime(
current.splineInterpolate.GetStartTime() + delta);
if (current.spline != nullptr) current.spline->ShiftTime(delta);
if (current.angularSpline != nullptr) current.angularSpline->ShiftTime(delta);
}
void idPhysics_Parametric::ClipRotation(trace_t* const results,
const idRotation* const rotation, const idClipModel* const model) {
if (results == nullptr) return;
const idClipModel* moving = model != nullptr ? model : clipModel;
if (clip == nullptr || moving == nullptr || rotation == nullptr) {
std::memset(results, 0, sizeof(*results));
results->fraction = 1.0f;
return;
}
clip->Rotation(results, current.worldOrigin, *rotation, moving,
current.worldAxis, clipMask, GetEntityNumber(), false,
"idPhysics_Parametric::ClipRotation");
}
int idPhysics_Parametric::ClipContents(const idClipModel* const model,
int queryMask) {
if (clip == nullptr || clipModel == nullptr) return 0;
if (queryMask == 0) queryMask = clipMask;
trace_t result{};
if (model != nullptr)
clip->ContentsModel(result, current.worldOrigin, clipModel,
current.worldAxis, queryMask, model->GetOrigin(), model,
model->GetAxis());
else
clip->Contents(&result, current.worldOrigin, clipModel,
current.worldAxis, queryMask, GetEntityNumber(),
"idPhysics_Parametric::ClipContents");
return result.c.contentFlags;
}
void idPhysics_Parametric::DisableClip() {
if (clipModel != nullptr) clipModel->Disable();
}
void idPhysics_Parametric::EnableClip() {
if (clipModel != nullptr) clipModel->Enable();
}
void idPhysics_Parametric::UnlinkClip() {
if (clipModel != nullptr) clipModel->Unlink();
}
void idPhysics_Parametric::LinkClip() {
if (clipModel != nullptr)
clipModel->Link(GetEntityNumber(), GetEntityNumber(), 0,
current.worldOrigin, current.worldAxis);
}
bool idPhysics_Parametric::EvaluateContacts() { return false; }
void idPhysics_Parametric::SetPushed(int) {}
idVec3* idPhysics_Parametric::GetPushedLinearVelocity(idVec3* result, int) {
if (result != nullptr) result->Zero(); return result;
}
idVec3* idPhysics_Parametric::GetPushedAngularVelocity(idVec3* result, int) {
if (result != nullptr) result->Zero(); return result;
}
void idPhysics_Parametric::SetMaster(const bool enable,
const idVec3* const masterOrigin, const idMat3* const masterAxis,
const bindFlags_t flags) {
if (enable && masterOrigin != nullptr && masterAxis != nullptr) {
current.localOrigin = masterAxis->Transpose()
* (current.worldOrigin - *masterOrigin);
current.localAngles = Mat3ToAngles((static_cast<int>(flags) & 1) != 0
? current.worldAxis * masterAxis->Transpose()
: current.worldAxis);
hasMaster = true;
isOrientated = (static_cast<int>(flags) & 1) != 0;
} else {
hasMaster = false;
}
}
void idPhysics_Parametric::SetLocalOrigin(const idVec3* origin, int) {
if (origin == nullptr) return;
current.localOrigin = *origin;
current.linearExtrapolation.SetStartValue(*origin);
Activate();
}
void idPhysics_Parametric::SetLocalAxis(const idMat3* axis, int) {
if (axis == nullptr) return;
current.localAngles = Mat3ToAngles(*axis);
current.angularExtrapolation.SetStartValue(current.localAngles);
Activate();
}
int idPhysics_Parametric::GetBlockingEntityNum() {
idPhysics* physics = idPhysics::GetPhysicsForId(blockingPhysicsId);
return physics != nullptr ? physics->GetEntityNumber() : 0x1FFF;
}
int idPhysics_Parametric::GetLinearEndTime() {
if (current.linearInterpolation.GetDuration() > 0.0f)
return static_cast<int>(current.linearInterpolation.GetEndTime());
return (static_cast<int>(current.linearExtrapolation.extrapolationType)
& EXTRAPOLATION_NOSTOP) != 0 ? 0
: static_cast<int>(current.linearExtrapolation.GetEndTime());
}
int idPhysics_Parametric::GetAngularEndTime() {
if (current.angularInterpolation.GetDuration() > 0.0f)
return static_cast<int>(current.angularInterpolation.GetEndTime());
return (static_cast<int>(current.angularExtrapolation.extrapolationType)
& EXTRAPOLATION_NOSTOP) != 0 ? 0
: static_cast<int>(current.angularExtrapolation.GetEndTime());
}
bool idPhysics_Parametric::IsOutsideWorld() {
return idPhysics_DynamicBase::IsOutsideWorld();
}
void idPhysics_Parametric::SetWorldOrientation(const idVec3& origin,
const idMat3& axis) {
if (hasWorldOrientation) ClearWorldOrientation();
worldOrigin = origin;
worldAxis = axis;
hasWorldOrientation = true;
}
void idPhysics_Parametric::ClearWorldOrientation() {
hasWorldOrientation = false;
worldOrigin.Zero();
worldAxis = idMat3(1.0f);
}
extrapolation_t idPhysics_Parametric::GetAngularExtrapolationType() const {
return current.angularExtrapolation.extrapolationType;
}
// Motion-matching parametric implementation. Its authority uses the same
// physics contract but stores quaternion interpolation and explicit velocity.
parametricPState_tMM::parametricPState_tMM()
: time(0), length(0.0f), totalLength(0.0f), atRest(-1),
worldOrigin(0.0f, 0.0f, 0.0f), worldAxis(1.0f),
localOrigin(0.0f, 0.0f, 0.0f), localAxis(1.0f),
linearExtrapolation(), angularExtrapolation(),
angularExtrapolationStartAxis(1.0f),
angularExtrapolationRotVec(0.0f, 0.0f, 1.0f),
linearVelocity(0.0f, 0.0f, 0.0f),
angularVelocity(0.0f, 0.0f, 0.0f), linearInterpolation(),
angularInterpolation(), splineInterpolate(),
splineAngleInterpolate(), spline(nullptr),
splineDerivative(0.0f, 0.0f, 0.0f), useSplineAngles(false),
pauseTime(0), oscillationExtrapolation{},
oscillationZRelative(false), localOffsetInterpolation(),
splineMaster(nullptr), localOriginScaleInterpolation(),
splineChilds(16), splineDummy(false) {
}
idPhysics_ParametricMM::idPhysics_ParametricMM()
: idPhysics_DynamicBase(), current(), saved(current),
blockingPhysicsId(-1), absBounds(kParametricZeroBounds), pusher(nullptr),
isPusher(false), clipModel(nullptr), pushFlags(0), hasMaster(false),
isOrientated(false), hasWorldOrientation(false), worldAxis(1.0f),
worldOrigin(0.0f, 0.0f, 0.0f), collideClipMask(0),
collideCallbackEnabled(false) {
type = PHYSICS_PARAMETRIC;
}
idPhysics_ParametricMM::~idPhysics_ParametricMM() {
if (clipModel != nullptr) clipModel->Unlink();
clipModel = nullptr;
}
void idPhysics_ParametricMM::SetPusher(idPush* push, int flags) {
pusher = push; isPusher = push != nullptr; pushFlags = flags;
}
idCurve_Spline<idVec3>* idPhysics_ParametricMM::GetSpline() {
return current.spline;
}
void idPhysics_ParametricMM::SetUseSplineAngles(bool value) {
current.useSplineAngles = value;
}
void idPhysics_ParametricMM::PauseParametricUntil(int resumeTime) {
current.pauseTime = resumeTime;
}
void idPhysics_ParametricMM::SetClipModel(idClipModel* model, float, int,
bool freeOld) {
if (clipModel != nullptr && clipModel != model && freeOld)
clipModel->Delete();
clipModel = model; LinkClip();
}
idClipModel* idPhysics_ParametricMM::GetClipModel(int) { return clipModel; }
int idPhysics_ParametricMM::GetNumClipModels() { return clipModel != nullptr; }
void idPhysics_ParametricMM::SetMass(float, int) {}
float idPhysics_ParametricMM::GetMass(int) { return 0.0f; }
void idPhysics_ParametricMM::SetContents(int value, int) {
if (clipModel != nullptr) clipModel->SetContents(value);
}
int idPhysics_ParametricMM::GetContents(int) {
return clipModel != nullptr ? clipModel->GetContents() : 0;
}
const idBounds* idPhysics_ParametricMM::GetBounds(int) {
return clipModel != nullptr ? &clipModel->GetBounds()
: &kParametricZeroBounds;
}
const idBounds* idPhysics_ParametricMM::GetAbsBounds(int) {
return clipModel != nullptr ? &clipModel->GetAbsBounds()
: &kParametricZeroBounds;
}
void idPhysics_ParametricMM::SetOrigin(const idVec3* value, int) {
if (value == nullptr) return;
current.worldOrigin = *value; current.localOrigin = *value;
current.linearExtrapolation.SetStartValue(*value); LinkClip(); Activate();
}
void idPhysics_ParametricMM::SetAxis(const idMat3* value, int) {
if (value == nullptr) return;
current.worldAxis = *value; current.localAxis = *value;
LinkClip(); Activate();
}
void idPhysics_ParametricMM::Translate(const idVec3* value, int) {
if (value == nullptr) return;
current.worldOrigin = current.worldOrigin + *value;
current.localOrigin = current.localOrigin + *value; LinkClip(); Activate();
}
void idPhysics_ParametricMM::Rotate(const idRotation* value, int) {
if (value == nullptr) return;
current.worldOrigin = *value * current.worldOrigin;
current.worldAxis *= value->ToMat3();
current.localAxis *= value->ToMat3(); LinkClip(); Activate();
}
const idVec3* idPhysics_ParametricMM::GetOrigin(int) {
return &current.worldOrigin;
}
const idMat3* idPhysics_ParametricMM::GetAxis(int) { return &current.worldAxis; }
const idVec3* idPhysics_ParametricMM::GetLocalOrigin(int) {
return &current.localOrigin;
}
const idMat3* idPhysics_ParametricMM::GetLocalAxis(int) {
return &current.localAxis;
}
void idPhysics_ParametricMM::SetLinearVelocity(const idVec3* value, int) {
if (value != nullptr) { current.linearVelocity = *value; Activate(); }
}
void idPhysics_ParametricMM::SetAngularVelocity(const idVec3* value, int) {
if (value != nullptr) { current.angularVelocity = *value; Activate(); }
}
idVec3* idPhysics_ParametricMM::GetLinearVelocity(idVec3* result, int) {
if (result != nullptr) *result = current.linearVelocity; return result;
}
idVec3* idPhysics_ParametricMM::GetAngularVelocity(idVec3* result, int) {
if (result != nullptr) *result = current.angularVelocity; return result;
}
void idPhysics_ParametricMM::SetWaterEntNum(int) {}
int idPhysics_ParametricMM::GetWaterEntNum() { return -1; }
void idPhysics_ParametricMM::SetWaterSurfaceWrldHeight(float) {}
float idPhysics_ParametricMM::GetWaterSurfaceWrldHeight() { return 0.0f; }
void idPhysics_ParametricMM::GetImpactInfo(int, const idVec3*,
impactInfo_t* info) {
if (info != nullptr) { info->Zero(); info->velocity = current.linearVelocity; }
}
void idPhysics_ParametricMM::ApplyImpulse(int, const idVec3*, const idVec3*) {}
void idPhysics_ParametricMM::ApplyForce(int, const idVec3*, const idVec3*) {}
void idPhysics_ParametricMM::Activate() {
current.atRest = -1;
if (callbacks != nullptr)
GameLib_NotifyPhysicsActivated(callbacks, GetPhysicsId());
}
void idPhysics_ParametricMM::PutToRest() {
current.atRest = current.time; current.linearVelocity.Zero();
current.angularVelocity.Zero();
}
bool idPhysics_ParametricMM::IsAtRest() { return current.atRest >= 0; }
bool idPhysics_ParametricMM::IsPushable(int) { return false; }
void idPhysics_ParametricMM::SaveState() { saved = current; }
void idPhysics_ParametricMM::RestoreState() { current = saved; LinkClip(); }
void idPhysics_ParametricMM::SetLinearExtrapolation(extrapolation_t type,
int currentTime, int startTime, int duration, const idVec3& base,
const idVec3& baseSpeed, const idVec3& speed) {
current.time = currentTime;
current.linearExtrapolation.Init(static_cast<float>(startTime),
static_cast<float>(duration), base, baseSpeed, speed, type);
current.localOrigin = base; Activate();
}
void idPhysics_ParametricMM::SetAngularExtrapolation(extrapolation_t type,
int currentTime, int startTime, int duration,
const idMat3& startAxis, const idVec3& rotationVector,
float baseSpeed, float speed) {
current.time = currentTime;
current.angularExtrapolationStartAxis = startAxis;
current.angularExtrapolationRotVec = rotationVector;
current.angularExtrapolation.Init(static_cast<float>(startTime),
static_cast<float>(duration), 0.0f, baseSpeed, speed, type);
Activate();
}
void idPhysics_ParametricMM::SetSpline(idCurve_Spline<idVec3>* spline,
int accelTime, int decelTime, bool useAngles) {
current.spline = spline; current.useSplineAngles = useAngles;
if (spline != nullptr && spline->GetNumValues() > 0) {
const float start = spline->GetTime(0);
const float end = spline->GetTime(spline->GetNumValues() - 1);
current.totalLength = spline->GetLengthForTime(end);
current.splineInterpolate.InitDuration(start, 0.0f,
end - start, 0.0f, current.totalLength);
(void)accelTime; (void)decelTime;
}
Activate();
}
bool idPhysics_ParametricMM::Evaluate(int timeStepMSec, int endTimeMSec) {
if (current.pauseTime > endTimeMSec) return false;
const idVec3 oldOrigin = current.worldOrigin;
const idMat3 oldAxis = current.worldAxis;
current.time = endTimeMSec;
idVec3 localOrigin = current.linearExtrapolation.GetCurrentValue(
static_cast<float>(endTimeMSec));
if (current.linearInterpolation.GetDuration() > 0.0f)
localOrigin = current.linearInterpolation.GetCurrentValue(
static_cast<float>(endTimeMSec));
if (current.spline != nullptr && current.spline->GetNumValues() > 0) {
current.length = current.splineInterpolate.GetCurrentValue(
static_cast<float>(endTimeMSec));
const float time = current.spline->GetTimeForLength(current.length);
localOrigin = current.spline->GetCurrentValue(time);
current.splineDerivative = current.spline->GetCurrentFirstDerivative(time);
}
idMat3 localAxis = current.localAxis;
if (current.angularInterpolation.GetDuration() > 0.0f)
localAxis = QuatToMat3(current.angularInterpolation.GetCurrentValue(
static_cast<float>(endTimeMSec)));
else {
const float angle = current.angularExtrapolation.GetCurrentValue(
static_cast<float>(endTimeMSec));
idRotation rotation(kParametricZeroVector,
current.angularExtrapolationRotVec, angle);
localAxis = current.angularExtrapolationStartAxis * rotation.ToMat3();
}
current.localOrigin = localOrigin;
current.localAxis = localAxis;
idVec3 desiredOrigin = localOrigin;
idMat3 desiredAxis = localAxis;
if (hasMaster && callbacks != nullptr) {
idVec3 masterOrigin; idMat3 masterAxis;
if (GameLib_GetMasterPhysicsTransform(callbacks, masterOrigin,
masterAxis)) {
desiredOrigin = masterOrigin + masterAxis * localOrigin;
if (isOrientated) desiredAxis *= masterAxis;
}
}
if (hasWorldOrientation) {
desiredOrigin = worldOrigin + worldAxis * desiredOrigin;
desiredAxis *= worldAxis;
}
blockingPhysicsId = -1;
if (isPusher && pusher != nullptr) {
trace_t trace{};
pusher->ClipPush(trace, this, pushFlags, oldOrigin, oldAxis,
desiredOrigin, desiredAxis);
if (trace.fraction < 1.0f) blockingPhysicsId = trace.c.physicsId;
}
current.worldOrigin = desiredOrigin;
current.worldAxis = desiredAxis;
if (timeStepMSec > 0) {
current.linearVelocity = (desiredOrigin - oldOrigin)
* (1000.0f / static_cast<float>(timeStepMSec));
const idAngles oldAngles = Mat3ToAngles(oldAxis);
const idAngles newAngles = Mat3ToAngles(desiredAxis);
current.angularVelocity = idVec3(
newAngles.pitch - oldAngles.pitch,
newAngles.yaw - oldAngles.yaw,
newAngles.roll - oldAngles.roll)
* (1000.0f / static_cast<float>(timeStepMSec));
}
LinkClip();
return (desiredOrigin - oldOrigin).LengthSqr() != 0.0f
|| MatrixChanged(desiredAxis, oldAxis);
}
void idPhysics_ParametricMM::UpdateTime(int endTimeMSec) {
const float delta = static_cast<float>(endTimeMSec - current.time);
current.time = endTimeMSec;
current.linearExtrapolation.SetStartTime(
current.linearExtrapolation.GetStartTime() + delta);
current.angularExtrapolation.SetStartTime(
current.angularExtrapolation.GetStartTime() + delta);
if (current.spline != nullptr) current.spline->ShiftTime(delta);
}
void idPhysics_ParametricMM::ClipRotation(trace_t* results,
const idRotation* rotation, const idClipModel* model) {
if (results == nullptr) return;
const idClipModel* moving = model != nullptr ? model : clipModel;
if (clip == nullptr || moving == nullptr || rotation == nullptr) {
std::memset(results, 0, sizeof(*results)); results->fraction = 1.0f;
return;
}
clip->Rotation(results, current.worldOrigin, *rotation, moving,
current.worldAxis, clipMask, GetEntityNumber(), false,
"idPhysics_ParametricMM::ClipRotation");
}
int idPhysics_ParametricMM::ClipContents(const idClipModel* model,
int mask) {
if (clip == nullptr || clipModel == nullptr) return 0;
if (mask == 0) mask = clipMask;
trace_t result{};
if (model != nullptr)
clip->ContentsModel(result, current.worldOrigin, clipModel,
current.worldAxis, mask, model->GetOrigin(), model,
model->GetAxis());
else
clip->Contents(&result, current.worldOrigin, clipModel,
current.worldAxis, mask, GetEntityNumber(),
"idPhysics_ParametricMM::ClipContents");
return result.c.contentFlags;
}
void idPhysics_ParametricMM::DisableClip() { if (clipModel) clipModel->Disable(); }
void idPhysics_ParametricMM::EnableClip() { if (clipModel) clipModel->Enable(); }
void idPhysics_ParametricMM::UnlinkClip() { if (clipModel) clipModel->Unlink(); }
void idPhysics_ParametricMM::LinkClip() {
if (clipModel) clipModel->Link(GetEntityNumber(), GetEntityNumber(), 0,
current.worldOrigin, current.worldAxis);
}
bool idPhysics_ParametricMM::EvaluateContacts() { return false; }
void idPhysics_ParametricMM::SetPushed(int) {}
idVec3* idPhysics_ParametricMM::GetPushedLinearVelocity(idVec3* result, int) {
if (result) result->Zero(); return result;
}
idVec3* idPhysics_ParametricMM::GetPushedAngularVelocity(idVec3* result, int) {
if (result) result->Zero(); return result;
}
void idPhysics_ParametricMM::SetMaster(bool enable,
const idVec3* masterOrigin, const idMat3* masterAxis,
bindFlags_t flags) {
if (enable && masterOrigin != nullptr && masterAxis != nullptr) {
current.localOrigin = masterAxis->Transpose()
* (current.worldOrigin - *masterOrigin);
current.localAxis = (static_cast<int>(flags) & 1) != 0
? current.worldAxis * masterAxis->Transpose() : current.worldAxis;
hasMaster = true; isOrientated = (static_cast<int>(flags) & 1) != 0;
} else hasMaster = false;
}
void idPhysics_ParametricMM::SetLocalOrigin(const idVec3* value, int) {
if (value) { current.localOrigin = *value; Activate(); }
}
void idPhysics_ParametricMM::SetLocalAxis(const idMat3* value, int) {
if (value) { current.localAxis = *value; Activate(); }
}
int idPhysics_ParametricMM::GetBlockingEntityNum() {
idPhysics* physics = idPhysics::GetPhysicsForId(blockingPhysicsId);
return physics ? physics->GetEntityNumber() : 0x1FFF;
}
int idPhysics_ParametricMM::GetLinearEndTime() {
return (static_cast<int>(current.linearExtrapolation.extrapolationType)
& EXTRAPOLATION_NOSTOP) != 0 ? 0
: static_cast<int>(current.linearExtrapolation.GetEndTime());
}
int idPhysics_ParametricMM::GetAngularEndTime() {
return (static_cast<int>(current.angularExtrapolation.extrapolationType)
& EXTRAPOLATION_NOSTOP) != 0 ? 0
: static_cast<int>(current.angularExtrapolation.GetEndTime());
}
bool idPhysics_ParametricMM::IsOutsideWorld() {
return idPhysics_DynamicBase::IsOutsideWorld();
}
+258 -194
View File
@@ -1,204 +1,268 @@
#pragma once
// Reconstructed C++ declarations from IDA Local Types and PDB/DIA metadata.
// Original PDB header: w:\tech5\engine\gamelib\physics\physics_parametric.h
// Recovered logical types: 2
// Signatures retain Xbox 360 ABI evidence and may still require manual review.
#include "gamelib/physics/physics_dynamicbase.h"
#include "idlib/containers/list.h"
#include "idlib/math/curve.h"
#include "idlib/math/interpolate.h"
class idPush;
// IDA Local Type ordinal 15500; PDB kind: class.
class idPhysics_Parametric : public idPhysics_DynamicBase
{
public:
// Recovered virtual interface; IDA vtable ordinal 15501.
virtual ~idPhysics_Parametric();
virtual void SetClipModel(idClipModel *, float, int, bool);
virtual idClipModel *GetClipModel(int);
virtual int GetNumClipModels();
virtual void SetMass(float, int);
virtual float GetMass(int);
virtual void SetContents(int, int);
virtual int GetContents(int);
virtual void SetClipMask(int, int);
virtual int GetClipMask(int);
virtual const idBounds *GetBounds(int);
virtual const idBounds *GetAbsBounds(int);
virtual void SetOrigin(const idVec3 *, int);
virtual void SetAxis(const idMat3 *, int);
virtual void Translate(const idVec3 *, int);
virtual void Rotate(const idRotation *, int);
virtual const idVec3 *GetOrigin(int);
virtual const idMat3 *GetAxis(int);
virtual const idVec3 *GetLocalOrigin(int);
virtual const idMat3 *GetLocalAxis(int);
virtual void SetLinearVelocity(const idVec3 *, int);
virtual void SetAngularVelocity(const idVec3 *, int);
virtual idVec3 *GetLinearVelocity(idVec3 *result, int);
virtual idVec3 *GetAngularVelocity(idVec3 *result, int);
virtual void SetGravity(const idVec3 *);
virtual const idVec3 *GetGravity();
virtual const idVec3 *GetGravityNormal();
virtual void SetWaterLevel(float, int);
virtual float GetWaterLevel(int);
virtual void SetWaterViscosity(float, int);
virtual float GetWaterViscosity(int);
virtual void SetWaterEntNum(int);
virtual int GetWaterEntNum();
virtual void SetWaterSurfaceWrldHeight(float);
virtual float GetWaterSurfaceWrldHeight();
virtual void GetImpactInfo(const int, const idVec3 *, impactInfo_t *);
virtual void ApplyImpulse(const int, const idVec3 *, const idVec3 *);
virtual void ApplyForce(const int, const idVec3 *, const idVec3 *);
virtual void Activate();
virtual void PutToRest();
virtual bool IsAtRest();
virtual bool IsPushable(int);
virtual void SaveState();
virtual void RestoreState();
virtual bool Evaluate(int, int);
virtual void UpdateTime(int);
virtual void ClipTranslation(trace_t *, const idVec3 *, const idClipModel *);
virtual void ClipRotation(trace_t *, const idRotation *, const idClipModel *);
virtual int ClipContents(const idClipModel *, int);
virtual void DisableClip();
virtual void EnableClip();
virtual void UnlinkClip();
virtual void LinkClip();
virtual bool EvaluateContacts();
virtual int GetNumContacts();
virtual const contactInfo_t *GetContact(int);
virtual void ClearContacts();
virtual void AddContactPhysics(idPhysics *);
virtual void RemoveContactPhysics(idPhysics *);
virtual int GetNumContactPhysics();
virtual idPhysics *GetContactPhysics(int);
virtual void ActivateContactPhysics();
virtual bool HasGroundContacts();
virtual bool IsGroundEntity(int);
virtual bool IsGroundClipModel(int, int);
virtual void SetPushed(int);
virtual idVec3 *GetPushedLinearVelocity(idVec3 *result, const int);
virtual idVec3 *GetPushedAngularVelocity(idVec3 *result, const int);
virtual void SetMaster(bool, const idVec3 *, const idMat3 *, const bindFlags_t);
virtual void SetLocalOrigin(const idVec3 *, int);
virtual void SetLocalAxis(const idMat3 *, int);
virtual int GetBlockingEntityNum();
virtual int GetLinearEndTime();
virtual int GetAngularEndTime();
virtual bool IsInNonResidentCollisionArea(bool);
virtual bool IsOutsideWorld();
struct parametricPState_t {
int time;
int atRest;
idVec3 worldOrigin;
idAngles worldAngles;
idMat3 worldAxis;
idVec3 localOrigin;
idAngles localAngles;
idExtrapolate<idVec3> linearExtrapolation;
idExtrapolate<idAngles> angularExtrapolation;
idInterpolateAccelDecelLinear<idVec3> linearInterpolation;
idInterpolateAccelDecelLinear<idAngles> angularInterpolation;
idCurve_Spline<idVec3>* spline;
idCurve_Spline<idAngles>* angularSpline;
idInterpolateAccelDecelLinear<float> splineInterpolate;
bool useSplineAngles;
parametricPState_t current;
parametricPState_t saved;
idVec6 spatialVelocity;
int blockingPhysicsId;
idBounds absBounds;
idPush *pusher;
bool isPusher;
idClipModel *clipModel;
int pushFlags;
bool hasMaster;
bool isOrientated;
bool hasWorldOrientation;
idMat3 worldAxis;
idVec3 worldOrigin;
parametricPState_t();
};
// IDA Local Type ordinal 19690; PDB kind: class.
class __declspec(align(4)) idPhysics_ParametricMM : public idPhysics_DynamicBase
{
class idPhysics_Parametric : public idPhysics_DynamicBase {
public:
// Recovered virtual interface; IDA vtable ordinal 19694.
virtual ~idPhysics_ParametricMM();
virtual void SetClipModel(idClipModel *, float, int, bool);
virtual idClipModel *GetClipModel(int);
virtual int GetNumClipModels();
virtual void SetMass(float, int);
virtual float GetMass(int);
virtual void SetContents(int, int);
virtual int GetContents(int);
virtual void SetClipMask(int, int);
virtual int GetClipMask(int);
virtual const idBounds *GetBounds(int);
virtual const idBounds *GetAbsBounds(int);
virtual void SetOrigin(const idVec3 *, int);
virtual void SetAxis(const idMat3 *, int);
virtual void Translate(const idVec3 *, int);
virtual void Rotate(const idRotation *, int);
virtual const idVec3 *GetOrigin(int);
virtual const idMat3 *GetAxis(int);
virtual const idVec3 *GetLocalOrigin(int);
virtual const idMat3 *GetLocalAxis(int);
virtual void SetLinearVelocity(const idVec3 *, int);
virtual void SetAngularVelocity(const idVec3 *, int);
virtual idVec3 *GetLinearVelocity(idVec3 *result, int);
virtual idVec3 *GetAngularVelocity(idVec3 *result, int);
virtual void SetGravity(const idVec3 *);
virtual const idVec3 *GetGravity();
virtual const idVec3 *GetGravityNormal();
virtual void SetWaterLevel(float, int);
virtual float GetWaterLevel(int);
virtual void SetWaterViscosity(float, int);
virtual float GetWaterViscosity(int);
virtual void SetWaterEntNum(int);
virtual int GetWaterEntNum();
virtual void SetWaterSurfaceWrldHeight(float);
virtual float GetWaterSurfaceWrldHeight();
virtual void GetImpactInfo(const int, const idVec3 *, impactInfo_t *);
virtual void ApplyImpulse(const int, const idVec3 *, const idVec3 *);
virtual void ApplyForce(const int, const idVec3 *, const idVec3 *);
virtual void Activate();
virtual void PutToRest();
virtual bool IsAtRest();
virtual bool IsPushable(int);
virtual void SaveState();
virtual void RestoreState();
virtual bool Evaluate(int, int);
virtual void UpdateTime(int);
virtual void ClipTranslation(trace_t *, const idVec3 *, const idClipModel *);
virtual void ClipRotation(trace_t *, const idRotation *, const idClipModel *);
virtual int ClipContents(const idClipModel *, int);
virtual void DisableClip();
virtual void EnableClip();
virtual void UnlinkClip();
virtual void LinkClip();
virtual bool EvaluateContacts();
virtual int GetNumContacts();
virtual const contactInfo_t *GetContact(int);
virtual void ClearContacts();
virtual void AddContactPhysics(idPhysics *);
virtual void RemoveContactPhysics(idPhysics *);
virtual int GetNumContactPhysics();
virtual idPhysics *GetContactPhysics(int);
virtual void ActivateContactPhysics();
virtual bool HasGroundContacts();
virtual bool IsGroundEntity(int);
virtual bool IsGroundClipModel(int, int);
virtual void SetPushed(int);
virtual idVec3 *GetPushedLinearVelocity(idVec3 *result, const int);
virtual idVec3 *GetPushedAngularVelocity(idVec3 *result, const int);
virtual void SetMaster(bool, const idVec3 *, const idMat3 *, const bindFlags_t);
virtual void SetLocalOrigin(const idVec3 *, int);
virtual void SetLocalAxis(const idMat3 *, int);
virtual int GetBlockingEntityNum();
virtual int GetLinearEndTime();
virtual int GetAngularEndTime();
virtual bool IsInNonResidentCollisionArea(bool);
virtual bool IsOutsideWorld();
idPhysics_Parametric();
~idPhysics_Parametric() override;
parametricPState_tMM current;
parametricPState_tMM saved;
int blockingPhysicsId;
idBounds absBounds;
idPush *pusher;
bool isPusher;
idClipModel *clipModel;
int pushFlags;
bool hasMaster;
bool isOrientated;
bool hasWorldOrientation;
idMat3 worldAxis;
idVec3 worldOrigin;
int collideClipMask;
bool collideCallbackEnabled;
void SetClipModel(idClipModel*, float, int, bool) override;
idClipModel* GetClipModel(int) override;
int GetNumClipModels() override;
void SetMass(float, int) override;
float GetMass(int) override;
void SetContents(int, int) override;
int GetContents(int) override;
const idBounds* GetBounds(int) override;
const idBounds* GetAbsBounds(int) override;
void SetOrigin(const idVec3*, int) override;
void SetAxis(const idMat3*, int) override;
void Translate(const idVec3*, int) override;
void Rotate(const idRotation*, int) override;
const idVec3* GetOrigin(int) override;
const idMat3* GetAxis(int) override;
const idVec3* GetLocalOrigin(int) override;
const idMat3* GetLocalAxis(int) override;
void SetLinearVelocity(const idVec3*, int) override;
void SetAngularVelocity(const idVec3*, int) override;
idVec3* GetLinearVelocity(idVec3*, int) override;
idVec3* GetAngularVelocity(idVec3*, int) override;
void SetWaterEntNum(int) override;
int GetWaterEntNum() override;
void SetWaterSurfaceWrldHeight(float) override;
float GetWaterSurfaceWrldHeight() override;
void GetImpactInfo(int, const idVec3*, impactInfo_t*) override;
void ApplyImpulse(int, const idVec3*, const idVec3*) override;
void ApplyForce(int, const idVec3*, const idVec3*) override;
void Activate() override;
void PutToRest() override;
bool IsAtRest() override;
bool IsPushable(int) override;
void SaveState() override;
void RestoreState() override;
bool Evaluate(int, int) override;
void UpdateTime(int) override;
void ClipRotation(trace_t*, const idRotation*, const idClipModel*) override;
int ClipContents(const idClipModel*, int) override;
void DisableClip() override;
void EnableClip() override;
void UnlinkClip() override;
void LinkClip() override;
bool EvaluateContacts() override;
void SetPushed(int) override;
idVec3* GetPushedLinearVelocity(idVec3*, int) override;
idVec3* GetPushedAngularVelocity(idVec3*, int) override;
void SetMaster(bool, const idVec3*, const idMat3*, bindFlags_t) override;
void SetLocalOrigin(const idVec3*, int) override;
void SetLocalAxis(const idMat3*, int) override;
int GetBlockingEntityNum() override;
int GetLinearEndTime() override;
int GetAngularEndTime() override;
bool IsOutsideWorld() override;
void SetPusher(idPush* push, int flags);
bool IsPusher() const;
idCurve_Spline<idVec3>* GetSpline();
const idAngles* GetLocalAngles() const;
void SetLinearExtrapolation(extrapolation_t type, int currentTime,
int startTime, int duration, const idVec3& base,
const idVec3& baseSpeed, const idVec3& speed);
void SetAngularExtrapolation(extrapolation_t type, int currentTime,
int startTime, int duration, const idAngles& base,
const idAngles& baseSpeed, const idAngles& speed);
idAngles GetCurrentAngularExtrapolationAngles(int time) const;
void SetLinearInterpolation(int currentTime, int startTime,
int accelTime, int decelTime, int duration,
const idVec3& start, const idVec3& end);
void SetAngularInterpolation(int currentTime, int startTime,
int accelTime, int decelTime, int duration,
const idAngles& start, const idAngles& end);
void SetSpline(idCurve_Spline<idVec3>* spline, int accelTime,
int decelTime, bool useSplineAngles,
idCurve_Spline<idAngles>* angularSpline = nullptr);
void SetWorldOrientation(const idVec3& origin, const idMat3& axis);
void ClearWorldOrientation();
void ForceUpdateSpatialVelocity(int timeStepMSec);
extrapolation_t GetAngularExtrapolationType() const;
parametricPState_t current;
parametricPState_t saved;
idVec6 spatialVelocity;
int blockingPhysicsId;
idBounds absBounds;
idPush* pusher;
bool isPusher;
idClipModel* clipModel;
int pushFlags;
bool hasMaster;
bool isOrientated;
bool hasWorldOrientation;
idMat3 worldAxis;
idVec3 worldOrigin;
};
class idPhysics_ParametricMM;
struct parametricSplineBatchInfo_tMM {
float DistanceFromMe;
idPhysics_ParametricMM* PhysObj;
};
struct parametricPState_tMM {
int time;
float length;
float totalLength;
int atRest;
idVec3 worldOrigin;
idMat3 worldAxis;
idVec3 localOrigin;
idMat3 localAxis;
idExtrapolate<idVec3> linearExtrapolation;
idExtrapolate<float> angularExtrapolation;
idMat3 angularExtrapolationStartAxis;
idVec3 angularExtrapolationRotVec;
idVec3 linearVelocity;
idVec3 angularVelocity;
idInterpolateAccelDecelLinear<idVec3> linearInterpolation;
idInterpolateAccelDecelLinear<idQuat> angularInterpolation;
idInterpolateAccelLinearEx<float> splineInterpolate;
idInterpolate<idQuat> splineAngleInterpolate;
idCurve_Spline<idVec3>* spline;
idVec3 splineDerivative;
bool useSplineAngles;
int pauseTime;
idExtrapolate<float> oscillationExtrapolation[3];
bool oscillationZRelative;
idInterpolate<idVec3> localOffsetInterpolation;
idPhysics_ParametricMM* splineMaster;
idInterpolate<idVec3> localOriginScaleInterpolation;
idList<parametricSplineBatchInfo_tMM, 5> splineChilds;
bool splineDummy;
parametricPState_tMM();
};
class idPhysics_ParametricMM : public idPhysics_DynamicBase {
public:
idPhysics_ParametricMM();
~idPhysics_ParametricMM() override;
void SetClipModel(idClipModel*, float, int, bool) override;
idClipModel* GetClipModel(int) override;
int GetNumClipModels() override;
void SetMass(float, int) override;
float GetMass(int) override;
void SetContents(int, int) override;
int GetContents(int) override;
const idBounds* GetBounds(int) override;
const idBounds* GetAbsBounds(int) override;
void SetOrigin(const idVec3*, int) override;
void SetAxis(const idMat3*, int) override;
void Translate(const idVec3*, int) override;
void Rotate(const idRotation*, int) override;
const idVec3* GetOrigin(int) override;
const idMat3* GetAxis(int) override;
const idVec3* GetLocalOrigin(int) override;
const idMat3* GetLocalAxis(int) override;
void SetLinearVelocity(const idVec3*, int) override;
void SetAngularVelocity(const idVec3*, int) override;
idVec3* GetLinearVelocity(idVec3*, int) override;
idVec3* GetAngularVelocity(idVec3*, int) override;
void SetWaterEntNum(int) override;
int GetWaterEntNum() override;
void SetWaterSurfaceWrldHeight(float) override;
float GetWaterSurfaceWrldHeight() override;
void GetImpactInfo(int, const idVec3*, impactInfo_t*) override;
void ApplyImpulse(int, const idVec3*, const idVec3*) override;
void ApplyForce(int, const idVec3*, const idVec3*) override;
void Activate() override;
void PutToRest() override;
bool IsAtRest() override;
bool IsPushable(int) override;
void SaveState() override;
void RestoreState() override;
bool Evaluate(int, int) override;
void UpdateTime(int) override;
void ClipRotation(trace_t*, const idRotation*, const idClipModel*) override;
int ClipContents(const idClipModel*, int) override;
void DisableClip() override;
void EnableClip() override;
void UnlinkClip() override;
void LinkClip() override;
bool EvaluateContacts() override;
void SetPushed(int) override;
idVec3* GetPushedLinearVelocity(idVec3*, int) override;
idVec3* GetPushedAngularVelocity(idVec3*, int) override;
void SetMaster(bool, const idVec3*, const idMat3*, bindFlags_t) override;
void SetLocalOrigin(const idVec3*, int) override;
void SetLocalAxis(const idMat3*, int) override;
int GetBlockingEntityNum() override;
int GetLinearEndTime() override;
int GetAngularEndTime() override;
bool IsOutsideWorld() override;
void SetPusher(idPush* push, int flags);
idCurve_Spline<idVec3>* GetSpline();
void SetUseSplineAngles(bool value);
void PauseParametricUntil(int resumeTime);
void SetLinearExtrapolation(extrapolation_t type, int currentTime,
int startTime, int duration, const idVec3& base,
const idVec3& baseSpeed, const idVec3& speed);
void SetAngularExtrapolation(extrapolation_t type, int currentTime,
int startTime, int duration, const idMat3& startAxis,
const idVec3& rotationVector, float baseSpeed, float speed);
void SetSpline(idCurve_Spline<idVec3>* spline, int accelTime,
int decelTime, bool useSplineAngles);
parametricPState_tMM current;
parametricPState_tMM saved;
int blockingPhysicsId;
idBounds absBounds;
idPush* pusher;
bool isPusher;
idClipModel* clipModel;
int pushFlags;
bool hasMaster;
bool isOrientated;
bool hasWorldOrientation;
idMat3 worldAxis;
idVec3 worldOrigin;
int collideClipMask;
bool collideCallbackEnabled;
};
#if defined(_WIN32) && !defined(_WIN64)
static_assert(sizeof(parametricPState_t) == 496,
"Recovered parametric state ABI changed");
static_assert(sizeof(idPhysics_Parametric) == 1232,
"Recovered idPhysics_Parametric ABI changed");
static_assert(sizeof(parametricPState_tMM) == 872,
"Recovered MM parametric state ABI changed");
static_assert(sizeof(idPhysics_ParametricMM) == 1968,
"Recovered idPhysics_ParametricMM ABI changed");
#endif
@@ -0,0 +1,978 @@
#include "gamelib/physics/physics_player.h"
#include "gamelib/physics/clipmodel.h"
#include "idlib/geometry/tracemodel.h"
#include "idlib/math/rotation.h"
#include <algorithm>
#include <cmath>
#include <cstring>
bool GameLib_GetMasterPhysicsTransform(idPhysicsCallbacks* callbacks,
idVec3& origin, idMat3& axis);
void GameLib_NotifyPhysicsActivated(idPhysicsCallbacks* callbacks,
int physicsId);
void GameLib_NotifyPhysicsDeactivated(idPhysicsCallbacks* callbacks,
int physicsId);
void GameLib_NotifyPhysicsCollision(idPhysicsCallbacks* callbacks,
int physicsId, const trace_t& collision, const idVec3& velocity);
void GameLib_SerializePlayerState(idSerializer* serializer,
playerPState_t& state, playerPState_t* catchupStart);
void GameLib_SerializePlayerNonPredictive(idSerializer* serializer,
idPhysics_Player& physics);
namespace {
constexpr int ENTITYNUM_NONE = 0x1FFF;
constexpr int PMF_JUMPED = 0x0001;
constexpr int PMF_DUCKED = 0x0002;
constexpr int PMF_STEPPED_UP = 0x0004;
constexpr int PMF_SPRINT_SLIDE = 0x0100;
constexpr float MIN_FLOOR_COSINE = 0.70f;
const idVec3 kZeroVector(0.0f, 0.0f, 0.0f);
const idMat3 kIdentityAxis(1.0f);
float AxisYaw(const idMat3& axis) {
return std::atan2(axis[0].y, axis[0].x) * 57.29577951308232f;
}
void ProjectOntoPlane(idVec3& vector, const idVec3& normal,
const float overBounce = 1.0f) {
const float backoff = vector.Dot(normal) * overBounce;
vector = vector - normal * backoff;
}
idBounds ScaledHeightBounds(const idBounds& source, const float scale) {
idBounds result = source;
const float height = source[1].z - source[0].z;
result[1].z = source[0].z + height * scale;
return result;
}
idClipModel* MakePlayerClipModel(idClip* owner, const idBounds& bounds,
const int contents, const idMaterial* material) {
idTraceModel traceModel;
traceModel.SetupCylinder(bounds, 8);
idClipModel* const model = new idClipModel(owner, &traceModel, -1,
material);
model->SetContents(contents);
return model;
}
} // namespace
idPhysics_Player::idPhysics_Player()
: idPhysics_Actor()
, explicitMove{}
, explicitMove2{}
, current{}
, previous{}
, saved{}
, clipModel_standing(nullptr)
, clipModel_crouched(nullptr)
, clipModel_sprintSlide(nullptr)
, clipModel_dead(nullptr)
, overrideClipMaterial(nullptr)
, pusher(nullptr)
, slideMoveQuery{}
, ladderQuery1{}
, ladderQuery2{}
, contentsQuery{}
, lastContents(0)
, walkSpeed(0.0f)
, crouchSpeed(0.0f)
, maxStepHeight(0.0f)
, maxJumpHeight(0.0f)
, debugLevel(0)
, walkAccelerate(10.0f)
, airAccelerate(1.0f)
, flyAccelerate(8.0f)
, waterAccelerate(4.0f)
, walkFriction(6.0f)
, airFriction(0.0f)
, flyFriction(3.0f)
, waterFriction(3.0f)
, slideFriction(1.5f)
, command{}
, prevcmd{}
, viewAngles{}
, framemsec(0)
, frametime(0.0f)
, playerSpeed(0.0f)
, viewForward(1.0f, 0.0f, 0.0f)
, viewRight(0.0f, -1.0f, 0.0f)
, walking(false)
, startedOnGround(false)
, groundPlane(false)
, groundTrace{}
, groundSurfaceFlags(0)
, inhibitSprint(false)
, inhibitJump(false)
, toggleCrouch(false)
, ladder(false)
, ladderNormal(0.0f, 0.0f, 0.0f)
, canLadder(true)
, currentSwimDepthState(SWIMDEPTH_STATE_NONE)
, swimStrokeVelocity(0.0f, 0.0f, 0.0f)
, swimStrokeTimeLeft(-1000)
, swimStrokeTime(-1000)
, swimStrokeAltCurve(false)
, swimStrokeIgnoreInput(false)
, currentWaterEnt(-1)
, currentWaterSurfaceHeight(0.0f)
, blockedAccelerationPercent(0.0f)
, blockedAccelerationVec(0.0f, 0.0f, 0.0f)
, modifiedMovementMaxPercent(1.0f)
, modifiedMovementAngle(90.0f)
, modifiedAccelerationVec(0.0f, 0.0f, 0.0f)
, canCrouchSprint(false)
, lastJumpChance(0)
, perfectOriginPosition(0.0f, 0.0f, 0.0f)
, perfectOriginDuration(0)
, perfectOriginTime(0)
, externalVelocity(0.0f, 0.0f, 0.0f)
, clientOriginSet(false)
, nextClientOrigin(0.0f, 0.0f, 0.0f)
, forcedClientCrouchState(false)
, clientPusherLocked(false)
, pushDeltaZ(0.0f)
, ownerJumpHandler(nullptr)
, ownerCrouchHandler(nullptr)
, ownerCrouchJumpHandler(nullptr) {
type = PHYSICS_PLAYER;
current.movementType = PM_NORMAL;
previous.movementType = PM_NORMAL;
saved.movementType = PM_NORMAL;
explicitMove.clipMove = true;
explicitMove.velocityType = playerExplicitMove_t::VEL_EXPLICIT;
explicitMove.ignoreEntityNum = ENTITYNUM_NONE;
explicitMove2.clipMove = true;
explicitMove2.velocityType = playerExplicitMove_t::VEL_EXPLICIT;
explicitMove2.ignoreEntityNum = ENTITYNUM_NONE;
groundTrace.fraction = 1.0f;
groundTrace.endAxis = kIdentityAxis;
}
idPhysics_Player::~idPhysics_Player() {
UnlinkClip();
idClipModel* models[] = {clipModel_standing, clipModel_crouched,
clipModel_sprintSlide, clipModel_dead};
for (int i = 0; i < 4; ++i) {
if (models[i] == nullptr) continue;
bool duplicate = false;
for (int j = 0; j < i; ++j) duplicate |= models[j] == models[i];
if (!duplicate) models[i]->Delete();
}
clipModels[0] = nullptr;
clipModels[1] = nullptr;
}
void idPhysics_Player::SelectClipModel(idClipModel* const model) {
if (model == nullptr || model == clipModels[0]) return;
if (clipModels[0] != nullptr) clipModels[0]->Unlink();
clipModels[0] = model;
idPhysics_Actor::LinkClip(current.worldOrigin, clipModelAxis);
}
void idPhysics_Player::SetClipModel(idClipModel* const model,
const float density, const int id, const bool freeOld) {
if (id != 0 || model == nullptr) {
idPhysics_Actor::SetClipModel(model, density, id, freeOld);
return;
}
const idBounds sourceBounds = model->GetBounds();
const int contents = model->GetContents();
const idVec3 oldOrigin = model->GetOrigin();
if (freeOld) model->Delete();
idClipModel* oldModels[] = {clipModel_standing, clipModel_crouched,
clipModel_sprintSlide, clipModel_dead};
for (int i = 0; i < 4; ++i) {
if (oldModels[i] == nullptr || oldModels[i] == model) continue;
bool duplicate = false;
for (int j = 0; j < i; ++j) duplicate |= oldModels[j] == oldModels[i];
if (!duplicate) oldModels[i]->Delete();
}
clipModel_standing = MakePlayerClipModel(clip, sourceBounds, contents,
overrideClipMaterial);
clipModel_crouched = MakePlayerClipModel(clip,
ScaledHeightBounds(sourceBounds, 0.65f), contents,
overrideClipMaterial);
clipModel_sprintSlide = MakePlayerClipModel(clip,
ScaledHeightBounds(sourceBounds, 0.45f), contents,
overrideClipMaterial);
clipModel_dead = MakePlayerClipModel(clip,
ScaledHeightBounds(sourceBounds, 0.35f), contents,
overrideClipMaterial);
clipModels[0] = nullptr;
SelectClipModel(clipModel_standing);
current.worldOrigin = oldOrigin;
current.localOrigin = oldOrigin;
LinkClip(current.worldOrigin, clipModelAxis);
if (density > 0.0f) SetMass(density, 0);
}
void idPhysics_Player::SetClipModelStanding(idClipModel* const model) {
if (model == nullptr) return;
if (clipModel_standing != nullptr && clipModel_standing != model)
clipModel_standing->Delete();
clipModel_standing = model;
if (!IsCrouching()) SelectClipModel(model);
}
void idPhysics_Player::SetOrigin(const idVec3* const origin, int) {
if (origin == nullptr) return;
slideMoveQuery.index = 0;
current.localOrigin = *origin;
current.worldOrigin = *origin;
if (hasMaster && callbacks != nullptr) {
idVec3 masterOrigin;
idMat3 masterAxis;
if (GameLib_GetMasterPhysicsTransform(callbacks, masterOrigin,
masterAxis))
current.worldOrigin = masterOrigin + masterAxis * *origin;
}
LinkClip(current.worldOrigin, clipModelAxis);
Activate();
}
void idPhysics_Player::SetAxis(const idMat3* const axis, int) {
if (axis == nullptr) return;
clipModelAxis = *axis;
LinkClip(current.worldOrigin, clipModelAxis);
}
void idPhysics_Player::Translate(const idVec3* const translation, int) {
if (translation == nullptr) return;
current.localOrigin = current.localOrigin + *translation;
current.worldOrigin = current.worldOrigin + *translation;
LinkClip(current.worldOrigin, clipModelAxis);
Activate();
}
void idPhysics_Player::Rotate(const idRotation* const rotation, int) {
if (rotation == nullptr) return;
current.worldOrigin = *rotation * current.worldOrigin;
current.localOrigin = *rotation * current.localOrigin;
clipModelAxis *= rotation->ToMat3();
LinkClip(current.worldOrigin, clipModelAxis);
Activate();
}
const idVec3* idPhysics_Player::GetLocalOrigin(int) {
return &current.localOrigin;
}
const idMat3* idPhysics_Player::GetLocalAxis(int) {
return &clipModelAxis;
}
void idPhysics_Player::SetLinearVelocity(const idVec3* const velocity, int) {
if (velocity == nullptr) return;
current.velocity = *velocity;
Activate();
}
void idPhysics_Player::SetAngularVelocity(const idVec3*, int) {}
idVec3* idPhysics_Player::GetLinearVelocity(idVec3* const result, int) {
if (result != nullptr) *result = current.velocity;
return result;
}
idVec3* idPhysics_Player::GetAngularVelocity(idVec3* const result, int) {
if (result != nullptr) result->Zero();
return result;
}
void idPhysics_Player::SetWaterLevel(const float level, const int id) {
idPhysics_DynamicBase::SetWaterLevel(level, id);
if (waterLevel <= 0.0f) currentSwimDepthState = SWIMDEPTH_STATE_NONE;
else if (waterLevel < 1.0f)
currentSwimDepthState = SWIMDEPTH_STATE_ON_SURFACE;
else currentSwimDepthState = SWIMDEPTH_STATE_UNDER_SURFACE;
}
void idPhysics_Player::SetWaterEntNum(const int entityNumber_) {
currentWaterEnt = entityNumber_;
}
int idPhysics_Player::GetWaterEntNum() { return currentWaterEnt; }
void idPhysics_Player::SetWaterSurfaceWrldHeight(const float height) {
currentWaterSurfaceHeight = height;
}
float idPhysics_Player::GetWaterSurfaceWrldHeight() {
return currentWaterSurfaceHeight;
}
void idPhysics_Player::GetImpactInfo(int, const idVec3*,
impactInfo_t* const info) {
if (info == nullptr) return;
info->Zero();
info->invMass = invMass;
info->velocity = current.velocity + current.pushVelocity;
info->position = current.worldOrigin;
}
void idPhysics_Player::ApplyImpulse(int, const idVec3*,
const idVec3* const impulse) {
if (impulse == nullptr) return;
current.velocity = current.velocity + *impulse * invMass;
Activate();
}
void idPhysics_Player::ApplyForce(int, const idVec3*,
const idVec3* const force) {
if (force == nullptr) return;
const float time = frametime > 0.0f ? frametime : 0.016f;
current.velocity = current.velocity + *force * (invMass * time);
Activate();
}
void idPhysics_Player::Activate() {
if (callbacks != nullptr)
GameLib_NotifyPhysicsActivated(callbacks, GetPhysicsId());
}
void idPhysics_Player::PutToRest() { current.velocity.Zero(); }
bool idPhysics_Player::IsAtRest() { return false; }
bool idPhysics_Player::IsPushable(int) { return true; }
void idPhysics_Player::SaveState() { saved = current; }
void idPhysics_Player::RestoreState() { RestoreStateFromState(&saved); }
void idPhysics_Player::RestoreStateFromState(playerPState_t* const state) {
if (state == nullptr) return;
current = *state;
LinkClip(current.worldOrigin, clipModelAxis);
}
void idPhysics_Player::Serialize(idSerializer* const serializer,
playerPState_t* const catchupStart) {
if (serializer != nullptr)
GameLib_SerializePlayerState(serializer, current, catchupStart);
}
void idPhysics_Player::SerializeNonPredictiveState(
idSerializer* const serializer) {
if (serializer != nullptr)
GameLib_SerializePlayerNonPredictive(serializer, *this);
}
void idPhysics_Player::UpdateTime(int) {}
void idPhysics_Player::SetPushed(const int deltaTime) {
if (deltaTime <= 0) {
current.pushVelocity.Zero();
return;
}
current.pushVelocity = (current.worldOrigin - saved.worldOrigin)
* (1000.0f / static_cast<float>(deltaTime));
pushDeltaZ = current.worldOrigin.z - saved.worldOrigin.z;
}
void idPhysics_Player::ClearPushedVelocity() {
current.pushVelocity.Zero();
pushDeltaZ = 0.0f;
}
idVec3* idPhysics_Player::GetPushedLinearVelocity(idVec3* const result,
int) {
if (result != nullptr) *result = current.pushVelocity;
return result;
}
idVec3* idPhysics_Player::GetPushedAngularVelocity(idVec3* const result,
int) {
if (result != nullptr) result->Zero();
return result;
}
void idPhysics_Player::SetMaster(const bool enable,
const idVec3* const masterOrigin, const idMat3* const masterAxis,
bindFlags_t) {
slideMoveQuery.index = 0;
if (enable && masterOrigin != nullptr && masterAxis != nullptr) {
if (!hasMaster) {
current.localOrigin = masterAxis->Transpose()
* (current.worldOrigin - *masterOrigin);
masterYaw = AxisYaw(*masterAxis);
}
hasMaster = true;
ClearContacts();
} else if (hasMaster) {
hasMaster = false;
Activate();
}
}
void idPhysics_Player::SetLocalOrigin(const idVec3* const origin, int) {
if (origin == nullptr) return;
current.localOrigin = *origin;
if (hasMaster && callbacks != nullptr) {
idVec3 masterOrigin;
idMat3 masterAxis;
if (GameLib_GetMasterPhysicsTransform(callbacks, masterOrigin,
masterAxis))
current.worldOrigin = masterOrigin + masterAxis * *origin;
} else current.worldOrigin = *origin;
LinkClip(current.worldOrigin, clipModelAxis);
}
void idPhysics_Player::SetLocalAxis(const idMat3* const axis, int) {
if (axis == nullptr) return;
clipModelAxis = *axis;
LinkClip(current.worldOrigin, clipModelAxis);
}
int idPhysics_Player::GetBlockingEntityNum() {
return groundTrace.fraction < 1.0f ? groundTrace.c.entityNum
: ENTITYNUM_NONE;
}
int idPhysics_Player::GetLinearEndTime() { return 0; }
int idPhysics_Player::GetAngularEndTime() { return 0; }
void idPhysics_Player::SetSlideFriction(const float value) {
slideFriction = (std::max)(0.0f, value);
}
bool idPhysics_Player::HasJumped() const {
return (current.movementFlags & PMF_JUMPED) != 0;
}
bool idPhysics_Player::HasCrouched() const {
return (previous.movementFlags & PMF_DUCKED) == 0 && IsCrouching();
}
bool idPhysics_Player::HasStoodUp() const {
return (previous.movementFlags & PMF_DUCKED) != 0 && !IsCrouching();
}
bool idPhysics_Player::HasSteppedUp() const {
return (current.movementFlags & PMF_STEPPED_UP) != 0;
}
float idPhysics_Player::GetStepUp() const { return current.stepUp; }
bool idPhysics_Player::IsCrouching() const {
return (current.movementFlags & PMF_DUCKED) != 0;
}
void idPhysics_Player::SetClientCrouch(const bool crouch) {
forcedClientCrouchState = crouch;
SetCrouch(crouch);
}
void idPhysics_Player::SetSprintSliding(const bool sliding) {
if (sliding) current.movementFlags |= PMF_SPRINT_SLIDE;
else current.movementFlags &= ~PMF_SPRINT_SLIDE;
CheckDuck();
}
void idPhysics_Player::SetWalkFriction(const float friction) {
walkFriction = (std::max)(0.0f, friction);
}
void idPhysics_Player::SetSpeed(const float walkingSpeed,
const float crouchingSpeed) {
walkSpeed = (std::max)(0.0f, walkingSpeed);
crouchSpeed = (std::max)(0.0f, crouchingSpeed);
}
void idPhysics_Player::SetMaxStepHeight(const float value) {
maxStepHeight = (std::max)(0.0f, value);
}
void idPhysics_Player::SetMaxJumpHeight(const float value) {
maxJumpHeight = (std::max)(0.0f, value);
}
void idPhysics_Player::SetMovementType(const pmtype_t movementType) {
current.movementType = movementType >= PM_NORMAL && movementType < PM_MAX
? movementType : PM_NORMAL;
}
void idPhysics_Player::SetKnockBack(const int knockBackTime,
const bool absoluteKnockBack) {
current.movementTime = absoluteKnockBack
? knockBackTime : (std::max)(current.movementTime, knockBackTime);
}
void idPhysics_Player::SetDebugLevel(const bool set) { debugLevel = set; }
void idPhysics_Player::SetSwimStroke(const idVec3& velocity,
const int duration, const bool alternateCurve,
const bool ignoreInput) {
swimStrokeVelocity = velocity;
swimStrokeTimeLeft = duration;
swimStrokeTime = duration;
swimStrokeAltCurve = alternateCurve;
swimStrokeIgnoreInput = ignoreInput;
}
bool idPhysics_Player::GetIsUnderWater() const {
return currentSwimDepthState == SWIMDEPTH_STATE_UNDER_SURFACE;
}
void idPhysics_Player::StartPerfectOrigin(const idVec3& idealPosition,
const int lerpTimeMS) {
perfectOriginPosition = idealPosition;
perfectOriginDuration = (std::max)(0, lerpTimeMS);
perfectOriginTime = 0;
current.movementType = PM_PERFECTORIGIN;
}
void idPhysics_Player::SetClientDeferredOrigin(const idVec3& origin) {
nextClientOrigin = origin;
clientOriginSet = true;
}
void idPhysics_Player::SetPlayerInput(const usercmd_t& cmd,
const idAngles& newViewAngles) {
prevcmd = command;
command = cmd;
viewAngles = newViewAngles;
}
bool idPhysics_Player::ClientPusherLocked(bool* const justUnlocked) {
const bool wasLocked = clientPusherLocked;
if (justUnlocked != nullptr) *justUnlocked = false;
if (clientOriginSet) {
clientPusherLocked = false;
if (justUnlocked != nullptr) *justUnlocked = wasLocked;
}
return clientPusherLocked;
}
void idPhysics_Player::UpdateNonPredictiveClip() {
if (!clientOriginSet) return;
current.worldOrigin = nextClientOrigin;
current.localOrigin = nextClientOrigin;
LinkClip(current.worldOrigin, clipModelAxis);
clientOriginSet = false;
}
float idPhysics_Player::CmdScale(const usercmd_t& cmd) const {
const int forward = std::abs(static_cast<int>(cmd.forwardmove));
const int right = std::abs(static_cast<int>(cmd.rightmove));
const int up = std::abs(static_cast<int>(cmd.upmove));
const int maximum = (std::max)(forward, (std::max)(right, up));
if (maximum == 0) return 0.0f;
const float total = std::sqrt(static_cast<float>(forward * forward
+ right * right + up * up));
return total > 0.0f ? playerSpeed * maximum / (127.0f * total) : 0.0f;
}
void idPhysics_Player::Accelerate(const idVec3& wishDirection,
const float wishSpeed, const float acceleration) {
const float currentSpeed = current.velocity.Dot(wishDirection);
const float addSpeed = wishSpeed - currentSpeed;
if (addSpeed <= 0.0f) return;
const float accelerationSpeed = (std::min)(addSpeed,
acceleration * frametime * wishSpeed);
current.velocity = current.velocity + wishDirection * accelerationSpeed;
}
void idPhysics_Player::UpdateExternalVelocity() {
current.velocity = current.velocity + externalVelocity;
externalVelocity.Zero();
}
void idPhysics_Player::Friction() {
idVec3 velocity = current.velocity;
if (walking) ProjectOntoPlane(velocity, gravityNormal);
const float speed = velocity.Length();
if (speed < 1.0f) {
if (walking) ProjectOntoPlane(current.velocity, -gravityNormal);
return;
}
float coefficient = walking ? walkFriction : airFriction;
if (current.movementType == PM_SPECTATOR
|| current.movementType == PM_NOCLIP)
coefficient = flyFriction;
if (waterLevel > 0.0f) coefficient = waterFriction * waterLevel;
if (current.movementType == PM_SLIDE) coefficient = slideFriction;
const float newSpeed = (std::max)(0.0f,
speed - speed * coefficient * frametime);
if (newSpeed != speed) current.velocity = current.velocity
* (newSpeed / speed);
}
bool idPhysics_Player::CheckJump() {
if (inhibitJump || !walking || command.upmove < 10) return false;
if (prevcmd.upmove >= 10 && current.movementTime <= 0) return false;
const float gravity = gravityVector.Length();
const float jumpSpeed = std::sqrt((std::max)(0.0f,
2.0f * gravity * maxJumpHeight));
ProjectOntoPlane(current.velocity, gravityNormal);
current.velocity = current.velocity - gravityNormal * jumpSpeed;
current.movementFlags |= PMF_JUMPED;
walking = false;
groundPlane = false;
if (ownerJumpHandler != nullptr)
ownerJumpHandler(GetEntityNumber(), &current.worldOrigin,
&current.velocity, &viewForward, &viewRight, &command);
return true;
}
void idPhysics_Player::CorrectAllSolid(trace_t& trace, int) {
trace.fraction = 0.0f;
trace.endpos = current.worldOrigin;
current.velocity.Zero();
}
void idPhysics_Player::SlideMoveDeferred(const bool gravity,
const bool stepUp, const bool stepDown, const bool push) {
SlideMoveNonDeferred(gravity, stepUp, stepDown, push);
}
void idPhysics_Player::SlideMoveNonDeferred(const bool applyGravity,
const bool allowStepUp, const bool allowStepDown, bool) {
idClipModel* const model = clipModels[0];
if (clip == nullptr || model == nullptr) {
if (applyGravity)
current.velocity = current.velocity + gravityVector * frametime;
current.worldOrigin = current.worldOrigin
+ current.velocity * frametime;
current.localOrigin = current.worldOrigin;
return;
}
if (applyGravity)
current.velocity = current.velocity + gravityVector * frametime;
const idVec3 start = current.worldOrigin;
const idVec3 end = start + current.velocity * frametime;
trace_t collision{};
collision.fraction = 1.0f;
collision.endpos = end;
collision.endAxis = clipModelAxis;
contactsResult_t result{};
const float up = allowStepUp ? maxStepHeight : 0.0f;
const float down = allowStepDown ? maxStepHeight * 2.0f : 0.0f;
slideMoveQuery = allowStepUp
? clip->StepMoveContacts(&collision, &result, start, end,
gravityNormal, up, down, model, clipModelAxis, clipMasks[0],
GetEntityNumber(), false,
"idPhysics_Player::SlideMoveNonDeferred")
: clip->SlideMoveContacts(&collision, &result, start, end,
gravityNormal, up, model, clipModelAxis, clipMasks[0],
GetEntityNumber(), false,
"idPhysics_Player::SlideMoveNonDeferred");
current.worldOrigin = collision.endpos;
current.localOrigin = current.worldOrigin;
ClearContacts();
const int count = (std::min)(12, result.numContacts);
for (int i = 0; i < count; ++i) {
contacts.Append(result.contacts[i]);
UpdateCollisionResidency(result.contacts[i]);
}
AddContactPhysicsForContacts();
if (collision.fraction < 1.0f) {
ProjectOntoPlane(current.velocity, collision.c.normal, 1.001f);
if (callbacks != nullptr)
GameLib_NotifyPhysicsCollision(callbacks, GetPhysicsId(),
collision, current.velocity);
}
const float stepped = (collision.endpos - start).Dot(-gravityNormal);
current.stepUp = stepped > 0.0f ? stepped : 0.0f;
if (current.stepUp > 0.0f) current.movementFlags |= PMF_STEPPED_UP;
LinkClip(current.worldOrigin, clipModelAxis);
}
void idPhysics_Player::SlideMove(const bool gravity, const bool stepUp,
const bool stepDown, const bool push) {
SlideMoveDeferred(gravity, stepUp, stepDown, push);
}
void idPhysics_Player::CheckGround() {
walking = false;
groundPlane = false;
groundTrace = {};
groundTrace.fraction = 1.0f;
groundTrace.endpos = current.worldOrigin;
groundTrace.endAxis = clipModelAxis;
idClipModel* const model = clipModels[0];
if (clip == nullptr || model == nullptr) return;
const idVec3 end = current.worldOrigin + gravityNormal
* (maxStepHeight > 0.0f ? maxStepHeight : 2.0f);
clip->Translation(&groundTrace, current.worldOrigin, end, model,
clipModelAxis, clipMasks[0], GetEntityNumber(), false,
"idPhysics_Player::CheckGround");
if (groundTrace.fraction < 1.0f) {
groundPlane = true;
walking = groundTrace.c.normal.Dot(-gravityNormal)
>= MIN_FLOOR_COSINE;
groundSurfaceFlags = groundTrace.c.surfaceFlags;
UpdateCollisionResidency(groundTrace.c);
if (walking) {
bool present = false;
for (int i = 0; i < contacts.Num(); ++i)
present |= contacts[i].entityNum == groundTrace.c.entityNum;
if (!present) contacts.Append(groundTrace.c);
}
}
}
bool idPhysics_Player::CanStand() {
return CanStand(current.worldOrigin);
}
bool idPhysics_Player::CanStand(const idVec3& position) {
if (clip == nullptr || clipModel_standing == nullptr) return true;
trace_t result{};
contentsQuery = clip->Contents(&result, position, clipModel_standing,
clipModelAxis, clipMasks[0], GetEntityNumber(),
"idPhysics_Player::CanStand");
return result.c.contentFlags == 0 && result.fraction != 0.0f;
}
void idPhysics_Player::CheckLadder(const bool oldLadder) {
if (!canLadder || clip == nullptr || clipModels[0] == nullptr) {
ladder = false;
return;
}
trace_t result{};
const idVec3 end = current.worldOrigin + viewForward * 2.0f;
ladderQuery1 = clip->Translation(&result, current.worldOrigin, end,
clipModels[0], clipModelAxis, clipMasks[0], GetEntityNumber(),
false, "idPhysics_Player::CheckLadder");
ladder = result.fraction < 1.0f
&& std::fabs(result.c.normal.Dot(gravityNormal)) < 0.5f;
if (ladder) ladderNormal = result.c.normal;
else if (oldLadder) ladderNormal.Zero();
}
void idPhysics_Player::NoclipMove() {
Friction();
const float scale = CmdScale(command);
idVec3 up = -gravityNormal;
idVec3 wish = viewForward * static_cast<float>(command.forwardmove)
+ viewRight * static_cast<float>(command.rightmove)
+ up * static_cast<float>(command.upmove);
const float length = wish.NormalizeFast();
if (length > 0.0f) Accelerate(wish, scale * length, flyAccelerate);
current.worldOrigin = current.worldOrigin + current.velocity * frametime;
current.localOrigin = current.worldOrigin;
LinkClip(current.worldOrigin, clipModelAxis);
}
void idPhysics_Player::WaterJumpMove() {
SlideMove(true, true, true, false);
}
void idPhysics_Player::SwimMove() {
Friction();
idVec3 up = -gravityNormal;
idVec3 wish = viewForward * static_cast<float>(command.forwardmove)
+ viewRight * static_cast<float>(command.rightmove)
+ up * static_cast<float>(command.upmove);
float wishSpeed = CmdScale(command) * wish.NormalizeFast();
if (!swimStrokeIgnoreInput) Accelerate(wish, wishSpeed, waterAccelerate);
if (swimStrokeTimeLeft > 0) {
current.velocity = current.velocity + swimStrokeVelocity
* frametime;
swimStrokeTimeLeft -= framemsec;
}
current.velocity = current.velocity
+ gravityVector * (frametime * (1.0f - waterLevel));
SlideMove(false, false, false, false);
}
void idPhysics_Player::AirMove() {
Friction();
idVec3 forward = viewForward;
idVec3 right = viewRight;
ProjectOntoPlane(forward, gravityNormal);
ProjectOntoPlane(right, gravityNormal);
forward.NormalizeFast();
right.NormalizeFast();
idVec3 wish = forward * static_cast<float>(command.forwardmove)
+ right * static_cast<float>(command.rightmove);
const float length = wish.NormalizeFast();
Accelerate(wish, CmdScale(command) * length, airAccelerate);
SlideMove(true, false, false, false);
}
void idPhysics_Player::WalkMove() {
if (CheckJump()) {
AirMove();
return;
}
Friction();
idVec3 forward = viewForward;
idVec3 right = viewRight;
ProjectOntoPlane(forward, groundTrace.c.normal);
ProjectOntoPlane(right, groundTrace.c.normal);
forward.NormalizeFast();
right.NormalizeFast();
idVec3 wish = forward * static_cast<float>(command.forwardmove)
+ right * static_cast<float>(command.rightmove);
const float length = wish.NormalizeFast();
playerSpeed = IsCrouching() ? crouchSpeed : walkSpeed;
Accelerate(wish, CmdScale(command) * length, walkAccelerate);
ProjectOntoPlane(current.velocity, groundTrace.c.normal);
SlideMove(false, true, true, true);
}
void idPhysics_Player::PerfectOriginMove(const int deltaMS) {
perfectOriginTime += deltaMS;
const float fraction = perfectOriginDuration > 0
? (std::min)(1.0f, static_cast<float>(perfectOriginTime)
/ static_cast<float>(perfectOriginDuration)) : 1.0f;
const idVec3 start = current.worldOrigin;
current.worldOrigin = start
+ (perfectOriginPosition - start) * fraction;
current.localOrigin = current.worldOrigin;
current.velocity = deltaMS > 0
? (current.worldOrigin - start) * (1000.0f / deltaMS)
: kZeroVector;
LinkClip(current.worldOrigin, clipModelAxis);
if (fraction >= 1.0f) current.movementType = PM_NORMAL;
}
void idPhysics_Player::DeadMove() {
Friction();
SlideMove(true, false, true, false);
}
void idPhysics_Player::SpectatorMove() { NoclipMove(); }
void idPhysics_Player::LadderMove() {
Friction();
idVec3 up = -gravityNormal;
idVec3 side = up.Cross(ladderNormal);
side.NormalizeFast();
idVec3 wish = up * static_cast<float>(command.forwardmove
+ command.upmove) + side * static_cast<float>(command.rightmove);
const float length = wish.NormalizeFast();
Accelerate(wish, CmdScale(command) * length, flyAccelerate);
ProjectOntoPlane(current.velocity, ladderNormal, 1.001f);
SlideMove(false, false, false, false);
}
void idPhysics_Player::ExplicitMove(playerExplicitMove_t& move) {
if (move.velocityType == playerExplicitMove_t::VEL_OVERRIDE)
current.velocity = move.overrideVelocity;
else if (move.velocityType == playerExplicitMove_t::VEL_EXPLICIT
&& frametime > 0.0f)
current.velocity = move.delta * (1.0f / frametime);
if (move.clipMove) {
const idVec3 originalVelocity = current.velocity;
current.velocity = move.delta * (frametime > 0.0f
? 1.0f / frametime : 0.0f);
SlideMove(false, false, false, false);
if (move.velocityType == playerExplicitMove_t::VEL_CURRENT)
current.velocity = originalVelocity;
} else {
current.worldOrigin = current.worldOrigin + move.delta;
current.localOrigin = current.worldOrigin;
LinkClip(current.worldOrigin, clipModelAxis);
}
move.delta.Zero();
}
void idPhysics_Player::CheckDuck() {
const bool sprint = (current.movementFlags & PMF_SPRINT_SLIDE) != 0;
bool wantCrouch = forcedClientCrouchState || toggleCrouch
|| command.upmove < 0 || sprint;
if (!wantCrouch && !CanStand()) wantCrouch = true;
if (wantCrouch) current.movementFlags |= PMF_DUCKED;
else current.movementFlags &= ~PMF_DUCKED;
idClipModel* desired = clipModel_standing;
if (current.movementType == PM_DEAD) desired = clipModel_dead;
else if (sprint && clipModel_sprintSlide != nullptr)
desired = clipModel_sprintSlide;
else if (wantCrouch) desired = clipModel_crouched;
SelectClipModel(desired);
}
void idPhysics_Player::ForcePhysicsQuery() {
slideMoveQuery.index = 0;
ladderQuery1.index = 0;
ladderQuery2.index = 0;
contentsQuery.index = 0;
CheckGround();
}
void idPhysics_Player::ClearCrouch() {
forcedClientCrouchState = false;
toggleCrouch = false;
if (CanStand()) {
current.movementFlags &= ~PMF_DUCKED;
SelectClipModel(clipModel_standing);
}
}
void idPhysics_Player::SetCrouch(const bool crouch) {
toggleCrouch = crouch;
CheckDuck();
if (ownerCrouchHandler != nullptr)
ownerCrouchHandler(GetEntityNumber(), &current.worldOrigin,
&current.velocity, &viewForward, &viewRight, &command);
}
void idPhysics_Player::ResolveSlideMove() {
if (clientOriginSet) UpdateNonPredictiveClip();
}
void idPhysics_Player::MovePlayer(const int milliseconds) {
framemsec = (std::max)(0, milliseconds);
frametime = framemsec * 0.001f;
previous = current;
current.stepUp = 0.0f;
current.movementFlags &= ~(PMF_JUMPED | PMF_STEPPED_UP);
if (current.movementTime > 0)
current.movementTime = (std::max)(0,
current.movementTime - framemsec);
viewAngles.ToVectors(&viewForward, &viewRight, nullptr);
UpdateExternalVelocity();
CheckDuck();
startedOnGround = walking;
CheckGround();
const bool oldLadder = ladder;
CheckLadder(oldLadder);
switch (current.movementType) {
case PM_FREEZE:
current.velocity.Zero();
break;
case PM_NOCLIP:
case PM_VEHICLE_NOCLIP:
NoclipMove();
break;
case PM_SPECTATOR:
SpectatorMove();
break;
case PM_DEAD:
DeadMove();
break;
case PM_PERFECTORIGIN:
PerfectOriginMove(milliseconds);
break;
case PM_EXPLICIT:
ExplicitMove(explicitMove);
ExplicitMove(explicitMove2);
break;
case PM_SLIDE:
Friction();
SlideMove(true, false, true, false);
break;
case PM_NORMAL:
default:
if (ladder) LadderMove();
else if (waterLevel > 0.5f) SwimMove();
else if (walking) WalkMove();
else AirMove();
break;
}
ResolveSlideMove();
CheckGround();
}
bool idPhysics_Player::Evaluate(const int timeStepMSec, int) {
RememberHistorySample();
if (hasMaster && callbacks != nullptr) {
idVec3 masterOrigin;
idMat3 masterAxis;
if (GameLib_GetMasterPhysicsTransform(callbacks, masterOrigin,
masterAxis)) {
const idVec3 oldOrigin = current.worldOrigin;
current.worldOrigin = masterOrigin
+ masterAxis * current.localOrigin;
LinkClip(current.worldOrigin, clipModelAxis);
const float seconds = timeStepMSec * 0.001f;
if (seconds > 0.0f)
current.velocity = (current.worldOrigin - oldOrigin)
* (1.0f / seconds);
masterDeltaYaw = AxisYaw(masterAxis) - masterYaw;
masterYaw += masterDeltaYaw;
}
} else MovePlayer(timeStepMSec);
if (IsOutsideWorld() && callbacks != nullptr)
GameLib_NotifyPhysicsDeactivated(callbacks, GetPhysicsId());
return true;
}
+273 -169
View File
@@ -1,175 +1,279 @@
#pragma once
// Reconstructed C++ declarations from IDA Local Types and PDB/DIA metadata.
// Original PDB header: w:\tech5\engine\gamelib\physics\physics_player.h
// Recovered logical types: 1
// Signatures retain Xbox 360 ABI evidence and may still require manual review.
#include "gamelib/physics/clip.h"
#include "gamelib/physics/physics_actor.h"
#include "idlib/math/angles.h"
#include <cstdint>
// IDA Local Type ordinal 15364; PDB kind: class.
class __declspec(align(8)) idPhysics_Player : public idPhysics_Actor
{
public:
// Recovered virtual interface; IDA vtable ordinal 15365.
virtual ~idPhysics_Player();
virtual void SetClipModel(idClipModel *, float, int, bool);
virtual idClipModel *GetClipModel(int);
virtual int GetNumClipModels();
virtual void SetMass(float, int);
virtual float GetMass(int);
virtual void SetContents(int, int);
virtual int GetContents(int);
virtual void SetClipMask(int, int);
virtual int GetClipMask(int);
virtual const idBounds *GetBounds(int);
virtual const idBounds *GetAbsBounds(int);
virtual void SetOrigin(const idVec3 *, int);
virtual void SetAxis(const idMat3 *, int);
virtual void Translate(const idVec3 *, int);
virtual void Rotate(const idRotation *, int);
virtual const idVec3 *GetOrigin(int);
virtual const idMat3 *GetAxis(int);
virtual const idVec3 *GetLocalOrigin(int);
virtual const idMat3 *GetLocalAxis(int);
virtual void SetLinearVelocity(const idVec3 *, int);
virtual void SetAngularVelocity(const idVec3 *, int);
virtual idVec3 *GetLinearVelocity(idVec3 *result, int);
virtual idVec3 *GetAngularVelocity(idVec3 *result, int);
virtual void SetGravity(const idVec3 *);
virtual const idVec3 *GetGravity();
virtual const idVec3 *GetGravityNormal();
virtual void SetWaterLevel(float, int);
virtual float GetWaterLevel(int);
virtual void SetWaterViscosity(float, int);
virtual float GetWaterViscosity(int);
virtual void SetWaterEntNum(int);
virtual int GetWaterEntNum();
virtual void SetWaterSurfaceWrldHeight(float);
virtual float GetWaterSurfaceWrldHeight();
virtual void GetImpactInfo(const int, const idVec3 *, impactInfo_t *);
virtual void ApplyImpulse(const int, const idVec3 *, const idVec3 *);
virtual void ApplyForce(const int, const idVec3 *, const idVec3 *);
virtual void Activate();
virtual void PutToRest();
virtual bool IsAtRest();
virtual bool IsPushable(int);
virtual void SaveState();
virtual void RestoreState();
virtual bool Evaluate(int, int);
virtual void UpdateTime(int);
virtual void ClipTranslation(trace_t *, const idVec3 *, const idClipModel *);
virtual void ClipRotation(trace_t *, const idRotation *, const idClipModel *);
virtual int ClipContents(const idClipModel *, int);
virtual void DisableClip();
virtual void EnableClip();
virtual void UnlinkClip();
virtual void LinkClip();
virtual bool EvaluateContacts();
virtual int GetNumContacts();
virtual const contactInfo_t *GetContact(int);
virtual void ClearContacts();
virtual void AddContactPhysics(idPhysics *);
virtual void RemoveContactPhysics(idPhysics *);
virtual int GetNumContactPhysics();
virtual idPhysics *GetContactPhysics(int);
virtual void ActivateContactPhysics();
virtual bool HasGroundContacts();
virtual bool IsGroundEntity(int);
virtual bool IsGroundClipModel(int, int);
virtual void SetPushed(int);
virtual idVec3 *GetPushedLinearVelocity(idVec3 *result, const int);
virtual idVec3 *GetPushedAngularVelocity(idVec3 *result, const int);
virtual void SetMaster(bool, const idVec3 *, const idMat3 *, const bindFlags_t);
virtual void SetLocalOrigin(const idVec3 *, int);
virtual void SetLocalAxis(const idMat3 *, int);
virtual int GetBlockingEntityNum();
virtual int GetLinearEndTime();
virtual int GetAngularEndTime();
virtual bool IsInNonResidentCollisionArea(bool);
virtual bool IsOutsideWorld();
virtual const idMat3 *GetGravityAxis();
virtual void DisableClip_2(const idPhysics_Actor::actorClipModel_t);
virtual void EnableClip_2(const idPhysics_Actor::actorClipModel_t);
virtual void LinkClip_2(const idVec3 *, const idMat3 *);
virtual void RestoreStateFromState(playerPState_t *);
virtual void ClearPushedVelocity();
virtual void Serialize(idSerializer *, playerPState_t *);
virtual void SerializeNonPredictiveState(idSerializer *);
class idMaterial;
class idPush;
class idSerializer;
playerExplicitMove_t explicitMove;
playerExplicitMove_t explicitMove2;
playerPState_t current;
playerPState_t previous;
playerPState_t saved;
idClipModel *clipModel_standing;
idClipModel *clipModel_crouched;
idClipModel *clipModel_sprintSlide;
idClipModel *clipModel_dead;
const idMaterial *overrideClipMaterial;
idPush *pusher;
idClipQuery slideMoveQuery;
idClipQuery ladderQuery1;
idClipQuery ladderQuery2;
idClipQuery contentsQuery;
int lastContents;
float walkSpeed;
float crouchSpeed;
float maxStepHeight;
float maxJumpHeight;
int debugLevel;
float walkAccelerate;
float airAccelerate;
float flyAccelerate;
float waterAccelerate;
float walkFriction;
float airFriction;
float flyFriction;
float waterFriction;
float slideFriction;
usercmd_t command;
usercmd_t prevcmd;
idAngles viewAngles;
int framemsec;
float frametime;
float playerSpeed;
idVec3 viewForward;
idVec3 viewRight;
bool walking;
bool startedOnGround;
bool groundPlane;
trace_t groundTrace;
int groundSurfaceFlags;
bool inhibitSprint;
bool inhibitJump;
bool toggleCrouch;
bool ladder;
idVec3 ladderNormal;
bool canLadder;
swimdepthstate_t currentSwimDepthState;
idVec3 swimStrokeVelocity;
int swimStrokeTimeLeft;
int swimStrokeTime;
bool swimStrokeAltCurve;
bool swimStrokeIgnoreInput;
int currentWaterEnt;
float currentWaterSurfaceHeight;
float blockedAccelerationPercent;
idVec3 blockedAccelerationVec;
float modifiedMovementMaxPercent;
float modifiedMovementAngle;
idVec3 modifiedAccelerationVec;
bool canCrouchSprint;
int lastJumpChance;
idVec3 perfectOriginPosition;
int perfectOriginDuration;
int perfectOriginTime;
idVec3 externalVelocity;
bool clientOriginSet;
idVec3 nextClientOrigin;
bool forcedClientCrouchState;
bool clientPusherLocked;
float pushDeltaZ;
bool (__fastcall *ownerJumpHandler)(int, const idVec3 *, const idVec3 *, const idVec3 *, const idVec3 *, const usercmd_t *);
bool (__fastcall *ownerCrouchHandler)(int, const idVec3 *, const idVec3 *, const idVec3 *, const idVec3 *, const usercmd_t *);
bool (__fastcall *ownerCrouchJumpHandler)(int, const idVec3 *, const idVec3 *, const idVec3 *, const idVec3 *, const usercmd_t *);
enum pmtype_t : int {
PM_NORMAL = 0,
PM_DEAD = 1,
PM_SPECTATOR = 2,
PM_FREEZE = 3,
PM_NOCLIP = 4,
PM_VEHICLE_NOCLIP = 5,
PM_PERFECTORIGIN = 6,
PM_EXPLICIT = 7,
PM_SLIDE = 8,
PM_MAX = 9
};
enum swimdepthstate_t : int {
SWIMDEPTH_STATE_NONE = 0,
SWIMDEPTH_STATE_ON_SURFACE = 1,
SWIMDEPTH_STATE_UNDER_SURFACE = 2
};
struct playerExplicitMove_t {
enum velocityType_t : int {
VEL_EXPLICIT = 0,
VEL_OVERRIDE = 1,
VEL_CURRENT = 2
};
idVec3 delta;
bool clipMove;
velocityType_t velocityType;
idVec3 overrideVelocity;
int ignoreEntityNum;
};
struct playerPState_t {
idVec3 localOrigin;
idVec3 worldOrigin;
idVec3 velocity;
idVec3 pushVelocity;
idAngles deltaViewAngles;
float stepUp;
pmtype_t movementType;
int movementFlags;
int movementTime;
};
#ifndef ID_USERCMD_T_DEFINED
#define ID_USERCMD_T_DEFINED
struct alignas(4) usercmd_t {
int buttons;
std::int16_t buttons2;
char forwardmove;
char rightmove;
char upmove;
std::uint8_t reserved : 6;
std::uint8_t fromBot : 1;
std::uint8_t inhibited : 1;
std::int16_t angles[3];
int clientGameFrame;
float pos[3];
std::int16_t pitch;
std::int16_t yaw;
std::int16_t roll;
std::uint8_t predictionStateBits;
int serverGameTime;
std::uint16_t fireCount;
std::int16_t fireAngles[2];
std::int16_t firePos[3];
std::uint8_t vehicleThrottle;
std::uint8_t speed;
};
#endif
class idPhysics_Player : public idPhysics_Actor {
public:
using playerMoveHandler_t = bool (*)(int, const idVec3*,
const idVec3*, const idVec3*, const idVec3*, const usercmd_t*);
idPhysics_Player();
~idPhysics_Player() override;
void SetClipModel(idClipModel*, float, int, bool) override;
void SetOrigin(const idVec3*, int) override;
void SetAxis(const idMat3*, int) override;
void Translate(const idVec3*, int) override;
void Rotate(const idRotation*, int) override;
const idVec3* GetLocalOrigin(int) override;
const idMat3* GetLocalAxis(int) override;
void SetLinearVelocity(const idVec3*, int) override;
void SetAngularVelocity(const idVec3*, int) override;
idVec3* GetLinearVelocity(idVec3*, int) override;
idVec3* GetAngularVelocity(idVec3*, int) override;
void SetWaterLevel(float, int) override;
void SetWaterEntNum(int) override;
int GetWaterEntNum() override;
void SetWaterSurfaceWrldHeight(float) override;
float GetWaterSurfaceWrldHeight() override;
void GetImpactInfo(int, const idVec3*, impactInfo_t*) override;
void ApplyImpulse(int, const idVec3*, const idVec3*) override;
void ApplyForce(int, const idVec3*, const idVec3*) override;
void Activate() override;
void PutToRest() override;
bool IsAtRest() override;
bool IsPushable(int) override;
void SaveState() override;
void RestoreState() override;
bool Evaluate(int, int) override;
void UpdateTime(int) override;
void SetPushed(int) override;
idVec3* GetPushedLinearVelocity(idVec3*, int) override;
idVec3* GetPushedAngularVelocity(idVec3*, int) override;
void SetMaster(bool, const idVec3*, const idMat3*, bindFlags_t) override;
void SetLocalOrigin(const idVec3*, int) override;
void SetLocalAxis(const idMat3*, int) override;
int GetBlockingEntityNum() override;
int GetLinearEndTime() override;
int GetAngularEndTime() override;
void RestoreStateFromState(playerPState_t*);
void ClearPushedVelocity();
void Serialize(idSerializer*, playerPState_t*);
void SerializeNonPredictiveState(idSerializer*);
void SetSlideFriction(float);
bool HasJumped() const;
bool HasCrouched() const;
bool HasStoodUp() const;
bool HasSteppedUp() const;
float GetStepUp() const;
bool IsCrouching() const;
void SetClientCrouch(bool);
void SetSprintSliding(bool);
void SetClipModelStanding(idClipModel*);
void SetWalkFriction(float);
void SetSpeed(float, float);
void SetMaxStepHeight(float);
void SetMaxJumpHeight(float);
void SetMovementType(pmtype_t);
void SetKnockBack(int, bool);
void SetDebugLevel(bool);
void SetSwimStroke(const idVec3&, int, bool, bool);
bool GetIsUnderWater() const;
void StartPerfectOrigin(const idVec3&, int);
void SetClientDeferredOrigin(const idVec3&);
void SetPlayerInput(const usercmd_t&, const idAngles&);
bool ClientPusherLocked(bool*);
void UpdateNonPredictiveClip();
bool CanStand();
bool CanStand(const idVec3&);
void CheckGround();
void CheckLadder(bool);
void ForcePhysicsQuery();
void ClearCrouch();
void SetCrouch(bool);
playerExplicitMove_t explicitMove;
playerExplicitMove_t explicitMove2;
playerPState_t current;
playerPState_t previous;
playerPState_t saved;
idClipModel* clipModel_standing;
idClipModel* clipModel_crouched;
idClipModel* clipModel_sprintSlide;
idClipModel* clipModel_dead;
const idMaterial* overrideClipMaterial;
idPush* pusher;
idClipQuery slideMoveQuery;
idClipQuery ladderQuery1;
idClipQuery ladderQuery2;
idClipQuery contentsQuery;
int lastContents;
float walkSpeed;
float crouchSpeed;
float maxStepHeight;
float maxJumpHeight;
int debugLevel;
float walkAccelerate;
float airAccelerate;
float flyAccelerate;
float waterAccelerate;
float walkFriction;
float airFriction;
float flyFriction;
float waterFriction;
float slideFriction;
usercmd_t command;
usercmd_t prevcmd;
idAngles viewAngles;
int framemsec;
float frametime;
float playerSpeed;
idVec3 viewForward;
idVec3 viewRight;
bool walking;
bool startedOnGround;
bool groundPlane;
trace_t groundTrace;
int groundSurfaceFlags;
bool inhibitSprint;
bool inhibitJump;
bool toggleCrouch;
bool ladder;
idVec3 ladderNormal;
bool canLadder;
swimdepthstate_t currentSwimDepthState;
idVec3 swimStrokeVelocity;
int swimStrokeTimeLeft;
int swimStrokeTime;
bool swimStrokeAltCurve;
bool swimStrokeIgnoreInput;
int currentWaterEnt;
float currentWaterSurfaceHeight;
float blockedAccelerationPercent;
idVec3 blockedAccelerationVec;
float modifiedMovementMaxPercent;
float modifiedMovementAngle;
idVec3 modifiedAccelerationVec;
bool canCrouchSprint;
int lastJumpChance;
idVec3 perfectOriginPosition;
int perfectOriginDuration;
int perfectOriginTime;
idVec3 externalVelocity;
bool clientOriginSet;
idVec3 nextClientOrigin;
bool forcedClientCrouchState;
bool clientPusherLocked;
float pushDeltaZ;
playerMoveHandler_t ownerJumpHandler;
playerMoveHandler_t ownerCrouchHandler;
playerMoveHandler_t ownerCrouchJumpHandler;
private:
float CmdScale(const usercmd_t&) const;
void Accelerate(const idVec3&, float, float);
void UpdateExternalVelocity();
void SlideMoveDeferred(bool, bool, bool, bool);
void SlideMoveNonDeferred(bool, bool, bool, bool);
void SlideMove(bool, bool, bool, bool);
void Friction();
void NoclipMove();
void CorrectAllSolid(trace_t&, int);
bool CheckJump();
void WaterJumpMove();
void SwimMove();
void AirMove();
void WalkMove();
void PerfectOriginMove(int);
void DeadMove();
void SpectatorMove();
void LadderMove();
void ExplicitMove(playerExplicitMove_t&);
void CheckDuck();
void ResolveSlideMove();
void MovePlayer(int);
void SelectClipModel(idClipModel*);
};
static_assert(sizeof(playerExplicitMove_t) == 36,
"Recovered explicit player movement ABI changed");
static_assert(sizeof(playerPState_t) == 76,
"Recovered player physics state ABI changed");
static_assert(sizeof(usercmd_t) == 60,
"Recovered user command ABI changed");
#if defined(_WIN32) && !defined(_WIN64)
static_assert(sizeof(idPhysics_Player) == 1352,
"Recovered idPhysics_Player ABI changed");
#endif
@@ -0,0 +1,606 @@
#include "gamelib/physics/physics_rigidbody.h"
#include "gamelib/physics/clipmodel.h"
#include "idlib/math/rotation.h"
#include <algorithm>
#include <cmath>
#include <cstring>
bool GameLib_GetMasterPhysicsTransform(idPhysicsCallbacks* callbacks,
idVec3& origin, idMat3& axis);
void GameLib_NotifyPhysicsActivated(idPhysicsCallbacks* callbacks,
int physicsId);
void GameLib_NotifyPhysicsDeactivated(idPhysicsCallbacks* callbacks,
int physicsId);
void GameLib_NotifyPhysicsCollision(idPhysicsCallbacks* callbacks,
int physicsId, const trace_t& collision, const idVec3& velocity);
namespace {
const idBounds kRigidZeroBounds{{idVec3(0.0f, 0.0f, 0.0f),
idVec3(0.0f, 0.0f, 0.0f)}};
const idVec3 kRigidZeroVector(0.0f, 0.0f, 0.0f);
const idMat3 kRigidIdentityAxis(1.0f);
idVec3 SpatialLinear(const idVec6& value) {
return idVec3(value[0], value[1], value[2]);
}
idVec3 SpatialAngular(const idVec6& value) {
return idVec3(value[3], value[4], value[5]);
}
void SetSpatialLinear(idVec6& value, const idVec3& vector) {
value[0] = vector.x; value[1] = vector.y; value[2] = vector.z;
}
void SetSpatialAngular(idVec6& value, const idVec3& vector) {
value[3] = vector.x; value[4] = vector.y; value[5] = vector.z;
}
void ZeroSpatial(idVec6& value) {
for (int index = 0; index < 6; ++index) value[index] = 0.0f;
}
idMat3 Inverse3x3(const idMat3& matrix) {
const float determinant =
matrix[0].x * (matrix[1].y * matrix[2].z
- matrix[1].z * matrix[2].y)
- matrix[0].y * (matrix[1].x * matrix[2].z
- matrix[1].z * matrix[2].x)
+ matrix[0].z * (matrix[1].x * matrix[2].y
- matrix[1].y * matrix[2].x);
if (std::fabs(determinant) < 1.0e-12f) return idMat3(1.0f);
const float inverse = 1.0f / determinant;
return idMat3(
(matrix[1].y * matrix[2].z - matrix[1].z * matrix[2].y) * inverse,
(matrix[0].z * matrix[2].y - matrix[0].y * matrix[2].z) * inverse,
(matrix[0].y * matrix[1].z - matrix[0].z * matrix[1].y) * inverse,
(matrix[1].z * matrix[2].x - matrix[1].x * matrix[2].z) * inverse,
(matrix[0].x * matrix[2].z - matrix[0].z * matrix[2].x) * inverse,
(matrix[0].z * matrix[1].x - matrix[0].x * matrix[1].z) * inverse,
(matrix[1].x * matrix[2].y - matrix[1].y * matrix[2].x) * inverse,
(matrix[0].y * matrix[2].x - matrix[0].x * matrix[2].y) * inverse,
(matrix[0].x * matrix[1].y - matrix[0].y * matrix[1].x) * inverse);
}
idMat3 WorldInverseInertia(const idPhysics_RigidBody& body) {
return body.current.worldAxis * body.inverseInertiaTensor
* body.current.worldAxis.Transpose();
}
} // namespace
idPhysics_RigidBody::idPhysics_RigidBody()
: idPhysics_DynamicBase()
, clipModel(nullptr)
, linearFriction(0.6f)
, angularFriction(0.6f)
, contactFriction(0.0f)
, linearFrictionWater(1.0f)
, angularFrictionWater(1.0f)
, bouncyness(0.6f)
, inertiaScale(1.0f, 1.0f, 1.0f)
, mass(1.0f)
, inverseMass(1.0f)
, centerOfMass(0.0f, 0.0f, 0.0f)
, inertiaTensor(1.0f)
, inverseInertiaTensor(1.0f)
, fl{}
, current{}
, saved{}
, motionQuery{0}
, lastTimeStep(0.0f) {
type = PHYSICS_RIGIDBODY;
idPhysics_DynamicBase::SetClipMask(1, -1);
current.atRest = -1;
current.localOrigin.Zero();
current.localAxis = idMat3(1.0f);
current.worldOrigin.Zero();
current.worldAxis = idMat3(1.0f);
ZeroSpatial(current.spatialVelocity);
ZeroSpatial(current.externalForce);
ZeroSpatial(current.pushVelocity);
saved = current;
}
idPhysics_RigidBody::~idPhysics_RigidBody() {
if (clipModel != nullptr) clipModel->Unlink();
clipModel = nullptr;
}
void idPhysics_RigidBody::SetClipModel(idClipModel* const model,
const float density, int, const bool freeOld) {
if (clipModel != nullptr && clipModel != model && freeOld)
clipModel->Delete();
clipModel = model;
if (clipModel == nullptr) return;
current.worldOrigin = clipModel->GetOrigin();
current.worldAxis = clipModel->GetAxis();
current.localOrigin = current.worldOrigin;
current.localAxis = current.worldAxis;
clipModel->Link(GetEntityNumber(), GetEntityNumber(), 0,
current.worldOrigin, current.worldAxis);
idVec3 modelCenter;
idMat3 modelInertia;
float modelMass = 0.0f;
clipModel->GetMassProperties(density, modelMass, modelCenter,
modelInertia);
if (modelMass > 0.0f && std::isfinite(modelMass)) {
mass = modelMass;
centerOfMass = modelCenter;
inertiaTensor = modelInertia;
inertiaTensor[0].x *= inertiaScale.x;
inertiaTensor[1].y *= inertiaScale.y;
inertiaTensor[2].z *= inertiaScale.z;
} else {
mass = 1.0f;
centerOfMass.Zero();
inertiaTensor = idMat3(1.0f);
}
inverseMass = 1.0f / mass;
inverseInertiaTensor = Inverse3x3(inertiaTensor);
ZeroSpatial(current.spatialVelocity);
}
idClipModel* idPhysics_RigidBody::GetClipModel(int) { return clipModel; }
int idPhysics_RigidBody::GetNumClipModels() { return clipModel != nullptr; }
void idPhysics_RigidBody::SetMass(const float newMass, int) {
if (newMass <= 0.0f || !std::isfinite(newMass)) return;
const float scale = newMass / mass;
for (int row = 0; row < 3; ++row)
for (int column = 0; column < 3; ++column)
inertiaTensor[row][column] *= scale;
mass = newMass;
inverseMass = 1.0f / mass;
inverseInertiaTensor = Inverse3x3(inertiaTensor);
}
float idPhysics_RigidBody::GetMass(int) { return mass; }
void idPhysics_RigidBody::SetFriction(const float linear,
const float angular, const float contact) {
linearFriction = (std::max)(0.0f, (std::min)(1.0f, linear));
angularFriction = (std::max)(0.0f, (std::min)(1.0f, angular));
contactFriction = (std::max)(0.0f, (std::min)(1.0f, contact));
}
void idPhysics_RigidBody::SetWaterFriction(const float linear,
const float angular) {
linearFrictionWater = (std::max)(0.0f, (std::min)(1.0f, linear));
angularFrictionWater = (std::max)(0.0f, (std::min)(1.0f, angular));
}
void idPhysics_RigidBody::SetBouncyness(const float value) {
bouncyness = (std::max)(0.0f, (std::min)(1.0f, value));
}
void idPhysics_RigidBody::SetInertiaScale(const idVec3& scale) {
inertiaScale = scale;
}
void idPhysics_RigidBody::SetContents(const int contents, int) {
if (clipModel != nullptr) clipModel->SetContents(contents);
}
int idPhysics_RigidBody::GetContents(int) {
return clipModel != nullptr ? clipModel->GetContents() : 0;
}
const idBounds* idPhysics_RigidBody::GetBounds(int) {
return clipModel != nullptr ? &clipModel->GetBounds() : &kRigidZeroBounds;
}
const idBounds* idPhysics_RigidBody::GetAbsBounds(int) {
return clipModel != nullptr ? &clipModel->GetAbsBounds() : &kRigidZeroBounds;
}
void idPhysics_RigidBody::SetOrigin(const idVec3* const origin, int) {
if (origin == nullptr) return;
current.worldOrigin = *origin;
if (fl.hasMaster && callbacks != nullptr) {
idVec3 masterOrigin;
idMat3 masterAxis;
if (GameLib_GetMasterPhysicsTransform(callbacks, masterOrigin,
masterAxis))
current.localOrigin = masterAxis.Transpose()
* (*origin - masterOrigin);
} else {
current.localOrigin = *origin;
}
LinkClip();
Activate();
}
void idPhysics_RigidBody::SetAxis(const idMat3* const axis, int) {
if (axis == nullptr) return;
current.worldAxis = *axis;
if (fl.hasMaster && fl.isOrientated && callbacks != nullptr) {
idVec3 masterOrigin;
idMat3 masterAxis;
if (GameLib_GetMasterPhysicsTransform(callbacks, masterOrigin,
masterAxis))
current.localAxis = *axis * masterAxis.Transpose();
} else {
current.localAxis = *axis;
}
LinkClip();
Activate();
}
void idPhysics_RigidBody::Translate(const idVec3* const translation, int) {
if (translation == nullptr) return;
ResolveCollisions();
current.worldOrigin = current.worldOrigin + *translation;
current.localOrigin = current.localOrigin + *translation;
LinkClip();
Activate();
}
void idPhysics_RigidBody::Rotate(const idRotation* const rotation, int) {
if (rotation == nullptr) return;
ResolveCollisions();
current.worldOrigin = *rotation * current.worldOrigin;
current.worldAxis *= rotation->ToMat3();
current.localOrigin = *rotation * current.localOrigin;
current.localAxis *= rotation->ToMat3();
LinkClip();
Activate();
}
const idVec3* idPhysics_RigidBody::GetOrigin(int) {
return &current.worldOrigin;
}
const idMat3* idPhysics_RigidBody::GetAxis(int) { return &current.worldAxis; }
const idVec3* idPhysics_RigidBody::GetLocalOrigin(int) {
return &current.localOrigin;
}
const idMat3* idPhysics_RigidBody::GetLocalAxis(int) {
return &current.localAxis;
}
void idPhysics_RigidBody::SetLinearVelocity(const idVec3* const value, int) {
if (value == nullptr) return;
SetSpatialLinear(current.spatialVelocity, *value);
Activate();
}
void idPhysics_RigidBody::SetAngularVelocity(const idVec3* const value, int) {
if (value == nullptr) return;
SetSpatialAngular(current.spatialVelocity, *value);
Activate();
}
idVec3* idPhysics_RigidBody::GetLinearVelocity(idVec3* const result, int) {
if (result != nullptr) *result = SpatialLinear(current.spatialVelocity);
return result;
}
idVec3* idPhysics_RigidBody::GetAngularVelocity(idVec3* const result, int) {
if (result != nullptr) *result = SpatialAngular(current.spatialVelocity);
return result;
}
void idPhysics_RigidBody::SetWaterEntNum(int) {}
int idPhysics_RigidBody::GetWaterEntNum() { return -1; }
void idPhysics_RigidBody::SetWaterSurfaceWrldHeight(float) {}
float idPhysics_RigidBody::GetWaterSurfaceWrldHeight() { return 0.0f; }
void idPhysics_RigidBody::GetImpactInfo(int, const idVec3* const point,
impactInfo_t* const info) {
if (info == nullptr) return;
info->Zero();
info->invMass = inverseMass;
info->invInertiaTensor = WorldInverseInertia(*this);
const idVec3 worldCenter = current.worldOrigin
+ current.worldAxis * centerOfMass;
info->position = point != nullptr ? *point - worldCenter : kRigidZeroVector;
info->velocity = SpatialLinear(current.spatialVelocity)
+ SpatialAngular(current.spatialVelocity).Cross(info->position);
}
void idPhysics_RigidBody::ApplyImpulse(int, const idVec3* const point,
const idVec3* const impulse) {
if (fl.noImpact || impulse == nullptr) return;
idVec3 linear = SpatialLinear(current.spatialVelocity)
+ *impulse * inverseMass;
idVec3 angular = SpatialAngular(current.spatialVelocity);
if (point != nullptr) {
const idVec3 center = current.worldOrigin
+ current.worldAxis * centerOfMass;
angular = angular + WorldInverseInertia(*this)
* ((*point - center).Cross(*impulse));
}
SetSpatialLinear(current.spatialVelocity, linear);
SetSpatialAngular(current.spatialVelocity, angular);
CapVelocity();
Activate();
}
void idPhysics_RigidBody::ApplyForce(int, const idVec3* const point,
const idVec3* const force) {
if (force == nullptr) return;
SetSpatialLinear(current.externalForce,
SpatialLinear(current.externalForce) + *force);
if (point != nullptr) {
const idVec3 center = current.worldOrigin
+ current.worldAxis * centerOfMass;
SetSpatialAngular(current.externalForce,
SpatialAngular(current.externalForce)
+ (*point - center).Cross(*force));
}
Activate();
}
void idPhysics_RigidBody::Activate() {
current.atRest = -1;
if (callbacks != nullptr)
GameLib_NotifyPhysicsActivated(callbacks, GetPhysicsId());
}
void idPhysics_RigidBody::PutToRest() {
current.atRest = 1;
ZeroSpatial(current.spatialVelocity);
ZeroSpatial(current.externalForce);
}
bool idPhysics_RigidBody::IsAtRest() { return current.atRest >= 0; }
bool idPhysics_RigidBody::IsPushable(const int sourceContentType) {
return (sourceContentType & fl.noPushMask) == 0;
}
void idPhysics_RigidBody::SaveState() { saved = current; }
void idPhysics_RigidBody::RestoreState() {
current = saved;
LinkClip();
}
void idPhysics_RigidBody::UpdateTime(int) {}
void idPhysics_RigidBody::ClipRotation(trace_t* const results,
const idRotation* const rotation, const idClipModel* const model) {
if (results == nullptr) return;
const idClipModel* moving = model != nullptr ? model : clipModel;
if (clip == nullptr || moving == nullptr || rotation == nullptr) {
std::memset(results, 0, sizeof(*results));
results->fraction = 1.0f;
return;
}
clip->Rotation(results, current.worldOrigin, *rotation, moving,
current.worldAxis, clipMask, GetEntityNumber(), false,
"idPhysics_RigidBody::ClipRotation");
}
int idPhysics_RigidBody::ClipContents(const idClipModel* const model,
int queryMask) {
if (clip == nullptr || clipModel == nullptr) return 0;
if (queryMask == 0) queryMask = clipMask;
trace_t result{};
if (model != nullptr)
clip->ContentsModel(result, current.worldOrigin, clipModel,
current.worldAxis, queryMask, model->GetOrigin(), model,
model->GetAxis());
else
clip->Contents(&result, current.worldOrigin, clipModel,
current.worldAxis, queryMask, GetEntityNumber(),
"idPhysics_RigidBody::ClipContents");
return result.c.contentFlags;
}
void idPhysics_RigidBody::DisableClip() {
if (clipModel != nullptr) clipModel->Disable();
}
void idPhysics_RigidBody::EnableClip() {
if (clipModel != nullptr) clipModel->Enable();
}
void idPhysics_RigidBody::UnlinkClip() {
if (clipModel != nullptr) clipModel->Unlink();
}
void idPhysics_RigidBody::LinkClip() {
if (clipModel != nullptr)
clipModel->Link(GetEntityNumber(), GetEntityNumber(),
clipModel->GetBodyId(), current.worldOrigin, current.worldAxis);
}
bool idPhysics_RigidBody::EvaluateContacts() {
ClearContacts();
AddGroundContacts(clipModel, 12);
return contacts.Num() != 0;
}
bool idPhysics_RigidBody::IsGroundClipModel(const int entityNum,
const int id) {
return idPhysics_DynamicBase::IsGroundClipModel(entityNum, id);
}
void idPhysics_RigidBody::SetPushed(const int deltaTime) {
if (deltaTime <= 0) {
ZeroSpatial(current.pushVelocity);
return;
}
const float scale = 1000.0f / static_cast<float>(deltaTime);
SetSpatialLinear(current.pushVelocity,
(current.worldOrigin - saved.worldOrigin) * scale);
SetSpatialAngular(current.pushVelocity,
SpatialAngular(current.spatialVelocity));
}
idVec3* idPhysics_RigidBody::GetPushedLinearVelocity(idVec3* const result,
int) {
if (result != nullptr) *result = SpatialLinear(current.pushVelocity);
return result;
}
idVec3* idPhysics_RigidBody::GetPushedAngularVelocity(idVec3* const result,
int) {
if (result != nullptr) *result = SpatialAngular(current.pushVelocity);
return result;
}
void idPhysics_RigidBody::SetMaster(const bool enable,
const idVec3* const masterOrigin, const idMat3* const masterAxis,
const bindFlags_t flags) {
motionQuery.index = 0;
if (enable && masterOrigin != nullptr && masterAxis != nullptr) {
if (!fl.hasMaster) {
current.localOrigin = masterAxis->Transpose()
* (current.worldOrigin - *masterOrigin);
current.localAxis = (static_cast<int>(flags) & 1) != 0
? current.worldAxis * masterAxis->Transpose()
: current.worldAxis;
}
fl.hasMaster = 1;
fl.isOrientated = (static_cast<int>(flags) & 1) != 0;
ClearContacts();
} else if (fl.hasMaster) {
fl.hasMaster = 0;
Activate();
}
}
void idPhysics_RigidBody::SetLocalOrigin(const idVec3* const origin, int) {
if (origin == nullptr) return;
current.localOrigin = *origin;
if (fl.hasMaster && callbacks != nullptr) {
idVec3 masterOrigin;
idMat3 masterAxis;
if (GameLib_GetMasterPhysicsTransform(callbacks, masterOrigin,
masterAxis))
current.worldOrigin = masterOrigin + masterAxis * *origin;
} else {
current.worldOrigin = *origin;
}
LinkClip();
Activate();
}
void idPhysics_RigidBody::SetLocalAxis(const idMat3* const axis, int) {
if (axis == nullptr) return;
current.localAxis = *axis;
if (fl.hasMaster && fl.isOrientated && callbacks != nullptr) {
idVec3 masterOrigin;
idMat3 masterAxis;
if (GameLib_GetMasterPhysicsTransform(callbacks, masterOrigin,
masterAxis)) current.worldAxis = *axis * masterAxis;
} else {
current.worldAxis = *axis;
}
LinkClip();
Activate();
}
void idPhysics_RigidBody::CapVelocity() {
idVec3 linear = SpatialLinear(current.spatialVelocity);
idVec3 angular = SpatialAngular(current.spatialVelocity);
const float linearSpeed = linear.Length();
const float angularSpeed = angular.Length();
if (linearSpeed > 16000.0f) linear = linear * (16000.0f / linearSpeed);
if (angularSpeed > 62.831853f)
angular = angular * (62.831853f / angularSpeed);
SetSpatialLinear(current.spatialVelocity, linear);
SetSpatialAngular(current.spatialVelocity, angular);
}
bool idPhysics_RigidBody::TestIfAtRest() {
const idVec3 linear = SpatialLinear(current.spatialVelocity);
const idVec3 angular = SpatialAngular(current.spatialVelocity);
if (linear.LengthSqr() > 4.0f || angular.LengthSqr() > 0.01f)
return false;
if (!EvaluateContacts()) return false;
PutToRest();
return true;
}
void idPhysics_RigidBody::ResolveCollisions(const trace_t* const collision,
const contactsResult_t* const contactResults) {
if (contactResults != nullptr) {
ClearContacts();
const int count = (std::min)(contactResults->numContacts, 12);
for (int index = 0; index < count; ++index) {
contacts.Append(contactResults->contacts[index]);
UpdateCollisionResidency(contactResults->contacts[index]);
}
AddContactPhysicsForContacts();
}
if (collision == nullptr || collision->fraction >= 1.0f) return;
idVec3 linear = SpatialLinear(current.spatialVelocity);
const float intoSurface = linear.Dot(collision->c.normal);
if (intoSurface < 0.0f)
linear = linear - collision->c.normal
* ((1.0f + bouncyness) * intoSurface);
const idVec3 tangent = linear
- collision->c.normal * linear.Dot(collision->c.normal);
linear = linear - tangent * contactFriction;
SetSpatialLinear(current.spatialVelocity, linear);
if (callbacks != nullptr)
GameLib_NotifyPhysicsCollision(callbacks, GetPhysicsId(),
*collision, linear);
}
void idPhysics_RigidBody::Evolve(const float timeStep,
trace_t* const collisionOverride,
contactsResult_t* const contactsOverride) {
if (clipModel == nullptr || clip == nullptr || timeStep <= 0.0f) return;
idVec3 linear = SpatialLinear(current.spatialVelocity);
idVec3 angular = SpatialAngular(current.spatialVelocity);
linear = linear + (gravityVector
+ SpatialLinear(current.externalForce) * inverseMass) * timeStep;
angular = angular + WorldInverseInertia(*this)
* SpatialAngular(current.externalForce) * timeStep;
float linearDrag = linearFriction;
float angularDrag = angularFriction;
if (waterLevel > 0.0f) {
linearDrag += waterLevel * linearFrictionWater;
angularDrag += waterLevel * angularFrictionWater;
}
linear = linear * (std::max)(0.0f, 1.0f - linearDrag * timeStep);
angular = angular * (std::max)(0.0f, 1.0f - angularDrag * timeStep);
SetSpatialLinear(current.spatialVelocity, linear);
SetSpatialAngular(current.spatialVelocity, angular);
CapVelocity();
idVec3 angularAxis = angular;
const float angularSpeed = angularAxis.NormalizeFast();
const idRotation rotation(current.worldOrigin,
angularSpeed > 0.0f ? angularAxis : idVec3(0.0f, 0.0f, 1.0f),
angularSpeed * timeStep * 57.29577951308232f);
const idVec3 end = current.worldOrigin + linear * timeStep;
trace_t localCollision{};
localCollision.fraction = 1.0f;
localCollision.endpos = end;
localCollision.endAxis = current.worldAxis * rotation.ToMat3();
contactsResult_t localContacts{};
trace_t* collision = collisionOverride != nullptr
? collisionOverride : &localCollision;
contactsResult_t* results = contactsOverride != nullptr
? contactsOverride : &localContacts;
motionQuery = clip->MotionContacts(collision, results,
current.worldOrigin, end, rotation, 0.25f, clipModel,
current.worldAxis, clipMask, GetEntityNumber(), false,
"idPhysics_RigidBody::Evolve");
current.worldOrigin = collision->endpos;
current.worldAxis = collision->endAxis;
LinkClip();
lastTimeStep = timeStep;
ResolveCollisions(collision, results);
}
void idPhysics_RigidBody::DropToFloorAndRest() {
if (!fl.dropToFloor || clipModel == nullptr || clip == nullptr) return;
fl.dropToFloor = 0;
trace_t trace{};
const idVec3 end = current.worldOrigin + gravityNormal * 128.0f;
clip->Translation(&trace, current.worldOrigin, end, clipModel,
current.worldAxis, clipMask, GetEntityNumber(), false,
"idPhysics_RigidBody::DropToFloorAndRest");
current.worldOrigin = trace.endpos;
LinkClip();
EvaluateContacts();
if (trace.fraction < 1.0f) PutToRest();
}
bool idPhysics_RigidBody::Evaluate(const int timeStepMSec, int) {
if (fl.hasMaster && callbacks != nullptr) {
idVec3 masterOrigin;
idMat3 masterAxis;
if (!GameLib_GetMasterPhysicsTransform(callbacks, masterOrigin,
masterAxis)) return false;
const idVec3 oldOrigin = current.worldOrigin;
current.worldOrigin = masterOrigin + masterAxis * current.localOrigin;
current.worldAxis = fl.isOrientated
? current.localAxis * masterAxis : current.localAxis;
LinkClip();
return (current.worldOrigin - oldOrigin).LengthSqr() != 0.0f;
}
DropToFloorAndRest();
if (IsAtRest()) return false;
Evolve(timeStepMSec * 0.001f);
ZeroSpatial(current.externalForce);
if (IsOutsideWorld()) {
PutToRest();
if (callbacks != nullptr)
GameLib_NotifyPhysicsDeactivated(callbacks, GetPhysicsId());
} else {
TestIfAtRest();
}
return true;
}
int idPhysics_RigidBody::GetBlockingEntityNum() {
return contacts.Num() != 0 ? contacts[0].entityNum : 0x1FFF;
}
int idPhysics_RigidBody::GetLinearEndTime() { return 0; }
int idPhysics_RigidBody::GetAngularEndTime() { return 0; }
bool idPhysics_RigidBody::IsOutsideWorld() {
return idPhysics_DynamicBase::IsOutsideWorld();
}
+121 -112
View File
@@ -1,121 +1,130 @@
#pragma once
// Reconstructed C++ declarations from IDA Local Types and PDB/DIA metadata.
// Original PDB header: w:\tech5\engine\gamelib\physics\physics_rigidbody.h
// Recovered logical types: 2
// Signatures retain Xbox 360 ABI evidence and may still require manual review.
#include "gamelib/physics/clip.h"
#include "gamelib/physics/physics_dynamicbase.h"
#include <cstdint>
// IDA Local Type ordinal 15433; PDB kind: struct.
struct __declspec(align(4)) idPhysics_RigidBody::rigidBodyFlags_t
{
int noPushMask;
unsigned __int8 : 3;
__int8 isOrientated : 1;
__int8 hasMaster : 1;
__int8 noImpact : 1;
__int8 testSolid : 1;
__int8 dropToFloor : 1;
struct rigidBodyPState_t {
int atRest;
idVec3 localOrigin;
idMat3 localAxis;
idVec3 worldOrigin;
idMat3 worldAxis;
idVec6 spatialVelocity;
idVec6 externalForce;
idVec6 pushVelocity;
};
// IDA Local Type ordinal 15435; PDB kind: class.
class __declspec(align(8)) idPhysics_RigidBody : public idPhysics_DynamicBase
{
class idPhysics_RigidBody : public idPhysics_DynamicBase {
public:
// Recovered virtual interface; IDA vtable ordinal 15436.
virtual ~idPhysics_RigidBody();
virtual void SetClipModel(idClipModel *, float, int, bool);
virtual idClipModel *GetClipModel(int);
virtual int GetNumClipModels();
virtual void SetMass(float, int);
virtual float GetMass(int);
virtual void SetContents(int, int);
virtual int GetContents(int);
virtual void SetClipMask(int, int);
virtual int GetClipMask(int);
virtual const idBounds *GetBounds(int);
virtual const idBounds *GetAbsBounds(int);
virtual void SetOrigin(const idVec3 *, int);
virtual void SetAxis(const idMat3 *, int);
virtual void Translate(const idVec3 *, int);
virtual void Rotate(const idRotation *, int);
virtual const idVec3 *GetOrigin(int);
virtual const idMat3 *GetAxis(int);
virtual const idVec3 *GetLocalOrigin(int);
virtual const idMat3 *GetLocalAxis(int);
virtual void SetLinearVelocity(const idVec3 *, int);
virtual void SetAngularVelocity(const idVec3 *, int);
virtual idVec3 *GetLinearVelocity(idVec3 *result, int);
virtual idVec3 *GetAngularVelocity(idVec3 *result, int);
virtual void SetGravity(const idVec3 *);
virtual const idVec3 *GetGravity();
virtual const idVec3 *GetGravityNormal();
virtual void SetWaterLevel(float, int);
virtual float GetWaterLevel(int);
virtual void SetWaterViscosity(float, int);
virtual float GetWaterViscosity(int);
virtual void SetWaterEntNum(int);
virtual int GetWaterEntNum();
virtual void SetWaterSurfaceWrldHeight(float);
virtual float GetWaterSurfaceWrldHeight();
virtual void GetImpactInfo(const int, const idVec3 *, impactInfo_t *);
virtual void ApplyImpulse(const int, const idVec3 *, const idVec3 *);
virtual void ApplyForce(const int, const idVec3 *, const idVec3 *);
virtual void Activate();
virtual void PutToRest();
virtual bool IsAtRest();
virtual bool IsPushable(int);
virtual void SaveState();
virtual void RestoreState();
virtual bool Evaluate(int, int);
virtual void UpdateTime(int);
virtual void ClipTranslation(trace_t *, const idVec3 *, const idClipModel *);
virtual void ClipRotation(trace_t *, const idRotation *, const idClipModel *);
virtual int ClipContents(const idClipModel *, int);
virtual void DisableClip();
virtual void EnableClip();
virtual void UnlinkClip();
virtual void LinkClip();
virtual bool EvaluateContacts();
virtual int GetNumContacts();
virtual const contactInfo_t *GetContact(int);
virtual void ClearContacts();
virtual void AddContactPhysics(idPhysics *);
virtual void RemoveContactPhysics(idPhysics *);
virtual int GetNumContactPhysics();
virtual idPhysics *GetContactPhysics(int);
virtual void ActivateContactPhysics();
virtual bool HasGroundContacts();
virtual bool IsGroundEntity(int);
virtual bool IsGroundClipModel(int, int);
virtual void SetPushed(int);
virtual idVec3 *GetPushedLinearVelocity(idVec3 *result, const int);
virtual idVec3 *GetPushedAngularVelocity(idVec3 *result, const int);
virtual void SetMaster(bool, const idVec3 *, const idMat3 *, const bindFlags_t);
virtual void SetLocalOrigin(const idVec3 *, int);
virtual void SetLocalAxis(const idMat3 *, int);
virtual int GetBlockingEntityNum();
virtual int GetLinearEndTime();
virtual int GetAngularEndTime();
virtual bool IsInNonResidentCollisionArea(bool);
virtual bool IsOutsideWorld();
struct rigidBodyFlags_t {
int noPushMask;
std::uint8_t reserved : 3;
std::uint8_t isOrientated : 1;
std::uint8_t hasMaster : 1;
std::uint8_t noImpact : 1;
std::uint8_t testSolid : 1;
std::uint8_t dropToFloor : 1;
std::uint8_t pad[3];
};
idClipModel *clipModel;
float linearFriction;
float angularFriction;
float contactFriction;
float linearFrictionWater;
float angularFrictionWater;
float bouncyness;
idVec3 inertiaScale;
float mass;
float inverseMass;
idVec3 centerOfMass;
idMat3 inertiaTensor;
idMat3 inverseInertiaTensor;
idPhysics_RigidBody::rigidBodyFlags_t fl;
rigidBodyPState_t current;
rigidBodyPState_t saved;
idClipQuery motionQuery;
float lastTimeStep;
idPhysics_RigidBody();
~idPhysics_RigidBody() override;
void SetClipModel(idClipModel*, float, int, bool) override;
idClipModel* GetClipModel(int) override;
int GetNumClipModels() override;
void SetMass(float, int) override;
float GetMass(int) override;
void SetContents(int, int) override;
int GetContents(int) override;
const idBounds* GetBounds(int) override;
const idBounds* GetAbsBounds(int) override;
void SetOrigin(const idVec3*, int) override;
void SetAxis(const idMat3*, int) override;
void Translate(const idVec3*, int) override;
void Rotate(const idRotation*, int) override;
const idVec3* GetOrigin(int) override;
const idMat3* GetAxis(int) override;
const idVec3* GetLocalOrigin(int) override;
const idMat3* GetLocalAxis(int) override;
void SetLinearVelocity(const idVec3*, int) override;
void SetAngularVelocity(const idVec3*, int) override;
idVec3* GetLinearVelocity(idVec3*, int) override;
idVec3* GetAngularVelocity(idVec3*, int) override;
void SetWaterEntNum(int) override;
int GetWaterEntNum() override;
void SetWaterSurfaceWrldHeight(float) override;
float GetWaterSurfaceWrldHeight() override;
void GetImpactInfo(int, const idVec3*, impactInfo_t*) override;
void ApplyImpulse(int, const idVec3*, const idVec3*) override;
void ApplyForce(int, const idVec3*, const idVec3*) override;
void Activate() override;
void PutToRest() override;
bool IsAtRest() override;
bool IsPushable(int) override;
void SaveState() override;
void RestoreState() override;
bool Evaluate(int, int) override;
void UpdateTime(int) override;
void ClipRotation(trace_t*, const idRotation*, const idClipModel*) override;
int ClipContents(const idClipModel*, int) override;
void DisableClip() override;
void EnableClip() override;
void UnlinkClip() override;
void LinkClip() override;
bool EvaluateContacts() override;
bool IsGroundClipModel(int, int) override;
void SetPushed(int) override;
idVec3* GetPushedLinearVelocity(idVec3*, int) override;
idVec3* GetPushedAngularVelocity(idVec3*, int) override;
void SetMaster(bool, const idVec3*, const idMat3*, bindFlags_t) override;
void SetLocalOrigin(const idVec3*, int) override;
void SetLocalAxis(const idMat3*, int) override;
int GetBlockingEntityNum() override;
int GetLinearEndTime() override;
int GetAngularEndTime() override;
bool IsOutsideWorld() override;
void SetFriction(float linear, float angular, float contact);
void SetWaterFriction(float linear, float angular);
void SetBouncyness(float bouncyness_);
void SetInertiaScale(const idVec3& scale);
void CapVelocity();
bool TestIfAtRest();
void Evolve(float timeStep, trace_t* collision = nullptr,
contactsResult_t* contacts = nullptr);
void ResolveCollisions(const trace_t* collision = nullptr,
const contactsResult_t* contacts = nullptr);
void DropToFloorAndRest();
idClipModel* clipModel;
float linearFriction;
float angularFriction;
float contactFriction;
float linearFrictionWater;
float angularFrictionWater;
float bouncyness;
idVec3 inertiaScale;
float mass;
float inverseMass;
idVec3 centerOfMass;
idMat3 inertiaTensor;
idMat3 inverseInertiaTensor;
rigidBodyFlags_t fl;
rigidBodyPState_t current;
rigidBodyPState_t saved;
idClipQuery motionQuery;
float lastTimeStep;
};
static_assert(sizeof(rigidBodyPState_t) == 172,
"Recovered rigid-body state ABI changed");
static_assert(sizeof(idPhysics_RigidBody::rigidBodyFlags_t) == 8,
"Recovered rigid-body flags ABI changed");
#if defined(_WIN32) && !defined(_WIN64)
static_assert(sizeof(idPhysics_RigidBody) == 624,
"Recovered idPhysics_RigidBody ABI changed");
#endif
@@ -0,0 +1,517 @@
#include "gamelib/physics/physics_rigidbody3dof.h"
#include "gamelib/physics/clipmodel.h"
#include "idlib/math/rotation.h"
#include <algorithm>
#include <cmath>
#include <cstring>
bool GameLib_GetMasterPhysicsTransform(idPhysicsCallbacks* callbacks,
idVec3& origin, idMat3& axis);
void GameLib_NotifyPhysicsActivated(idPhysicsCallbacks* callbacks,
int physicsId);
void GameLib_NotifyPhysicsDeactivated(idPhysicsCallbacks* callbacks,
int physicsId);
void GameLib_NotifyPhysicsCollision(idPhysicsCallbacks* callbacks,
int physicsId, const trace_t& collision, const idVec3& velocity);
namespace {
const idBounds kThreeDofZeroBounds{{idVec3(0.0f, 0.0f, 0.0f),
idVec3(0.0f, 0.0f, 0.0f)}};
const idVec3 kThreeDofZeroVector(0.0f, 0.0f, 0.0f);
const idMat3 kThreeDofIdentityAxis(1.0f);
float ClampUnit(const float value) {
return (std::max)(0.0f, (std::min)(1.0f, value));
}
} // namespace
idPhysics_RigidBody3DOF::bodyState_t::bodyState_t()
: atRest(-1)
, lastTimeStep(0.0f)
, localOrigin(0.0f, 0.0f, 0.0f)
, localAxis(1.0f)
, linearPushVelocity(0.0f, 0.0f, 0.0f)
, angularPushVelocity(0.0f, 0.0f, 0.0f)
, externalForce(0.0f, 0.0f, 0.0f)
, i{} {
i.position.Zero();
i.orientation = idMat3(1.0f);
i.linearVelocity.Zero();
i.angularVelocity.Zero();
}
idPhysics_RigidBody3DOF::idPhysics_RigidBody3DOF()
: idPhysics_DynamicBase()
, clipModel(nullptr)
, mass(1.0f)
, inverseMass(1.0f)
, linearFriction(1.0f)
, angularFriction(1.0f)
, contactFriction(1.0f)
, linearFrictionWater(1.0f)
, angularFrictionWater(1.0f)
, coefficientOfRestitution(1.0f)
, current()
, saved()
, random(0)
, translationQuery{0}
, flags{} {
type = PHYSICS_RIGIDBODY3DOF;
}
idPhysics_RigidBody3DOF::~idPhysics_RigidBody3DOF() {
if (clipModel != nullptr) clipModel->Unlink();
clipModel = nullptr;
}
void idPhysics_RigidBody3DOF::SetCoefficientOfRestitution(
const float coefficient) {
coefficientOfRestitution = ClampUnit(coefficient);
}
void idPhysics_RigidBody3DOF::SetFriction(const float linear,
const float angular, const float contact) {
linearFriction = ClampUnit(linear);
angularFriction = ClampUnit(angular);
contactFriction = ClampUnit(contact);
}
void idPhysics_RigidBody3DOF::SetWaterFriction(const float linear,
const float angular) {
linearFrictionWater = ClampUnit(linear);
angularFrictionWater = ClampUnit(angular);
}
void idPhysics_RigidBody3DOF::SetClipModel(idClipModel* const model,
const float density, int, const bool freeOld) {
if (clipModel != nullptr && clipModel != model && freeOld)
clipModel->Delete();
clipModel = model;
if (clipModel == nullptr) return;
current.i.position = clipModel->GetOrigin();
current.i.orientation = clipModel->GetAxis();
current.localOrigin = current.i.position;
current.localAxis = current.i.orientation;
LinkClip();
const idBounds& bounds = clipModel->GetBounds();
const idVec3 size = bounds[1] - bounds[0];
SetMass(size.x > 0.0f && size.y > 0.0f && size.z > 0.0f
? size.x * size.y * size.z * density : 1.0f, 0);
current.i.linearVelocity.Zero();
current.i.angularVelocity.Zero();
}
idClipModel* idPhysics_RigidBody3DOF::GetClipModel(int) {
return clipModel;
}
int idPhysics_RigidBody3DOF::GetNumClipModels() {
return clipModel != nullptr;
}
void idPhysics_RigidBody3DOF::SetMass(const float newMass, int) {
mass = newMass > 0.0f && std::isfinite(newMass) ? newMass : 1.0f;
inverseMass = 1.0f / mass;
}
float idPhysics_RigidBody3DOF::GetMass(int) { return mass; }
void idPhysics_RigidBody3DOF::SetContents(const int contents, int) {
if (clipModel != nullptr) clipModel->SetContents(contents);
}
int idPhysics_RigidBody3DOF::GetContents(int) {
return clipModel != nullptr ? clipModel->GetContents() : 0;
}
const idBounds* idPhysics_RigidBody3DOF::GetBounds(int) {
return clipModel != nullptr ? &clipModel->GetBounds()
: &kThreeDofZeroBounds;
}
const idBounds* idPhysics_RigidBody3DOF::GetAbsBounds(int) {
return clipModel != nullptr ? &clipModel->GetAbsBounds()
: &kThreeDofZeroBounds;
}
void idPhysics_RigidBody3DOF::SetOrigin(const idVec3* const origin, int) {
if (origin == nullptr) return;
current.i.position = *origin;
if (flags.hasMaster && callbacks != nullptr) {
idVec3 masterOrigin;
idMat3 masterAxis;
if (GameLib_GetMasterPhysicsTransform(callbacks, masterOrigin,
masterAxis))
current.localOrigin = masterAxis.Transpose()
* (*origin - masterOrigin);
} else {
current.localOrigin = *origin;
}
LinkClip();
Activate();
}
void idPhysics_RigidBody3DOF::SetAxis(const idMat3* const axis, int) {
if (axis == nullptr) return;
current.i.orientation = *axis;
current.localAxis = *axis;
LinkClip();
Activate();
}
void idPhysics_RigidBody3DOF::Translate(const idVec3* const translation,
int) {
if (translation == nullptr) return;
current.i.position = current.i.position + *translation;
current.localOrigin = current.localOrigin + *translation;
LinkClip();
Activate();
}
void idPhysics_RigidBody3DOF::Rotate(const idRotation* const rotation, int) {
if (rotation == nullptr) return;
current.i.position = *rotation * current.i.position;
current.i.orientation *= rotation->ToMat3();
current.localOrigin = *rotation * current.localOrigin;
current.localAxis *= rotation->ToMat3();
LinkClip();
Activate();
}
const idVec3* idPhysics_RigidBody3DOF::GetOrigin(int) {
return &current.i.position;
}
const idMat3* idPhysics_RigidBody3DOF::GetAxis(int) {
return &current.i.orientation;
}
const idVec3* idPhysics_RigidBody3DOF::GetLocalOrigin(int) {
return &current.localOrigin;
}
const idMat3* idPhysics_RigidBody3DOF::GetLocalAxis(int) {
return &current.localAxis;
}
void idPhysics_RigidBody3DOF::SetLinearVelocity(const idVec3* const value,
int) {
if (value == nullptr) return;
current.i.linearVelocity = *value;
Activate();
}
void idPhysics_RigidBody3DOF::SetAngularVelocity(const idVec3* const value,
int) {
if (value == nullptr) return;
current.i.angularVelocity = *value;
Activate();
}
idVec3* idPhysics_RigidBody3DOF::GetLinearVelocity(idVec3* const result,
int) {
if (result != nullptr) *result = current.i.linearVelocity;
return result;
}
idVec3* idPhysics_RigidBody3DOF::GetAngularVelocity(idVec3* const result,
int) {
if (result != nullptr) *result = current.i.angularVelocity;
return result;
}
void idPhysics_RigidBody3DOF::SetWaterEntNum(int) {}
int idPhysics_RigidBody3DOF::GetWaterEntNum() { return -1; }
void idPhysics_RigidBody3DOF::SetWaterSurfaceWrldHeight(float) {}
float idPhysics_RigidBody3DOF::GetWaterSurfaceWrldHeight() { return 0.0f; }
void idPhysics_RigidBody3DOF::GetImpactInfo(int,
const idVec3* const point, impactInfo_t* const info) {
if (info == nullptr) return;
info->Zero();
info->invMass = inverseMass;
info->position = point != nullptr
? *point - current.i.position : kThreeDofZeroVector;
info->velocity = current.i.linearVelocity
+ current.i.angularVelocity.Cross(info->position);
}
void idPhysics_RigidBody3DOF::ApplyImpulse(int,
const idVec3* const point, const idVec3* const impulse) {
if (flags.noImpact || impulse == nullptr) return;
current.i.linearVelocity = current.i.linearVelocity
+ *impulse * inverseMass;
if (point != nullptr)
current.i.angularVelocity = current.i.angularVelocity
+ (*point - current.i.position).Cross(*impulse) * inverseMass;
Activate();
}
void idPhysics_RigidBody3DOF::ApplyForce(int,
const idVec3*, const idVec3* const force) {
if (force == nullptr) return;
current.externalForce = current.externalForce + *force * inverseMass;
Activate();
}
void idPhysics_RigidBody3DOF::Activate() {
current.atRest = -1;
if (callbacks != nullptr)
GameLib_NotifyPhysicsActivated(callbacks, GetPhysicsId());
}
void idPhysics_RigidBody3DOF::PutToRest() {
current.atRest = 1;
current.i.linearVelocity.Zero();
current.i.angularVelocity.Zero();
current.externalForce.Zero();
}
bool idPhysics_RigidBody3DOF::IsAtRest() { return current.atRest >= 0; }
bool idPhysics_RigidBody3DOF::IsPushable(int) { return true; }
void idPhysics_RigidBody3DOF::SaveState() { saved = current; }
void idPhysics_RigidBody3DOF::RestoreState() {
current = saved;
LinkClip();
}
void idPhysics_RigidBody3DOF::UpdateTime(int) {}
void idPhysics_RigidBody3DOF::ClipTranslation(trace_t* const results,
const idVec3* const translation, const idClipModel* const model) {
idPhysics_DynamicBase::ClipTranslation(results, translation,
model != nullptr ? model : clipModel);
}
void idPhysics_RigidBody3DOF::ClipRotation(trace_t* const results,
const idRotation* const rotation, const idClipModel* const model) {
if (results == nullptr) return;
const idClipModel* moving = model != nullptr ? model : clipModel;
if (clip == nullptr || moving == nullptr || rotation == nullptr) {
std::memset(results, 0, sizeof(*results));
results->fraction = 1.0f;
return;
}
clip->Rotation(results, current.i.position, *rotation, moving,
current.i.orientation, clipMask, GetEntityNumber(), false,
"idPhysics_RigidBody3DOF::ClipRotation");
}
int idPhysics_RigidBody3DOF::ClipContents(const idClipModel* const model,
int queryMask) {
if (clip == nullptr || clipModel == nullptr) return 0;
if (queryMask == 0) queryMask = clipMask;
trace_t result{};
if (model != nullptr)
clip->ContentsModel(result, current.i.position, clipModel,
current.i.orientation, queryMask, model->GetOrigin(), model,
model->GetAxis());
else
clip->Contents(&result, current.i.position, clipModel,
current.i.orientation, queryMask, GetEntityNumber(),
"idPhysics_RigidBody3DOF::ClipContents");
return result.c.contentFlags;
}
void idPhysics_RigidBody3DOF::DisableClip() {
if (clipModel != nullptr) clipModel->Disable();
}
void idPhysics_RigidBody3DOF::EnableClip() {
if (clipModel != nullptr) clipModel->Enable();
}
void idPhysics_RigidBody3DOF::UnlinkClip() {
if (clipModel != nullptr) clipModel->Unlink();
}
void idPhysics_RigidBody3DOF::LinkClip() {
if (clipModel != nullptr)
clipModel->Link(GetEntityNumber(), GetEntityNumber(),
clipModel->GetBodyId(), current.i.position,
current.i.orientation);
}
bool idPhysics_RigidBody3DOF::EvaluateContacts() {
ClearContacts();
AddGroundContacts(clipModel, 12);
return contacts.Num() != 0;
}
void idPhysics_RigidBody3DOF::SetPushed(const int deltaTime) {
if (deltaTime <= 0) {
current.linearPushVelocity.Zero();
current.angularPushVelocity.Zero();
return;
}
current.linearPushVelocity = (current.i.position - saved.i.position)
* (1000.0f / static_cast<float>(deltaTime));
current.angularPushVelocity = current.i.angularVelocity;
}
idVec3* idPhysics_RigidBody3DOF::GetPushedLinearVelocity(
idVec3* const result, int) {
if (result != nullptr) *result = current.linearPushVelocity;
return result;
}
idVec3* idPhysics_RigidBody3DOF::GetPushedAngularVelocity(
idVec3* const result, int) {
if (result != nullptr) *result = current.angularPushVelocity;
return result;
}
void idPhysics_RigidBody3DOF::SetMaster(const bool enable,
const idVec3* const masterOrigin, const idMat3* const masterAxis,
const bindFlags_t bindFlags) {
translationQuery.index = 0;
if (enable && masterOrigin != nullptr && masterAxis != nullptr) {
if (!flags.hasMaster) {
current.localOrigin = masterAxis->Transpose()
* (current.i.position - *masterOrigin);
current.localAxis = (static_cast<int>(bindFlags) & 1) != 0
? current.i.orientation * masterAxis->Transpose()
: current.i.orientation;
}
flags.hasMaster = 1;
flags.isOriented = (static_cast<int>(bindFlags) & 1) != 0;
ClearContacts();
} else if (flags.hasMaster) {
flags.hasMaster = 0;
Activate();
}
}
void idPhysics_RigidBody3DOF::SetLocalOrigin(const idVec3* const origin,
int) {
if (origin == nullptr) return;
current.localOrigin = *origin;
if (flags.hasMaster && callbacks != nullptr) {
idVec3 masterOrigin;
idMat3 masterAxis;
if (GameLib_GetMasterPhysicsTransform(callbacks, masterOrigin,
masterAxis))
current.i.position = masterOrigin + masterAxis * *origin;
} else {
current.i.position = *origin;
}
LinkClip();
Activate();
}
void idPhysics_RigidBody3DOF::SetLocalAxis(const idMat3* const axis, int) {
if (axis == nullptr) return;
current.localAxis = *axis;
if (flags.hasMaster && flags.isOriented && callbacks != nullptr) {
idVec3 masterOrigin;
idMat3 masterAxis;
if (GameLib_GetMasterPhysicsTransform(callbacks, masterOrigin,
masterAxis)) current.i.orientation = *axis * masterAxis;
} else {
current.i.orientation = *axis;
}
LinkClip();
Activate();
}
void idPhysics_RigidBody3DOF::Integrate(const float deltaTime,
const bodyState_t& source, bodyState_t& next) const {
next = source;
next.lastTimeStep = deltaTime;
next.i.position = source.i.position
+ (source.i.linearVelocity + source.externalForce) * deltaTime;
idVec3 axis = source.i.angularVelocity;
const float speed = axis.NormalizeFast();
const idRotation rotation(kThreeDofZeroVector,
speed > 0.0f ? axis : idVec3(0.0f, 0.0f, 1.0f),
speed * deltaTime * 57.29577951308232f);
next.i.orientation *= rotation.ToMat3();
next.i.linearVelocity = source.i.linearVelocity
+ gravityVector * deltaTime;
float linearDrag = linearFriction;
float angularDrag = angularFriction;
if (waterLevel > 0.0f) {
linearDrag += waterLevel * linearFrictionWater;
angularDrag += waterLevel * angularFrictionWater;
}
next.i.linearVelocity = next.i.linearVelocity
* (std::max)(0.0f, 1.0f - linearDrag * deltaTime);
next.i.angularVelocity = source.i.angularVelocity
* (std::max)(0.0f, 1.0f - angularDrag * deltaTime);
}
bool idPhysics_RigidBody3DOF::CheckForCollisions(
const bodyState_t& source, bodyState_t& next,
trace_t& collision) {
if (clip == nullptr || clipModel == nullptr) return false;
idVec3 angularAxis = source.i.angularVelocity;
const float speed = angularAxis.NormalizeFast();
const idRotation rotation(source.i.position,
speed > 0.0f ? angularAxis : idVec3(0.0f, 0.0f, 1.0f),
speed * next.lastTimeStep * 57.29577951308232f);
collision = {};
collision.fraction = 1.0f;
collision.endpos = next.i.position;
collision.endAxis = next.i.orientation;
translationQuery = clip->Motion(&collision, source.i.position,
next.i.position, rotation, clipModel, source.i.orientation,
clipMask, GetEntityNumber(), false,
"idPhysics_RigidBody3DOF::CheckForCollisions");
next.i.position = collision.endpos;
next.i.orientation = collision.endAxis;
return collision.fraction < 1.0f;
}
bool idPhysics_RigidBody3DOF::CollisionImpulse(
const trace_t& collision, float, bodyState_t& state,
idVec3& impulse) {
const float normalSpeed = state.i.linearVelocity.Dot(collision.c.normal);
if (normalSpeed >= 0.0f) {
impulse.Zero();
return false;
}
impulse = collision.c.normal
* (-(1.0f + coefficientOfRestitution) * normalSpeed * mass);
state.i.linearVelocity = state.i.linearVelocity + impulse * inverseMass;
const idVec3 tangent = state.i.linearVelocity
- collision.c.normal * state.i.linearVelocity.Dot(collision.c.normal);
state.i.linearVelocity = state.i.linearVelocity
- tangent * contactFriction;
return true;
}
bool idPhysics_RigidBody3DOF::Evaluate(const int timeStepMSec, int) {
const float deltaTime = timeStepMSec * 0.001f;
current.lastTimeStep = deltaTime;
if (flags.hasMaster && callbacks != nullptr) {
idVec3 masterOrigin;
idMat3 masterAxis;
if (!GameLib_GetMasterPhysicsTransform(callbacks, masterOrigin,
masterAxis)) return false;
const idVec3 oldPosition = current.i.position;
current.i.position = masterOrigin + masterAxis * current.localOrigin;
current.i.orientation = flags.isOriented
? current.localAxis * masterAxis : current.localAxis;
if (deltaTime > 0.0f)
current.i.linearVelocity = (current.i.position - oldPosition)
* (1.0f / deltaTime);
LinkClip();
current.externalForce.Zero();
return (current.i.position - oldPosition).LengthSqr() != 0.0f;
}
if (current.atRest >= 0 || deltaTime <= 0.0f) return false;
if (flags.dropToFloor) {
flags.dropToFloor = 0;
trace_t down{};
const idVec3 end = current.i.position + gravityNormal * 128.0f;
clip->Translation(&down, current.i.position, end, clipModel,
current.i.orientation, clipMask, GetEntityNumber(), false,
"idPhysics_RigidBody3DOF::DropToFloor");
current.i.position = down.endpos;
if (down.fraction < 1.0f) PutToRest();
LinkClip();
return true;
}
bodyState_t next;
Integrate(deltaTime, current, next);
trace_t collision{};
const bool collided = CheckForCollisions(current, next, collision);
current = next;
if (collided) {
idVec3 impulse;
CollisionImpulse(collision, deltaTime, current, impulse);
ClearContacts();
contacts.Append(collision.c);
UpdateCollisionResidency(collision.c);
AddContactPhysicsForContacts();
if (callbacks != nullptr)
GameLib_NotifyPhysicsCollision(callbacks, GetPhysicsId(),
collision, current.i.linearVelocity);
const idVec3 alongGround = current.i.linearVelocity
- gravityNormal * current.i.linearVelocity.Dot(gravityNormal);
if (alongGround.Length() <= 10.0f
&& std::fabs(current.i.linearVelocity.Dot(gravityNormal))
< 20.0f)
PutToRest();
}
LinkClip();
current.linearPushVelocity.Zero();
current.angularPushVelocity.Zero();
current.externalForce.Zero();
if (IsOutsideWorld() && callbacks != nullptr)
GameLib_NotifyPhysicsDeactivated(callbacks, GetPhysicsId());
return true;
}
int idPhysics_RigidBody3DOF::GetBlockingEntityNum() {
return contacts.Num() != 0 ? contacts[0].entityNum : 0x1FFF;
}
int idPhysics_RigidBody3DOF::GetLinearEndTime() { return 0; }
int idPhysics_RigidBody3DOF::GetAngularEndTime() { return 0; }
bool idPhysics_RigidBody3DOF::IsOutsideWorld() {
return idPhysics_DynamicBase::IsOutsideWorld();
}
@@ -1,138 +1,132 @@
#pragma once
// Reconstructed C++ declarations from IDA Local Types and PDB/DIA metadata.
// Original PDB header: w:\tech5\engine\gamelib\physics\physics_rigidbody3dof.h
// Recovered logical types: 4
// Signatures retain Xbox 360 ABI evidence and may still require manual review.
#include "gamelib/physics/clip.h"
#include "gamelib/physics/physics_dynamicbase.h"
#include "idlib/math/random.h"
#include <cstdint>
// IDA Local Type ordinal 17461; PDB kind: struct.
struct idPhysics_RigidBody3DOF::bodyIntState_t
{
idVec3 position;
idMat3 orientation;
idVec3 linearVelocity;
idVec3 angularVelocity;
};
// IDA Local Type ordinal 17462; PDB kind: struct.
struct idPhysics_RigidBody3DOF::bodyState_t
{
int atRest;
float lastTimeStep;
idVec3 localOrigin;
idMat3 localAxis;
idVec3 linearPushVelocity;
idVec3 angularPushVelocity;
idVec3 externalForce;
idPhysics_RigidBody3DOF::bodyIntState_t i;
};
// IDA Local Type ordinal 17463; PDB kind: struct.
struct idPhysics_RigidBody3DOF::simpleBodyFlags_t
{
unsigned __int8 : 3;
__int8 noImpact : 1;
__int8 isOriented : 1;
__int8 hasMaster : 1;
__int8 testSolid : 1;
__int8 dropToFloor : 1;
};
// IDA Local Type ordinal 17464; PDB kind: class.
class __declspec(align(8)) idPhysics_RigidBody3DOF : public idPhysics_DynamicBase
{
class idPhysics_RigidBody3DOF : public idPhysics_DynamicBase {
public:
// Recovered virtual interface; IDA vtable ordinal 17465.
virtual ~idPhysics_RigidBody3DOF();
virtual void SetClipModel(idClipModel *, float, int, bool);
virtual idClipModel *GetClipModel(int);
virtual int GetNumClipModels();
virtual void SetMass(float, int);
virtual float GetMass(int);
virtual void SetContents(int, int);
virtual int GetContents(int);
virtual void SetClipMask(int, int);
virtual int GetClipMask(int);
virtual const idBounds *GetBounds(int);
virtual const idBounds *GetAbsBounds(int);
virtual void SetOrigin(const idVec3 *, int);
virtual void SetAxis(const idMat3 *, int);
virtual void Translate(const idVec3 *, int);
virtual void Rotate(const idRotation *, int);
virtual const idVec3 *GetOrigin(int);
virtual const idMat3 *GetAxis(int);
virtual const idVec3 *GetLocalOrigin(int);
virtual const idMat3 *GetLocalAxis(int);
virtual void SetLinearVelocity(const idVec3 *, int);
virtual void SetAngularVelocity(const idVec3 *, int);
virtual idVec3 *GetLinearVelocity(idVec3 *result, int);
virtual idVec3 *GetAngularVelocity(idVec3 *result, int);
virtual void SetGravity(const idVec3 *);
virtual const idVec3 *GetGravity();
virtual const idVec3 *GetGravityNormal();
virtual void SetWaterLevel(float, int);
virtual float GetWaterLevel(int);
virtual void SetWaterViscosity(float, int);
virtual float GetWaterViscosity(int);
virtual void SetWaterEntNum(int);
virtual int GetWaterEntNum();
virtual void SetWaterSurfaceWrldHeight(float);
virtual float GetWaterSurfaceWrldHeight();
virtual void GetImpactInfo(const int, const idVec3 *, impactInfo_t *);
virtual void ApplyImpulse(const int, const idVec3 *, const idVec3 *);
virtual void ApplyForce(const int, const idVec3 *, const idVec3 *);
virtual void Activate();
virtual void PutToRest();
virtual bool IsAtRest();
virtual bool IsPushable(int);
virtual void SaveState();
virtual void RestoreState();
virtual bool Evaluate(int, int);
virtual void UpdateTime(int);
virtual void ClipTranslation(trace_t *, const idVec3 *, const idClipModel *);
virtual void ClipRotation(trace_t *, const idRotation *, const idClipModel *);
virtual int ClipContents(const idClipModel *, int);
virtual void DisableClip();
virtual void EnableClip();
virtual void UnlinkClip();
virtual void LinkClip();
virtual bool EvaluateContacts();
virtual int GetNumContacts();
virtual const contactInfo_t *GetContact(int);
virtual void ClearContacts();
virtual void AddContactPhysics(idPhysics *);
virtual void RemoveContactPhysics(idPhysics *);
virtual int GetNumContactPhysics();
virtual idPhysics *GetContactPhysics(int);
virtual void ActivateContactPhysics();
virtual bool HasGroundContacts();
virtual bool IsGroundEntity(int);
virtual bool IsGroundClipModel(int, int);
virtual void SetPushed(int);
virtual idVec3 *GetPushedLinearVelocity(idVec3 *result, const int);
virtual idVec3 *GetPushedAngularVelocity(idVec3 *result, const int);
virtual void SetMaster(bool, const idVec3 *, const idMat3 *, const bindFlags_t);
virtual void SetLocalOrigin(const idVec3 *, int);
virtual void SetLocalAxis(const idMat3 *, int);
virtual int GetBlockingEntityNum();
virtual int GetLinearEndTime();
virtual int GetAngularEndTime();
virtual bool IsInNonResidentCollisionArea(bool);
virtual bool IsOutsideWorld();
struct bodyIntState_t {
idVec3 position;
idMat3 orientation;
idVec3 linearVelocity;
idVec3 angularVelocity;
};
struct bodyState_t {
int atRest;
float lastTimeStep;
idVec3 localOrigin;
idMat3 localAxis;
idVec3 linearPushVelocity;
idVec3 angularPushVelocity;
idVec3 externalForce;
bodyIntState_t i;
idClipModel *clipModel;
float mass;
float inverseMass;
float linearFriction;
float angularFriction;
float contactFriction;
float linearFrictionWater;
float angularFrictionWater;
float coefficientOfRestitution;
idPhysics_RigidBody3DOF::bodyState_t current;
idPhysics_RigidBody3DOF::bodyState_t saved;
idRandom random;
idClipQuery translationQuery;
idPhysics_RigidBody3DOF::simpleBodyFlags_t flags;
bodyState_t();
};
struct simpleBodyFlags_t {
std::uint8_t reserved : 3;
std::uint8_t noImpact : 1;
std::uint8_t isOriented : 1;
std::uint8_t hasMaster : 1;
std::uint8_t testSolid : 1;
std::uint8_t dropToFloor : 1;
};
idPhysics_RigidBody3DOF();
~idPhysics_RigidBody3DOF() override;
void SetClipModel(idClipModel*, float, int, bool) override;
idClipModel* GetClipModel(int) override;
int GetNumClipModels() override;
void SetMass(float, int) override;
float GetMass(int) override;
void SetContents(int, int) override;
int GetContents(int) override;
const idBounds* GetBounds(int) override;
const idBounds* GetAbsBounds(int) override;
void SetOrigin(const idVec3*, int) override;
void SetAxis(const idMat3*, int) override;
void Translate(const idVec3*, int) override;
void Rotate(const idRotation*, int) override;
const idVec3* GetOrigin(int) override;
const idMat3* GetAxis(int) override;
const idVec3* GetLocalOrigin(int) override;
const idMat3* GetLocalAxis(int) override;
void SetLinearVelocity(const idVec3*, int) override;
void SetAngularVelocity(const idVec3*, int) override;
idVec3* GetLinearVelocity(idVec3*, int) override;
idVec3* GetAngularVelocity(idVec3*, int) override;
void SetWaterEntNum(int) override;
int GetWaterEntNum() override;
void SetWaterSurfaceWrldHeight(float) override;
float GetWaterSurfaceWrldHeight() override;
void GetImpactInfo(int, const idVec3*, impactInfo_t*) override;
void ApplyImpulse(int, const idVec3*, const idVec3*) override;
void ApplyForce(int, const idVec3*, const idVec3*) override;
void Activate() override;
void PutToRest() override;
bool IsAtRest() override;
bool IsPushable(int) override;
void SaveState() override;
void RestoreState() override;
bool Evaluate(int, int) override;
void UpdateTime(int) override;
void ClipTranslation(trace_t*, const idVec3*, const idClipModel*) override;
void ClipRotation(trace_t*, const idRotation*, const idClipModel*) override;
int ClipContents(const idClipModel*, int) override;
void DisableClip() override;
void EnableClip() override;
void UnlinkClip() override;
void LinkClip() override;
bool EvaluateContacts() override;
void SetPushed(int) override;
idVec3* GetPushedLinearVelocity(idVec3*, int) override;
idVec3* GetPushedAngularVelocity(idVec3*, int) override;
void SetMaster(bool, const idVec3*, const idMat3*, bindFlags_t) override;
void SetLocalOrigin(const idVec3*, int) override;
void SetLocalAxis(const idMat3*, int) override;
int GetBlockingEntityNum() override;
int GetLinearEndTime() override;
int GetAngularEndTime() override;
bool IsOutsideWorld() override;
void SetFriction(float linear, float angular, float contact);
void SetWaterFriction(float linear, float angular);
void SetCoefficientOfRestitution(float coefficient);
void Integrate(float deltaTime, const bodyState_t& current,
bodyState_t& next) const;
bool CheckForCollisions(const bodyState_t& current,
bodyState_t& next, trace_t& collision);
bool CollisionImpulse(const trace_t& collision, float timeStep,
bodyState_t& state, idVec3& impulse);
idClipModel* clipModel;
float mass;
float inverseMass;
float linearFriction;
float angularFriction;
float contactFriction;
float linearFrictionWater;
float angularFrictionWater;
float coefficientOfRestitution;
bodyState_t current;
bodyState_t saved;
idRandom random;
idClipQuery translationQuery;
simpleBodyFlags_t flags;
};
static_assert(sizeof(idPhysics_RigidBody3DOF::bodyIntState_t) == 72,
"Recovered 3DOF integration state ABI changed");
static_assert(sizeof(idPhysics_RigidBody3DOF::bodyState_t) == 164,
"Recovered 3DOF body state ABI changed");
static_assert(sizeof(idPhysics_RigidBody3DOF::simpleBodyFlags_t) == 1,
"Recovered 3DOF flags ABI changed");
#if defined(_WIN32) && !defined(_WIN64)
static_assert(sizeof(idPhysics_RigidBody3DOF) == 504,
"Recovered idPhysics_RigidBody3DOF ABI changed");
#endif
@@ -0,0 +1,509 @@
#include "gamelib/physics/physics_staticmulti.h"
#include "gamelib/physics/clip.h"
#include "gamelib/physics/clipmodel.h"
#include "idlib/lib_print.h"
#include "idlib/math/rotation.h"
#include <algorithm>
#include <cstring>
bool GameLib_GetMasterPhysicsTransform(idPhysicsCallbacks* callbacks,
idVec3& origin, idMat3& axis);
namespace {
const idVec3 kZeroVector(0.0f, 0.0f, 0.0f);
const idVec3 kDownVector(0.0f, 0.0f, -1.0f);
const idMat3 kIdentityAxis(1.0f);
const idBounds kZeroBounds{{idVec3(0.0f, 0.0f, 0.0f),
idVec3(0.0f, 0.0f, 0.0f)}};
staticPState_t DefaultState() {
staticPState_t state{};
state.worldOrigin.Zero();
state.worldAxis = idMat3(1.0f);
state.localOrigin.Zero();
state.localAxis = idMat3(1.0f);
return state;
}
void AddBounds(idBounds& destination, const idBounds& source,
bool& initialized) {
if (!initialized) {
destination = source;
initialized = true;
return;
}
for (int axis = 0; axis < 3; ++axis) {
destination[0][axis] = (std::min)(destination[0][axis],
source[0][axis]);
destination[1][axis] = (std::max)(destination[1][axis],
source[1][axis]);
}
}
} // namespace
idPhysics_StaticMulti::idPhysics_StaticMulti()
: idPhysics()
, clipModels(16)
, mass(16)
, bounds(kZeroBounds)
, absBounds(kZeroBounds)
, hasMaster(false)
, isOrientated(false)
, current(16) {
type = PHYSICS_STATICMULTI;
clipModels.SetNum(1);
mass.SetNum(1);
current.SetNum(1);
clipModels[0] = nullptr;
mass[0] = 1.0f;
current[0] = DefaultState();
}
idPhysics_StaticMulti::~idPhysics_StaticMulti() {
for (int index = 0; index < clipModels.Num(); ++index) {
if (clipModels[index] != nullptr) clipModels[index]->Delete();
clipModels[index] = nullptr;
}
}
bool idPhysics_StaticMulti::IsValidId(const int id) const {
return id >= 0 && id < clipModels.Num();
}
void idPhysics_StaticMulti::LinkModel(const int id) {
if (!IsValidId(id) || clipModels[id] == nullptr) return;
clipModels[id]->Link(GetEntityNumber(), GetEntityNumber(), id,
current[id].worldOrigin, current[id].worldAxis);
}
void idPhysics_StaticMulti::SetClipModel(idClipModel* const model,
const float density, const int id, const bool freeOld) {
if (id < 0) return;
if (id >= clipModels.Num()) {
const int oldNum = clipModels.Num();
const int newNum = id + 1;
if (!clipModels.SetNum(newNum) || !mass.SetNum(newNum)
|| !current.SetNum(newNum)) return;
for (int index = oldNum; index < newNum; ++index) {
clipModels[index] = nullptr;
mass[index] = 1.0f;
current[index] = DefaultState();
}
}
if (clipModels[id] != nullptr && clipModels[id] != model && freeOld)
clipModels[id]->Delete();
clipModels[id] = model;
if (model != nullptr) {
if (model->GetNumTraceModels() != 0) {
idVec3 centerOfMass;
idMat3 inertia;
model->GetMassProperties(density, mass[id], centerOfMass,
inertia);
} else {
mass[id] = 1.0f;
}
LinkModel(id);
}
int newNum = clipModels.Num();
while (newNum > 1 && clipModels[newNum - 1] == nullptr) --newNum;
clipModels.SetNum(newNum);
mass.SetNum(newNum);
current.SetNum(newNum);
}
idClipModel* idPhysics_StaticMulti::GetClipModel(const int id) {
if (IsValidId(id) && clipModels[id] != nullptr) return clipModels[id];
return clip != nullptr ? clip->defaultClipModel : nullptr;
}
int idPhysics_StaticMulti::GetNumClipModels() { return clipModels.Num(); }
void idPhysics_StaticMulti::SetMass(const float newMass, const int id) {
if (id == -1) {
if (mass.Num() == 0) return;
const float each = newMass / static_cast<float>(mass.Num());
for (int index = 0; index < mass.Num(); ++index) mass[index] = each;
} else if (IsValidId(id)) {
mass[id] = newMass;
}
}
float idPhysics_StaticMulti::GetMass(const int id) {
if (id >= 0) return IsValidId(id) ? mass[id] : 0.0f;
float total = 0.0f;
for (int index = 0; index < mass.Num(); ++index) total += mass[index];
return total;
}
void idPhysics_StaticMulti::SetContents(const int contents, const int id) {
if (id == -1) {
for (int index = 0; index < clipModels.Num(); ++index)
if (clipModels[index] != nullptr)
clipModels[index]->SetContents(contents);
} else if (IsValidId(id) && clipModels[id] != nullptr) {
clipModels[id]->SetContents(contents);
}
}
int idPhysics_StaticMulti::GetContents(const int id) {
if (id >= 0) return IsValidId(id) && clipModels[id] != nullptr
? clipModels[id]->GetContents() : 0;
int contents = 0;
for (int index = 0; index < clipModels.Num(); ++index)
if (clipModels[index] != nullptr)
contents |= clipModels[index]->GetContents();
return contents;
}
void idPhysics_StaticMulti::SetClipMask(int, int) {}
int idPhysics_StaticMulti::GetClipMask(int) { return 0; }
const idBounds* idPhysics_StaticMulti::GetBounds(const int id) {
if (IsValidId(id) && clipModels[id] != nullptr)
return &clipModels[id]->GetBounds();
if (id != -1) return &kZeroBounds;
bool initialized = false;
for (int index = 0; index < clipModels.Num(); ++index)
if (clipModels[index] != nullptr)
AddBounds(bounds, clipModels[index]->GetBounds(), initialized);
if (!initialized) return &kZeroBounds;
const idVec3 origin = current.Num() != 0
? current[0].worldOrigin : kZeroVector;
bounds[0] = bounds[0] - origin;
bounds[1] = bounds[1] - origin;
return &bounds;
}
const idBounds* idPhysics_StaticMulti::GetAbsBounds(const int id) {
if (IsValidId(id) && clipModels[id] != nullptr)
return &clipModels[id]->GetAbsBounds();
if (id != -1) return &kZeroBounds;
bool initialized = false;
for (int index = 0; index < clipModels.Num(); ++index)
if (clipModels[index] != nullptr)
AddBounds(absBounds, clipModels[index]->GetAbsBounds(),
initialized);
return initialized ? &absBounds : &kZeroBounds;
}
bool idPhysics_StaticMulti::Evaluate(int, int) {
if (!hasMaster || callbacks == nullptr) return false;
idVec3 masterOrigin;
idMat3 masterAxis;
if (!GameLib_GetMasterPhysicsTransform(callbacks, masterOrigin,
masterAxis)) return false;
bool moved = false;
for (int index = 0; index < current.Num(); ++index) {
const idVec3 oldOrigin = current[index].worldOrigin;
const idMat3 oldAxis = current[index].worldAxis;
current[index].worldOrigin = masterOrigin
+ masterAxis * current[index].localOrigin;
current[index].worldAxis = isOrientated
? current[index].localAxis * masterAxis
: current[index].localAxis;
moved = moved
|| (current[index].worldOrigin - oldOrigin).LengthSqr() != 0.0f
|| (current[index].worldAxis[0] - oldAxis[0]).LengthSqr() != 0.0f
|| (current[index].worldAxis[1] - oldAxis[1]).LengthSqr() != 0.0f
|| (current[index].worldAxis[2] - oldAxis[2]).LengthSqr() != 0.0f;
LinkModel(index);
}
return moved;
}
void idPhysics_StaticMulti::SetOrigin(const idVec3* const newOrigin,
const int id) {
if (newOrigin == nullptr || current.Num() == 0) return;
if (id == -1) {
const idVec3 translation = *newOrigin - current[0].worldOrigin;
Translate(&translation, -1);
return;
}
if (!IsValidId(id)) return;
current[id].worldOrigin = *newOrigin;
if (hasMaster && callbacks != nullptr) {
idVec3 masterOrigin;
idMat3 masterAxis;
if (GameLib_GetMasterPhysicsTransform(callbacks, masterOrigin,
masterAxis))
current[id].localOrigin = masterAxis.Transpose()
* (*newOrigin - masterOrigin);
} else {
current[id].localOrigin = *newOrigin;
}
LinkModel(id);
}
void idPhysics_StaticMulti::SetAxis(const idMat3* const newAxis,
const int id) {
if (newAxis == nullptr || current.Num() == 0) return;
if (id == -1) {
const idMat3 delta = current[0].worldAxis.Transpose() * *newAxis;
const idVec3 pivot = current[0].worldOrigin;
for (int index = 0; index < current.Num(); ++index) {
current[index].worldOrigin = pivot
+ delta * (current[index].worldOrigin - pivot);
current[index].worldAxis *= delta;
current[index].localAxis *= delta;
LinkModel(index);
}
return;
}
if (!IsValidId(id)) return;
current[id].worldAxis = *newAxis;
if (hasMaster && isOrientated && callbacks != nullptr) {
idVec3 masterOrigin;
idMat3 masterAxis;
if (GameLib_GetMasterPhysicsTransform(callbacks, masterOrigin,
masterAxis))
current[id].localAxis = *newAxis * masterAxis.Transpose();
} else {
current[id].localAxis = *newAxis;
}
LinkModel(id);
}
void idPhysics_StaticMulti::Translate(const idVec3* const translation,
const int id) {
if (translation == nullptr) return;
const int first = id == -1 ? 0 : id;
const int last = id == -1 ? current.Num() : id + 1;
if (first < 0 || last > current.Num()) return;
for (int index = first; index < last; ++index) {
current[index].worldOrigin = current[index].worldOrigin + *translation;
current[index].localOrigin = current[index].localOrigin + *translation;
LinkModel(index);
}
}
void idPhysics_StaticMulti::Rotate(const idRotation* const rotation,
const int id) {
if (rotation == nullptr) return;
const int first = id == -1 ? 0 : id;
const int last = id == -1 ? current.Num() : id + 1;
if (first < 0 || last > current.Num()) return;
const idMat3 rotationAxis = rotation->ToMat3();
for (int index = first; index < last; ++index) {
current[index].worldOrigin = *rotation * current[index].worldOrigin;
current[index].worldAxis *= rotationAxis;
current[index].localOrigin = *rotation * current[index].localOrigin;
current[index].localAxis *= rotationAxis;
LinkModel(index);
}
}
const idVec3* idPhysics_StaticMulti::GetOrigin(const int id) {
return IsValidId(id) ? &current[id].worldOrigin : &kZeroVector;
}
const idMat3* idPhysics_StaticMulti::GetAxis(const int id) {
return IsValidId(id) ? &current[id].worldAxis : &kIdentityAxis;
}
const idVec3* idPhysics_StaticMulti::GetLocalOrigin(const int id) {
return IsValidId(id) ? &current[id].localOrigin : &kZeroVector;
}
const idMat3* idPhysics_StaticMulti::GetLocalAxis(const int id) {
return IsValidId(id) ? &current[id].localAxis : &kIdentityAxis;
}
void idPhysics_StaticMulti::SetLinearVelocity(const idVec3*, int) {}
void idPhysics_StaticMulti::SetAngularVelocity(const idVec3*, int) {}
idVec3* idPhysics_StaticMulti::GetLinearVelocity(idVec3* result, int) {
if (result != nullptr) result->Zero();
return result;
}
idVec3* idPhysics_StaticMulti::GetAngularVelocity(idVec3* result, int) {
if (result != nullptr) result->Zero();
return result;
}
void idPhysics_StaticMulti::SetGravity(const idVec3*) {}
const idVec3* idPhysics_StaticMulti::GetGravity() { return &kZeroVector; }
const idVec3* idPhysics_StaticMulti::GetGravityNormal() {
return &kDownVector;
}
void idPhysics_StaticMulti::SetWaterLevel(float, int) {}
float idPhysics_StaticMulti::GetWaterLevel(int) { return 0.0f; }
void idPhysics_StaticMulti::SetWaterViscosity(float, int) {}
float idPhysics_StaticMulti::GetWaterViscosity(int) { return 0.0f; }
void idPhysics_StaticMulti::SetWaterEntNum(int) {}
int idPhysics_StaticMulti::GetWaterEntNum() { return -1; }
void idPhysics_StaticMulti::SetWaterSurfaceWrldHeight(float) {}
float idPhysics_StaticMulti::GetWaterSurfaceWrldHeight() { return 0.0f; }
void idPhysics_StaticMulti::GetImpactInfo(int, const idVec3*,
impactInfo_t* const info) {
if (info != nullptr) info->Zero();
}
void idPhysics_StaticMulti::ApplyImpulse(int, const idVec3*, const idVec3*) {}
void idPhysics_StaticMulti::ApplyForce(int, const idVec3*, const idVec3*) {}
void idPhysics_StaticMulti::Activate() {}
void idPhysics_StaticMulti::PutToRest() {}
bool idPhysics_StaticMulti::IsAtRest() { return true; }
bool idPhysics_StaticMulti::IsPushable(int) { return false; }
void idPhysics_StaticMulti::SaveState() {}
void idPhysics_StaticMulti::RestoreState() {}
void idPhysics_StaticMulti::UpdateTime(int) {}
void idPhysics_StaticMulti::ClipTranslation(trace_t* const results,
const idVec3*, const idClipModel*) {
if (results != nullptr) std::memset(results, 0, sizeof(*results));
idLibPrint::Warning("idPhysics_StaticMulti::ClipTranslation called");
}
void idPhysics_StaticMulti::ClipRotation(trace_t* const results,
const idRotation*, const idClipModel*) {
if (results != nullptr) std::memset(results, 0, sizeof(*results));
idLibPrint::Warning("idPhysics_StaticMulti::ClipRotation called");
}
int idPhysics_StaticMulti::ClipContents(const idClipModel* const model,
int clipMask) {
if (clip == nullptr) return 0;
if (clipMask == 0) clipMask = -1;
int contents = 0;
for (int index = 0; index < clipModels.Num(); ++index) {
idClipModel* self = clipModels[index];
if (self == nullptr) continue;
trace_t result{};
if (model != nullptr) {
clip->ContentsModel(result, self->GetOrigin(), self,
self->GetAxis(), clipMask, model->GetOrigin(), model,
model->GetAxis());
} else {
clip->Contents(&result, self->GetOrigin(), self,
self->GetAxis(), clipMask, 0x1FFF,
"idPhysics_StaticMulti::ClipContents");
}
contents |= result.c.contentFlags;
}
return contents;
}
void idPhysics_StaticMulti::DisableClip() {
for (int index = 0; index < clipModels.Num(); ++index)
if (clipModels[index] != nullptr) clipModels[index]->Disable();
}
void idPhysics_StaticMulti::EnableClip() {
for (int index = 0; index < clipModels.Num(); ++index)
if (clipModels[index] != nullptr) clipModels[index]->Enable();
}
void idPhysics_StaticMulti::UnlinkClip() {
for (int index = 0; index < clipModels.Num(); ++index)
if (clipModels[index] != nullptr) clipModels[index]->Unlink();
}
void idPhysics_StaticMulti::LinkClip() {
for (int index = 0; index < clipModels.Num(); ++index) LinkModel(index);
}
bool idPhysics_StaticMulti::EvaluateContacts() { return false; }
int idPhysics_StaticMulti::GetNumContacts() { return 0; }
const contactInfo_t* idPhysics_StaticMulti::GetContact(int) {
static contactInfo_t info{};
std::memset(&info, 0, sizeof(info));
return &info;
}
void idPhysics_StaticMulti::ClearContacts() {}
void idPhysics_StaticMulti::AddContactPhysics(idPhysics*) {}
void idPhysics_StaticMulti::RemoveContactPhysics(idPhysics*) {}
int idPhysics_StaticMulti::GetNumContactPhysics() { return 0; }
idPhysics* idPhysics_StaticMulti::GetContactPhysics(int) { return nullptr; }
void idPhysics_StaticMulti::ActivateContactPhysics() {}
bool idPhysics_StaticMulti::HasGroundContacts() { return false; }
bool idPhysics_StaticMulti::IsGroundEntity(int) { return false; }
bool idPhysics_StaticMulti::IsGroundClipModel(int, int) { return false; }
void idPhysics_StaticMulti::SetPushed(int) {}
idVec3* idPhysics_StaticMulti::GetPushedLinearVelocity(idVec3* result, int) {
if (result != nullptr) result->Zero();
return result;
}
idVec3* idPhysics_StaticMulti::GetPushedAngularVelocity(idVec3* result, int) {
if (result != nullptr) result->Zero();
return result;
}
void idPhysics_StaticMulti::SetMaster(const bool enable,
const idVec3* const masterOrigin, const idMat3* const masterAxis,
const bindFlags_t flags) {
if (enable && masterOrigin != nullptr && masterAxis != nullptr) {
if (!hasMaster) {
const idMat3 inverse = masterAxis->Transpose();
for (int index = 0; index < current.Num(); ++index) {
current[index].localOrigin = inverse
* (current[index].worldOrigin - *masterOrigin);
current[index].localAxis =
(static_cast<int>(flags) & 1) != 0
? current[index].worldAxis * inverse
: current[index].worldAxis;
}
}
hasMaster = true;
isOrientated = (static_cast<int>(flags) & 1) != 0;
} else {
hasMaster = false;
}
}
void idPhysics_StaticMulti::SetLocalOrigin(const idVec3* const newOrigin,
const int id) {
if (newOrigin == nullptr || current.Num() == 0) return;
if (id == -1) {
if (hasMaster && callbacks != nullptr) {
idVec3 masterOrigin;
idMat3 masterAxis;
if (GameLib_GetMasterPhysicsTransform(callbacks, masterOrigin,
masterAxis)) {
const idVec3 target = masterOrigin + masterAxis * *newOrigin;
const idVec3 translation = target - current[0].worldOrigin;
Translate(&translation, -1);
}
} else {
const idVec3 translation = *newOrigin - current[0].worldOrigin;
Translate(&translation, -1);
}
return;
}
if (!IsValidId(id)) return;
current[id].localOrigin = *newOrigin;
if (hasMaster && callbacks != nullptr) {
idVec3 masterOrigin;
idMat3 masterAxis;
if (GameLib_GetMasterPhysicsTransform(callbacks, masterOrigin,
masterAxis))
current[id].worldOrigin = masterOrigin + masterAxis * *newOrigin;
} else {
current[id].worldOrigin = *newOrigin;
}
LinkModel(id);
}
void idPhysics_StaticMulti::SetLocalAxis(const idMat3* const newAxis,
const int id) {
if (newAxis == nullptr || current.Num() == 0) return;
if (id == -1) {
idMat3 target = *newAxis;
if (hasMaster && isOrientated && callbacks != nullptr) {
idVec3 masterOrigin;
idMat3 masterAxis;
if (GameLib_GetMasterPhysicsTransform(callbacks, masterOrigin,
masterAxis)) target *= masterAxis;
}
SetAxis(&target, -1);
return;
}
if (!IsValidId(id)) return;
current[id].localAxis = *newAxis;
if (hasMaster && isOrientated && callbacks != nullptr) {
idVec3 masterOrigin;
idMat3 masterAxis;
if (GameLib_GetMasterPhysicsTransform(callbacks, masterOrigin,
masterAxis)) current[id].worldAxis = *newAxis * masterAxis;
} else {
current[id].worldAxis = *newAxis;
}
LinkModel(id);
}
int idPhysics_StaticMulti::GetBlockingEntityNum() { return 0x1FFF; }
int idPhysics_StaticMulti::GetLinearEndTime() { return 0; }
int idPhysics_StaticMulti::GetAngularEndTime() { return 0; }
@@ -1,97 +1,100 @@
#pragma once
// Reconstructed C++ declarations from IDA Local Types and PDB/DIA metadata.
// Original PDB header: w:\tech5\engine\gamelib\physics\physics_staticmulti.h
// Recovered logical types: 1
// Signatures retain Xbox 360 ABI evidence and may still require manual review.
#include "gamelib/physics/physics_static.h"
// IDA Local Type ordinal 18829; PDB kind: class.
class __declspec(align(8)) idPhysics_StaticMulti : public idPhysics
{
class idPhysics_StaticMulti : public idPhysics {
public:
// Recovered virtual interface; IDA vtable ordinal 18830.
virtual ~idPhysics_StaticMulti();
virtual void SetClipModel(idClipModel *, float, int, bool);
virtual idClipModel *GetClipModel(int);
virtual int GetNumClipModels();
virtual void SetMass(float, int);
virtual float GetMass(int);
virtual void SetContents(int, int);
virtual int GetContents(int);
virtual void SetClipMask(int, int);
virtual int GetClipMask(int);
virtual const idBounds *GetBounds(int);
virtual const idBounds *GetAbsBounds(int);
virtual void SetOrigin(const idVec3 *, int);
virtual void SetAxis(const idMat3 *, int);
virtual void Translate(const idVec3 *, int);
virtual void Rotate(const idRotation *, int);
virtual const idVec3 *GetOrigin(int);
virtual const idMat3 *GetAxis(int);
virtual const idVec3 *GetLocalOrigin(int);
virtual const idMat3 *GetLocalAxis(int);
virtual void SetLinearVelocity(const idVec3 *, int);
virtual void SetAngularVelocity(const idVec3 *, int);
virtual idVec3 *GetLinearVelocity(idVec3 *result, int);
virtual idVec3 *GetAngularVelocity(idVec3 *result, int);
virtual void SetGravity(const idVec3 *);
virtual const idVec3 *GetGravity();
virtual const idVec3 *GetGravityNormal();
virtual void SetWaterLevel(float, int);
virtual float GetWaterLevel(int);
virtual void SetWaterViscosity(float, int);
virtual float GetWaterViscosity(int);
virtual void SetWaterEntNum(int);
virtual int GetWaterEntNum();
virtual void SetWaterSurfaceWrldHeight(float);
virtual float GetWaterSurfaceWrldHeight();
virtual void GetImpactInfo(const int, const idVec3 *, impactInfo_t *);
virtual void ApplyImpulse(const int, const idVec3 *, const idVec3 *);
virtual void ApplyForce(const int, const idVec3 *, const idVec3 *);
virtual void Activate();
virtual void PutToRest();
virtual bool IsAtRest();
virtual bool IsPushable(int);
virtual void SaveState();
virtual void RestoreState();
virtual bool Evaluate(int, int);
virtual void UpdateTime(int);
virtual void ClipTranslation(trace_t *, const idVec3 *, const idClipModel *);
virtual void ClipRotation(trace_t *, const idRotation *, const idClipModel *);
virtual int ClipContents(const idClipModel *, int);
virtual void DisableClip();
virtual void EnableClip();
virtual void UnlinkClip();
virtual void LinkClip();
virtual bool EvaluateContacts();
virtual int GetNumContacts();
virtual const contactInfo_t *GetContact(int);
virtual void ClearContacts();
virtual void AddContactPhysics(idPhysics *);
virtual void RemoveContactPhysics(idPhysics *);
virtual int GetNumContactPhysics();
virtual idPhysics *GetContactPhysics(int);
virtual void ActivateContactPhysics();
virtual bool HasGroundContacts();
virtual bool IsGroundEntity(int);
virtual bool IsGroundClipModel(int, int);
virtual void SetPushed(int);
virtual idVec3 *GetPushedLinearVelocity(idVec3 *result, const int);
virtual idVec3 *GetPushedAngularVelocity(idVec3 *result, const int);
virtual void SetMaster(bool, const idVec3 *, const idMat3 *, const bindFlags_t);
virtual void SetLocalOrigin(const idVec3 *, int);
virtual void SetLocalAxis(const idMat3 *, int);
virtual int GetBlockingEntityNum();
virtual int GetLinearEndTime();
virtual int GetAngularEndTime();
virtual bool IsInNonResidentCollisionArea(bool);
idPhysics_StaticMulti();
~idPhysics_StaticMulti() override;
idList<idClipModel *,77> clipModels;
idList<float,77> mass;
idBounds bounds;
idBounds absBounds;
bool hasMaster;
bool isOrientated;
idList<staticPState_t,77> current;
void SetClipModel(idClipModel*, float, int, bool) override;
idClipModel* GetClipModel(int) override;
int GetNumClipModels() override;
void SetMass(float, int) override;
float GetMass(int) override;
void SetContents(int, int) override;
int GetContents(int) override;
void SetClipMask(int, int) override;
int GetClipMask(int) override;
const idBounds* GetBounds(int) override;
const idBounds* GetAbsBounds(int) override;
void SetOrigin(const idVec3*, int) override;
void SetAxis(const idMat3*, int) override;
void Translate(const idVec3*, int) override;
void Rotate(const idRotation*, int) override;
const idVec3* GetOrigin(int) override;
const idMat3* GetAxis(int) override;
const idVec3* GetLocalOrigin(int) override;
const idMat3* GetLocalAxis(int) override;
void SetLinearVelocity(const idVec3*, int) override;
void SetAngularVelocity(const idVec3*, int) override;
idVec3* GetLinearVelocity(idVec3*, int) override;
idVec3* GetAngularVelocity(idVec3*, int) override;
void SetGravity(const idVec3*) override;
const idVec3* GetGravity() override;
const idVec3* GetGravityNormal() override;
void SetWaterLevel(float, int) override;
float GetWaterLevel(int) override;
void SetWaterViscosity(float, int) override;
float GetWaterViscosity(int) override;
void SetWaterEntNum(int) override;
int GetWaterEntNum() override;
void SetWaterSurfaceWrldHeight(float) override;
float GetWaterSurfaceWrldHeight() override;
void GetImpactInfo(int, const idVec3*, impactInfo_t*) override;
void ApplyImpulse(int, const idVec3*, const idVec3*) override;
void ApplyForce(int, const idVec3*, const idVec3*) override;
void Activate() override;
void PutToRest() override;
bool IsAtRest() override;
bool IsPushable(int) override;
void SaveState() override;
void RestoreState() override;
bool Evaluate(int, int) override;
void UpdateTime(int) override;
void ClipTranslation(trace_t*, const idVec3*, const idClipModel*) override;
void ClipRotation(trace_t*, const idRotation*, const idClipModel*) override;
int ClipContents(const idClipModel*, int) override;
void DisableClip() override;
void EnableClip() override;
void UnlinkClip() override;
void LinkClip() override;
bool EvaluateContacts() override;
int GetNumContacts() override;
const contactInfo_t* GetContact(int) override;
void ClearContacts() override;
void AddContactPhysics(idPhysics*) override;
void RemoveContactPhysics(idPhysics*) override;
int GetNumContactPhysics() override;
idPhysics* GetContactPhysics(int) override;
void ActivateContactPhysics() override;
bool HasGroundContacts() override;
bool IsGroundEntity(int) override;
bool IsGroundClipModel(int, int) override;
void SetPushed(int) override;
idVec3* GetPushedLinearVelocity(idVec3*, int) override;
idVec3* GetPushedAngularVelocity(idVec3*, int) override;
void SetMaster(bool, const idVec3*, const idMat3*, bindFlags_t) override;
void SetLocalOrigin(const idVec3*, int) override;
void SetLocalAxis(const idMat3*, int) override;
int GetBlockingEntityNum() override;
int GetLinearEndTime() override;
int GetAngularEndTime() override;
idList<idClipModel*, 77> clipModels;
idList<float, 77> mass;
idBounds bounds;
idBounds absBounds;
bool hasMaster;
bool isOrientated;
idList<staticPState_t, 77> current;
private:
bool IsValidId(int id) const;
void LinkModel(int id);
};
#if defined(_WIN32) && !defined(_WIN64)
static_assert(sizeof(idPhysics_StaticMulti) == 152,
"Recovered idPhysics_StaticMulti ABI changed");
#endif