753 lines
32 KiB
C++
753 lines
32 KiB
C++
#include "gamelib/physics/clip.h"
|
|
|
|
#include "cm/collisionmodel.h"
|
|
#include "cm/collisionmodelmanager.h"
|
|
#include "gamelib/aas2/aas2.h"
|
|
#include "gamelib/physics/tracemodelcache.h"
|
|
#include "gamelib/physics/tracemodelrecycler.h"
|
|
#include "idlib/geometry/tracemodel.h"
|
|
#include "idlib/geometry/winding.h"
|
|
|
|
#include <algorithm>
|
|
#include <cstring>
|
|
#include <vector>
|
|
|
|
namespace {
|
|
|
|
bool BoundsIntersect(const idBounds& first, const idBounds& second) {
|
|
for (int axis = 0; axis < 3; ++axis) {
|
|
if (first[1][axis] < second[0][axis]
|
|
|| first[0][axis] > second[1][axis]) return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
idBounds PointBounds(const idVec3& point) {
|
|
idBounds result;
|
|
result[0] = point;
|
|
result[1] = point;
|
|
return result;
|
|
}
|
|
|
|
idBounds MotionBounds(const idVec3& start, const idVec3& end,
|
|
const idClipModel* const model, const idMat3& axis) {
|
|
idBounds result;
|
|
if (model != nullptr) {
|
|
result.FromTransformedBounds(model->GetBounds(), start, axis);
|
|
idBounds endBounds;
|
|
endBounds.FromTransformedBounds(model->GetBounds(), end, axis);
|
|
for (int component = 0; component < 3; ++component) {
|
|
result[0][component] = (std::min)(result[0][component],
|
|
endBounds[0][component]);
|
|
result[1][component] = (std::max)(result[1][component],
|
|
endBounds[1][component]);
|
|
}
|
|
} else {
|
|
result[0].Set((std::min)(start.x, end.x),
|
|
(std::min)(start.y, end.y), (std::min)(start.z, end.z));
|
|
result[1].Set((std::max)(start.x, end.x),
|
|
(std::max)(start.y, end.y), (std::max)(start.z, end.z));
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void CollectTraceModels(const idClipModel* const model,
|
|
std::vector<const idTraceModel*>& output) {
|
|
if (model == nullptr) return;
|
|
for (int index = 0; index < model->GetNumTraceModels(); ++index) {
|
|
const idTraceModel* const traceModel = model->GetTraceModel(index);
|
|
if (traceModel != nullptr) output.push_back(traceModel);
|
|
}
|
|
}
|
|
|
|
void AppendPositionedModel(const idClipModel* const model,
|
|
std::vector<idPositionedCollisionModel>& output) {
|
|
if (model == nullptr || !model->IsEnabled() || model->IsDeleted()) return;
|
|
idCollisionModel* const collisionModel = model->GetCollisionModel();
|
|
if (collisionModel == nullptr) return;
|
|
idPositionedCollisionModel positioned{};
|
|
positioned.model = collisionModel;
|
|
positioned.modelJoints = nullptr;
|
|
positioned.modelOrigin = model->GetOrigin();
|
|
positioned.modelAxis = model->GetAxis();
|
|
positioned.modelEntityNum = model->GetEntityNumber();
|
|
positioned.modelPhysicsId = model->GetPhysicsId();
|
|
positioned.modelBodyId = model->GetBodyId();
|
|
positioned.modelContentsOverride = model->GetContents();
|
|
positioned.modelQuery = model->collisionQuery;
|
|
output.push_back(positioned);
|
|
}
|
|
|
|
void CollectPositionedModels(const idClip& clip, const int contentMask,
|
|
const int passEntityNumber, const bool ignoreWorld,
|
|
std::vector<idPositionedCollisionModel>& output) {
|
|
if (!ignoreWorld && clip.world != nullptr
|
|
&& (clip.world->GetContents() & contentMask) != 0) {
|
|
AppendPositionedModel(clip.world, output);
|
|
}
|
|
if (clip.clipSectors.IsEmpty()) return;
|
|
for (clipLink_t* link = clip.clipSectors[0].clipLinks;
|
|
link != nullptr; link = link->nextInSector) {
|
|
idClipModel* const model = link->clipModel;
|
|
if (model == nullptr || model == clip.world
|
|
|| model->GetEntityNumber() == passEntityNumber
|
|
|| (model->GetContents() & contentMask) == 0) continue;
|
|
AppendPositionedModel(model, output);
|
|
}
|
|
}
|
|
|
|
idClipQuery ToClipQuery(const idCollisionQuery query) {
|
|
idClipQuery result{};
|
|
result.index = query.offset;
|
|
return result;
|
|
}
|
|
|
|
idCollisionQuery ToCollisionQuery(const idClipQuery query) {
|
|
idCollisionQuery result{};
|
|
result.offset = query.index;
|
|
return result;
|
|
}
|
|
|
|
idClipModel* FindLinkedModel(const idClip& clip, const int entityNumber,
|
|
const int physicsId, const int bodyId) {
|
|
if (clip.world != nullptr && clip.world->GetEntityNumber() == entityNumber
|
|
&& clip.world->GetPhysicsId() == physicsId
|
|
&& clip.world->GetBodyId() == bodyId) return clip.world;
|
|
if (clip.clipSectors.IsEmpty()) return nullptr;
|
|
for (clipLink_t* link = clip.clipSectors[0].clipLinks;
|
|
link != nullptr; link = link->nextInSector) {
|
|
idClipModel* const model = link->clipModel;
|
|
if (model != nullptr && model->GetEntityNumber() == entityNumber
|
|
&& model->GetPhysicsId() == physicsId
|
|
&& model->GetBodyId() == bodyId) return model;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
idClip::idClip()
|
|
: world(nullptr), temporaryClipModel(nullptr), defaultClipModel(nullptr),
|
|
playerMeleeClipModel(nullptr), clip8x8(nullptr), clip8x8x8(nullptr),
|
|
clip16x16(nullptr), clip16x16x16(nullptr), clip24x24(nullptr),
|
|
clip32x32(nullptr), clip8x16(nullptr), clip48x48(nullptr),
|
|
clip96x96(nullptr), clip24x24x96(nullptr), clip32x32x96(nullptr),
|
|
clip48x48x96(nullptr), clipLinkAllocator(false), clipSectors(),
|
|
touchCount(0), aases{}, traceModelCache(nullptr),
|
|
traceModelRecycler(nullptr), deletedClipModels(nullptr), streamAreas(),
|
|
queryParms(nullptr), numQueryParms(0), translationQueries(),
|
|
rotationQueries(), motionQueries(), motionContactsQueries(),
|
|
stepMoveQueries(), stepMoveContactsQueries(), slideMoveQueries(),
|
|
slideMoveContactsQueries(), contentsQueries(), contactsQueries(),
|
|
clipQueries(), localTranslationQueries(), localContentsQueries(),
|
|
translationTraceModelQueries(), collisionQueries{},
|
|
collisionQueryFirstSubmittedIndex(0), collisionQueryLastSubmittedIndex(0),
|
|
collisionQueryFirstAllocedIndex(0), collisionQueryLastAllocedIndex(0),
|
|
collisionQueryLastResolvedIndex(0), gatherQueryUserNames{},
|
|
gatherQueries{}, gatherQueryFirstSubmittedIndex(0),
|
|
gatherQueryLastSubmittedIndex(0), gatherQueryFirstAllocedIndex(0),
|
|
gatherQueryLastAllocedIndex(0), gatherResults{},
|
|
gatherResultFirstSubmittedIndex(0), gatherResultLastSubmittedIndex(0),
|
|
gatherResultFirstAllocedIndex(0), gatherResultLastAllocedIndex(0),
|
|
residencyQueries{}, residencyQueryFirstSubmittedIndex(0),
|
|
residencyQueryLastSubmittedIndex(0), residencyQueryFirstAllocedIndex(0),
|
|
residencyQueryLastAllocedIndex(0) {
|
|
}
|
|
|
|
idClip::~idClip() {
|
|
Shutdown();
|
|
}
|
|
|
|
void idClip::Init(idCollisionModel* const worldModel,
|
|
idTraceModelCache* const cache, idTraceModelRecycler* const recycler) {
|
|
Shutdown();
|
|
traceModelCache = cache;
|
|
traceModelRecycler = recycler;
|
|
clipSectors.SetNum(1);
|
|
clipSectors[0].axis = -1;
|
|
clipSectors[0].dist = 0.0f;
|
|
clipSectors[0].children[0] = nullptr;
|
|
clipSectors[0].children[1] = nullptr;
|
|
clipSectors[0].clipLinks = nullptr;
|
|
if (worldModel != nullptr) {
|
|
world = new idClipModel(this, worldModel);
|
|
world->Link(0, -1, 0, idVec3(), idMat3(1.0f));
|
|
}
|
|
}
|
|
|
|
void idClip::Shutdown() {
|
|
DeleteClipModels();
|
|
if (world != nullptr) {
|
|
idClipModel* const oldWorld = world;
|
|
world = nullptr;
|
|
delete oldWorld;
|
|
}
|
|
clipSectors.SetNum(0);
|
|
clipLinkAllocator.Shutdown();
|
|
streamAreas.ClearFree();
|
|
delete[] queryParms;
|
|
queryParms = nullptr;
|
|
numQueryParms = 0;
|
|
traceModelCache = nullptr;
|
|
traceModelRecycler = nullptr;
|
|
deletedClipModels = nullptr;
|
|
}
|
|
|
|
void idClip::StartQueryFrame() {
|
|
collisionModelManager.StartQueryFrame();
|
|
}
|
|
|
|
void idClip::EndQueryFrame() {
|
|
ResolveCollisionQueries();
|
|
collisionModelManager.EndQueryFrame();
|
|
DeleteClipModels();
|
|
}
|
|
|
|
void idClip::ResolveCollisionQueries() {
|
|
collisionModelManager.WaitForAllQueries();
|
|
collisionQueryLastResolvedIndex = collisionQueryLastSubmittedIndex;
|
|
}
|
|
|
|
void idClip::DeleteClipModel(idClipModel* const clipModel) {
|
|
if (clipModel == nullptr || clipModel == world) return;
|
|
clipModel->Unlink();
|
|
clipModel->nextDeleted = deletedClipModels;
|
|
deletedClipModels = clipModel;
|
|
}
|
|
|
|
void idClip::DeleteClipModels() {
|
|
while (deletedClipModels != nullptr) {
|
|
idClipModel* const model = deletedClipModels;
|
|
deletedClipModels = model->nextDeleted;
|
|
model->nextDeleted = nullptr;
|
|
delete model;
|
|
}
|
|
}
|
|
|
|
void idClip::InitializeAASLinks(const int aasType) {
|
|
if (aasType < 0 || aasType >= 8 || aases[aasType] == nullptr
|
|
|| clipSectors.IsEmpty()) return;
|
|
for (clipLink_t* link = clipSectors[0].clipLinks;
|
|
link != nullptr; link = link->nextInSector) {
|
|
idClipModel* const model = link->clipModel;
|
|
if (model != nullptr && model->aasLinks[aasType] == nullptr)
|
|
model->aasLinks[aasType] = aases[aasType]->LinkClipModel(model);
|
|
}
|
|
}
|
|
|
|
const idBounds& idClip::GetWorldBounds() const {
|
|
static idBounds emptyBounds{};
|
|
return world != nullptr ? world->GetBounds() : emptyBounds;
|
|
}
|
|
|
|
void idClip::AddStreamArea(const int areaNum) {
|
|
if (streamAreas.FindIndex(areaNum) < 0) streamAreas.Append(areaNum);
|
|
}
|
|
|
|
void idClip::ClearStreamAreas() {
|
|
streamAreas.Clear();
|
|
}
|
|
|
|
int idClip::FindStreamArea(const idClipModel*) {
|
|
return streamAreas.IsEmpty() ? -1 : streamAreas[0];
|
|
}
|
|
|
|
int idClip::GetClipModelsTouchingBounds(const idBounds& queryBounds,
|
|
const int contentMask, idClipModel** const output,
|
|
const int maxOutput) const {
|
|
if (output == nullptr || maxOutput <= 0 || clipSectors.IsEmpty()) return 0;
|
|
int count = 0;
|
|
for (clipLink_t* link = clipSectors[0].clipLinks;
|
|
link != nullptr && count < maxOutput; link = link->nextInSector) {
|
|
idClipModel* const model = link->clipModel;
|
|
if (model == nullptr || !model->IsEnabled()
|
|
|| (model->GetContents() & contentMask) == 0
|
|
|| !BoundsIntersect(queryBounds, model->GetAbsBounds())) continue;
|
|
output[count++] = model;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
int idClip::GetClipModelsTouchingLine(const idVec3& start,
|
|
const idVec3& end, const int contentMask,
|
|
idClipModel** const output, const int maxOutput) const {
|
|
if (output == nullptr || maxOutput <= 0 || clipSectors.IsEmpty()) return 0;
|
|
int count = 0;
|
|
for (clipLink_t* link = clipSectors[0].clipLinks;
|
|
link != nullptr && count < maxOutput; link = link->nextInSector) {
|
|
idClipModel* const model = link->clipModel;
|
|
if (model == nullptr || !model->IsEnabled()
|
|
|| (model->GetContents() & contentMask) == 0
|
|
|| !model->GetAbsBounds().LineIntersection(start, end)) continue;
|
|
output[count++] = model;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
int idClip::GetEntitiesTouchingBounds(const idBounds& bounds,
|
|
const int contentMask, int* const entities,
|
|
const int maxEntities) const {
|
|
if (entities == nullptr || maxEntities <= 0) return 0;
|
|
std::vector<idClipModel*> models(static_cast<std::size_t>(maxEntities));
|
|
const int modelCount = GetClipModelsTouchingBounds(bounds, contentMask,
|
|
models.data(), maxEntities);
|
|
int count = 0;
|
|
for (int index = 0; index < modelCount; ++index) {
|
|
const int entity = models[index]->GetEntityNumber();
|
|
bool duplicate = false;
|
|
for (int other = 0; other < count; ++other)
|
|
if (entities[other] == entity) duplicate = true;
|
|
if (!duplicate) entities[count++] = entity;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
int idClip::GetEntitiesTouchingLine(const idVec3& start,
|
|
const idVec3& end, const int contentMask, int* const entities,
|
|
const int maxEntities) const {
|
|
if (entities == nullptr || maxEntities <= 0) return 0;
|
|
std::vector<idClipModel*> models(static_cast<std::size_t>(maxEntities));
|
|
const int modelCount = GetClipModelsTouchingLine(start, end, contentMask,
|
|
models.data(), maxEntities);
|
|
int count = 0;
|
|
for (int index = 0; index < modelCount; ++index) {
|
|
const int entity = models[index]->GetEntityNumber();
|
|
bool duplicate = false;
|
|
for (int other = 0; other < count; ++other)
|
|
if (entities[other] == entity) duplicate = true;
|
|
if (!duplicate) entities[count++] = entity;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
idGatherQuery idClip::GatherTouchingBounds(const idBounds& bounds,
|
|
const int contentMask, const int passEntityNumber,
|
|
const char* const userName) {
|
|
const std::uint64_t queryIndex = gatherQueryLastSubmittedIndex++;
|
|
idClipGatherQuery& query = gatherQueries[queryIndex & 255];
|
|
query.vectors[0] = bounds[0];
|
|
query.vectors[1] = bounds[1];
|
|
query.clipMask = contentMask;
|
|
query.passEntityNumber = static_cast<std::int16_t>(passEntityNumber);
|
|
query.gatherType = GATHER_TOUCHING_BOUNDS;
|
|
query.firstResultIndex = static_cast<std::uint16_t>(
|
|
gatherResultLastSubmittedIndex & 2047);
|
|
idClipModel* models[2048];
|
|
const int count = GetClipModelsTouchingBounds(bounds, contentMask,
|
|
models, 2048);
|
|
query.numResults = static_cast<std::uint16_t>(count);
|
|
for (int index = 0; index < count; ++index) {
|
|
idGatherResult& result = gatherResults[
|
|
gatherResultLastSubmittedIndex++ & 2047];
|
|
result.query = models[index]->collisionQuery;
|
|
result.physicsId = models[index]->GetPhysicsId();
|
|
result.bodyId = static_cast<std::int16_t>(models[index]->GetBodyId());
|
|
result.entityNumber = static_cast<std::int16_t>(
|
|
models[index]->GetEntityNumber());
|
|
}
|
|
gatherQueryUserNames[queryIndex & 255] = userName;
|
|
return idGatherQuery{queryIndex};
|
|
}
|
|
|
|
idGatherQuery idClip::GatherTouchingClipModel(const idVec3& origin,
|
|
const idClipModel* const model, const idMat3& axis,
|
|
const int contentMask, const int passEntityNumber,
|
|
const char* const userName) {
|
|
idBounds bounds = PointBounds(origin);
|
|
if (model != nullptr)
|
|
bounds.FromTransformedBounds(model->GetBounds(), origin, axis);
|
|
return GatherTouchingBounds(bounds, contentMask, passEntityNumber,
|
|
userName);
|
|
}
|
|
|
|
int idClip::GetGatheredClipModels(const idGatherQuery& handle,
|
|
idClipModel** const output, const int maxOutput) {
|
|
if (output == nullptr || maxOutput <= 0
|
|
|| handle.index >= gatherQueryLastSubmittedIndex) return 0;
|
|
const idClipGatherQuery& query = gatherQueries[handle.index & 255];
|
|
const int count = (std::min)(maxOutput,
|
|
static_cast<int>(query.numResults));
|
|
int outputCount = 0;
|
|
for (int index = 0; index < count; ++index) {
|
|
const idGatherResult& result = gatherResults[
|
|
(query.firstResultIndex + index) & 2047];
|
|
idClipModel* const model = FindLinkedModel(*this,
|
|
result.entityNumber, result.physicsId, result.bodyId);
|
|
if (model != nullptr) output[outputCount++] = model;
|
|
}
|
|
return outputCount;
|
|
}
|
|
|
|
int idClip::GetGatheredEntities(const idGatherQuery& handle,
|
|
int* const output, const int maxOutput) {
|
|
if (output == nullptr || maxOutput <= 0
|
|
|| handle.index >= gatherQueryLastSubmittedIndex) return 0;
|
|
const idClipGatherQuery& query = gatherQueries[handle.index & 255];
|
|
int count = 0;
|
|
for (int index = 0; index < query.numResults && count < maxOutput;
|
|
++index) {
|
|
const int entity = gatherResults[
|
|
(query.firstResultIndex + index) & 2047].entityNumber;
|
|
bool duplicate = false;
|
|
for (int other = 0; other < count; ++other)
|
|
if (output[other] == entity) duplicate = true;
|
|
if (!duplicate) output[count++] = entity;
|
|
}
|
|
return count;
|
|
}
|
|
|
|
idResidencyQuery idClip::TestResidency(const idBounds& bounds) {
|
|
const std::uint64_t index = residencyQueryLastSubmittedIndex++;
|
|
idClipResidencyQuery& query = residencyQueries[index & 1023];
|
|
query.absBounds = bounds;
|
|
query.resident = true;
|
|
return idResidencyQuery{index};
|
|
}
|
|
|
|
idClipQuery idClip::Translation(trace_t* const result,
|
|
const idVec3& start, const idVec3& end,
|
|
const idClipModel* const movingModel, const idMat3& axis,
|
|
const int contentMask, const int passEntityNumber,
|
|
const bool ignoreWorld, const char* const userName) {
|
|
std::vector<const idTraceModel*> traceModels;
|
|
std::vector<idPositionedCollisionModel> models;
|
|
CollectTraceModels(movingModel, traceModels);
|
|
CollectPositionedModels(*this, contentMask, passEntityNumber,
|
|
ignoreWorld, models);
|
|
const idBounds bounds = MotionBounds(start, end, movingModel, axis);
|
|
return ToClipQuery(collisionModelManager.Translation(result, start, end,
|
|
bounds, traceModels.empty() ? nullptr : traceModels.data(),
|
|
static_cast<int>(traceModels.size()), axis, contentMask,
|
|
models.empty() ? nullptr : models.data(),
|
|
static_cast<int>(models.size()), userName));
|
|
}
|
|
|
|
idClipQuery idClip::LocalTranslation(const idClipQuery localSpace,
|
|
const idVec3& start, const idVec3& end,
|
|
const idClipModel* const movingModel, const idMat3& axis,
|
|
const int contentMask, const int passEntityNumber,
|
|
const bool ignoreWorld, const char* const userName) {
|
|
std::vector<const idTraceModel*> traceModels;
|
|
std::vector<idPositionedCollisionModel> models;
|
|
CollectTraceModels(movingModel, traceModels);
|
|
CollectPositionedModels(*this, contentMask, passEntityNumber,
|
|
ignoreWorld, models);
|
|
const idBounds bounds = MotionBounds(start, end, movingModel, axis);
|
|
return ToClipQuery(collisionModelManager.LocalTranslation(
|
|
ToCollisionQuery(localSpace), start, end, bounds,
|
|
traceModels.empty() ? nullptr : traceModels.data(),
|
|
static_cast<int>(traceModels.size()), axis, contentMask,
|
|
models.empty() ? nullptr : models.data(),
|
|
static_cast<int>(models.size()), userName));
|
|
}
|
|
|
|
idClipQuery idClip::TranslationTraceModel(trace_t* const result,
|
|
const idVec3& start, const idVec3& end,
|
|
const idClipModel* const movingModel, const idVec3& modelOrigin,
|
|
const idMat3& modelAxis, const int contentMask,
|
|
const char* const userName) {
|
|
std::vector<const idTraceModel*> traceModels;
|
|
CollectTraceModels(movingModel, traceModels);
|
|
idPositionedCollisionModel positioned{};
|
|
positioned.model = movingModel != nullptr
|
|
? movingModel->GetCollisionModel() : nullptr;
|
|
positioned.modelOrigin = modelOrigin;
|
|
positioned.modelAxis = modelAxis;
|
|
positioned.modelContentsOverride = contentMask;
|
|
const idBounds bounds = MotionBounds(start, end, movingModel, modelAxis);
|
|
return ToClipQuery(collisionModelManager.Translation(result, start, end,
|
|
bounds, traceModels.empty() ? nullptr : traceModels.data(),
|
|
static_cast<int>(traceModels.size()), modelAxis, contentMask,
|
|
positioned.model != nullptr ? &positioned : nullptr,
|
|
positioned.model != nullptr ? 1 : 0, userName));
|
|
}
|
|
|
|
idClipQuery idClip::Rotation(trace_t* const result, const idVec3& start,
|
|
const idRotation& rotation, const idClipModel* const movingModel,
|
|
const idMat3& axis, const int contentMask,
|
|
const int passEntityNumber, const bool ignoreWorld,
|
|
const char* const userName) {
|
|
std::vector<const idTraceModel*> traceModels;
|
|
std::vector<idPositionedCollisionModel> models;
|
|
CollectTraceModels(movingModel, traceModels);
|
|
CollectPositionedModels(*this, contentMask, passEntityNumber,
|
|
ignoreWorld, models);
|
|
const idBounds bounds = MotionBounds(start, start, movingModel, axis);
|
|
return ToClipQuery(collisionModelManager.Rotation(result, start,
|
|
rotation, bounds,
|
|
traceModels.empty() ? nullptr : traceModels.data(),
|
|
static_cast<int>(traceModels.size()), axis, contentMask,
|
|
models.empty() ? nullptr : models.data(),
|
|
static_cast<int>(models.size()), userName));
|
|
}
|
|
|
|
idClipQuery idClip::Motion(trace_t* const result, const idVec3& start,
|
|
const idVec3& end, const idRotation& rotation,
|
|
const idClipModel* const movingModel, const idMat3& axis,
|
|
const int contentMask, const int passEntityNumber,
|
|
const bool ignoreWorld, const char* const userName) {
|
|
std::vector<const idTraceModel*> traceModels;
|
|
std::vector<idPositionedCollisionModel> models;
|
|
CollectTraceModels(movingModel, traceModels);
|
|
CollectPositionedModels(*this, contentMask, passEntityNumber,
|
|
ignoreWorld, models);
|
|
const idBounds bounds = MotionBounds(start, end, movingModel, axis);
|
|
return ToClipQuery(collisionModelManager.Motion(result, start, end,
|
|
rotation, bounds,
|
|
traceModels.empty() ? nullptr : traceModels.data(),
|
|
static_cast<int>(traceModels.size()), axis, contentMask,
|
|
models.empty() ? nullptr : models.data(),
|
|
static_cast<int>(models.size()), userName));
|
|
}
|
|
|
|
idClipQuery idClip::MotionContacts(trace_t* const result,
|
|
contactsResult_t* const contacts, const idVec3& start,
|
|
const idVec3& end, const idRotation& rotation, const float depth,
|
|
const idClipModel* const movingModel, const idMat3& axis,
|
|
const int contentMask, const int passEntityNumber,
|
|
const bool ignoreWorld, const char* const userName) {
|
|
std::vector<const idTraceModel*> traceModels;
|
|
std::vector<idPositionedCollisionModel> models;
|
|
CollectTraceModels(movingModel, traceModels);
|
|
CollectPositionedModels(*this, contentMask, passEntityNumber,
|
|
ignoreWorld, models);
|
|
const idBounds bounds = MotionBounds(start, end, movingModel, axis);
|
|
return ToClipQuery(collisionModelManager.MotionContacts(result, contacts,
|
|
start, end, rotation, depth, bounds,
|
|
traceModels.empty() ? nullptr : traceModels.data(),
|
|
static_cast<int>(traceModels.size()), axis, contentMask,
|
|
models.empty() ? nullptr : models.data(),
|
|
static_cast<int>(models.size()), userName));
|
|
}
|
|
|
|
idClipQuery idClip::StepMove(trace_t* const result, const idVec3& start,
|
|
const idVec3& end, const idVec3& downNormal, const float stepUp,
|
|
const float stepDown, const idClipModel* const movingModel,
|
|
const idMat3& axis, const int contentMask,
|
|
const int passEntityNumber, const bool ignoreWorld,
|
|
const char* const userName) {
|
|
std::vector<const idTraceModel*> traceModels;
|
|
std::vector<idPositionedCollisionModel> models;
|
|
CollectTraceModels(movingModel, traceModels);
|
|
CollectPositionedModels(*this, contentMask, passEntityNumber,
|
|
ignoreWorld, models);
|
|
const idBounds bounds = MotionBounds(start, end, movingModel, axis);
|
|
return ToClipQuery(collisionModelManager.StepMove(result, start, end,
|
|
downNormal, stepUp, stepDown, bounds,
|
|
traceModels.empty() ? nullptr : traceModels.data(),
|
|
static_cast<int>(traceModels.size()), axis, contentMask,
|
|
models.empty() ? nullptr : models.data(),
|
|
static_cast<int>(models.size()), userName));
|
|
}
|
|
|
|
idClipQuery idClip::StepMoveContacts(trace_t* const result,
|
|
contactsResult_t* const contacts, const idVec3& start,
|
|
const idVec3& end, const idVec3& downNormal, const float stepUp,
|
|
const float stepDown, const idClipModel* const movingModel,
|
|
const idMat3& axis, const int contentMask,
|
|
const int passEntityNumber, const bool ignoreWorld,
|
|
const char* const userName) {
|
|
std::vector<const idTraceModel*> traceModels;
|
|
std::vector<idPositionedCollisionModel> models;
|
|
CollectTraceModels(movingModel, traceModels);
|
|
CollectPositionedModels(*this, contentMask, passEntityNumber,
|
|
ignoreWorld, models);
|
|
const idBounds bounds = MotionBounds(start, end, movingModel, axis);
|
|
return ToClipQuery(collisionModelManager.StepMoveContacts(result,
|
|
contacts, start, end, downNormal, stepUp, stepDown, bounds,
|
|
traceModels.empty() ? nullptr : traceModels.data(),
|
|
static_cast<int>(traceModels.size()), axis, contentMask,
|
|
models.empty() ? nullptr : models.data(),
|
|
static_cast<int>(models.size()), userName));
|
|
}
|
|
|
|
idClipQuery idClip::SlideMoveContacts(trace_t* const result,
|
|
contactsResult_t* const contacts, const idVec3& start,
|
|
const idVec3& velocity, const idVec3& gravityVector,
|
|
const float stepUp, const idClipModel* const movingModel,
|
|
const idMat3& axis, const int contentMask,
|
|
const int passEntityNumber, const bool ignoreWorld,
|
|
const char* const userName) {
|
|
std::vector<const idTraceModel*> traceModels;
|
|
std::vector<idPositionedCollisionModel> models;
|
|
CollectTraceModels(movingModel, traceModels);
|
|
CollectPositionedModels(*this, contentMask, passEntityNumber,
|
|
ignoreWorld, models);
|
|
const idBounds bounds = MotionBounds(start, start + velocity,
|
|
movingModel, axis);
|
|
return ToClipQuery(collisionModelManager.SlideMoveContacts(result,
|
|
contacts, start, velocity, gravityVector, stepUp, stepUp, bounds,
|
|
traceModels.empty() ? nullptr : traceModels.data(),
|
|
static_cast<int>(traceModels.size()), axis, contentMask,
|
|
models.empty() ? nullptr : models.data(),
|
|
static_cast<int>(models.size()), userName));
|
|
}
|
|
|
|
idClipQuery idClip::Contents(trace_t* const result, const idVec3& start,
|
|
const idClipModel* const movingModel, const idMat3& axis,
|
|
const int contentMask, const int passEntityNumber,
|
|
const char* const userName) {
|
|
std::vector<const idTraceModel*> traceModels;
|
|
std::vector<idPositionedCollisionModel> models;
|
|
CollectTraceModels(movingModel, traceModels);
|
|
CollectPositionedModels(*this, contentMask, passEntityNumber,
|
|
false, models);
|
|
const idBounds bounds = MotionBounds(start, start, movingModel, axis);
|
|
return ToClipQuery(collisionModelManager.Contents(result, start, bounds,
|
|
traceModels.empty() ? nullptr : traceModels.data(),
|
|
static_cast<int>(traceModels.size()), axis, contentMask,
|
|
models.empty() ? nullptr : models.data(),
|
|
static_cast<int>(models.size()), userName));
|
|
}
|
|
|
|
idClipQuery idClip::LocalContents(const idClipQuery localSpace,
|
|
const idVec3& start, const idClipModel* const movingModel,
|
|
const idMat3& axis, const int contentMask,
|
|
const int passEntityNumber, const char* const userName) {
|
|
std::vector<const idTraceModel*> traceModels;
|
|
std::vector<idPositionedCollisionModel> models;
|
|
CollectTraceModels(movingModel, traceModels);
|
|
CollectPositionedModels(*this, contentMask, passEntityNumber,
|
|
false, models);
|
|
const idBounds bounds = MotionBounds(start, start, movingModel, axis);
|
|
return ToClipQuery(collisionModelManager.LocalContents(
|
|
ToCollisionQuery(localSpace), start, bounds,
|
|
traceModels.empty() ? nullptr : traceModels.data(),
|
|
static_cast<int>(traceModels.size()), axis, contentMask,
|
|
models.empty() ? nullptr : models.data(),
|
|
static_cast<int>(models.size()), userName));
|
|
}
|
|
|
|
idClipQuery idClip::Contacts(contactsResult_t* const result,
|
|
const idVec3& start, const idVec3& direction, const float depth,
|
|
const idClipModel* const movingModel, const idMat3& axis,
|
|
const int contentMask, const int passEntityNumber,
|
|
const char* const userName) {
|
|
std::vector<const idTraceModel*> traceModels;
|
|
std::vector<idPositionedCollisionModel> models;
|
|
CollectTraceModels(movingModel, traceModels);
|
|
CollectPositionedModels(*this, contentMask, passEntityNumber,
|
|
false, models);
|
|
const idBounds bounds = MotionBounds(start, start + direction * depth,
|
|
movingModel, axis);
|
|
return ToClipQuery(collisionModelManager.Contacts(result, start,
|
|
direction, depth, bounds,
|
|
traceModels.empty() ? nullptr : traceModels.data(),
|
|
static_cast<int>(traceModels.size()), axis, contentMask,
|
|
models.empty() ? nullptr : models.data(),
|
|
static_cast<int>(models.size()), userName));
|
|
}
|
|
|
|
idClipQuery idClip::Clip(clipResult_t* const result, const idVec3& start,
|
|
const idTraceModel* const traceModel, const idMat3& axis,
|
|
const int contentMask, const int passEntityNumber,
|
|
const char* const userName) {
|
|
std::vector<idPositionedCollisionModel> models;
|
|
CollectPositionedModels(*this, contentMask, passEntityNumber,
|
|
false, models);
|
|
const idTraceModel* traceModels[1] = { traceModel };
|
|
const idBounds bounds = traceModel != nullptr
|
|
? MotionBounds(start, start, nullptr, axis) : PointBounds(start);
|
|
return ToClipQuery(collisionModelManager.Clip(result, start, bounds,
|
|
traceModel != nullptr ? traceModels : nullptr,
|
|
traceModel != nullptr ? 1 : 0, axis, contentMask,
|
|
models.empty() ? nullptr : models.data(),
|
|
static_cast<int>(models.size()), userName));
|
|
}
|
|
|
|
void idClip::TranslationModel(trace_t& result, const idVec3& start,
|
|
const idVec3& end, const idClipModel* const movingModel,
|
|
const idMat3& axis, const int contentMask,
|
|
const idVec3& modelOrigin, const idClipModel* const model,
|
|
const idMat3& modelAxis) const {
|
|
std::vector<const idTraceModel*> traces;
|
|
CollectTraceModels(movingModel, traces);
|
|
idPositionedCollisionModel positioned{};
|
|
if (model != nullptr) {
|
|
positioned.model = model->GetCollisionModel();
|
|
positioned.modelOrigin = modelOrigin;
|
|
positioned.modelAxis = modelAxis;
|
|
positioned.modelEntityNum = model->GetEntityNumber();
|
|
positioned.modelPhysicsId = model->GetPhysicsId();
|
|
positioned.modelBodyId = model->GetBodyId();
|
|
positioned.modelContentsOverride = model->GetContents();
|
|
}
|
|
collisionModelManager.Translation(&result, start, end,
|
|
MotionBounds(start, end, movingModel, axis),
|
|
traces.empty() ? nullptr : traces.data(),
|
|
static_cast<int>(traces.size()), axis, contentMask,
|
|
positioned.model != nullptr ? &positioned : nullptr,
|
|
positioned.model != nullptr ? 1 : 0, "TranslationModel");
|
|
}
|
|
|
|
void idClip::RotationModel(trace_t& result, const idVec3& start,
|
|
const idRotation& rotation, const idClipModel* const movingModel,
|
|
const idMat3& axis, const int contentMask,
|
|
const idVec3& modelOrigin, const idClipModel* const model,
|
|
const idMat3& modelAxis) const {
|
|
std::vector<const idTraceModel*> traces;
|
|
CollectTraceModels(movingModel, traces);
|
|
idPositionedCollisionModel positioned{};
|
|
if (model != nullptr) {
|
|
positioned.model = model->GetCollisionModel();
|
|
positioned.modelOrigin = modelOrigin;
|
|
positioned.modelAxis = modelAxis;
|
|
positioned.modelContentsOverride = model->GetContents();
|
|
}
|
|
collisionModelManager.Rotation(&result, start, rotation,
|
|
MotionBounds(start, start, movingModel, axis),
|
|
traces.empty() ? nullptr : traces.data(),
|
|
static_cast<int>(traces.size()), axis, contentMask,
|
|
positioned.model != nullptr ? &positioned : nullptr,
|
|
positioned.model != nullptr ? 1 : 0, "RotationModel");
|
|
}
|
|
|
|
void idClip::ContentsModel(trace_t& result, const idVec3& start,
|
|
const idClipModel* const movingModel, const idMat3& axis,
|
|
const int contentMask, const idVec3& modelOrigin,
|
|
const idClipModel* const model, const idMat3& modelAxis) const {
|
|
std::vector<const idTraceModel*> traces;
|
|
CollectTraceModels(movingModel, traces);
|
|
idPositionedCollisionModel positioned{};
|
|
if (model != nullptr) {
|
|
positioned.model = model->GetCollisionModel();
|
|
positioned.modelOrigin = modelOrigin;
|
|
positioned.modelAxis = modelAxis;
|
|
positioned.modelContentsOverride = model->GetContents();
|
|
}
|
|
collisionModelManager.Contents(&result, start,
|
|
MotionBounds(start, start, movingModel, axis),
|
|
traces.empty() ? nullptr : traces.data(),
|
|
static_cast<int>(traces.size()), axis, contentMask,
|
|
positioned.model != nullptr ? &positioned : nullptr,
|
|
positioned.model != nullptr ? 1 : 0, "ContentsModel");
|
|
}
|
|
|
|
bool idClip::GetModelContactFeature(const contactInfo_t& contact,
|
|
const idClipModel* const model, idFixedWinding& winding) const {
|
|
if (model == nullptr) return false;
|
|
idCollisionModel* const collisionModel = model->GetCollisionModel();
|
|
if (collisionModel == nullptr) return false;
|
|
if (contact.type == CONTACT_EDGE) {
|
|
idVec3 points[2];
|
|
if (!collisionModel->GetEdge(contact.modelFeature,
|
|
points[0], points[1])) return false;
|
|
winding.Clear();
|
|
winding.AddPoint(points[0]);
|
|
winding.AddPoint(points[1]);
|
|
return true;
|
|
}
|
|
if (contact.type == CONTACT_MODELVERTEX) {
|
|
idVec3 point;
|
|
if (!collisionModel->GetVertex(contact.modelFeature, point))
|
|
return false;
|
|
winding.Clear();
|
|
winding.AddPoint(point);
|
|
return true;
|
|
}
|
|
return collisionModel->GetPolygon(contact.modelFeature, winding);
|
|
}
|
|
|
|
void idClip::PrintStatistics() {
|
|
}
|