Files
tech5/source/engine/cm/jobs/spheremodel/spheremodel.cpp
T
2026-08-09 01:29:43 -07:00

107 lines
4.7 KiB
C++

#include "cm/jobs/spheremodel/spheremodel.h"
#include "cm/jobs/collisionresults.h"
#include "idlib/geometry/jointtransform.h"
#include <algorithm>
#include <cmath>
#include <cstring>
int idSphereModelCollisionDetection::SetupCollisionSpherePtrs(
const cm_sphereModel_t* const model,
cm_sphereModelPtrs_t& pointers) {
std::uint8_t* const base = reinterpret_cast<std::uint8_t*>(
const_cast<cm_sphereModel_t*>(model));
pointers.joint = base + model->jointOffset;
pointers.offsetX = reinterpret_cast<float*>(base + model->offsetXOffset);
pointers.offsetY = reinterpret_cast<float*>(base + model->offsetYOffset);
pointers.offsetZ = reinterpret_cast<float*>(base + model->offsetZOffset);
pointers.radius = reinterpret_cast<float*>(base + model->radiusOffset);
pointers.surfType = base + model->surfTypeOffset;
return model->numSpheres;
}
void idSphereModelCollisionDetection::TraceThroughModel(trace_t& trace,
const cm_sphereModel_t& model, const idVec3& start, const idVec3& end,
const float radius, const idMat3& trmAxis,
const idJointMat* const modelJoints, const idVec3& modelOrigin,
const idMat3& modelAxis, const int modelEntityNum,
const int modelPhysicsId, const int modelBodyId, const int selfId,
const int modelContentsOverride) {
std::memset(&trace, 0, sizeof(trace));
trace.fraction = 1.0f;
trace.endpos = end;
trace.endAxis = trmAxis;
cm_sphereModelPtrs_t spheres;
const int numSpheres = SetupCollisionSpherePtrs(&model, spheres);
const idVec3 movement = end - start;
const float movementLengthSqr = movement.LengthSqr();
for (int sphereNumber = 0; sphereNumber < numSpheres; ++sphereNumber) {
const int jointNumber = spheres.joint[sphereNumber];
const idVec3 offset(spheres.offsetX[sphereNumber],
spheres.offsetY[sphereNumber], spheres.offsetZ[sphereNumber]);
idVec3 jointSpace = offset;
if (modelJoints != nullptr) {
const idJointMat& joint = modelJoints[jointNumber];
jointSpace.Set(
joint.mat[0] * offset.x + joint.mat[1] * offset.y
+ joint.mat[2] * offset.z + joint.mat[3],
joint.mat[4] * offset.x + joint.mat[5] * offset.y
+ joint.mat[6] * offset.z + joint.mat[7],
joint.mat[8] * offset.x + joint.mat[9] * offset.y
+ joint.mat[10] * offset.z + joint.mat[11]);
}
const idVec3 sphereCenter = modelOrigin + idVec3(
modelAxis[0].x * jointSpace.x + modelAxis[1].x * jointSpace.y
+ modelAxis[2].x * jointSpace.z,
modelAxis[0].y * jointSpace.x + modelAxis[1].y * jointSpace.y
+ modelAxis[2].y * jointSpace.z,
modelAxis[0].z * jointSpace.x + modelAxis[1].z * jointSpace.y
+ modelAxis[2].z * jointSpace.z);
const float combinedRadius = radius + spheres.radius[sphereNumber];
const idVec3 relativeStart = start - sphereCenter;
float fraction = 1.0f;
if (relativeStart.LengthSqr() <= combinedRadius * combinedRadius) {
fraction = 0.0f;
} else if (movementLengthSqr > 1.0e-20f) {
const float b = relativeStart.Dot(movement);
const float c = relativeStart.LengthSqr()
- combinedRadius * combinedRadius;
const float discriminant = b * b - movementLengthSqr * c;
if (discriminant >= 0.0f) {
fraction = (-b - std::sqrt(discriminant))
/ movementLengthSqr;
}
}
if (fraction < 0.0f || fraction >= trace.fraction
|| fraction > 1.0f) {
continue;
}
trace.fraction = fraction;
trace.endpos = start + movement * fraction;
idVec3 normal = trace.endpos - sphereCenter;
if (normal.NormalizeFast() == 0.0f) {
normal.Set(0.0f, 0.0f, 1.0f);
}
trace.c.type = CONTACT_SPHERE;
trace.c.normal = normal;
trace.c.point = trace.endpos - normal * radius;
trace.c.dist = normal.Dot(trace.c.point);
trace.c.separation = spheres.radius[sphereNumber];
trace.c.contentFlags = modelContentsOverride != 0
? modelContentsOverride : static_cast<int>(model.contents);
trace.c.surfaceFlags = 0;
trace.c.surfaceType = spheres.surfType[sphereNumber];
trace.c.surfaceColor[0] = trace.c.surfaceColor[1]
= trace.c.surfaceColor[2] = 0xFF;
trace.c.modelFeature = (std::min)(sphereNumber, numSpheres - 1);
trace.c.trmFeature = jointNumber;
trace.c.entityNum = modelEntityNum;
trace.c.physicsId = modelPhysicsId;
trace.c.bodyId = modelBodyId;
trace.c.selfId = selfId;
trace.c.flags = 0;
}
}