518 lines
19 KiB
C++
518 lines
19 KiB
C++
#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 ¤t.i.position;
|
|
}
|
|
const idMat3* idPhysics_RigidBody3DOF::GetAxis(int) {
|
|
return ¤t.i.orientation;
|
|
}
|
|
const idVec3* idPhysics_RigidBody3DOF::GetLocalOrigin(int) {
|
|
return ¤t.localOrigin;
|
|
}
|
|
const idMat3* idPhysics_RigidBody3DOF::GetLocalAxis(int) {
|
|
return ¤t.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();
|
|
}
|