Files
tech5/source/shared/idlib/geometry/tracemodel.cpp
T

206 lines
7.1 KiB
C++

#include "idlib/geometry/tracemodel.h"
#include <algorithm>
#include <cmath>
#include <cstring>
#include <malloc.h>
#include <new>
void* idTraceModel::operator new(const std::size_t size) {
void* const memory = _aligned_malloc(size, 128);
if (memory == nullptr) {
throw std::bad_alloc();
}
return memory;
}
void idTraceModel::operator delete(void* const memory) {
if (memory != nullptr) {
_aligned_free(memory);
}
}
void idTraceModel::ClearUnused() {
std::memset(vertsX + numVerts, 0,
sizeof(float) * (32 - numVerts));
std::memset(vertsY + numVerts, 0,
sizeof(float) * (32 - numVerts));
std::memset(vertsZ + numVerts, 0,
sizeof(float) * (32 - numVerts));
std::memset(edgeNormalX + numEdges, 0,
sizeof(float) * (32 - numEdges));
std::memset(edgeNormalY + numEdges, 0,
sizeof(float) * (32 - numEdges));
std::memset(edgeNormalZ + numEdges, 0,
sizeof(float) * (32 - numEdges));
std::memset(polyPlaneX + numPolys, 0,
sizeof(float) * (16 - numPolys));
std::memset(polyPlaneY + numPolys, 0,
sizeof(float) * (16 - numPolys));
std::memset(polyPlaneZ + numPolys, 0,
sizeof(float) * (16 - numPolys));
std::memset(polyPlaneW + numPolys, 0,
sizeof(float) * (16 - numPolys));
std::memset(edges + numEdges, 0,
sizeof(traceModelEdge_t) * (32 - numEdges));
std::memset(numPolyEdges + numPolys, 0,
sizeof(unsigned int) * (16 - numPolys));
std::memset(polyEdges + numPolys, 0,
sizeof(polyEdges[0]) * (16 - numPolys));
maxPolyEdges = 0;
for (unsigned int polygon = 0; polygon < numPolys; ++polygon) {
maxPolyEdges = (std::max)(maxPolyEdges, numPolyEdges[polygon]);
const std::uint8_t fill = numPolyEdges[polygon] > 0
? polyEdges[polygon][numPolyEdges[polygon] - 1]
: 0;
for (unsigned int edge = numPolyEdges[polygon]; edge < 16; ++edge) {
polyEdges[polygon][edge] = fill;
}
}
}
int idTraceModel::GenerateEdgeNormals() {
std::memset(edgeNormalX, 0, sizeof(edgeNormalX));
std::memset(edgeNormalY, 0, sizeof(edgeNormalY));
std::memset(edgeNormalZ, 0, sizeof(edgeNormalZ));
for (unsigned int polygon = 0; polygon < numPolys; ++polygon) {
for (unsigned int edge = 0; edge < numPolyEdges[polygon]; ++edge) {
const unsigned int edgeIndex = polyEdges[polygon][edge] & 0x7F;
if (edgeIndex >= numEdges) {
continue;
}
edgeNormalX[edgeIndex] += polyPlaneX[polygon];
edgeNormalY[edgeIndex] += polyPlaneY[polygon];
edgeNormalZ[edgeIndex] += polyPlaneZ[polygon];
}
}
for (unsigned int edge = 0; edge < numEdges; ++edge) {
idVec3 normal(edgeNormalX[edge], edgeNormalY[edge],
edgeNormalZ[edge]);
normal.NormalizeFast();
edgeNormalX[edge] = normal.x;
edgeNormalY[edge] = normal.y;
edgeNormalZ[edge] = normal.z;
}
return 1;
}
bool idTraceModel::IsClosedSurface() const {
unsigned int edgeUseCounts[32]{};
for (unsigned int polygon = 0; polygon < numPolys; ++polygon) {
for (unsigned int edge = 0; edge < numPolyEdges[polygon]; ++edge) {
const unsigned int edgeIndex = polyEdges[polygon][edge] & 0x7Fu;
if (edgeIndex < 32) {
++edgeUseCounts[edgeIndex];
}
}
}
for (unsigned int edge = 0; edge < numEdges; ++edge) {
if (edgeUseCounts[edge] != 2) {
return false;
}
}
return true;
}
void idTraceModel::TestConvexity() {
isConvex = true;
for (unsigned int polygon = 0; polygon < numPolys; ++polygon) {
for (unsigned int vertex = 0; vertex < numVerts; ++vertex) {
const float distance =
vertsX[vertex] * polyPlaneX[polygon]
+ vertsY[vertex] * polyPlaneY[polygon]
+ vertsZ[vertex] * polyPlaneZ[polygon]
+ polyPlaneW[polygon];
if (distance > 0.01f) {
isConvex = false;
return;
}
}
}
}
void idTraceModel::CalculateInsetSphereRadius() {
const float lower = (std::min)(std::fabs(bounds[0].x),
(std::min)(std::fabs(bounds[0].y), std::fabs(bounds[0].z)));
const float upper = (std::min)(std::fabs(bounds[1].x),
(std::min)(std::fabs(bounds[1].y), std::fabs(bounds[1].z)));
radius = (std::min)(lower, upper);
}
void idTraceModel::InitBox() {
type = TRM_BOX;
numVerts = 8;
numEdges = 12;
numPolys = 6;
maxPolyEdges = 4;
const std::uint16_t edgeVertices[12][2] = {
{0, 1}, {1, 2}, {2, 3}, {3, 0},
{4, 5}, {5, 6}, {6, 7}, {7, 4},
{0, 4}, {1, 5}, {2, 6}, {3, 7}};
std::memcpy(edges, edgeVertices, sizeof(edgeVertices));
const std::uint8_t boxPolygonEdges[6][4] = {
{0x83, 0x82, 0x81, 0x80},
{4, 5, 6, 7},
{0, 9, 0x84, 0x88},
{1, 10, 0x85, 0x89},
{2, 11, 0x86, 0x8A},
{3, 8, 0x87, 0x8B}};
for (int polygon = 0; polygon < 6; ++polygon) {
numPolyEdges[polygon] = 4;
std::memcpy(polyEdges[polygon], boxPolygonEdges[polygon], 4);
}
const idVec3 normals[6] = {
idVec3(0.0f, 0.0f, -1.0f), idVec3(0.0f, 0.0f, 1.0f),
idVec3(0.0f, -1.0f, 0.0f), idVec3(1.0f, 0.0f, 0.0f),
idVec3(0.0f, 1.0f, 0.0f), idVec3(-1.0f, 0.0f, 0.0f)};
for (int polygon = 0; polygon < 6; ++polygon) {
polyPlaneX[polygon] = normals[polygon].x;
polyPlaneY[polygon] = normals[polygon].y;
polyPlaneZ[polygon] = normals[polygon].z;
polyPlaneW[polygon] = 0.0f;
}
isConvex = true;
GenerateEdgeNormals();
ClearUnused();
}
void idTraceModel::SetupBox(const idBounds& boxBounds) {
if (type != TRM_BOX) {
InitBox();
}
offset = (boxBounds[0] + boxBounds[1]) * 0.5f;
const idVec3 vertices[8] = {
idVec3(boxBounds[0].x, boxBounds[0].y, boxBounds[0].z),
idVec3(boxBounds[1].x, boxBounds[0].y, boxBounds[0].z),
idVec3(boxBounds[1].x, boxBounds[1].y, boxBounds[0].z),
idVec3(boxBounds[0].x, boxBounds[1].y, boxBounds[0].z),
idVec3(boxBounds[0].x, boxBounds[0].y, boxBounds[1].z),
idVec3(boxBounds[1].x, boxBounds[0].y, boxBounds[1].z),
idVec3(boxBounds[1].x, boxBounds[1].y, boxBounds[1].z),
idVec3(boxBounds[0].x, boxBounds[1].y, boxBounds[1].z)};
for (int vertex = 0; vertex < 8; ++vertex) {
vertsX[vertex] = vertices[vertex].x;
vertsY[vertex] = vertices[vertex].y;
vertsZ[vertex] = vertices[vertex].z;
}
polyPlaneW[0] = boxBounds[0].z;
polyPlaneW[1] = -boxBounds[1].z;
polyPlaneW[2] = boxBounds[0].y;
polyPlaneW[3] = -boxBounds[1].x;
polyPlaneW[4] = -boxBounds[1].y;
polyPlaneW[5] = boxBounds[0].x;
bounds = boxBounds;
CalculateInsetSphereRadius();
}
void idTraceModel::SetupBox(const float size) {
idBounds boxBounds;
const float halfSize = size * 0.5f;
boxBounds[0].Set(-halfSize, -halfSize, -halfSize);
boxBounds[1].Set(halfSize, halfSize, halfSize);
SetupBox(boxBounds);
}