First pass idLib conversion from hex rays4.
This commit is contained in:
@@ -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
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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");
|
||||
@@ -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");
|
||||
Reference in New Issue
Block a user