Skip to content
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 48 additions & 16 deletions plugin_sa/game_sa/CMatrix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,57 +73,77 @@ void CMatrix::SetScale(float scale)
((void (__thiscall *)(CMatrix *, float))0x59AED0)(this, scale);
}

void CMatrix::SetScale(CVector const &scale) {
SetScale(scale.x, scale.y, scale.z);
}

// scale on three axes
void CMatrix::SetScale(float x, float y, float z)
{
((void (__thiscall *)(CMatrix *, float, float, float))0x59AF00)(this, x, y, z);
}

void CMatrix::SetTranslateOnly(CVector const &newPos) {
SetTranslateOnly(newPos.x, newPos.y, newPos.z);
}

void CMatrix::SetTranslateOnly(float x, float y, float z)
{
((void (__thiscall *)(CMatrix *, float, float, float))0x59AF80)(this, x, y, z);
}

void CMatrix::SetTranslate(CVector const &newPos) {
SetTranslate(newPos.x, newPos.y, newPos.z);
}

// like previous + reset orientation
void CMatrix::SetTranslate(float x, float y, float z)
{
((void (__thiscall *)(CMatrix *, float, float, float))0x59AF40)(this, x, y, z);
}

void CMatrix::SetRotateXOnly(float angle)
void CMatrix::SetRotateXOnly(float pitch)
{
((void (__thiscall *)(CMatrix *, float))0x59AFA0)(this, angle);
((void (__thiscall *)(CMatrix *, float))0x59AFA0)(this, pitch);
}

void CMatrix::SetRotateYOnly(float angle)
void CMatrix::SetRotateYOnly(float roll)
{
((void (__thiscall *)(CMatrix *, float))0x59AFE0)(this, angle);
((void (__thiscall *)(CMatrix *, float))0x59AFE0)(this, roll);
}

void CMatrix::SetRotateZOnly(float angle)
void CMatrix::SetRotateZOnly(float yaw)
{
((void (__thiscall *)(CMatrix *, float))0x59B020)(this, angle);
((void (__thiscall *)(CMatrix *, float))0x59B020)(this, yaw);
}

void CMatrix::SetRotateX(float angle)
void CMatrix::SetRotateX(float pitch)
{
((void (__thiscall *)(CMatrix *, float))0x59B060)(this, angle);
((void (__thiscall *)(CMatrix *, float))0x59B060)(this, pitch);
}

void CMatrix::SetRotateY(float angle)
void CMatrix::SetRotateY(float roll)
{
((void (__thiscall *)(CMatrix *, float))0x59B0A0)(this, angle);
((void (__thiscall *)(CMatrix *, float))0x59B0A0)(this, roll);
}

void CMatrix::SetRotateZ(float angle)
void CMatrix::SetRotateZ(float yaw)
{
((void (__thiscall *)(CMatrix *, float))0x59B0E0)(this, angle);
((void (__thiscall *)(CMatrix *, float))0x59B0E0)(this, yaw);
}

void CMatrix::SetRotate(CVector const &rotation) {
SetRotate(rotation.x, rotation.y, rotation.z);
}

// set rotate on 3 axes
void CMatrix::SetRotate(float x, float y, float z)
void CMatrix::SetRotate(float roll, float pitch, float yaw)
{
((void (__thiscall *)(CMatrix *, float, float, float))0x59B120)(this, x, y, z);
((void (__thiscall *)(CMatrix *, float, float, float))0x59B120)(this, roll, pitch, yaw);
}

void CMatrix::Translate(CVector const &offset) {
pos += offset;
}

void CMatrix::Translate(float x, float y, float z)
Expand All @@ -148,10 +168,14 @@ void CMatrix::RotateZ(float angle)
((void (__thiscall *)(CMatrix *, float))0x59B390)(this, angle);
}

void CMatrix::Rotate(CVector const &rotation) {
Rotate(rotation.x, rotation.y, rotation.z);
}

// rotate on 3 axes
void CMatrix::Rotate(float x, float y, float z)
void CMatrix::Rotate(float roll, float pitch, float yaw)
{
((void (__thiscall *)(CMatrix *, float, float, float))0x59B460)(this, x, y, z);
((void (__thiscall *)(CMatrix *, float, float, float))0x59B460)(this, roll, pitch, yaw);
}

void CMatrix::Reorthogonalise()
Expand All @@ -178,6 +202,14 @@ void CMatrix::Scale(float x, float y, float z) {
plugin::CallMethod<0x459350, CMatrix *, float, float, float>(this, x, y, z);
}

void CMatrix::ConvertToEulerAngles(float &x, float &y, float &z, CMatrix::t_EulerAngleConversionSetup flags) const {
plugin::CallMethod<0x59A840, const CMatrix*, float*, float*, float*, t_EulerAngleConversionSetup>(this, &x, &y, &z, flags);
}

void CMatrix::ConvertFromEulerAngles(float x, float y, float z, CMatrix::t_EulerAngleConversionSetup flags) {
plugin::CallMethod<0x59AA40, CMatrix*, float, float, float, t_EulerAngleConversionSetup>(this, x, y, z, flags);
}

