Implement MxVector2/3/4 and MxMatrix (#100)

* All of the MxVectors share an inheritance chain. MxVector4 inherits
  from MxVector3 which inherits from MxVector2.

* They all operate on a shared `float*` data member which points to the
  underlying storage.

* There are also MxVector3/4Data classes, which inherit from Vector3/4,
  but add concrete storage for the Vector data rather than just an
  abstract data pointer.

* The same is true for MxMatrix, with there being an abstract and a
  concrete variant of it.

* Also improve reccmp.py register matching algorithm. It previously
  could not recognize an effective match when a swap had to take place
  between two registers used on the same line. It turns out this happens
  a lot in floating point math code so I adjusted the implementation to
  break the disassembly lines on spaces rather than just linebreaks
  allowing the existing effective match code to handle that case too.
This commit is contained in:
Mark Langen 2023-08-03 11:25:29 -07:00 committed by GitHub
parent ee7c419be8
commit 694045abd8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 881 additions and 4 deletions

View file

@ -128,6 +128,7 @@ add_library(lego1 SHARED
LEGO1/mxloopingflcpresenter.cpp LEGO1/mxloopingflcpresenter.cpp
LEGO1/mxloopingmidipresenter.cpp LEGO1/mxloopingmidipresenter.cpp
LEGO1/mxloopingsmkpresenter.cpp LEGO1/mxloopingsmkpresenter.cpp
LEGO1/mxmatrix.cpp
LEGO1/mxmediapresenter.cpp LEGO1/mxmediapresenter.cpp
LEGO1/mxmidipresenter.cpp LEGO1/mxmidipresenter.cpp
LEGO1/mxmusicpresenter.cpp LEGO1/mxmusicpresenter.cpp
@ -156,6 +157,7 @@ add_library(lego1 SHARED
LEGO1/mxunknown100dc6b0.cpp LEGO1/mxunknown100dc6b0.cpp
LEGO1/mxunknown100dc6e0.cpp LEGO1/mxunknown100dc6e0.cpp
LEGO1/mxvariabletable.cpp LEGO1/mxvariabletable.cpp
LEGO1/mxvector.cpp
LEGO1/mxvideomanager.cpp LEGO1/mxvideomanager.cpp
LEGO1/mxvideoparam.cpp LEGO1/mxvideoparam.cpp
LEGO1/mxvideoparamflags.cpp LEGO1/mxvideoparamflags.cpp

188
LEGO1/mxmatrix.cpp Normal file
View file

@ -0,0 +1,188 @@
#include "mxmatrix.h"
#include <memory.h>
#include "math.h"
#include "decomp.h"
DECOMP_SIZE_ASSERT(MxMatrix, 0x8);
DECOMP_SIZE_ASSERT(MxMatrixData, 0x48);
// OFFSET: LEGO1 0x10002340
void MxMatrix::EqualsMxMatrix(const MxMatrix *p_other)
{
memcpy(m_data, p_other->m_data, 16 * sizeof(float));
}
// OFFSET: LEGO1 0x10002320
void MxMatrix::EqualsMatrixData(const float *p_matrix)
{
memcpy(m_data, p_matrix, 16 * sizeof(float));
}
// OFFSET: LEGO1 0x10002370
void MxMatrix::SetData(float *p_data)
{
m_data = p_data;
}
// OFFSET: LEGO1 0x10002360
void MxMatrix::AnotherSetData(float *p_data)
{
m_data = p_data;
}
// OFFSET: LEGO1 0x10002390
float *MxMatrix::GetData()
{
return m_data;
}
// OFFSET: LEGO1 0x10002380
const float *MxMatrix::GetData() const
{
return m_data;
}
// OFFSET: LEGO1 0x100023c0
float *MxMatrix::Element(int p_row, int p_col)
{
return &m_data[p_row * 4 + p_col];
}
// OFFSET: LEGO1 0x100023a0
const float *MxMatrix::Element(int p_row, int p_col) const
{
return &m_data[p_row * 4 + p_col];
}
// OFFSET: LEGO1 0x100023e0
void MxMatrix::Clear()
{
memset(m_data, 0, 16 * sizeof(float));
}
// OFFSET: LEGO1 0x100023f0
void MxMatrix::SetIdentity()
{
Clear();
m_data[0] = 1.0f;
m_data[5] = 1.0f;
m_data[10] = 1.0f;
m_data[15] = 1.0f;
}
// OFFSET: LEGO1 0x10002850
void MxMatrix::operator=(const MxMatrix& p_other)
{
EqualsMxMatrix(&p_other);
}
// OFFSET: LEGO1 0x10002430
MxMatrix* MxMatrix::operator+=(const float *p_matrix)
{
for (int i = 0; i < 16; ++i)
m_data[i] += p_matrix[i];
return this;
}
// Matches but instructions are significantly out of order. Probably not wrong
// code given that the very similar SetTranslation does match.
// OFFSET: LEGO1 0x10002460
void MxMatrix::TranslateBy(const float *p_x, const float *p_y, const float *p_z)
{
m_data[12] += *p_x;
m_data[13] += *p_y;
m_data[14] += *p_z;
}
// OFFSET: LEGO1 0x100024a0
void MxMatrix::SetTranslation(const float *p_x, const float *p_y, const float *p_z)
{
m_data[12] = *p_x;
m_data[13] = *p_y;
m_data[14] = *p_z;
}
// OFFSET: LEGO1 0x10002530
void MxMatrix::EqualsMxProduct(const MxMatrix *p_a, const MxMatrix *p_b)
{
EqualsDataProduct(p_a->m_data, p_b->m_data);
}
// Just a placeholder matrix multiply implementation. I think the decomp will
// look roughly like this but it's not close to matching and won't be until
// an exact match is found given it's all loop and float crunching.
// OFFSET: LEGO1 0x100024d0 STUB
void MxMatrix::EqualsDataProduct(const float *p_a, const float *p_b)
{
for (int row = 0; row < 4; ++row)
{
for (int col = 0; col < 4; ++col)
{
m_data[row * 4 + col] = 0.0f;
for (int k = 0; k < 4; ++k)
{
m_data[row * 4 + col] += p_a[row * 4 + k] * p_b[k * 4 + col];
}
}
}
}
// Not close, Ghidra struggles understinging this method so it will have to
// be manually worked out. Included since I at least figured out what it was
// doing with rotateIndex and what overall operation it's trying to do.
// OFFSET: LEGO1 0x10002550 STUB
void MxMatrix::ToQuaternion(MxVector4 *p_outQuat)
{
float trace = m_data[0] + m_data[5] + m_data[10];
if (trace > 0)
{
trace = sqrt(trace + 1.0);
p_outQuat->GetData()[3] = trace * 0.5f;
p_outQuat->GetData()[0] = (m_data[9] - m_data[6]) * trace;
p_outQuat->GetData()[1] = (m_data[2] - m_data[8]) * trace;
p_outQuat->GetData()[2] = (m_data[4] - m_data[1]) * trace;
return;
}
// OFFSET: LEGO1 0x100d4090
static int rotateIndex[] = {1, 2, 0};
// Largest element along the trace
int largest = m_data[0] < m_data[5];
if (*Element(largest, largest) < m_data[10])
largest = 2;
int next = rotateIndex[largest];
int nextNext = rotateIndex[next];
float valueA = *Element(nextNext, nextNext);
float valueB = *Element(next, next);
float valueC = *Element(largest, largest);
// Above is somewhat decomped, below is pure speculation since the automatic
// decomp becomes very garbled.
float traceValue = sqrt(valueA - valueB - valueC + 1.0);
p_outQuat->GetData()[largest] = traceValue * 0.5f;
traceValue = 0.5f / traceValue;
p_outQuat->GetData()[3] = (m_data[next + 4 * nextNext] - m_data[nextNext + 4 * next]) * traceValue;
p_outQuat->GetData()[next] = (m_data[next + 4 * largest] + m_data[largest + 4 * next]) * traceValue;
p_outQuat->GetData()[nextNext] = (m_data[nextNext + 4 * largest] + m_data[largest + 4 * nextNext]) * traceValue;
}
// No idea what this function is doing and it will be hard to tell until
// we have a confirmed usage site.
// OFFSET: LEGO1 0x10002710 STUB
MxResult MxMatrix::DoSomethingWithLength(const MxVector3 *p_vec)
{
return FAILURE;
}
// OFFSET: LEGO1 0x10002860
void MxMatrixData::operator=(const MxMatrixData& p_other)
{
EqualsMxMatrix(&p_other);
}

70
LEGO1/mxmatrix.h Normal file
View file

@ -0,0 +1,70 @@
#ifndef MXMATRIX_H
#define MXMATRIX_H
#include "mxvector.h"
// VTABLE 0x100d4350
// SIZE 0x8
class MxMatrix
{
public:
inline MxMatrix(float *p_data) : m_data(p_data) {}
// vtable + 0x00
virtual void EqualsMxMatrix(const MxMatrix *p_other);
virtual void EqualsMatrixData(const float *p_matrix);
virtual void SetData(float *p_data);
virtual void AnotherSetData(float *p_data);
// vtable + 0x10
virtual float *GetData();
virtual const float *GetData() const;
virtual float *Element(int p_row, int p_col);
virtual const float *Element(int p_row, int p_col) const;
// vtable + 0x20
virtual void Clear();
virtual void SetIdentity();
virtual void operator=(const MxMatrix& p_other);
virtual MxMatrix *operator+=(const float *p_matrix);
// vtable + 0x30
virtual void TranslateBy(const float *p_x, const float *p_y, const float *p_z);
virtual void SetTranslation(const float *p_x, const float *p_y, const float *p_z);
virtual void EqualsMxProduct(const MxMatrix *p_a, const MxMatrix *p_b);
virtual void EqualsDataProduct(const float *p_a, const float *p_b);
// vtable + 0x40
virtual void ToQuaternion(MxVector4 *p_resultQuat);
virtual MxResult DoSomethingWithLength(const MxVector3 *p_vec);
private:
float *m_data;
};
// VTABLE 0x100d4300
// SIZE 0x48
class MxMatrixData : public MxMatrix
{
public:
inline MxMatrixData() : MxMatrix(e) {}
// No idea why there's another equals. Maybe to some other type like the
// DirectX Retained Mode Matrix type which is also a float* alias?
// vtable + 0x44
virtual void operator=(const MxMatrixData& p_other);
// Alias an easy way to access the translation part of the matrix, because
// various members / other functions benefit from the clarity.
union
{
float e[16];
struct
{
float _[12];
float x, y, z, w;
};
};
};
#endif // MXMATRIX_H

466
LEGO1/mxvector.cpp Normal file
View file

@ -0,0 +1,466 @@
#include "mxvector.h"
#include <math.h>
#include <memory.h>
#include "decomp.h"
DECOMP_SIZE_ASSERT(MxVector2, 0x8);
DECOMP_SIZE_ASSERT(MxVector3, 0x8);
DECOMP_SIZE_ASSERT(MxVector4, 0x8);
DECOMP_SIZE_ASSERT(MxVector3Data, 0x14);
DECOMP_SIZE_ASSERT(MxVector4Data, 0x18);
// OFFSET: LEGO1 0x10002060
void MxVector2::SetData(float *p_data)
{
m_data = p_data;
}
// OFFSET: LEGO1 0x100020a0
const float *MxVector2::GetData() const
{
return m_data;
}
// OFFSET: LEGO1 0x10002090
float *MxVector2::GetData()
{
return m_data;
}
// OFFSET: LEGO1 0x10002130
float MxVector2::Dot(MxVector2 *p_a, float *p_b) const
{
return DotImpl(p_a->m_data, p_b);
}
// OFFSET: LEGO1 0x10002110
float MxVector2::Dot(float *p_a, MxVector2 *p_b) const
{
return DotImpl(p_a, p_b->m_data);
}
// OFFSET: LEGO1 0x100020f0
float MxVector2::Dot(MxVector2 *p_a, MxVector2 *p_b) const
{
return DotImpl(p_a->m_data, p_b->m_data);
}
// OFFSET: LEGO1 0x100020d0
float MxVector2::Dot(float *p_a, float *p_b) const
{
return DotImpl(p_a, p_b);
}
// OFFSET: LEGO1 0x10002160
MxResult MxVector2::Unitize()
{
float sq = LenSquared();
if (sq > 0.0f)
{
float root = sqrt(sq);
if (root > 0)
{
DivScalarImpl(&root);
return SUCCESS;
}
}
return FAILURE;
}
// OFFSET: LEGO1 0x100021e0
void MxVector2::AddVector(MxVector2 *p_other)
{
AddVectorImpl(p_other->m_data);
}
// OFFSET: LEGO1 0x100021d0
void MxVector2::AddVector(float *p_other)
{
AddVectorImpl(p_other);
}
// OFFSET: LEGO1 0x100021c0
void MxVector2::AddScalar(float p_value)
{
AddScalarImpl(p_value);
}
// OFFSET: LEGO1 0x10002200
void MxVector2::SubVector(MxVector2 *p_other)
{
SubVectorImpl(p_other->m_data);
}
// OFFSET: LEGO1 0x100021f0
void MxVector2::SubVector(float *p_other)
{
SubVectorImpl(p_other);
}
// OFFSET: LEGO1 0x10002230
void MxVector2::MullScalar(float *p_value)
{
MullScalarImpl(p_value);
}
// OFFSET: LEGO1 0x10002220
void MxVector2::MullVector(MxVector2 *p_other)
{
MullVectorImpl(p_other->m_data);
}
// OFFSET: LEGO1 0x10002210
void MxVector2::MullVector(float *p_other)
{
MullVectorImpl(p_other);
}
// OFFSET: LEGO1 0x10002240
void MxVector2::DivScalar(float *p_value)
{
DivScalarImpl(p_value);
}
// OFFSET: LEGO1 0x10002260
void MxVector2::SetVector(MxVector2 *p_other)
{
EqualsImpl(p_other->m_data);
}
// OFFSET: LEGO1 0x10002250
void MxVector2::SetVector(float *p_other)
{
EqualsImpl(p_other);
}
// OFFSET: LEGO1 0x10001fa0
void MxVector2::AddScalarImpl(float p_value)
{
m_data[0] += p_value;
m_data[1] += p_value;
}
// OFFSET: LEGO1 0x10001f80
void MxVector2::AddVectorImpl(float *p_value)
{
m_data[0] += p_value[0];
m_data[1] += p_value[1];
}
// OFFSET: LEGO1 0x10001fc0
void MxVector2::SubVectorImpl(float *p_value)
{
m_data[0] -= p_value[0];
m_data[1] -= p_value[1];
}
// OFFSET: LEGO1 0x10002000
void MxVector2::MullScalarImpl(float *p_value)
{
m_data[0] *= *p_value;
m_data[1] *= *p_value;
}
// OFFSET: LEGO1 0x10001fe0
void MxVector2::MullVectorImpl(float *p_value)
{
m_data[0] *= p_value[0];
m_data[1] *= p_value[1];
}
// OFFSET: LEGO1 0x10002020
void MxVector2::DivScalarImpl(float *p_value)
{
m_data[0] /= *p_value;
m_data[1] /= *p_value;
}
// OFFSET: LEGO1 0x10002040
float MxVector2::DotImpl(float *p_a, float *p_b) const
{
return p_b[0] * p_a[0] + p_b[1] * p_a[1];
}
// OFFSET: LEGO1 0x10002070
void MxVector2::EqualsImpl(float *p_data)
{
float *vec = m_data;
vec[0] = p_data[0];
vec[1] = p_data[1];
}
// OFFSET: LEGO1 0x100020b0
void MxVector2::Clear()
{
float *vec = m_data;
vec[0] = 0.0f;
vec[1] = 0.0f;
}
// OFFSET: LEGO1 0x10002150
float MxVector2::LenSquared() const
{
return m_data[0] * m_data[0] + m_data[1] * m_data[1];
}
// OFFSET: LEGO1 0x10003a90
void MxVector3::AddScalarImpl(float p_value)
{
m_data[0] += p_value;
m_data[1] += p_value;
m_data[2] += p_value;
}
// OFFSET: LEGO1 0x10003a60
void MxVector3::AddVectorImpl(float *p_value)
{
m_data[0] += p_value[0];
m_data[1] += p_value[1];
m_data[2] += p_value[2];
}
// OFFSET: LEGO1 0x10003ac0
void MxVector3::SubVectorImpl(float *p_value)
{
m_data[0] -= p_value[0];
m_data[1] -= p_value[1];
m_data[2] -= p_value[2];
}
// OFFSET: LEGO1 0x10003b20
void MxVector3::MullScalarImpl(float *p_value)
{
m_data[0] *= *p_value;
m_data[1] *= *p_value;
m_data[2] *= *p_value;
}
// OFFSET: LEGO1 0x10003af0
void MxVector3::MullVectorImpl(float *p_value)
{
m_data[0] *= p_value[0];
m_data[1] *= p_value[1];
m_data[2] *= p_value[2];
}
// OFFSET: LEGO1 0x10003b50
void MxVector3::DivScalarImpl(float *p_value)
{
m_data[0] /= *p_value;
m_data[1] /= *p_value;
m_data[2] /= *p_value;
}
// OFFSET: LEGO1 0x10003b80
float MxVector3::DotImpl(float *p_a, float *p_b) const
{
return p_a[0] * p_b[0] + p_a[2] * p_b[2] + p_a[1] * p_b[1];
}
// OFFSET: LEGO1 0x10003ba0
void MxVector3::EqualsImpl(float *p_data)
{
float *vec = m_data;
vec[0] = p_data[0];
vec[1] = p_data[1];
vec[2] = p_data[2];
}
// OFFSET: LEGO1 0x10003bc0
void MxVector3::Clear()
{
float *vec = m_data;
vec[0] = 0.0f;
vec[1] = 0.0f;
vec[2] = 0.0f;
}
// OFFSET: LEGO1 0x10003bd0
float MxVector3::LenSquared() const
{
return m_data[1] * m_data[1] + m_data[0] * m_data[0] + m_data[2] * m_data[2];
}
// OFFSET: LEGO1 0x10002270
void MxVector3::EqualsCrossImpl(float* p_a, float* p_b)
{
m_data[0] = p_a[1] * p_b[2] - p_a[2] * p_b[1];
m_data[1] = p_a[2] * p_b[0] - p_a[0] * p_b[2];
m_data[2] = p_a[0] * p_b[1] - p_a[1] * p_b[0];
}
// OFFSET: LEGO1 0x10002300
void MxVector3::EqualsCross(float *p_a, MxVector3 *p_b)
{
EqualsCrossImpl(p_a, p_b->m_data);
}
// OFFSET: LEGO1 0x100022e0
void MxVector3::EqualsCross(MxVector3 *p_a, float *p_b)
{
EqualsCrossImpl(p_a->m_data, p_b);
}
// OFFSET: LEGO1 0x100022c0
void MxVector3::EqualsCross(MxVector3 *p_a, MxVector3 *p_b)
{
EqualsCrossImpl(p_a->m_data, p_b->m_data);
}
// OFFSET: LEGO1 0x10003bf0
void MxVector3::EqualsScalar(float *p_value)
{
m_data[0] = *p_value;
m_data[1] = *p_value;
m_data[2] = *p_value;
}
// OFFSET: LEGO1 0x100028b0
void MxVector4::AddScalarImpl(float p_value)
{
m_data[0] += p_value;
m_data[1] += p_value;
m_data[2] += p_value;
m_data[3] += p_value;
}
// OFFSET: LEGO1 0x10002870
void MxVector4::AddVectorImpl(float *p_value)
{
m_data[0] += p_value[0];
m_data[1] += p_value[1];
m_data[2] += p_value[2];
m_data[3] += p_value[3];
}
// OFFSET: LEGO1 0x100028f0
void MxVector4::SubVectorImpl(float *p_value)
{
m_data[0] -= p_value[0];
m_data[1] -= p_value[1];
m_data[2] -= p_value[2];
m_data[3] -= p_value[3];
}
// OFFSET: LEGO1 0x10002970
void MxVector4::MullScalarImpl(float *p_value)
{
m_data[0] *= *p_value;
m_data[1] *= *p_value;
m_data[2] *= *p_value;
m_data[3] *= *p_value;
}
// OFFSET: LEGO1 0x10002930
void MxVector4::MullVectorImpl(float *p_value)
{
m_data[0] *= p_value[0];
m_data[1] *= p_value[1];
m_data[2] *= p_value[2];
m_data[3] *= p_value[3];
}
// OFFSET: LEGO1 0x100029b0
void MxVector4::DivScalarImpl(float *p_value)
{
m_data[0] /= *p_value;
m_data[1] /= *p_value;
m_data[2] /= *p_value;
m_data[3] /= *p_value;
}
// OFFSET: LEGO1 0x100029f0
float MxVector4::DotImpl(float *p_a, float *p_b) const
{
return
p_a[0] * p_b[0] + p_a[2] * p_b[2] +
p_a[1] * p_b[1] + p_a[3] * p_b[3];
}
// OFFSET: LEGO1 0x10002a20
void MxVector4::EqualsImpl(float *p_data)
{
float *vec = m_data;
vec[0] = p_data[0];
vec[1] = p_data[1];
vec[2] = p_data[2];
vec[3] = p_data[3];
}
// OFFSET: LEGO1 0x10002b00
void MxVector4::Clear()
{
float *vec = m_data;
vec[0] = 0.0f;
vec[1] = 0.0f;
vec[2] = 0.0f;
vec[3] = 0.0f;
}
// OFFSET: LEGO1 0x10002b20
float MxVector4::LenSquared() const
{
return m_data[1] * m_data[1] + m_data[0] * m_data[0] +
m_data[2] * m_data[2] + m_data[3] * m_data[3];
}
// OFFSET: LEGO1 0x10002b40
void MxVector4::EqualsScalar(float *p_value)
{
m_data[0] = *p_value;
m_data[1] = *p_value;
m_data[2] = *p_value;
m_data[3] = *p_value;
}
// OFFSET: LEGO1 0x10002ae0 STUB
void MxVector4::unk1(MxVector4 *p_a, float *p_b)
{
}
// OFFSET: LEGO1 0x10002a40
void MxVector4::SetMatrixProduct(float *p_vec, float *p_mat)
{
m_data[0] =
p_vec[0] * p_mat[0] + p_vec[1] * p_mat[4] +
p_vec[2] * p_mat[8] + p_vec[3] * p_mat[12];
m_data[1] =
p_vec[0] * p_mat[1] + p_vec[1] * p_mat[5] +
p_vec[2] * p_mat[9] + p_vec[4] * p_mat[13];
m_data[2] =
p_vec[0] * p_mat[2] + p_vec[1] * p_mat[6] +
p_vec[2] * p_mat[10] + p_vec[4] * p_mat[14];
m_data[3] =
p_vec[0] * p_mat[3] + p_vec[1] * p_mat[7] +
p_vec[2] * p_mat[11] + p_vec[4] * p_mat[15];
}
// Note close yet, included because I'm at least confident I know what operation
// it's trying to do.
// OFFSET: LEGO1 0x10002b70 STUB
MxResult MxVector4::NormalizeQuaternion()
{
float *v = m_data;
float magnitude = v[1] * v[1] + v[2] * v[2] + v[0] * v[0];
if (magnitude > 0.0f)
{
float theta = v[3] * 0.5f;
v[3] = cos(theta);
float frac = sin(theta);
magnitude = frac / sqrt(magnitude);
v[0] *= magnitude;
v[1] *= magnitude;
v[2] *= magnitude;
return SUCCESS;
}
return FAILURE;
}
// OFFSET: LEGO1 0x10002bf0 STUB
void MxVector4::UnknownQuaternionOp(MxVector4 *p_a, MxVector4 *p_b)
{
}

150
LEGO1/mxvector.h Normal file
View file

@ -0,0 +1,150 @@
#ifndef MXVECTOR_H
#define MXVECTOR_H
#include "mxtypes.h"
// VTABLE 0x100d4288
// SIZE 0x8
class MxVector2
{
public:
// OFFSET: LEGO1 0x1000c0f0
inline MxVector2(float* p_data) : m_data(p_data) {}
// vtable + 0x00 (no virtual destructor)
virtual void AddScalarImpl(float p_value) = 0;
virtual void AddVectorImpl(float *p_value) = 0;
virtual void SubVectorImpl(float *p_value) = 0;
virtual void MullScalarImpl(float *p_value) = 0;
// vtable + 0x10
virtual void MullVectorImpl(float *p_value) = 0;
virtual void DivScalarImpl(float *p_value) = 0;
virtual float DotImpl(float *p_a, float *p_b) const = 0;
virtual void SetData(float *p_data);
// vtable + 0x20
virtual void EqualsImpl(float *p_data) = 0;
virtual const float *GetData() const;
virtual float *GetData();
virtual void Clear() = 0;
// vtable + 0x30
virtual float Dot(MxVector2 *p_a, float *p_b) const;
virtual float Dot(float *p_a, MxVector2 *p_b) const;
virtual float Dot(MxVector2 *p_a, MxVector2 *p_b) const;
virtual float Dot(float *p_a, float *p_b) const;
// vtable + 0x40
virtual float LenSquared() const = 0;
virtual MxResult Unitize();
// vtable + 0x48
virtual void AddVector(MxVector2 *p_other);
virtual void AddVector(float *p_other);
virtual void AddScalar(float p_value);
// vtable + 0x54
virtual void SubVector(MxVector2 *p_other);
virtual void SubVector(float *p_other);
// vtable + 0x5C
virtual void MullScalar(float *p_value);
virtual void MullVector(MxVector2 *p_other);
virtual void MullVector(float *p_other);
virtual void DivScalar(float *p_value);
// vtable + 0x6C
virtual void SetVector(MxVector2 *other);
virtual void SetVector(float *other);
protected:
float *m_data;
};
// VTABLE 0x100d4518
// SIZE 0x8
class MxVector3 : public MxVector2
{
public:
inline MxVector3(float* p_data) : MxVector2(p_data) {}
void AddScalarImpl(float p_value);
void AddVectorImpl(float *p_value);
void SubVectorImpl(float *p_value);
void MullScalarImpl(float *p_value);
void MullVectorImpl(float *p_value);
void DivScalarImpl(float *p_value);
float DotImpl(float *p_a, float *p_b) const;
void EqualsImpl(float *p_data);
void Clear();
float LenSquared() const;
// vtable + 0x74
virtual void EqualsCrossImpl(float* p_a, float* p_b);
virtual void EqualsCross(float *p_a, MxVector3 *p_b);
virtual void EqualsCross(MxVector3 *p_a, float *p_b);
virtual void EqualsCross(MxVector3 *p_a, MxVector3 *p_b);
virtual void EqualsScalar(float *p_value);
};
// VTABLE 0x100d45a0
// SIZE 0x8
class MxVector4 : public MxVector3
{
public:
inline MxVector4(float* p_data) : MxVector3(p_data) {}
void AddScalarImpl(float p_value);
void AddVectorImpl(float *p_value);
void SubVectorImpl(float *p_value);
void MullScalarImpl(float *p_value);
void MullVectorImpl(float *p_value);
void DivScalarImpl(float *p_value);
float DotImpl(float *p_a, float *p_b) const;
void EqualsImpl(float *p_data);
void Clear();
float LenSquared() const;
void EqualsScalar(float *p_value);
// vtable + 0x84
virtual void unk1(MxVector4 *p_a, float *p_b);
virtual void SetMatrixProduct(float *p_vec, float *p_mat);
virtual MxResult NormalizeQuaternion();
virtual void UnknownQuaternionOp(MxVector4 *p_a, MxVector4 *p_b);
};
// VTABLE 0x100d4488
// SIZE 0x14
class MxVector3Data : public MxVector3
{
public:
inline MxVector3Data() : MxVector3(&x) {}
inline MxVector3Data(float p_x, float p_y, float p_z)
: MxVector3(&x)
, x(p_x), y(p_y), z(p_z)
{}
float x, y, z;
};
// VTABLE 0x100d41e8
// SIZE 0x18
class MxVector4Data : public MxVector4
{
public:
inline MxVector4Data() : MxVector4(&x) {}
float x, y, z, w;
};
#endif // MXVECTOR_H

View file

@ -343,14 +343,15 @@ def replace_register(lines: list[str], start_line: int, reg: str, replacement: s
# Is it possible to make new_asm the same as original_asm by swapping registers? # Is it possible to make new_asm the same as original_asm by swapping registers?
def can_resolve_register_differences(original_asm, new_asm): def can_resolve_register_differences(original_asm, new_asm):
# Split the ASM on spaces to get more granularity, and so
# that we don't modify the original arrays passed in.
original_asm = [part for line in original_asm for part in line.split()]
new_asm = [part for line in new_asm for part in line.split()]
# Swapping ain't gonna help if the lengths are different # Swapping ain't gonna help if the lengths are different
if len(original_asm) != len(new_asm): if len(original_asm) != len(new_asm):
return False return False
# Make copies so we don't modify the original
original_asm = original_asm.copy()
new_asm = new_asm.copy()
# Look for the mismatching lines # Look for the mismatching lines
for i in range(len(original_asm)): for i in range(len(original_asm)):
new_line = new_asm[i] new_line = new_asm[i]