Merge pull request #71 from h4570/refactor/matrix

Refactor of Matrix and Vector3 class.
This commit is contained in:
Michał Mostowik
2020-12-24 10:54:04 +01:00
committed by GitHub
15 changed files with 553 additions and 444 deletions
+113 -32
View File
@@ -13,79 +13,160 @@
#include "vector3.hpp" #include "vector3.hpp"
#include "../screen_settings.hpp" #include "../screen_settings.hpp"
#include <string.h>
/** https://en.wikipedia.org/wiki/Matrix_(mathematics) */ /** 4x4 Matrix class. */
class Matrix class Matrix
{ {
public: public:
float data[16]; float data[16] __attribute__((aligned(64)));
Matrix(float m11, float m12, float m13, float m14, // ----
float m21, float m22, float m23, float m24, // Constructors/Destructors
float m31, float m32, float m33, float m34, // ----
float m41, float m42, float m43, float m44);
Matrix(const Matrix &v); /** Create empty matrix. */
Matrix operator*(const Matrix &v);
void operator*=(const Matrix &v);
Matrix(); Matrix();
~Matrix();
void lookAt(Vector3 &t_up, Vector3 &t_position, Vector3 &t_target); /**
* Create identity/empty matrix.
* @param t_do_identity Identity matrix if true, random matrix values otherwise
*/
Matrix(const u8 &t_do_identity)
{
if (t_do_identity)
identity();
}
/** Init matrix with given values. */
Matrix(const float &m11, const float &m12, const float &m13, const float &m14,
const float &m21, const float &m22, const float &m23, const float &m24,
const float &m31, const float &m32, const float &m33, const float &m34,
const float &m41, const float &m42, const float &m43, const float &m44);
/** Init matrix with other matrix values. */
Matrix(const Matrix &v) { memcpy(data, v.data, 16 * sizeof(float)); }
// ----
// Operators
// ----
Vector3 operator*(const Vector3 &v) const;
Matrix operator*(const Matrix &v) const
{
Matrix result;
cross(result.data, this->data, v.data);
return result;
}
inline void operator*=(const Matrix &v) { cross(this->data, this->data, v.data); }
float &operator[](const u8 &t_index) { return data[t_index]; }
// ----
// Functions
// ----
/**
* 1 0 0 0
* 0 1 0 0
* 0 0 1 0
* 0 0 0 1
*/
void identity(); void identity();
/**
* 1 0 0 0
* 0 1 0 0
* 0 0 1 0
* 0 0 0 1
*/
inline void unit() { identity(); }; inline void unit() { identity(); };
// Translation /** Create translation matrix. */
void translate(const Vector3 &t_val);
inline void translation(const Vector3 &t_val) inline void translation(const Vector3 &t_val)
{ {
identity(); identity();
translate(t_val); translate(t_val);
} }
// Rotation /** Create rotation matrix. */
inline void rotation(const Vector3 &t_val)
{
identity();
Matrix temp = Matrix();
void rotateX(const float &t_radians); temp.identity();
void rotateY(const float &t_radians); temp.rotateX(t_val.x);
void rotateZ(const float &t_radians); operator*=(temp);
temp.identity();
temp.rotateY(t_val.y);
operator*=(temp);
temp.identity();
temp.rotateZ(t_val.z);
operator*=(temp);
}
/** Create X rotation matrix. */
inline void rotationX(const float &t_radians) inline void rotationX(const float &t_radians)
{ {
identity(); identity();
rotateX(t_radians); rotateX(t_radians);
} }
/** Create Y rotation matrix. */
inline void rotationY(const float &t_radians) inline void rotationY(const float &t_radians)
{ {
identity(); identity();
rotateY(t_radians); rotateY(t_radians);
} }
/** Create Z rotation matrix. */
inline void rotationZ(const float &t_radians) inline void rotationZ(const float &t_radians)
{ {
identity(); identity();
rotateZ(t_radians); rotateZ(t_radians);
} }
inline void rotate(const Vector3 &t_val) /** Create angle rotation matrix. */
{ void rotationByAngle(const float &t_angle, const Vector3 &t_axis);
rotateX(t_val.x);
rotateY(t_val.y);
rotateX(t_val.z);
}
inline void rotation(const Vector3 &t_val) /** Create scale matrix. */
{ void setScale(const Vector3 &t_val);
identity();
rotate(t_val);
}
// /**
* Create perspective projection matrix.
*
* Complies with OpenGL standard (gluPerspective).
* @see https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml
* @param screen Screen settings
*/
void setPerspective(const ScreenSettings &screen);
void setPerspective(ScreenSettings &screen); /**
* Create a view matrix that transforms coordinates in
* such a way that the user looks at a target vector
* direction from a position vector.
*
* Complies with OpenGL standard (glLookAt).
* @see https://learnopengl.com/Getting-started/Camera
*/
void lookAt(const Vector3 &t_position, const Vector3 &t_target);
/** Print matrix (printf). */
const void print() const; const void print() const;
private:
void rotateX(const float &t_radians);
void rotateY(const float &t_radians);
void rotateZ(const float &t_radians);
void translate(const Vector3 &t_val);
void cross(float res[16], const float a[16], const float b[16]) const;
void setCamera(const float t_pos[4], const float t_vz[4], const float t_vy[4]);
}; };
#endif #endif
+80 -19
View File
@@ -12,6 +12,7 @@
#define _TYRA_VECTOR3_ #define _TYRA_VECTOR3_
#include <tamtypes.h> #include <tamtypes.h>
#include <stdio.h>
class Math; // Forward definition class Math; // Forward definition
@@ -20,6 +21,7 @@ class Vector3
{ {
public: public:
/** This trick will allow use to use vec.x and vex[0] */
union union
{ {
struct struct
@@ -31,32 +33,91 @@ public:
float xyz[3] __attribute__((__aligned__(16))); float xyz[3] __attribute__((__aligned__(16)));
}; };
Vector3(float t_x, float t_y, float t_z); // ----
Vector3(const Vector3 &v); // Constructors/Destructors
// ----
/** Create empty vector. */
Vector3(); Vector3();
~Vector3();
Vector3 operator+(Vector3 v); /** Create vector with given vector values. */
Vector3 operator-(const Vector3 &v); Vector3(const Vector3 &t_v) { set(t_v); }
Vector3 operator*(Vector3 &v);
Vector3 operator*(const float &t); /** Create vector with given values. */
Vector3(const float &t_x, const float &t_y, const float &t_z) { set(t_x, t_y, t_z); }
// ----
// Operators
// ----
Vector3 operator+(const Vector3 &v) const;
Vector3 operator-(const Vector3 &v) const;
/** Also called "cross product" */
Vector3 operator*(const Vector3 &v) const;
Vector3 operator*(const float &t) const;
Vector3 operator/(const float &t) const;
Vector3 operator-(void) const { return Vector3(-x, -y, -z); }
void operator+=(const Vector3 &t);
void operator*=(const float &t); void operator*=(const float &t);
Vector3 operator/(float t);
Vector3 operator-(void);
static u8 shouldBeBackfaceCulled(const Vector3 *t_cameraPos, const Vector3 *v0, const Vector3 *v1, const Vector3 *v2); // ----
u8 collidesSquare(const Vector3 &t_min, const Vector3 &t_max) const; // Functions
u8 isOnSquare(const Vector3 &t_min, const Vector3 &t_max) const; // ----
float length();
void normalize(); /** Set vector values via VU0. */
void setByLerp(const Vector3 &v1, const Vector3 &v2, const float &t_interp, const float &t_scale);
float innerProduct(Vector3 &v);
void set(const Vector3 &v); void set(const Vector3 &v);
void rotate(const Vector3 &v, u8 inversed = false);
/** Set vector values. */
void set(const float &t_x, const float &t_y, const float &t_z); void set(const float &t_x, const float &t_y, const float &t_z);
void copy(Vector3 &v);
/** Also called dot3. */
float innerProduct(const Vector3 &v) const;
/** Get vector length */
float length() const;
/** Normalize vector. */
void normalize();
/** Returns distance between two vectors */
float distanceTo(const Vector3 &v) const; float distanceTo(const Vector3 &v) const;
const void print() const;
/**
* Checks intersection with given box
* @param t_min Opposite min vertex (ex. near, left, down vertex of bounding box)
* @param t_max Opposite max vertex (ex. far, right, up vertex of bounding box)
*/
u8 collidesBox(const Vector3 &t_min, const Vector3 &t_max) const
{
return ((this->x <= t_max.x && this->x >= t_min.x) && (this->y < t_max.y && this->y >= t_min.y) && (this->z <= t_max.z && this->z >= t_min.z)) ? 1 : 0;
}
/**
* Checks if this vector is on given box (this->y >= box.y)
* @param t_min Opposite min vertex (ex. near, left, down vertex of bounding box)
* @param t_max Opposite max vertex (ex. far, right, up vertex of bounding box)
*/
u8 isOnBox(const Vector3 &t_min, const Vector3 &t_max) const
{
return ((this->x <= t_max.x && this->x >= t_min.x) && (this->y >= t_max.y) && (this->z <= t_max.z && this->z >= t_min.z)) ? 1 : 0;
}
/** Check if given triangle should be backface culled. */
static u8 shouldBeBackfaceCulled(const Vector3 *t_cameraPos, const Vector3 *t_v0, const Vector3 *t_v1, const Vector3 *t_v2);
/**
* Set by linear interpolation between two vertices (animation).
* @param t_v1 Before vertex
* @param t_v2 After vertex
* @param t_interp State of interpolation
* @param t_scale Scale
*/
void setByLerp(const Vector3 &t_v1, const Vector3 &t_v2, const float &t_interp, const float &t_scale);
const void print() const
{
printf("Vector3(%f, %f, %f)\n", x, y, z);
}
}; };
#endif #endif
+3 -2
View File
@@ -21,7 +21,7 @@ class CameraBase
{ {
public: public:
CameraBase(ScreenSettings *t_screen, Vector3 *t_position, Vector3 *t_up); CameraBase(ScreenSettings *t_screen, Vector3 *t_position);
virtual ~CameraBase(){}; virtual ~CameraBase(){};
/** /**
@@ -56,9 +56,10 @@ protected:
void updatePlanes(Vector3 t_target); void updatePlanes(Vector3 t_target);
private: private:
Vector3 *p_position, *p_up; Vector3 *p_position;
float farPlaneDist, nearPlaneDist, nearHeight, nearWidth, farHeight, farWidth; float farPlaneDist, nearPlaneDist, nearHeight, nearWidth, farHeight, farWidth;
Vector3 ftl, ftr, fbl, fbr, ntl, ntr, nbl, nbr; Vector3 ftl, ftr, fbl, fbr, ntl, ntr, nbl, nbr;
Vector3 up; // always 0.0F, 1.0F, 0.0F
}; };
#endif #endif
+1 -1
View File
@@ -125,7 +125,7 @@ private:
void flipBuffers(); void flipBuffers();
void beginFrameIfNeeded(); void beginFrameIfNeeded();
u8 isFrameEmpty; u8 isFrameEmpty;
Matrix perspective; Matrix perspective, camRotation;
Light light; Light light;
RenderData renderData; RenderData renderData;
TextureRepository textureRepo; TextureRepository textureRepo;
+243 -188
View File
@@ -17,11 +17,16 @@
// Constructors/Destructors // Constructors/Destructors
// ---- // ----
/** Create by specifying all points */ Matrix::Matrix()
Matrix::Matrix(float m11, float m12, float m13, float m14, {
float m21, float m22, float m23, float m24, for (u8 i = 0; i < 16; i++)
float m31, float m32, float m33, float m34, data[i] = 0.0F;
float m41, float m42, float m43, float m44) }
Matrix::Matrix(const float &m11, const float &m12, const float &m13, const float &m14,
const float &m21, const float &m22, const float &m23, const float &m24,
const float &m31, const float &m32, const float &m33, const float &m34,
const float &m41, const float &m42, const float &m43, const float &m44)
{ {
data[0] = m11; data[0] = m11;
data[1] = m12; data[1] = m12;
@@ -44,30 +49,34 @@ Matrix::Matrix(float m11, float m12, float m13, float m14,
data[15] = m44; data[15] = m44;
} }
/** Create with another matrix values */ // ----
Matrix::Matrix(const Matrix &v) // Operators
// ----
Vector3 Matrix::operator*(const Vector3 &v) const
{ {
data[0] = v.data[0]; float a[4] = {v.x, v.y, v.z, 1.0F};
data[1] = v.data[1]; float res[4];
data[2] = v.data[2]; asm volatile(
data[3] = v.data[3]; "lqc2 vf4, 0x00(%1) \n\t"
"lqc2 vf5, 0x10(%1) \n\t"
data[4] = v.data[4]; "lqc2 vf6, 0x20(%1) \n\t"
data[5] = v.data[5]; "lqc2 vf7, 0x30(%1) \n\t"
data[6] = v.data[6]; "lqc2 vf8, 0x00(%2) \n\t"
data[7] = v.data[7]; "vmulax.xyzw ACC, vf4, vf8 \n\t"
"vmadday.xyzw ACC, vf5, vf8 \n\t"
data[8] = v.data[8]; "vmaddaz.xyzw ACC, vf6, vf8 \n\t"
data[9] = v.data[9]; "vmaddw.xyzw vf9, vf7, vf8 \n\t"
data[10] = v.data[10]; "sqc2 vf9, 0x00(%0) \n\t"
data[11] = v.data[11]; :
: "r"(res), "r"(this->data), "r"(a));
data[12] = v.data[12]; return Vector3(res[0], res[1], res[2]);
data[13] = v.data[13];
data[14] = v.data[14];
data[15] = v.data[15];
} }
// ----
// Functions
// ----
void Matrix::identity() void Matrix::identity()
{ {
asm volatile( asm volatile(
@@ -84,13 +93,145 @@ void Matrix::identity()
: "r"(this->data)); : "r"(this->data));
} }
void Matrix::translate(const Vector3 &t_val) void Matrix::rotationByAngle(const float &t_angle, const Vector3 &t_axis)
{ {
this->data[12] += t_val.x; // 3,0 Vector3 localAxis = Vector3(t_axis);
this->data[13] += t_val.y; // 3,1 localAxis.normalize();
this->data[14] += t_val.z; // 3,2 float x = localAxis.x;
float y = localAxis.y;
float z = localAxis.z;
float c = Math::cos(t_angle);
float s = Math::sin(t_angle);
this->data[0] = x * x * (1 - c) + c;
this->data[1] = y * x * (1 - c) + z * s;
this->data[2] = x * z * (1 - c) - y * s;
this->data[3] = 0.0F;
this->data[4] = x * y * (1 - c) - z * s;
this->data[5] = y * y * (1 - c) + c;
this->data[6] = y * z * (1 - c) + x * s;
this->data[7] = 0.0F;
this->data[8] = x * z * (1 - c) + y * s;
this->data[9] = y * z * (1 - c) - x * s;
this->data[10] = z * z * (1 - c) + c;
this->data[11] = 0.0F;
this->data[12] = 0.0F;
this->data[13] = 0.0F;
this->data[14] = 0.0F;
this->data[15] = 1.0F;
} }
void Matrix::setScale(const Vector3 &t_val)
{
this->identity();
this->data[0] = t_val.x;
this->data[5] = t_val.y;
this->data[10] = t_val.z;
this->data[15] = 1.0F;
}
void Matrix::setPerspective(const ScreenSettings &t_screen)
{
float fovYdiv2 = Math::HALF_ANG2RAD * t_screen.fov;
float cotFOV = 1.0F / (Math::sin(fovYdiv2) / Math::cos(fovYdiv2));
float w = cotFOV * (t_screen.width / t_screen.projectionScale) / t_screen.aspectRatio;
float h = cotFOV * (t_screen.height / t_screen.projectionScale);
this->data[0] = w;
this->data[1] = 0.0F;
this->data[2] = 0.0F;
this->data[3] = 0.0F;
this->data[4] = 0.0F;
this->data[5] = -h;
this->data[6] = 0.0F;
this->data[7] = 0.0F;
this->data[8] = 0.0F;
this->data[9] = 0.0F;
this->data[10] =
(t_screen.farPlaneDist + t_screen.nearPlaneDist) /
(t_screen.farPlaneDist - t_screen.nearPlaneDist);
this->data[11] = -1.0F;
this->data[12] = 0.0F;
this->data[13] = 0.0F;
this->data[14] =
(2.0F * t_screen.farPlaneDist * t_screen.nearPlaneDist) /
(t_screen.farPlaneDist - t_screen.nearPlaneDist);
this->data[15] = 0.0F;
}
void Matrix::lookAt(const Vector3 &t_position, const Vector3 &t_target)
{
VECTOR up_vec, view_vec;
VECTOR eye = {t_position.x, t_position.y, t_position.z, 1.0F};
VECTOR obj = {t_target.x, t_target.y, t_target.z, 1.0F};
asm volatile(
"lqc2 vf4, 0x00(%2) # eye \n\t"
"lqc2 vf5, 0x00(%3) # obj \n\t"
"vsub.xyz vf7, vf4, vf5 # view_vec = vf7 \n\t"
"vmove.xyzw vf6, vf0 \n\t"
"vaddw.y vf6, vf0, vf0 # vf6 = { 0.0f, 1.0f, 0.0f, 1.0f } \n\t"
"vopmula.xyz ACC, vf6, vf7 \n\t"
"vopmsub.xyz vf9, vf7, vf6 # vec = vf9 \n\t"
"vopmula.xyz ACC, vf7, vf9 \n\t"
"vopmsub.xyz vf8, vf9, vf7 # up_vec = vf8 \n\t"
"sqc2 vf7, 0x00(%0) # view_vec \n\t"
"sqc2 vf6, 0x00(%1) # up_vec \n\t"
:
: "r"(view_vec), "r"(up_vec), "r"(eye), "r"(obj));
Matrix temp;
temp.setCamera(eye, view_vec, up_vec);
identity();
cross(this->data, this->data, temp.data);
// Vector3 camForward, camUp, camRight;
// Vector3 t_up = Vector3(0.0F, 1.0F, 0.0F);
// camForward = t_position - t_target;
// camForward.normalize();
// camRight = t_up * camForward;
// camRight.normalize();
// camUp = camForward * camRight;
// data[0] = camRight.x;
// data[4] = camRight.y;
// data[8] = camRight.z;
// data[12] = -camRight.innerProduct(t_position);
// data[1] = camUp.x;
// data[5] = camUp.y;
// data[9] = camUp.z;
// data[13] = -camUp.innerProduct(t_position);
// data[2] = camForward.x;
// data[6] = camForward.y;
// data[10] = camForward.z;
// data[14] = -camForward.innerProduct(t_position);
// data[3] = 0;
// data[7] = 0;
// data[11] = 0;
// data[15] = 1;
}
const void Matrix::print() const
{
printf("MATRIX(\n%f, %f, %f, %f\n%f, %f, %f, %f\n%f, %f, %f, %f\n%f, %f, %f, %f\n)\n",
data[0], data[1], data[2], data[3],
data[4], data[5], data[6], data[7],
data[8], data[9], data[10], data[11],
data[12], data[13], data[14], data[15]);
}
// ----
// Private
// ----
void Matrix::rotateX(const float &t_radians) void Matrix::rotateX(const float &t_radians)
{ {
Matrix temp = Matrix(); Matrix temp = Matrix();
@@ -127,45 +268,80 @@ void Matrix::rotateZ(const float &t_radians)
this->data[5] = c; // 1,1 this->data[5] = c; // 1,1
} }
Matrix Matrix::operator*(const Matrix &t) void Matrix::translate(const Vector3 &t_val)
{ {
Matrix result; this->data[12] += t_val.x; // 3,0
asm volatile( this->data[13] += t_val.y; // 3,1
"lqc2 vf1, 0x00(%1) \n\t" this->data[14] += t_val.z; // 3,2
"lqc2 vf2, 0x10(%1) \n\t"
"lqc2 vf3, 0x20(%1) \n\t"
"lqc2 vf4, 0x30(%1) \n\t"
"lqc2 vf5, 0x00(%2) \n\t"
"lqc2 vf6, 0x10(%2) \n\t"
"lqc2 vf7, 0x20(%2) \n\t"
"lqc2 vf8, 0x30(%2) \n\t"
"vmulax.xyzw ACC, vf5, vf1 \n\t"
"vmadday.xyzw ACC, vf6, vf1 \n\t"
"vmaddaz.xyzw ACC, vf7, vf1 \n\t"
"vmaddw.xyzw vf1, vf8, vf1 \n\t"
"vmulax.xyzw ACC, vf5, vf2 \n\t"
"vmadday.xyzw ACC, vf6, vf2 \n\t"
"vmaddaz.xyzw ACC, vf7, vf2 \n\t"
"vmaddw.xyzw vf2, vf8, vf2 \n\t"
"vmulax.xyzw ACC, vf5, vf3 \n\t"
"vmadday.xyzw ACC, vf6, vf3 \n\t"
"vmaddaz.xyzw ACC, vf7, vf3 \n\t"
"vmaddw.xyzw vf3, vf8, vf3 \n\t"
"vmulax.xyzw ACC, vf5, vf4 \n\t"
"vmadday.xyzw ACC, vf6, vf4 \n\t"
"vmaddaz.xyzw ACC, vf7, vf4 \n\t"
"vmaddw.xyzw vf4, vf8, vf4 \n\t"
"sqc2 vf1, 0x00(%0) \n\t"
"sqc2 vf2, 0x10(%0) \n\t"
"sqc2 vf3, 0x20(%0) \n\t"
"sqc2 vf4, 0x30(%0) \n\t"
:
: "r"(result.data), "r"(this->data), "r"(t.data)
: "memory");
return result;
} }
void Matrix::operator*=(const Matrix &t) void Matrix::setCamera(const float t_pos[4], const float t_vz[4], const float t_vy[4])
{
// Matrix vf4, vf5, vf6, vf7
// t_pos vf8
// t_vz vf9
// t_vy vf10
// vtmp vf11
asm volatile(
"lqc2 vf9, 0x00(%2) \n\t"
"lqc2 vf10, 0x00(%3) \n\t"
// mtmp.unit()
"vsub.w vf5, vf0, vf0 # mtmp[1][PW] = 0.0F \n\t"
// vtmp.outerProduct(vy, vz);
"vopmula.xyz ACC, vf10, vf9 \n\t"
"vopmsub.xyz vf11, vf9, vf10 \n\t"
// mtmp[0] = vtmp.normalize();
"vmul.xyz vf12, vf11, vf11 \n\t"
"vaddy.x vf12, vf12, vf12 \n\t"
"vaddz.x vf12, vf12, vf12 \n\t"
"vrsqrt Q, vf0w, vf12x \n\t"
"vsub.xyzw vf4, vf0, vf0 \n\t"
"vwaitq \n\t"
"vmulq.xyz vf4, vf11, Q \n\t"
// mtmp[2] = vz.normalize();
"vmul.xyz vf12, vf9, vf9 \n\t"
"vaddy.x vf12, vf12, vf12 \n\t"
"vaddz.x vf12, vf12, vf12 \n\t"
"vrsqrt Q, vf0w, vf12x \n\t"
"vsub.xyzw vf6, vf0, vf0 \n\t"
"vwaitq \n\t"
"vmulq.xyz vf6, vf9, Q \n\t"
// mtmp[1].outerProduct(mtmp[2], mtmp[0]);
"vopmula.xyz ACC, vf6, vf4 \n\t"
"vopmsub.xyz vf5, vf4, vf6 \n\t"
// mtmp.transpose(pos);
"lqc2 vf7, 0x00(%1) \n\t"
// m = mtmp.inverse();
"qmfc2.ni $11, vf0 \n\t"
"qmfc2.ni $8, vf4 \n\t"
"qmfc2.ni $9, vf5 \n\t"
"qmfc2.ni $10, vf6 \n\t"
"pextlw $12, $9, $8 \n\t"
"pextuw $13, $9, $8 \n\t"
"pextlw $14, $11, $10 \n\t"
"pextuw $15, $11, $10 \n\t"
"pcpyld $8, $14, $12 \n\t"
"pcpyud $9, $12, $14 \n\t"
"pcpyld $10, $15, $13 \n\t"
"qmtc2.ni $8, vf16 \n\t"
"qmtc2.ni $9, vf17 \n\t"
"qmtc2.ni $10, vf18 \n\t"
"vmulax.xyz ACC, vf16, vf7 \n\t"
"vmadday.xyz ACC, vf17, vf7 \n\t"
"vmaddz.xyz vf5, vf18, vf7 \n\t"
"vsub.xyzw vf5, vf0, vf5 \n\t"
"sq $8, 0x00(%0) \n\t"
"sq $9, 0x10(%0) \n\t"
"sq $10, 0x20(%0) \n\t"
"sqc2 vf5, 0x30(%0) \n\t"
:
: "r"(this->data), "r"(t_pos), "r"(t_vz), "r"(t_vy));
}
void Matrix::cross(float res[16], const float a[16], const float b[16]) const
{ {
asm volatile( asm volatile(
"lqc2 vf1, 0x00(%1) \n\t" "lqc2 vf1, 0x00(%1) \n\t"
@@ -197,127 +373,6 @@ void Matrix::operator*=(const Matrix &t)
"sqc2 vf3, 0x20(%0) \n\t" "sqc2 vf3, 0x20(%0) \n\t"
"sqc2 vf4, 0x30(%0) \n\t" "sqc2 vf4, 0x30(%0) \n\t"
: :
: "r"(this->data), "r"(this->data), "r"(t.data) : "r"(res), "r"(b), "r"(a)
: "memory"); : "memory");
} }
/** Create empty matrix */
Matrix::Matrix()
{
data[0] = 0.0F;
data[1] = 0.0F;
data[2] = 0.0F;
data[3] = 0.0F;
data[4] = 0.0F;
data[5] = 0.0F;
data[6] = 0.0F;
data[7] = 0.0F;
data[8] = 0.0F;
data[9] = 0.0F;
data[10] = 0.0F;
data[11] = 0.0F;
data[12] = 0.0F;
data[13] = 0.0F;
data[14] = 0.0F;
data[15] = 0.0F;
}
Matrix::~Matrix() {}
// ----
// Methods
// ----
/** Set up a perspective projection matrix
*
* Clone of gluPerspective()
* https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/gluPerspective.xml
* @param fov (FOV in radians)/2
* @param aspect Aspect ratio
* @param scrW Half of screen width
* @param scrH Half of screen height
* @param zNear Distance to near plane
* @param zFar Distance to far plane
* @param projScale Projection scale
*/
void Matrix::setPerspective(ScreenSettings &t_screen)
{
float fovYdiv2 = Math::HALF_ANG2RAD * t_screen.fov;
float cotFOV = 1.0F / (Math::sin(fovYdiv2) / Math::cos(fovYdiv2));
float w = cotFOV * (t_screen.width / t_screen.projectionScale) / t_screen.aspectRatio;
float h = cotFOV * (t_screen.height / t_screen.projectionScale);
this->data[0] = w;
this->data[1] = 0.0F;
this->data[2] = 0.0F;
this->data[3] = 0.0F;
this->data[4] = 0.0F;
this->data[5] = -h;
this->data[6] = 0.0F;
this->data[7] = 0.0F;
this->data[8] = 0.0F;
this->data[9] = 0.0F;
this->data[10] =
(t_screen.farPlaneDist + t_screen.nearPlaneDist) /
(t_screen.farPlaneDist - t_screen.nearPlaneDist);
this->data[11] = -1.0F;
this->data[12] = 0.0F;
this->data[13] = 0.0F;
this->data[14] =
(2.0F * t_screen.farPlaneDist * t_screen.nearPlaneDist) /
(t_screen.farPlaneDist - t_screen.nearPlaneDist);
this->data[15] = 0.0F;
}
/** Create a view matrix that transforms coordinates in
* such a way that the user looks at a target vector
* direction from a position vector.
*
* Clone of OpenGL lookAt function
* https://learnopengl.com/Getting-started/Camera
*/
void Matrix::lookAt(Vector3 &t_up, Vector3 &t_position, Vector3 &t_target)
{
Vector3 camForward, camUp, camRight;
camForward = t_position - t_target;
camForward.normalize();
camRight = t_up * camForward;
camRight.normalize();
camUp = camForward * camRight;
data[0] = camRight.x;
data[4] = camRight.y;
data[8] = camRight.z;
data[12] = -camRight.innerProduct(t_position);
data[1] = camUp.x;
data[5] = camUp.y;
data[9] = camUp.z;
data[13] = -camUp.innerProduct(t_position);
data[2] = camForward.x;
data[6] = camForward.y;
data[10] = camForward.z;
data[14] = -camForward.innerProduct(t_position);
data[3] = 0;
data[7] = 0;
data[11] = 0;
data[15] = 1;
}
const void Matrix::print() const
{
printf("MATRIX(\n%f, %f, %f, %f\n%f, %f, %f, %f\n%f, %f, %f, %f\n%f, %f, %f, %f\n)\n",
data[0], data[1], data[2], data[3],
data[4], data[5], data[6], data[7],
data[8], data[9], data[10], data[11],
data[12], data[13], data[14], data[15]);
}
+100 -181
View File
@@ -9,63 +9,24 @@
*/ */
#include "../../include/models/math/vector3.hpp" #include "../../include/models/math/vector3.hpp"
#include "../../include/utils/math.hpp" #include "../../include/utils/math.hpp"
#include <stdio.h>
// ---- // ----
// Constructors/Destructors // Constructors/Destructors
// ---- // ----
/** Create by specifying 3 points */
Vector3::Vector3(float t_x, float t_y, float t_z)
{
x = t_x;
y = t_y;
z = t_z;
}
/** Create with another vector values */
Vector3::Vector3(const Vector3 &another)
{
x = another.x;
y = another.y;
z = another.z;
}
void Vector3::setByLerp(const Vector3 &v1, const Vector3 &v2, const float &t_interp, const float &t_scale)
{
asm volatile(
"lqc2 vf4, 0x0(%1) \n\t" // vf4 = v1
"lqc2 vf5, 0x0(%2) \n\t" // vf5 = v2
"mfc1 $8, %3 \n\t" // vf6 = t
"qmtc2 $8, vf6 \n\t" // lerp:
"vsub.xyz vf7, vf5, vf4 \n\t" // vf7 = v2 - v1
"vmulx.xyz vf8, vf7, vf6 \n\t" // vf8 = vf7 * t
"vadd.xyz vf9, vf8, vf4 \n\t" // vf9 = vf8 + vf4
"sqc2 vf9, 0x0(%0) \n\t" // v0 = vf9
:
: "r"(&this->xyz), "r"(&v1.xyz), "r"(&v2.xyz), "f"(t_interp));
x *= t_scale;
y *= t_scale;
z *= t_scale;
}
/** Create empty vector */
Vector3::Vector3() Vector3::Vector3()
{ {
x = 0; x = 0.0F;
y = 0; y = 0.0F;
z = 0; z = 0.0F;
} }
Vector3::~Vector3() {}
// ---- // ----
// Methods // Operators
// ---- // ----
Vector3 Vector3::operator+(Vector3 v) Vector3 Vector3::operator+(const Vector3 &v) const
{ {
Vector3 result; Vector3 result;
asm volatile( // VU0 Macro program asm volatile( // VU0 Macro program
@@ -78,7 +39,7 @@ Vector3 Vector3::operator+(Vector3 v)
return result; return result;
} }
Vector3 Vector3::operator-(const Vector3 &v) Vector3 Vector3::operator-(const Vector3 &v) const
{ {
Vector3 result; Vector3 result;
asm volatile( // VU0 Macro program asm volatile( // VU0 Macro program
@@ -91,17 +52,7 @@ Vector3 Vector3::operator-(const Vector3 &v)
return result; return result;
} }
Vector3 Vector3::operator-(void) Vector3 Vector3::operator*(const Vector3 &v) const
{
Vector3 result;
result.x = -x;
result.y = -y;
result.z = -z;
return result;
}
/** Also called "cross product" */
Vector3 Vector3::operator*(Vector3 &v)
{ {
Vector3 res; Vector3 res;
asm volatile( // VU0 Macro program asm volatile( // VU0 Macro program
@@ -119,7 +70,7 @@ Vector3 Vector3::operator*(Vector3 &v)
return res; return res;
} }
Vector3 Vector3::operator*(const float &t) Vector3 Vector3::operator*(const float &t) const
{ {
Vector3 result; Vector3 result;
asm volatile( asm volatile(
@@ -133,6 +84,26 @@ Vector3 Vector3::operator*(const float &t)
return result; return result;
} }
Vector3 Vector3::operator/(const float &t) const
{
Vector3 result;
result.x = x / t;
result.y = y / t;
result.z = z / t;
return result;
}
void Vector3::operator+=(const Vector3 &t)
{
asm volatile( // VU0 Macro program
"lqc2 vf4, 0x0(%0) \n\t"
"lqc2 vf5, 0x0(%1) \n\t"
"vadd.xyz vf4, vf4, vf5 \n\t"
"sqc2 vf4, 0x0(%0) \n\t"
:
: "r"(this->xyz), "r"(t.xyz));
}
void Vector3::operator*=(const float &t) void Vector3::operator*=(const float &t)
{ {
asm volatile( asm volatile(
@@ -145,54 +116,46 @@ void Vector3::operator*=(const float &t)
: "r"(this->xyz), "f"(t)); : "r"(this->xyz), "f"(t));
} }
Vector3 Vector3::operator/(float t) // ----
// Functions
// ----
void Vector3::set(const Vector3 &v)
{ {
Vector3 result; asm volatile( // VU0 Macro program
result.x = x / t; "lq $6, 0x0(%1) \n\t"
result.y = y / t; "sq $6, 0x0(%0) \n\t"
result.z = z / t; :
: "r"(this->xyz), "r"(v.xyz));
}
void Vector3::set(const float &t_x, const float &t_y, const float &t_z)
{
x = t_x;
y = t_y;
z = t_z;
}
float Vector3::innerProduct(const Vector3 &v) const
{
float result;
asm volatile( // VU0 Macro program
"lqc2 vf4, 0x0(%1) \n\t"
"lqc2 vf5, 0x0(%2) \n\t"
"vmul.xyz vf6, vf4, vf5 \n\t"
"vaddy.x vf6, vf6, vf6 \n\t"
"vaddz.x vf6, vf6, vf6 \n\t"
"qmfc2 $2, vf6 \n\t"
"mtc1 $2, %0 \n\t"
: "=f"(result)
: "r"(this->xyz), "r"(v.xyz));
return result; return result;
// return (x * v.x + y * v.y + z * v.z);
} }
u8 Vector3::shouldBeBackfaceCulled(const Vector3 *t_cameraPos, const Vector3 *v0, const Vector3 *v1, const Vector3 *v2) float Vector3::length() const
{ {
register float dot; float result;
asm volatile(
"lqc2 vf4, 0x0(%1) \n\t" // vf4 = cameraPos
"lqc2 vf5, 0x0(%2) \n\t" // vf5 = v0
"lqc2 vf6, 0x0(%3) \n\t" // vf6 = v1
"lqc2 vf7, 0x0(%4) \n\t" // vf7 = v2
"vsub.xyz vf8, vf7, vf5 \n\t" // vf8 = vf7(v2) - vf5(v0)
"vsub.xyz vf9, vf6, vf5 \n\t" // vf9 = vf6(v1) - vf5(v0)
"vopmula.xyz ACC, vf8, vf9 \n\t" // vf6 = cross(vf8, vf9)
"vopmsub.xyz vf6, vf9, vf8 \n\t"
"vsub.w vf6, vf6, vf6 \n\t"
"vsub.xyz vf7, vf5, vf4 \n\t" // vf7 = vf5(v0) - vf4(cameraPos)
"vmul.xyz vf5, vf7, vf6 \n\t" // vf5 = dot(vf7, vf6)
"vaddy.x vf5, vf5, vf5 \n\t"
"vaddz.x vf5, vf5, vf5 \n\t"
"qmfc2 $2, vf5 \n\t" // store result on `dot` variable
"mtc1 $2, %0 \n\t"
: "=f"(dot)
: "r"(t_cameraPos->xyz), "r"(v0->xyz), "r"(v1->xyz), "r"(v2->xyz));
return dot <= 0.0F;
}
/** Checks intersection with given square */
u8 Vector3::collidesSquare(const Vector3 &t_min, const Vector3 &t_max) const
{
return ((this->x <= t_max.x && this->x >= t_min.x) && (this->y < t_max.y && this->y >= t_min.y) && (this->z <= t_max.z && this->z >= t_min.z)) ? 1 : 0;
}
/** Checks is this vector is on given square */
u8 Vector3::isOnSquare(const Vector3 &t_min, const Vector3 &t_max) const
{
return ((this->x <= t_max.x && this->x >= t_min.x) && (this->y >= t_max.y) && (this->z <= t_max.z && this->z >= t_min.z)) ? 1 : 0;
}
float Vector3::length()
{
register float result;
asm volatile( // VU0 Macro program asm volatile( // VU0 Macro program
"lqc2 vf4, 0x0(%1) \n\t" "lqc2 vf4, 0x0(%1) \n\t"
"vmul.xyz vf5, vf4, vf4 \n\t" "vmul.xyz vf5, vf4, vf4 \n\t"
@@ -227,85 +190,6 @@ void Vector3::normalize()
: "r"(this->xyz)); : "r"(this->xyz));
} }
/** Also called dot3 */
float Vector3::innerProduct(Vector3 &v)
{
register float result;
asm volatile( // VU0 Macro program
"lqc2 vf4, 0x0(%1) \n\t"
"lqc2 vf5, 0x0(%2) \n\t"
"vmul.xyz vf6, vf4, vf5 \n\t"
"vaddy.x vf6, vf6, vf6 \n\t"
"vaddz.x vf6, vf6, vf6 \n\t"
"qmfc2 $2, vf6 \n\t"
"mtc1 $2, %0 \n\t"
: "=f"(result)
: "r"(this->xyz), "r"(v.xyz));
return result;
// return (x * v.x + y * v.y + z * v.z);
}
void Vector3::set(const float &t_x, const float &t_y, const float &t_z)
{
x = t_x;
y = t_y;
z = t_z;
}
void Vector3::rotate(const Vector3 &v, u8 inversed)
{
VECTOR cameraPos = {x, y, z, 0.0F};
VECTOR rotation;
if (inversed)
{
rotation[0] = -v.x;
rotation[1] = -v.y;
rotation[2] = -v.z;
}
else
{
rotation[0] = v.x;
rotation[1] = v.y;
rotation[2] = v.z;
}
rotation[3] = 0.0F;
MATRIX rotationMatrix;
matrix_unit(rotationMatrix);
matrix_rotate(rotationMatrix, rotationMatrix, rotation);
VECTOR result;
asm volatile(
"lqc2 vf4, 0x0(%1) \n\t"
"lqc2 vf5, 0x10(%1) \n\t"
"lqc2 vf6, 0x20(%1) \n\t"
"lqc2 vf7, 0x30(%1) \n\t"
"lqc2 vf8, 0x0(%2) \n\t"
"vmulax.xyzw ACC, vf4, vf8 \n\t"
"vmadday.xyzw ACC, vf5, vf8 \n\t"
"vmaddaz.xyzw ACC, vf6, vf8 \n\t"
"vmaddw.xyzw vf9, vf7, vf8 \n\t"
"sqc2 vf9, 0x0(%0) \n\t"
:
: "r"(&result), "r"(&rotationMatrix), "r"(&cameraPos));
set(Vector3(result[0], result[1], result[2]));
}
void Vector3::set(const Vector3 &v)
{
this->x = v.x;
this->y = v.y;
this->z = v.z;
}
void Vector3::copy(Vector3 &v)
{
asm volatile( // VU0 Macro program
"lq $6, 0x0(%1) \n\t"
"sq $6, 0x0(%0) \n\t"
:
: "r"(v.xyz), "r"(this->xyz));
}
float Vector3::distanceTo(const Vector3 &v) const float Vector3::distanceTo(const Vector3 &v) const
{ {
register float result; register float result;
@@ -329,7 +213,42 @@ float Vector3::distanceTo(const Vector3 &v) const
// (this->z - v.z) * (this->z - v.z)); // (this->z - v.z) * (this->z - v.z));
} }
const void Vector3::print() const u8 Vector3::shouldBeBackfaceCulled(const Vector3 *t_cameraPos, const Vector3 *t_v0, const Vector3 *t_v1, const Vector3 *t_v2)
{ {
printf("Vector3(%f, %f, %f)\n", x, y, z); register float dot;
asm volatile(
"lqc2 vf4, 0x0(%1) \n\t" // vf4 = cameraPos
"lqc2 vf5, 0x0(%2) \n\t" // vf5 = v0
"lqc2 vf6, 0x0(%3) \n\t" // vf6 = v1
"lqc2 vf7, 0x0(%4) \n\t" // vf7 = v2
"vsub.xyz vf8, vf7, vf5 \n\t" // vf8 = vf7(v2) - vf5(v0)
"vsub.xyz vf9, vf6, vf5 \n\t" // vf9 = vf6(v1) - vf5(v0)
"vopmula.xyz ACC, vf8, vf9 \n\t" // vf6 = cross(vf8, vf9)
"vopmsub.xyz vf6, vf9, vf8 \n\t"
"vsub.w vf6, vf6, vf6 \n\t"
"vsub.xyz vf7, vf5, vf4 \n\t" // vf7 = vf5(v0) - vf4(cameraPos)
"vmul.xyz vf5, vf7, vf6 \n\t" // vf5 = dot(vf7, vf6)
"vaddy.x vf5, vf5, vf5 \n\t"
"vaddz.x vf5, vf5, vf5 \n\t"
"qmfc2 $2, vf5 \n\t" // store result on `dot` variable
"mtc1 $2, %0 \n\t"
: "=f"(dot)
: "r"(t_cameraPos->xyz), "r"(t_v0->xyz), "r"(t_v1->xyz), "r"(t_v2->xyz));
return dot <= 0.0F;
}
void Vector3::setByLerp(const Vector3 &t_v1, const Vector3 &t_v2, const float &t_interp, const float &t_scale)
{
asm volatile(
"lqc2 vf4, 0x0(%1) \n\t" // vf4 = v1
"lqc2 vf5, 0x0(%2) \n\t" // vf5 = v2
"mfc1 $8, %3 \n\t" // vf6 = t
"qmtc2 $8, vf6 \n\t" // lerp:
"vsub.xyz vf7, vf5, vf4 \n\t" // vf7 = v2 - v1
"vmulx.xyz vf8, vf7, vf6 \n\t" // vf8 = vf7 * t
"vadd.xyz vf9, vf8, vf4 \n\t" // vf9 = vf8 + vf4
"sqc2 vf9, 0x0(%0) \n\t" // v0 = vf9
:
: "r"(&this->xyz), "r"(&t_v1.xyz), "r"(&t_v2.xyz), "f"(t_interp));
operator*=(t_scale);
} }
+4 -4
View File
@@ -18,7 +18,7 @@
// Constructors/Destructors // Constructors/Destructors
// ---- // ----
CameraBase::CameraBase(ScreenSettings *t_screen, Vector3 *t_position, Vector3 *t_up) CameraBase::CameraBase(ScreenSettings *t_screen, Vector3 *t_position)
: screen(t_screen) : screen(t_screen)
{ {
PRINT_LOG("Initializing frustum"); PRINT_LOG("Initializing frustum");
@@ -30,7 +30,7 @@ CameraBase::CameraBase(ScreenSettings *t_screen, Vector3 *t_position, Vector3 *t
farHeight = tang * farPlaneDist; farHeight = tang * farPlaneDist;
farWidth = farHeight * screen->aspectRatio; farWidth = farHeight * screen->aspectRatio;
p_position = t_position; p_position = t_position;
p_up = t_up; up.set(0.0F, 1.0F, 0.0F);
PRINT_LOG("CameraBase initialized!"); PRINT_LOG("CameraBase initialized!");
} }
@@ -41,7 +41,7 @@ CameraBase::CameraBase(ScreenSettings *t_screen, Vector3 *t_position, Vector3 *t
void CameraBase::lookAt(Vector3 &t_target) void CameraBase::lookAt(Vector3 &t_target)
{ {
updatePlanes(t_target); updatePlanes(t_target);
worldView.lookAt(*p_up, *p_position, t_target); worldView.lookAt(*p_position, t_target);
} }
void CameraBase::updatePlanes(Vector3 t_target) void CameraBase::updatePlanes(Vector3 t_target)
@@ -51,7 +51,7 @@ void CameraBase::updatePlanes(Vector3 t_target)
Z = *p_position - t_target; Z = *p_position - t_target;
Z.normalize(); Z.normalize();
// X axis of camera of given "up" vector and Z axis // X axis of camera of given "up" vector and Z axis
X = *p_up * Z; X = up * Z;
X.normalize(); X.normalize();
// the real "up" vector is the cross product of Z and X // the real "up" vector is the cross product of Z and X
Y = Z * X; Y = Z * X;
+2 -2
View File
@@ -277,8 +277,8 @@ void Renderer::draw(Mesh &t_mesh, LightBulb *t_bulbs, u16 t_bulbsCount)
if (!t_mesh.isDataLoaded()) if (!t_mesh.isDataLoaded())
PRINT_ERR("Can't draw, because no mesh data was loaded!"); PRINT_ERR("Can't draw, because no mesh data was loaded!");
Vector3 rotatedCamera = Vector3(*renderData.cameraPosition); camRotation.rotation(-t_mesh.rotation);
rotatedCamera.rotate(t_mesh.rotation, true); Vector3 rotatedCamera = Vector3(camRotation * *renderData.cameraPosition);
if (t_mesh.getCurrentAnimationFrame() != t_mesh.getNextAnimationFrame()) if (t_mesh.getCurrentAnimationFrame() != t_mesh.getNextAnimationFrame())
t_mesh.animate(); t_mesh.animate();
+1 -4
View File
@@ -14,12 +14,9 @@
const float CAMERA_Y = 15.0F; const float CAMERA_Y = 15.0F;
Camera::Camera(ScreenSettings *t_screen) : CameraBase(t_screen, &position, &up) Camera::Camera(ScreenSettings *t_screen) : CameraBase(t_screen, &position)
{ {
verticalLevel = 30.0F; verticalLevel = 30.0F;
up.x = 0.0F;
up.y = 1.0F;
up.z = 0.0F;
} }
Camera::~Camera() {} Camera::~Camera() {}
+1 -2
View File
@@ -22,7 +22,7 @@ class Camera : public CameraBase
{ {
public: public:
Vector3 position,up, unitCirclePosition; Vector3 position, up, unitCirclePosition;
float horizontalLevel, verticalLevel; float horizontalLevel, verticalLevel;
Camera(ScreenSettings *t_screen); Camera(ScreenSettings *t_screen);
@@ -34,7 +34,6 @@ public:
protected: protected:
Vector3 *getPosition() { return &position; }; Vector3 *getPosition() { return &position; };
Vector3 *getUp() { return &up; };
ScreenSettings screen; ScreenSettings screen;
}; };
+1 -4
View File
@@ -19,13 +19,10 @@ const float CAMERA_Y = 30.0F;
// Constructors/Destructors // Constructors/Destructors
// ---- // ----
Camera::Camera(ScreenSettings *t_screen) : CameraBase(t_screen, &position, &up) Camera::Camera(ScreenSettings *t_screen) : CameraBase(t_screen, &position)
{ {
PRINT_LOG("Initializing camera"); PRINT_LOG("Initializing camera");
verticalLevel = 80.0F; verticalLevel = 80.0F;
up.x = 0.0F;
up.y = 1.0F;
up.z = 0.0F;
PRINT_LOG("Camera initialized!"); PRINT_LOG("Camera initialized!");
} }
-1
View File
@@ -35,7 +35,6 @@ public:
protected: protected:
Vector3 *getPosition() { return &position; }; Vector3 *getPosition() { return &position; };
Vector3 *getUp() { return &up; };
ScreenSettings screen; ScreenSettings screen;
}; };
+2 -2
View File
@@ -211,13 +211,13 @@ FloorsCheck *Player::checkFloors(const FloorManager &t_floorManager, const Vecto
for (u32 i = 0; i < t_floorManager.floorAmount; i++) for (u32 i = 0; i < t_floorManager.floorAmount; i++)
{ {
Utils::getMinMax(t_floorManager.floors[i].mesh, min, max); Utils::getMinMax(t_floorManager.floors[i].mesh, min, max);
if (result->currentFloor == NULL && this->mesh.position.isOnSquare(min, max)) if (result->currentFloor == NULL && this->mesh.position.isOnBox(min, max))
{ {
result->currentFloor = &t_floorManager.floors[i]; result->currentFloor = &t_floorManager.floors[i];
result->currFloorMin.set(min); result->currFloorMin.set(min);
result->currFloorMax.set(max); result->currFloorMax.set(max);
} }
if (result->willCollideFloor == NULL && t_nextPos.collidesSquare(min, max)) if (result->willCollideFloor == NULL && t_nextPos.collidesBox(min, max))
{ {
result->willCollideFloor = &t_floorManager.floors[i]; result->willCollideFloor = &t_floorManager.floors[i];
result->willCollideFloorMin.set(min); result->willCollideFloorMin.set(min);