First pass idLib conversion from hex rays4.

This commit is contained in:
Justin Marshall
2026-08-08 13:54:26 -07:00
parent 3d01d735ce
commit 09a4cb91c3
120 changed files with 17718 additions and 0 deletions
+89
View File
@@ -0,0 +1,89 @@
#pragma once
#include <cstdint>
class idBoundedIntBase {
public:
virtual ~idBoundedIntBase() = default;
virtual void SetValue(int value) = 0;
virtual int GetValue() const = 0;
};
template<int MIN_VALUE, int MAX_VALUE>
class idBoundedInt final : public idBoundedIntBase {
public:
explicit idBoundedInt(const int initialValue = MIN_VALUE)
: value(MIN_VALUE) {
SetValue(initialValue);
}
void SetValue(const int newValue) override {
value = newValue < MIN_VALUE ? MIN_VALUE
: (newValue > MAX_VALUE ? MAX_VALUE : newValue);
}
int GetValue() const override {
return value;
}
operator int() const {
return value;
}
private:
int value;
};
class idBoundedFloatBase {
public:
virtual ~idBoundedFloatBase() = default;
virtual void SetValue(float value) = 0;
virtual float GetValue() const = 0;
};
// The original uses four integral template arguments so floating-point bounds
// remain legal in the C++03-era source. Only <0,0,1,0> occurs in tungsten;
// the second and fourth arguments represent the fractional decimal component.
template<int MIN_WHOLE, int MIN_FRACTION, int MAX_WHOLE, int MAX_FRACTION>
class idBoundedFloat final : public idBoundedFloatBase {
public:
explicit idBoundedFloat(const float initialValue = Minimum())
: value(Minimum()) {
SetValue(initialValue);
}
void SetValue(const float newValue) override {
value = newValue < Minimum() ? Minimum()
: (newValue > Maximum() ? Maximum() : newValue);
}
float GetValue() const override {
return value;
}
operator float() const {
return value;
}
private:
float value;
static constexpr float Fraction(const int digits) {
return static_cast<float>(digits) / 1000.0f;
}
static constexpr float Minimum() {
return static_cast<float>(MIN_WHOLE) + Fraction(MIN_FRACTION);
}
static constexpr float Maximum() {
return static_cast<float>(MAX_WHOLE) + Fraction(MAX_FRACTION);
}
};
#if INTPTR_MAX == INT32_MAX
static_assert(sizeof(idBoundedInt<0, 4>) == 8,
"Recovered idBoundedInt ABI changed");
static_assert(sizeof(idBoundedFloat<0, 0, 1, 0>) == 8,
"Recovered idBoundedFloat ABI changed");
#endif
+53
View File
@@ -0,0 +1,53 @@
#include "decay.h"
#include <cmath>
idParametricDecay::idParametricDecay()
: delta(0.0f)
, linear(0.0f)
, t0(0.0f)
, tdelta(0.0f)
, lambda(0.0f) {
}
void idParametricDecay::Init(
const float newDelta,
const float newLinear,
const float newT0,
const float newTDelta,
const float newLambda
) {
delta = newDelta;
linear = newLinear;
t0 = newT0;
tdelta = newTDelta;
lambda = newLambda;
}
void idParametricDecay::SetTZero(const float newT0) {
t0 = newT0;
}
void idParametricDecay::SetDelta(const float newDelta) {
delta = newDelta;
}
float idParametricDecay::Evaluate(const float t) const {
if (t < t0) {
return delta;
}
const float elapsed = t - t0;
if (elapsed > tdelta) {
return 0.0f;
}
const float normalizedTime = elapsed / tdelta;
const float exponential = std::pow(
0.5f,
elapsed / (lambda * tdelta)
);
return ((1.0f - linear) * exponential
+ (1.0f - normalizedTime) * linear) * delta;
}
+23
View File
@@ -0,0 +1,23 @@
#pragma once
// tungsten.exe.h type 12849.
class idParametricDecay {
public:
idParametricDecay();
void Init(float delta, float linear, float t0, float tdelta, float lambda);
void SetTZero(float t0);
void SetDelta(float delta);
float Evaluate(float t) const;
private:
float delta;
float linear;
float t0;
float tdelta;
float lambda;
};
static_assert(sizeof(idParametricDecay) == 20,
"Recovered idParametricDecay layout changed");
+87
View File
@@ -0,0 +1,87 @@
#pragma once
#include <cmath>
class idFader {
public:
enum type_t {
FADE_LINEAR = 0,
FADE_SINE = 1,
FADE_INVERSE_SINE = 2
};
idFader(const type_t fadeType = FADE_LINEAR, const float initialValue = 0.0f)
: type(fadeType), startTime(0), duration(0),
startValue(initialValue), endValue(initialValue) {
}
float GetValue(const int time) const {
switch (type) {
case FADE_SINE: return GetSine(time);
case FADE_INVERSE_SINE: return GetInverseSine(time);
default: return GetLinear(time);
}
}
float GetLinear(const int time) const {
return Interpolate(time, LinearFraction(time));
}
float GetSine(const int time) const {
const float fraction = LinearFraction(time);
const float shaped = std::sin(fraction * 1.5707963267948966f);
return Interpolate(time, shaped);
}
float GetInverseSine(const int time) const {
const float fraction = LinearFraction(time);
const float shaped = 1.0f + std::sin(
fraction * 1.5707963267948966f + 4.71238898038469f
);
return Interpolate(time, shaped);
}
void FadeTowards(const float newEndValue, const int time,
const int newDuration) {
startValue = GetValue(time);
startTime = time;
endValue = newEndValue;
duration = newDuration < 0 ? 0 : newDuration;
}
void SetType(const type_t fadeType) {
type = fadeType;
}
private:
type_t type;
int startTime;
int duration;
float startValue;
float endValue;
float LinearFraction(const int time) const {
if (time <= startTime) {
return 0.0f;
}
if (duration <= 0) {
return 1.0f;
}
if (time >= startTime + duration) {
return 1.0f;
}
return static_cast<float>(time - startTime) / static_cast<float>(duration);
}
float Interpolate(const int time, const float fraction) const {
if (time < startTime) {
return startValue;
}
if (duration <= 0 || time >= startTime + duration) {
return endValue;
}
return startValue + fraction * (endValue - startValue);
}
};
static_assert(sizeof(idFader) == 20, "Recovered idFader ABI changed");
+82
View File
@@ -0,0 +1,82 @@
#pragma once
#include "idlib/precompiled.h"
class idMat3x4 {
public:
idMat3x4() {
Identity();
}
idMat3x4(const idMat3& rotation, const idVec3& translation) {
for (int row = 0; row < 3; ++row) {
for (int column = 0; column < 3; ++column) {
mat[row * 4 + column] = rotation[column][row];
}
mat[row * 4 + 3] = translation[row];
}
}
void Identity() {
for (int index = 0; index < 12; ++index) {
mat[index] = 0.0f;
}
mat[0] = mat[5] = mat[10] = 1.0f;
}
void Transform(idVec3& result, const idVec3& value) const {
result.x = value.x * mat[0] + value.y * mat[1]
+ value.z * mat[2] + mat[3];
result.y = value.x * mat[4] + value.y * mat[5]
+ value.z * mat[6] + mat[7];
result.z = value.x * mat[8] + value.y * mat[9]
+ value.z * mat[10] + mat[11];
}
void Rotate(idMat3& result, const idMat3& value) const {
for (int column = 0; column < 3; ++column) {
result[column].x = mat[0] * value[column].x
+ mat[1] * value[column].y + mat[2] * value[column].z;
result[column].y = mat[4] * value[column].x
+ mat[5] * value[column].y + mat[6] * value[column].z;
result[column].z = mat[8] * value[column].x
+ mat[9] * value[column].y + mat[10] * value[column].z;
}
}
void Invert() {
const float old[12] = {
mat[0], mat[1], mat[2], mat[3],
mat[4], mat[5], mat[6], mat[7],
mat[8], mat[9], mat[10], mat[11]
};
mat[0] = old[0]; mat[1] = old[4]; mat[2] = old[8];
mat[4] = old[1]; mat[5] = old[5]; mat[6] = old[9];
mat[8] = old[2]; mat[9] = old[6]; mat[10] = old[10];
mat[3] = -(mat[0] * old[3] + mat[1] * old[7] + mat[2] * old[11]);
mat[7] = -(mat[4] * old[3] + mat[5] * old[7] + mat[6] * old[11]);
mat[11] = -(mat[8] * old[3] + mat[9] * old[7] + mat[10] * old[11]);
}
void LeftTransposeMultiply(const idMat3& value) {
float old[12];
for (int index = 0; index < 12; ++index) {
old[index] = mat[index];
}
for (int row = 0; row < 3; ++row) {
for (int column = 0; column < 4; ++column) {
mat[row * 4 + column] = value[0][row] * old[column]
+ value[1][row] * old[4 + column]
+ value[2][row] * old[8 + column];
}
}
}
float* ToFloatPtr() { return mat; }
const float* ToFloatPtr() const { return mat; }
private:
float mat[12];
};
static_assert(sizeof(idMat3x4) == 48, "Recovered idMat3x4 ABI changed");
+31
View File
@@ -0,0 +1,31 @@
#include "mathlib.h"
#include <cstdint>
int InterleaveBits(const int x, const int y) {
const std::uint32_t xBits = static_cast<std::uint32_t>(x);
const std::uint32_t yBits = static_cast<std::uint32_t>(y);
std::uint32_t interleaved = 0;
for (int bit = 0; bit < 16; ++bit) {
interleaved |= ((xBits >> bit) & 1u) << (bit * 2);
interleaved |= ((yBits >> bit) & 1u) << (bit * 2 + 1);
}
return static_cast<int>(interleaved);
}
void DeInterleaveBits(const int bits, int& x, int& y) {
const std::uint32_t interleaved = static_cast<std::uint32_t>(bits);
std::uint32_t xBits = 0;
std::uint32_t yBits = 0;
for (int bit = 0; bit < 16; ++bit) {
xBits |= ((interleaved >> (bit * 2)) & 1u) << bit;
yBits |= ((interleaved >> (bit * 2 + 1)) & 1u) << bit;
}
x = static_cast<int>(xBits);
y = static_cast<int>(yBits);
}
+8
View File
@@ -0,0 +1,8 @@
#pragma once
// Recovered PDB signatures:
// ?InterleaveBits@@YAHHH@Z
// ?DeInterleaveBits@@YAXHAAH0@Z
int InterleaveBits(int x, int y);
void DeInterleaveBits(int bits, int& x, int& y);
+391
View File
@@ -0,0 +1,391 @@
#include "spatialmat.h"
#include <algorithm>
#include <cmath>
#include <cstring>
#include <malloc.h>
namespace {
constexpr std::size_t SPATIAL_MAT_FLOATS =
idSpatialMat::MAX_ROWS * idSpatialMat::ROW_STRIDE;
constexpr std::size_t SPATIAL_MAT_BYTES =
SPATIAL_MAT_FLOATS * sizeof(float);
float* AllocSpatialMat() {
return static_cast<float*>(_aligned_malloc(SPATIAL_MAT_BYTES, 16));
}
bool IsValidSize(const int rows, const int columns) {
return rows >= 0 && rows <= idSpatialMat::MAX_ROWS
&& columns >= 0 && columns <= idSpatialMat::MAX_COLUMNS;
}
} // namespace
idSpatialMat::idSpatialMat()
: numRows(0), numColumns(0), allocatedRows(0), mat(nullptr) {
}
idSpatialMat::idSpatialMat(const int rows, const int columns)
: idSpatialMat() {
SetSize(rows, columns);
}
idSpatialMat::idSpatialMat(const idSpatialMat& other)
: idSpatialMat() {
*this = other;
}
idSpatialMat::~idSpatialMat() {
if (mat != nullptr && allocatedRows > 0) {
_aligned_free(mat);
}
}
idSpatialMat& idSpatialMat::operator=(const idSpatialMat& other) {
if (this == &other) {
return *this;
}
SetSize(other.numRows, other.numColumns);
if (mat != nullptr && other.mat != nullptr) {
std::memcpy(mat, other.mat, SPATIAL_MAT_BYTES);
}
return *this;
}
void idSpatialMat::SetSize(const int rows, const int columns) {
if (!IsValidSize(rows, columns)) {
numRows = 0;
numColumns = 0;
return;
}
if (mat == nullptr) {
mat = AllocSpatialMat();
if (mat == nullptr) {
numRows = 0;
numColumns = 0;
allocatedRows = 0;
return;
}
allocatedRows = MAX_ROWS;
std::memset(mat, 0, SPATIAL_MAT_BYTES);
}
numRows = rows;
numColumns = columns;
ClearPadding();
}
void idSpatialMat::ChangeNumRows(const int rows) {
if (rows < 0 || rows > MAX_ROWS || mat == nullptr) {
return;
}
if (rows != numRows) {
const int firstClearedRow = std::min(rows, numRows);
const int rowCount = std::max(rows, numRows) - firstClearedRow;
if (rowCount > 0) {
std::memset(mat + firstClearedRow * ROW_STRIDE, 0,
static_cast<std::size_t>(rowCount * ROW_STRIDE) * sizeof(float));
}
numRows = rows;
}
}
void idSpatialMat::Zero(const int rows, const int columns) {
SetSize(rows, columns);
Zero();
}
void idSpatialMat::Zero() {
if (mat != nullptr) {
std::memset(mat, 0, SPATIAL_MAT_BYTES);
}
}
void idSpatialMat::Set(const idMat3& m1, const idMat3& m2) {
SetSize(3, 6);
if (mat == nullptr) {
return;
}
for (int row = 0; row < 3; ++row) {
for (int column = 0; column < 3; ++column) {
(*this)(row, column) = m1[row][column];
(*this)(row, column + 3) = m2[row][column];
}
}
}
void idSpatialMat::Set(const idMat3& m1, const idMat3& m2,
const idMat3& m3, const idMat3& m4) {
SetSize(6, 6);
if (mat == nullptr) {
return;
}
for (int row = 0; row < 3; ++row) {
for (int column = 0; column < 3; ++column) {
(*this)(row, column) = m1[row][column];
(*this)(row, column + 3) = m2[row][column];
(*this)(row + 3, column) = m3[row][column];
(*this)(row + 3, column + 3) = m4[row][column];
}
}
}
void idSpatialMat::SetData(const int rows, const int columns, float* data) {
if (!IsValidSize(rows, columns) || data == nullptr) {
return;
}
if (mat != nullptr && allocatedRows > 0) {
_aligned_free(mat);
}
numRows = rows;
numColumns = columns;
allocatedRows = -MAX_ROWS;
mat = data;
ClearPadding();
}
void idSpatialMat::ClearPadding() {
if (mat == nullptr) {
return;
}
for (int row = 0; row < MAX_ROWS; ++row) {
const int first = row < numRows ? numColumns : 0;
std::fill(mat + row * ROW_STRIDE + first,
mat + (row + 1) * ROW_STRIDE, 0.0f);
}
}
void idSpatialMat::Negate() {
if (mat == nullptr) {
return;
}
for (int row = 0; row < numRows; ++row) {
for (int column = 0; column < ROW_STRIDE; ++column) {
(*this)[row][column] = -(*this)[row][column];
}
}
}
void idSpatialMat::Transpose(idSpatialMat& dst) const {
float values[MAX_ROWS][MAX_COLUMNS] = {};
for (int row = 0; row < numRows; ++row) {
for (int column = 0; column < numColumns; ++column) {
values[column][row] = (*this)(row, column);
}
}
dst.Zero(numColumns, numRows);
for (int row = 0; row < numColumns; ++row) {
for (int column = 0; column < numRows; ++column) {
dst(row, column) = values[row][column];
}
}
}
void idSpatialMat::Subtract(const idSpatialMat& other) {
if (mat == nullptr || other.mat == nullptr
|| numRows != other.numRows || numColumns != other.numColumns) {
return;
}
for (int index = 0; index < MAX_ROWS * ROW_STRIDE; ++index) {
mat[index] -= other.mat[index];
}
}
void idSpatialMat::Multiply(idSpatialVec& dst, const idSpatialVec& vec) const {
float result[MAX_ROWS] = {};
const int terms = std::min(numColumns, vec.GetSize());
for (int row = 0; row < numRows; ++row) {
for (int column = 0; column < terms; ++column) {
result[row] += (*this)(row, column) * vec[column];
}
}
dst.SetSize(numRows);
for (int row = 0; row < numRows; ++row) {
dst[row] = result[row];
}
}
void idSpatialMat::MultiplyAdd(idSpatialVec& dst, const idSpatialVec& vec) const {
if (dst.GetSize() < numRows) {
dst.SetSize(numRows);
}
const int terms = std::min(numColumns, vec.GetSize());
for (int row = 0; row < numRows; ++row) {
float value = 0.0f;
for (int column = 0; column < terms; ++column) {
value += (*this)(row, column) * vec[column];
}
dst[row] += value;
}
}
void idSpatialMat::MultiplySub(idSpatialVec& dst, const idSpatialVec& vec) const {
if (dst.GetSize() < numRows) {
dst.SetSize(numRows);
}
const int terms = std::min(numColumns, vec.GetSize());
for (int row = 0; row < numRows; ++row) {
float value = 0.0f;
for (int column = 0; column < terms; ++column) {
value += (*this)(row, column) * vec[column];
}
dst[row] -= value;
}
}
void idSpatialMat::TransposeMultiplyAdd(idSpatialVec& dst,
const idSpatialVec& vec) const {
if (dst.GetSize() < numColumns) {
dst.SetSize(numColumns);
}
const int terms = std::min(numRows, vec.GetSize());
for (int column = 0; column < numColumns; ++column) {
float value = 0.0f;
for (int row = 0; row < terms; ++row) {
value += (*this)(row, column) * vec[row];
}
dst[column] += value;
}
}
void idSpatialMat::TransposeMultiplySub(idSpatialVec& dst,
const idSpatialVec& vec) const {
if (dst.GetSize() < numColumns) {
dst.SetSize(numColumns);
}
const int terms = std::min(numRows, vec.GetSize());
for (int column = 0; column < numColumns; ++column) {
float value = 0.0f;
for (int row = 0; row < terms; ++row) {
value += (*this)(row, column) * vec[row];
}
dst[column] -= value;
}
}
void idSpatialMat::Multiply(idSpatialMat& dst,
const idSpatialMat& other) const {
if (numColumns != other.numRows) {
dst.Zero(0, 0);
return;
}
float values[MAX_ROWS][MAX_COLUMNS] = {};
for (int row = 0; row < numRows; ++row) {
for (int column = 0; column < other.numColumns; ++column) {
for (int term = 0; term < numColumns; ++term) {
values[row][column] +=
(*this)(row, term) * other(term, column);
}
}
}
dst.Zero(numRows, other.numColumns);
for (int row = 0; row < numRows; ++row) {
for (int column = 0; column < other.numColumns; ++column) {
dst(row, column) = values[row][column];
}
}
}
void idSpatialMat::TransposeMultiply(idSpatialMat& dst,
const idSpatialMat& other) const {
if (numRows != other.numRows) {
dst.Zero(0, 0);
return;
}
float values[MAX_ROWS][MAX_COLUMNS] = {};
for (int row = 0; row < numColumns; ++row) {
for (int column = 0; column < other.numColumns; ++column) {
for (int term = 0; term < numRows; ++term) {
values[row][column] +=
(*this)(term, row) * other(term, column);
}
}
}
dst.Zero(numColumns, other.numColumns);
for (int row = 0; row < numColumns; ++row) {
for (int column = 0; column < other.numColumns; ++column) {
dst(row, column) = values[row][column];
}
}
}
bool idSpatialMat::Inverse(idSpatialMat& dst) const {
if (numRows != numColumns || numRows < 1 || numRows > MAX_ROWS) {
return false;
}
switch (numRows) {
case 1: return Inverse1x1(dst);
case 2: return Inverse2x2(dst);
case 3: return Inverse3x3(dst);
case 4: return Inverse4x4(dst);
case 5: return Inverse5x5(dst);
case 6: return Inverse6x6(dst);
default: return false;
}
}
bool idSpatialMat::InverseNxN(idSpatialMat& dst, const int dimension) const {
double work[MAX_ROWS][MAX_ROWS * 2] = {};
for (int row = 0; row < dimension; ++row) {
for (int column = 0; column < dimension; ++column) {
work[row][column] = (*this)(row, column);
}
work[row][dimension + row] = 1.0;
}
for (int pivotColumn = 0; pivotColumn < dimension; ++pivotColumn) {
int pivotRow = pivotColumn;
for (int row = pivotColumn + 1; row < dimension; ++row) {
if (std::fabs(work[row][pivotColumn])
> std::fabs(work[pivotRow][pivotColumn])) {
pivotRow = row;
}
}
if (std::fabs(work[pivotRow][pivotColumn]) < 1.0e-14) {
return false;
}
if (pivotRow != pivotColumn) {
for (int column = 0; column < dimension * 2; ++column) {
std::swap(work[pivotRow][column], work[pivotColumn][column]);
}
}
const double reciprocal = 1.0 / work[pivotColumn][pivotColumn];
for (int column = 0; column < dimension * 2; ++column) {
work[pivotColumn][column] *= reciprocal;
}
for (int row = 0; row < dimension; ++row) {
if (row == pivotColumn) {
continue;
}
const double scale = work[row][pivotColumn];
for (int column = 0; column < dimension * 2; ++column) {
work[row][column] -= scale * work[pivotColumn][column];
}
}
}
dst.Zero(dimension, dimension);
for (int row = 0; row < dimension; ++row) {
for (int column = 0; column < dimension; ++column) {
dst(row, column) = static_cast<float>(work[row][dimension + column]);
}
}
return true;
}
bool idSpatialMat::Inverse1x1(idSpatialMat& dst) const { return InverseNxN(dst, 1); }
bool idSpatialMat::Inverse2x2(idSpatialMat& dst) const { return InverseNxN(dst, 2); }
bool idSpatialMat::Inverse3x3(idSpatialMat& dst) const { return InverseNxN(dst, 3); }
bool idSpatialMat::Inverse4x4(idSpatialMat& dst) const { return InverseNxN(dst, 4); }
bool idSpatialMat::Inverse5x5(idSpatialMat& dst) const { return InverseNxN(dst, 5); }
bool idSpatialMat::Inverse6x6(idSpatialMat& dst) const { return InverseNxN(dst, 6); }
idSpatialVec idSpatialMat::SubSpatialVec(const int row) const {
idSpatialVec result;
if (mat != nullptr && row >= 0 && row < numRows) {
result.SetData(MAX_COLUMNS, mat + row * ROW_STRIDE);
}
return result;
}
+77
View File
@@ -0,0 +1,77 @@
#pragma once
#include "idlib/precompiled.h"
#include "spatialvec.h"
// Tungsten stores every spatial matrix in a six-row, eight-float-stride slab.
// The two padding floats per row are intentional: the Xenon implementation
// loads complete VMX vectors from each half-row.
class idSpatialMat {
public:
static const int MAX_ROWS = 6;
static const int MAX_COLUMNS = 6;
static const int ROW_STRIDE = 8;
idSpatialMat();
idSpatialMat(int rows, int columns);
idSpatialMat(const idSpatialMat& other);
~idSpatialMat();
idSpatialMat& operator=(const idSpatialMat& other);
void SetSize(int rows, int columns);
void ChangeNumRows(int rows);
void Zero(int rows, int columns);
void Zero();
void Set(const idMat3& m1, const idMat3& m2);
void Set(const idMat3& m1, const idMat3& m2,
const idMat3& m3, const idMat3& m4);
void SetData(int rows, int columns, float* data);
void Negate();
void Transpose(idSpatialMat& dst) const;
void Subtract(const idSpatialMat& other);
void Multiply(idSpatialVec& dst, const idSpatialVec& vec) const;
void MultiplyAdd(idSpatialVec& dst, const idSpatialVec& vec) const;
void MultiplySub(idSpatialVec& dst, const idSpatialVec& vec) const;
void TransposeMultiplyAdd(idSpatialVec& dst, const idSpatialVec& vec) const;
void TransposeMultiplySub(idSpatialVec& dst, const idSpatialVec& vec) const;
void Multiply(idSpatialMat& dst, const idSpatialMat& other) const;
void TransposeMultiply(idSpatialMat& dst, const idSpatialMat& other) const;
bool Inverse(idSpatialMat& dst) const;
idSpatialVec SubSpatialVec(int row) const;
int GetNumRows() const { return numRows; }
int GetNumColumns() const { return numColumns; }
int GetAllocatedRows() const { return allocatedRows; }
float* ToFloatPtr() { return mat; }
const float* ToFloatPtr() const { return mat; }
float* operator[](int row) { return mat + row * ROW_STRIDE; }
const float* operator[](int row) const { return mat + row * ROW_STRIDE; }
float& operator()(int row, int column) { return mat[row * ROW_STRIDE + column]; }
float operator()(int row, int column) const { return mat[row * ROW_STRIDE + column]; }
private:
bool InverseNxN(idSpatialMat& dst, int dimension) const;
bool Inverse1x1(idSpatialMat& dst) const;
bool Inverse2x2(idSpatialMat& dst) const;
bool Inverse3x3(idSpatialMat& dst) const;
bool Inverse4x4(idSpatialMat& dst) const;
bool Inverse5x5(idSpatialMat& dst) const;
bool Inverse6x6(idSpatialMat& dst) const;
void ClearPadding();
int numRows;
int numColumns;
int allocatedRows;
float* mat;
};
#if INTPTR_MAX == INT32_MAX
static_assert(sizeof(idSpatialMat) == 16, "Recovered idSpatialMat ABI changed");
#endif
+153
View File
@@ -0,0 +1,153 @@
#pragma once
#include <algorithm>
#include <cmath>
#include <cstdint>
#include <cstdlib>
#include <cstring>
class idSpatialVec {
public:
idSpatialVec()
: size(0), allocated(0), p(nullptr) {
}
explicit idSpatialVec(const int length)
: idSpatialVec() {
SetSize(length);
}
idSpatialVec(const idSpatialVec& other)
: idSpatialVec() {
SetSize(other.size);
if (p != nullptr && other.p != nullptr) {
std::memcpy(p, other.p, sizeof(float) * other.size);
}
}
idSpatialVec(idSpatialVec&& other) noexcept
: size(other.size), allocated(other.allocated), p(other.p) {
other.size = 0;
other.allocated = 0;
other.p = nullptr;
}
~idSpatialVec() {
if (allocated > 0) {
std::free(p);
}
}
idSpatialVec& operator=(const idSpatialVec& other) {
if (this != &other) {
SetSize(other.size);
if (p != nullptr && other.p != nullptr) {
std::memcpy(p, other.p, sizeof(float) * other.size);
}
}
return *this;
}
idSpatialVec& operator=(idSpatialVec&& other) noexcept {
if (this != &other) {
if (allocated > 0) {
std::free(p);
}
size = other.size;
allocated = other.allocated;
p = other.p;
other.size = 0;
other.allocated = 0;
other.p = nullptr;
}
return *this;
}
void SetData(const int length, float* data) {
if (allocated > 0) {
std::free(p);
}
p = data;
size = static_cast<std::int16_t>(std::max(0, length));
allocated = static_cast<std::int16_t>(-std::max(8, length));
if (p != nullptr) {
for (int index = size; index < -allocated; ++index) {
p[index] = 0.0f;
}
}
}
bool SetSize(const int newSize) {
if (newSize < 0 || newSize > 32767) {
return false;
}
const int capacity = allocated < 0 ? -allocated : allocated;
if (p == nullptr || newSize > capacity) {
const int newCapacity = std::max(8, (newSize + 7) & ~7);
float* const replacement = static_cast<float*>(
std::calloc(static_cast<std::size_t>(newCapacity), sizeof(float))
);
if (replacement == nullptr) {
return false;
}
if (p != nullptr) {
std::memcpy(replacement, p,
sizeof(float) * static_cast<std::size_t>(std::min<int>(size, newSize)));
}
if (allocated > 0) {
std::free(p);
}
p = replacement;
allocated = static_cast<std::int16_t>(newCapacity);
} else if (newSize > size) {
std::memset(p + size, 0,
sizeof(float) * static_cast<std::size_t>(newSize - size));
}
size = static_cast<std::int16_t>(newSize);
return true;
}
void ChangeSize(const int newSize) {
SetSize(newSize);
}
void Zero() {
if (p != nullptr) {
std::memset(p, 0, sizeof(float) * static_cast<std::size_t>(size));
}
}
void Clamp(const float minimum, const float maximum) {
for (int index = 0; index < size; ++index) {
p[index] = std::max(minimum, std::min(maximum, p[index]));
}
}
float LengthSqr() const {
float sum = 0.0f;
for (int index = 0; index < size; ++index) {
sum += p[index] * p[index];
}
return sum;
}
float Length() const {
return std::sqrt(LengthSqr());
}
int GetSize() const { return size; }
float* ToFloatPtr() { return p; }
const float* ToFloatPtr() const { return p; }
float& operator[](const int index) { return p[index]; }
float operator[](const int index) const { return p[index]; }
private:
std::int16_t size;
std::int16_t allocated;
float* p;
};
#if INTPTR_MAX == INT32_MAX
static_assert(sizeof(idSpatialVec) == 8, "Recovered idSpatialVec ABI changed");
#endif
+117
View File
@@ -0,0 +1,117 @@
#pragma once
#include "vector.h"
#include <algorithm>
#include <cmath>
template<typename vectorType>
struct idSpringDimension;
template<> struct idSpringDimension<idVec1> { static constexpr int value = 1; };
template<> struct idSpringDimension<idVec2> { static constexpr int value = 2; };
template<> struct idSpringDimension<idVec3> { static constexpr int value = 3; };
template<typename vectorType>
class idSpring {
public:
idSpring()
: maxSpeed(0.0f), hasPMax(false), hasPMin(false),
k(1.0f), c(2.0f), m(1.0f), restLength(0.0f) {
p0.Zero();
p1.Zero();
vel.Zero();
pMin.Zero();
pMax.Zero();
}
void SetConstants(float springConstant, const float dampingConstant) {
k = std::min(10000.0f, std::max(0.0f, springConstant));
c = dampingConstant < 0.0f ? 2.0f * std::sqrt(m * k)
: dampingConstant;
}
void SetMass(const float mass) { m = mass > 0.0f ? mass : 1.0f; }
void SetRestLength(const float length) { restLength = std::max(0.0f, length); }
void SetMaxSpeed(const float speed) { maxSpeed = speed; }
void SetAnchor(const vectorType& anchor) { p0 = anchor; }
void SetPosition(const vectorType& position) { p1 = position; }
void SetVelocity(const vectorType& velocity) { vel = velocity; }
void SetMinimum(const vectorType& minimum) { pMin = minimum; hasPMin = true; }
void SetMaximum(const vectorType& maximum) { pMax = maximum; hasPMax = true; }
void ClearMinimum() { hasPMin = false; }
void ClearMaximum() { hasPMax = false; }
const vectorType& GetPosition() const { return p1; }
const vectorType& GetVelocity() const { return vel; }
void Update(float deltaTime) {
while (deltaTime > 0.0f) {
const float step = std::min(deltaTime, 0.0085f);
deltaTime -= step;
float distanceSquared = 0.0f;
float difference[idSpringDimension<vectorType>::value];
for (int index = 0; index < idSpringDimension<vectorType>::value; ++index) {
difference[index] = p1[index] - p0[index];
distanceSquared += difference[index] * difference[index];
}
const float distance = std::sqrt(distanceSquared);
const float inverseDistance = distance > 0.00001f ? 1.0f / distance : 0.0f;
const float springForce = -(distance - restLength) * k;
for (int index = 0; index < idSpringDimension<vectorType>::value; ++index) {
const float force = difference[index] * inverseDistance * springForce
- vel[index] * c;
vel[index] += (force / m) * step;
}
float speedSquared = 0.0f;
for (int index = 0; index < idSpringDimension<vectorType>::value; ++index) {
speedSquared += vel[index] * vel[index];
}
const float speed = std::sqrt(speedSquared);
if (maxSpeed > 0.0f && speed > maxSpeed) {
const float scale = maxSpeed / speed;
for (int index = 0; index < idSpringDimension<vectorType>::value; ++index) {
vel[index] *= scale;
}
}
if (speed < 0.00001f) {
vel.Zero();
}
for (int index = 0; index < idSpringDimension<vectorType>::value; ++index) {
p1[index] += vel[index] * step;
}
if (distance < 0.00001f) {
p1 = p0;
}
}
for (int index = 0; index < idSpringDimension<vectorType>::value; ++index) {
if (hasPMin) {
p1[index] = std::max(p1[index], pMin[index]);
}
if (hasPMax) {
p1[index] = std::min(p1[index], pMax[index]);
}
}
}
private:
vectorType p0;
vectorType p1;
vectorType vel;
float maxSpeed;
vectorType pMin;
vectorType pMax;
bool hasPMax;
bool hasPMin;
float k;
float c;
float m;
float restLength;
};
static_assert(sizeof(idSpring<idVec1>) == 44, "Recovered idSpring<idVec1> ABI changed");
static_assert(sizeof(idSpring<idVec2>) == 64, "Recovered idSpring<idVec2> ABI changed");
static_assert(sizeof(idSpring<idVec3>) == 84, "Recovered idSpring<idVec3> ABI changed");
+329
View File
@@ -0,0 +1,329 @@
#pragma once
#include <cassert>
#include <cmath>
#include <cstdlib>
#include <cstring>
class idVec1 {
public:
float x;
idVec1() = default;
explicit idVec1(const float newX) : x(newX) {}
void Zero() { x = 0.0f; }
float operator[](const int) const { return x; }
float& operator[](const int) { return x; }
};
static_assert(sizeof(idVec1) == 4, "Recovered idVec1 layout changed");
// Minimal recovered ABI surface for tungsten's idVec2. More vector operations
// will move here as their out-of-line idTech 5 implementations are activated.
class idVec2 {
public:
float x;
float y;
idVec2() = default;
idVec2(const float newX, const float newY)
: x(newX)
, y(newY) {
}
void Set(const float newX, const float newY) {
x = newX;
y = newY;
}
void Zero() {
x = 0.0f;
y = 0.0f;
}
float operator[](const int index) const {
assert(index >= 0 && index < 2);
return (&x)[index];
}
float& operator[](const int index) {
assert(index >= 0 && index < 2);
return (&x)[index];
}
};
static_assert(sizeof(idVec2) == 8, "Recovered idVec2 layout changed");
// Minimal recovered ABI surface for tungsten's idVec3. The class deliberately
// stays a three-float POD layout; Xbox-only SIMD assumptions belong in the PC
// portability layer rather than in this type.
class idVec3 {
public:
float x;
float y;
float z;
idVec3() = default;
idVec3(const float newX, const float newY, const float newZ)
: x(newX)
, y(newY)
, z(newZ) {
}
void Set(const float newX, const float newY, const float newZ) {
x = newX;
y = newY;
z = newZ;
}
void Zero() {
x = 0.0f;
y = 0.0f;
z = 0.0f;
}
float operator[](const int index) const {
assert(index >= 0 && index < 3);
return (&x)[index];
}
float& operator[](const int index) {
assert(index >= 0 && index < 3);
return (&x)[index];
}
idVec3 operator-() const {
return idVec3(-x, -y, -z);
}
idVec3 operator+(const idVec3& other) const {
return idVec3(x + other.x, y + other.y, z + other.z);
}
idVec3 operator-(const idVec3& other) const {
return idVec3(x - other.x, y - other.y, z - other.z);
}
idVec3 operator*(const float scale) const {
return idVec3(x * scale, y * scale, z * scale);
}
float Dot(const idVec3& other) const {
return x * other.x + y * other.y + z * other.z;
}
idVec3 Cross(const idVec3& other) const {
return idVec3(
y * other.z - z * other.y,
z * other.x - x * other.z,
x * other.y - y * other.x
);
}
float LengthSqr() const {
return Dot(*this);
}
float Length() const {
return std::sqrt(LengthSqr());
}
};
static_assert(sizeof(idVec3) == 12, "Recovered idVec3 layout changed");
class idMat3 {
public:
idVec3 mat[3];
idMat3() = default;
explicit idMat3(float diagonal) {
mat[0].Set(diagonal, 0.0f, 0.0f);
mat[1].Set(0.0f, diagonal, 0.0f);
mat[2].Set(0.0f, 0.0f, diagonal);
}
idVec3& operator[](const int index) { return mat[index]; }
const idVec3& operator[](const int index) const { return mat[index]; }
};
static_assert(sizeof(idMat3) == 36, "Recovered idMat3 layout changed");
class idVec4 {
public:
float x;
float y;
float z;
float w;
idVec4() = default;
idVec4(
const float newX,
const float newY,
const float newZ,
const float newW
)
: x(newX)
, y(newY)
, z(newZ)
, w(newW) {
}
void Set(
const float newX,
const float newY,
const float newZ,
const float newW
) {
x = newX;
y = newY;
z = newZ;
w = newW;
}
float operator[](const int index) const {
assert(index >= 0 && index < 4);
return (&x)[index];
}
float& operator[](const int index) {
assert(index >= 0 && index < 4);
return (&x)[index];
}
};
static_assert(sizeof(idVec4) == 16, "Recovered idVec4 layout changed");
class idAngles {
public:
float pitch;
float yaw;
float roll;
idAngles() = default;
idAngles(const float newPitch, const float newYaw, const float newRoll)
: pitch(newPitch), yaw(newYaw), roll(newRoll) {
}
float operator[](const int index) const { return (&pitch)[index]; }
float& operator[](const int index) { return (&pitch)[index]; }
};
static_assert(sizeof(idAngles) == 12, "Recovered idAngles layout changed");
class idQuat {
public:
float x;
float y;
float z;
float w;
idQuat() = default;
idQuat(const float newX, const float newY, const float newZ, const float newW)
: x(newX), y(newY), z(newZ), w(newW) {
}
float operator[](const int index) const { return (&x)[index]; }
float& operator[](const int index) { return (&x)[index]; }
};
static_assert(sizeof(idQuat) == 16, "Recovered idQuat layout changed");
// The Xbox 360 type-information stream serializes the dynamic math types by
// their three/four-field facades. Keep these definitions allocation-simple on
// the standalone recovery targets; the complete idLib target uses BFG's
// layout-compatible implementations.
class idVecX {
public:
idVecX() : size(0), alloced(0), p(nullptr) {}
explicit idVecX(const int newSize) : idVecX() { SetSize(newSize); }
idVecX(const idVecX& other) : idVecX() {
SetSize(other.size);
if (size > 0) std::memcpy(p, other.p, sizeof(float) * size);
}
~idVecX() { std::free(p); }
idVecX& operator=(const idVecX& other) {
if (this != &other) {
SetSize(other.size);
if (size > 0) std::memcpy(p, other.p, sizeof(float) * size);
}
return *this;
}
void SetSize(const int newSize) {
const int safeSize = newSize > 0 ? newSize : 0;
if (safeSize > alloced) {
float* const replacement = static_cast<float*>(
std::realloc(p, sizeof(float) * safeSize));
if (replacement == nullptr) return;
p = replacement;
alloced = safeSize;
}
size = safeSize;
}
int GetSize() const { return size; }
float& operator[](const int index) { return p[index]; }
float operator[](const int index) const { return p[index]; }
private:
int size;
int alloced;
float* p;
};
static_assert(sizeof(idVecX) == 12, "Recovered idVecX layout changed");
class idMatX {
public:
idMatX() : numRows(0), numColumns(0), alloced(0), mat(nullptr) {}
idMatX(const int rows, const int columns) : idMatX() {
SetSize(rows, columns);
}
idMatX(const idMatX& other) : idMatX() {
SetSize(other.numRows, other.numColumns);
const int count = numRows * numColumns;
if (count > 0) std::memcpy(mat, other.mat, sizeof(float) * count);
}
~idMatX() { std::free(mat); }
idMatX& operator=(const idMatX& other) {
if (this != &other) {
SetSize(other.numRows, other.numColumns);
const int count = numRows * numColumns;
if (count > 0) std::memcpy(mat, other.mat, sizeof(float) * count);
}
return *this;
}
void SetSize(const int rows, const int columns) {
const int safeRows = rows > 0 ? rows : 0;
const int safeColumns = columns > 0 ? columns : 0;
const int count = safeRows * safeColumns;
if (count > alloced) {
float* const replacement = static_cast<float*>(
std::realloc(mat, sizeof(float) * count));
if (replacement == nullptr) return;
mat = replacement;
alloced = count;
}
numRows = safeRows;
numColumns = safeColumns;
}
int GetNumRows() const { return numRows; }
int GetNumColumns() const { return numColumns; }
float* operator[](const int row) { return mat + row * numColumns; }
const float* operator[](const int row) const {
return mat + row * numColumns;
}
private:
int numRows;
int numColumns;
int alloced;
float* mat;
};
static_assert(sizeof(idMatX) == 16, "Recovered idMatX layout changed");