void CMatrix::operator=(CMatrix const& rvalue)
{
((void (__thiscall *)(CMatrix *, CMatrix const&))0x59BBC0)(this, rvalue);
Expand Down
69 changes: 55 additions & 14 deletions plugin_sa/game_sa/CMatrix.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,45 @@

class CMatrix {
public:
union t_EulerAngleConversionSetup {
enum class e_AngleType : unsigned char {
TaitBryan, // three distinct axes (yaw/pitch/roll style)
ProperEuler, // repeated axis (e.g. ZXZ, XYX)
};
enum class e_RotationSequence : unsigned char {
// Tait-Bryan Sequence
ZXY = 0b10000, // YawPitchRoll
YXZ = 0b10001, // RollPitchYaw
ZYX = 0b10100, // YawRollPitch
XYZ = 0b10101, // PitchRollYaw
// XZY = ?,
// YZX = ?,

// The rest of the remaining sequence are yet to discover
// ...
} sequence;
struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is flags struct needed at all? Modern reversed just used enum with values that make sense:
https://github.com/gta-reversed/gta-reversed/blob/master/source/game_sa/Core/Matrix.h#L13
In real use-case person will just want to select one of reasonable options, not spending time configuring each flag one by one in some configuration object.

Copy link
Author

@Aldrin-John-Olaer-Manalansan Aldrin-John-Olaer-Manalansan Dec 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was my planing on declaring the conversion flag type into pure enum when the combinations are completely understood. Which is why I decided for the flags struct to stay the way it is as a safer fallback for advanced users to configure onto.

I wasn't aware about reversed source codes containing the euler conversion flags while was specifying the struct type. It's a bad habit of mine of reversing something myself instead of digging onto existing reversed source codes about it. The source material you've tagged here is identical to my findings and seems simpler to use than the current. Yea I think we should adapt the current onto that.

bool swapXAndZ: 1;
e_AngleType angleType: 1;
bool swapYAndZ: 1;
unsigned char primaryAxisIndex: 2; // index (0, 1, 2) into byte_866D9C[] that selects primary axis/order
} flags;
/*
* Tested Combinations:
* { true, true, true, 1} = 0x0F: Always used by the game
* {false, false, false, 2} = 0x10: Returns Relative Angles(x=yaw, y=pitch, z=roll) without negation(less CPU Cycles)
* {false, false, true, 2} = 0x14: Returns Relative Angles(x=yaw, y=pitch, z=roll) that matches the angles returned by Native Commands
*/
};

VALIDATE_SIZE(t_EulerAngleConversionSetup, 1);

// RwV3d-like:
CVector right;
CVector right; // x-axis
unsigned int flags;
CVector up;
CVector up; // y-axis, the member name is supposed to be "forward"
unsigned int pad1;
CVector at;
CVector at; // z-axis, the member name is supposed to be "up"
unsigned int pad2;
CVector pos;
unsigned int pad3;
Expand All @@ -43,20 +76,28 @@ class CMatrix {
void SetUnity();
void ResetOrientation();
void SetScale(float scale); // set (scaled)
void SetScale(CVector const &scale);
void SetScale(float x, float y, float z); // set (scaled)
void SetTranslateOnly(CVector const &pos);
void SetTranslateOnly(float x, float y, float z);
void SetTranslate(CVector const &pos);
void SetTranslate(float x, float y, float z); // like previous + reset orientation
void SetRotateXOnly(float angle);
void SetRotateYOnly(float angle);
void SetRotateZOnly(float angle);
void SetRotateX(float angle);
void SetRotateY(float angle);
void SetRotateZ(float angle);
void SetRotate(float x, float y, float z); // set rotate on 3 axes
void RotateX(float angle);
void RotateY(float angle);
void RotateZ(float angle);
void Rotate(float x, float y, float z); // rotate on 3 axes
void SetRotateXOnly(float pitch);
void SetRotateYOnly(float roll);
void SetRotateZOnly(float yaw);
void SetRotateX(float pitch);
void SetRotateY(float roll);
void SetRotateZ(float yaw);
void SetRotate(CVector const &rotation);
void SetRotate(float pitch, float roll, float yaw); // sets the rotation on 3 axes + resets the position to origin(0, 0, 0)
void RotateX(float pitch);
void RotateY(float roll);
void RotateZ(float yaw);
void Rotate(CVector const &rotation);
void Rotate(float pitch, float roll, float yaw); // rotate on 3 axes
void ConvertToEulerAngles(float &initial, float &intermediate, float &final, CMatrix::t_EulerAngleConversionSetup flags) const;
void ConvertFromEulerAngles(float initial, float intermediate, float final, t_EulerAngleConversionSetup flags);
void Translate(CVector const &offset);
void Translate(float x, float y, float z); // move the position
void Reorthogonalise();
void CopyToRwMatrix(RwMatrix *matrix); // similar to UpdateRW(RwMatrixTag *)
Expand Down