Files
tech5/source/engine/gamelib/physics/clipmodel.cpp
T

280 lines
8.8 KiB
C++

#include "gamelib/physics/clipmodel.h"
#include "cm/collisionmodel.h"
#include "cm/collisionmodelmanager.h"
#include "gamelib/aas2/aas2.h"
#include "gamelib/physics/clip.h"
#include "gamelib/physics/tracemodelcache.h"
#include "idlib/geometry/tracemodel.h"
#include "idlib/lib_print.h"
#include <algorithm>
namespace {
void ClearAASLinks(idClipModel& model) {
for (idAASClipLink*& link : model.aasLinks) link = nullptr;
}
} // namespace
idClipModel::idClipModel() {
Init(nullptr);
}
idClipModel::idClipModel(idClip* const ownerClip, const char* modelName,
const idMaterial* const material) {
Init(ownerClip);
LoadCollisionModel(modelName, material);
}
idClipModel::idClipModel(idClip* const ownerClip,
idCollisionModel* const model) {
Init(ownerClip);
LoadCollisionModel(model);
}
idClipModel::idClipModel(idClip* const ownerClip,
const idTraceModel* const traceModel, const int traceModelIndex,
const idMaterial* const material) {
Init(ownerClip);
LoadTraceModel(traceModel, traceModelIndex, material);
}
idClipModel::idClipModel(idClip* const ownerClip,
idTreeAnimator* const animator) {
Init(ownerClip);
LoadAnimator(animator);
}
idClipModel::idClipModel(idClip* const ownerClip,
const idClipModel& other) {
Init(ownerClip);
enabled = other.enabled;
entityNumber = other.entityNumber;
ownerNumber = other.ownerNumber;
physicsId = other.physicsId;
bodyId = other.bodyId;
bodyMask = other.bodyMask;
origin = other.origin;
axis = other.axis;
bounds = other.bounds;
absBounds = other.absBounds;
contents = other.contents;
collisionModel = other.collisionModel;
animatedModel = other.animatedModel;
if (clip != nullptr && clip->traceModelCache != nullptr) {
for (int index = 0; index < other.traceModels.Num(); ++index) {
traceModels.Append(clip->traceModelCache->CopyTraceModel(
other.traceModels[index]));
}
}
}
idClipModel::~idClipModel() {
Unlink();
FreeModel();
}
void idClipModel::Init(idClip* const ownerClip) {
enabled = true;
deleted = false;
entityNumber = -1;
ownerNumber = -1;
physicsId = 0;
bodyId = 0;
bodyMask = -1;
origin.Zero();
axis = idMat3(1.0f);
bounds[0].Zero();
bounds[1].Zero();
absBounds = bounds;
contents = 0;
collisionModel = nullptr;
traceModels.Clear();
animatedModel = nullptr;
clip = ownerClip;
clipLinks = nullptr;
collisionQuery.offset = 0;
touchCount = 0;
nextDeleted = nullptr;
ClearAASLinks(*this);
}
void idClipModel::Delete() {
if (deleted) return;
deleted = true;
if (clip != nullptr) clip->DeleteClipModel(this);
}
idCollisionModel* idClipModel::NoTraceModelWarning() const {
idLibPrint::Warning("idClipModel::GetCollisionModel: clip model %d on "
"entity %d is not a collision or trace model", bodyId, entityNumber);
return nullptr;
}
idCollisionModel* idClipModel::GetCollisionModel() const {
if (collisionModel != nullptr) return collisionModel;
if (clip != nullptr && clip->traceModelCache != nullptr
&& traceModels.Num() > 0) {
const idTraceModelCache::trmCache_t* const entry =
clip->traceModelCache->GetEntry(traceModels[0]);
if (entry != nullptr) return entry->collisionModel;
}
return NoTraceModelWarning();
}
const idTraceModel* idClipModel::GetTraceModel(const int index) const {
if (clip == nullptr || clip->traceModelCache == nullptr
|| index < 0 || index >= traceModels.Num()) return nullptr;
const idTraceModelCache::trmCache_t* const entry =
clip->traceModelCache->GetEntry(traceModels[index]);
return entry != nullptr ? entry->trm : nullptr;
}
void idClipModel::GetMassProperties(const float density, float& mass,
idVec3& centerOfMass, idMat3& inertiaTensor) const {
mass = 0.0f;
centerOfMass.Zero();
inertiaTensor[0].Zero();
inertiaTensor[1].Zero();
inertiaTensor[2].Zero();
if (clip == nullptr || clip->traceModelCache == nullptr) return;
for (int index = 0; index < traceModels.Num(); ++index) {
float partMass = 0.0f;
idVec3 partCenter;
idMat3 partInertia;
clip->traceModelCache->GetMassProperties(traceModels[index],
density, partMass, partCenter, partInertia);
centerOfMass = centerOfMass + partCenter * partMass;
mass += partMass;
for (int row = 0; row < 3; ++row)
for (int column = 0; column < 3; ++column)
inertiaTensor[row][column] += partInertia[row][column];
}
if (mass > 0.0f) centerOfMass = centerOfMass * (1.0f / mass);
}
void idClipModel::SetContents(const int newContents) {
if (contents == newContents) return;
const bool relink = IsLinked();
if (relink) Unlink();
contents = newContents;
if (relink) Link();
}
void idClipModel::FreeModel() {
if (clip != nullptr && clip->traceModelCache != nullptr) {
for (int index = 0; index < traceModels.Num(); ++index)
clip->traceModelCache->FreeTraceModel(traceModels[index]);
}
traceModels.ClearFree();
collisionModel = nullptr;
animatedModel = nullptr;
}
bool idClipModel::LoadCollisionModel(const char* const modelName,
const idMaterial*) {
if (modelName == nullptr || *modelName == '\0') return false;
LoadCollisionModel(collisionModelManager.LoadModel(modelName));
return collisionModel != nullptr;
}
void idClipModel::LoadCollisionModel(idCollisionModel* const model) {
FreeModel();
collisionModel = model;
if (model != nullptr) {
model->GetBounds(bounds);
model->GetContents(contents);
absBounds.FromTransformedBounds(bounds, origin, axis);
}
}
void idClipModel::LoadTraceModel(const idTraceModel* const traceModel,
const int traceModelIndex, const idMaterial* const material) {
FreeModel();
if (traceModel == nullptr || clip == nullptr
|| clip->traceModelCache == nullptr) return;
const int index = traceModelIndex >= 0
? clip->traceModelCache->CopyTraceModel(traceModelIndex)
: clip->traceModelCache->AllocTraceModel(*traceModel, material);
traceModels.Append(index);
bounds = traceModel->bounds;
absBounds.FromTransformedBounds(bounds, origin, axis);
}
void idClipModel::LoadAnimator(idTreeAnimator* const animator) {
FreeModel();
animatedModel = animator;
}
void idClipModel::Serialize(idSerializer&) {
// The serializer transport lives in network; all recovered clip-model
// state is held in explicit fields and can be serialized by that layer.
}
void idClipModel::Unlink() {
for (int aas = 0; aas < 8; ++aas) {
if (aasLinks[aas] != nullptr && clip != nullptr
&& clip->aases[aas] != nullptr) {
aasLinks[aas] = clip->aases[aas]->UnLinkClipModel(aasLinks[aas]);
}
}
while (clipLinks != nullptr) {
clipLink_t* const link = clipLinks;
clipLinks = link->nextLink;
if (link->prevInSector != nullptr)
link->prevInSector->nextInSector = link->nextInSector;
else if (link->sector != nullptr)
link->sector->clipLinks = link->nextInSector;
if (link->nextInSector != nullptr)
link->nextInSector->prevInSector = link->prevInSector;
if (clip != nullptr) clip->clipLinkAllocator.Free(link);
}
}
void idClipModel::Link_r(clipSector_t* const sector) {
if (sector == nullptr || clip == nullptr) return;
clipLink_t* const link = clip->clipLinkAllocator.Alloc();
if (link == nullptr) return;
link->clipModel = this;
link->sector = sector;
link->prevInSector = nullptr;
link->nextInSector = sector->clipLinks;
if (sector->clipLinks != nullptr)
sector->clipLinks->prevInSector = link;
sector->clipLinks = link;
link->nextLink = clipLinks;
clipLinks = link;
}
void idClipModel::Link() {
if (clip == nullptr || deleted) return;
Unlink();
absBounds.FromTransformedBounds(bounds, origin, axis);
if (!clip->clipSectors.IsEmpty()) Link_r(&clip->clipSectors[0]);
for (int aas = 0; aas < 8; ++aas) {
if (clip->aases[aas] != nullptr)
aasLinks[aas] = clip->aases[aas]->LinkClipModel(this);
}
}
void idClipModel::Link(const int entityNum, const int ownerNum,
const int physicsBodyId, const idVec3& newOrigin,
const idMat3& newAxis) {
entityNumber = entityNum;
ownerNumber = ownerNum;
physicsId = physicsBodyId;
bodyId = physicsBodyId;
origin = newOrigin;
axis = newAxis;
Link();
}
void idClipModel::Link(const int entityNum, const int ownerNum,
const int physicsBodyId, const idVec3& newOrigin,
const idMat3& newAxis, const idBounds& newBounds) {
bounds = newBounds;
Link(entityNum, ownerNum, physicsBodyId, newOrigin, newAxis);
}