parent
27e6a9065c
commit
aedb3cdfcb
@ -0,0 +1,74 @@
|
||||
//
|
||||
// Created by Wouter Groeneveld on 08/07/20.
|
||||
//
|
||||
|
||||
#ifndef GBA_BITMAP_ENGINE_PROJECT_GBAMATRIX_H
|
||||
#define GBA_BITMAP_ENGINE_PROJECT_GBAMATRIX_H
|
||||
|
||||
#define MATRIX_DIMENSION 16
|
||||
|
||||
#ifdef CODE_COMPILED_AS_PART_OF_TEST
|
||||
#include <libgba-sprite-engine/gba/tonc_math_stub.h>
|
||||
#else
|
||||
#include <libgba-sprite-engine/gba/tonc_math.h>
|
||||
#endif
|
||||
|
||||
FIXED HALF = float2fx(0.5);
|
||||
FIXED ONE = int2fx(1);
|
||||
|
||||
class GBAMatrix {
|
||||
private:
|
||||
FIXED m[MATRIX_DIMENSION];
|
||||
|
||||
public:
|
||||
inline static FIXED tan(FIXED angle) {
|
||||
FIXED sin = lu_sin(angle) >> 4;
|
||||
FIXED cos = lu_cos(angle) >> 4;
|
||||
|
||||
return fxdiv(sin, cos);
|
||||
}
|
||||
|
||||
inline static GBAMatrix zero() { return GBAMatrix(); }
|
||||
inline FIXED mAt(int index) const {
|
||||
return m[index];
|
||||
}
|
||||
GBAMatrix() {}
|
||||
GBAMatrix(FIXED m11, FIXED m12, FIXED m13, FIXED m14, FIXED m21, FIXED m22, FIXED m23, FIXED m24, FIXED m31, FIXED m32, FIXED m33, FIXED m34, FIXED m41, FIXED m42, FIXED m43, FIXED m44) {
|
||||
m[0] = m11;
|
||||
m[1] = m12;
|
||||
m[2] = m13;
|
||||
m[3] = m14;
|
||||
|
||||
m[4] = m21;
|
||||
m[5] = m22;
|
||||
m[6] = m23;
|
||||
m[7] = m24;
|
||||
|
||||
m[8] = m31;
|
||||
m[9] = m32;
|
||||
m[10] = m33;
|
||||
m[11] = m34;
|
||||
|
||||
m[12] = m41;
|
||||
m[13] = m42;
|
||||
m[14] = m43;
|
||||
m[15] = m44;
|
||||
}
|
||||
|
||||
inline static GBAMatrix perspectiveFovLH(FIXED fov, FIXED aspect, FIXED znear, FIXED zfar) {
|
||||
auto matrix = GBAMatrix::zero();
|
||||
FIXED tanResult = fxdiv(ONE, tan(fxmul(fov, HALF)));
|
||||
matrix.m[0] = fxdiv(tanResult, aspect);
|
||||
matrix.m[1] = matrix.m[2] = matrix.m[3] = 0;
|
||||
matrix.m[5] = tanResult;
|
||||
matrix.m[4] = matrix.m[6] = matrix.m[7] = 0;
|
||||
matrix.m[8] = matrix.m[9] = 0;
|
||||
matrix.m[10] = fxdiv(-zfar, (znear - zfar));
|
||||
matrix.m[11] = ONE;
|
||||
matrix.m[12] = matrix.m[13] = matrix.m[15] = 0;
|
||||
matrix.m[14] = fxdiv(fxmul(znear, zfar), (znear - zfar));
|
||||
return matrix;
|
||||
}
|
||||
};
|
||||
|
||||
#endif //GBA_BITMAP_ENGINE_PROJECT_GBAMATRIX_H
|
@ -1,33 +1,97 @@
|
||||
//
|
||||
// Created by Wouter Groeneveld on 14/12/18.
|
||||
// This is a FIXED-POINT VECTOR REPRESENTATION!
|
||||
// Wrapper around Tonc's VECTOR for convenience and readability.
|
||||
//
|
||||
|
||||
#ifndef GBA_SPRITE_ENGINE_PROJECT_MATH_H
|
||||
#define GBA_SPRITE_ENGINE_PROJECT_MATH_H
|
||||
#ifndef GBA_VECTOR_H_
|
||||
#define GBA_VECTOR_H_
|
||||
|
||||
#include <string>
|
||||
#include <deque>
|
||||
#include <libgba-sprite-engine/gba/tonc_bios.h>
|
||||
|
||||
#ifdef CODE_COMPILED_AS_PART_OF_TEST
|
||||
#include <libgba-sprite-engine/gba/tonc_math_stub.h>
|
||||
#include <libgba-sprite-engine/gba/tonc_math_stub.h>
|
||||
#else
|
||||
#include <libgba-sprite-engine/gba/tonc_math.h>
|
||||
#include <libgba-sprite-engine/gba/tonc_math.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
class GBAVector {
|
||||
private:
|
||||
VECTOR v;
|
||||
public:
|
||||
GBAVector() : v({}) {}
|
||||
GBAVector(const GBAVector& other) : v(other.v) {}
|
||||
GBAVector(VECTOR v) : v(v) {}
|
||||
GBAVector(FIXED x, FIXED y, FIXED z) : v({ x, y, z}) {}
|
||||
|
||||
static GBAVector fromInt(int x, int y, int z) {
|
||||
return GBAVector(int2fx(x), int2fx(y), int2fx(z));
|
||||
}
|
||||
|
||||
inline GBAVector toInt() {
|
||||
return GBAVector(fx2int(v.x), fx2int(v.y), fx2int(v.z));
|
||||
}
|
||||
|
||||
std::deque<VECTOR> bresenhamLineTo(VECTOR dest);
|
||||
VECTOR rotateAsCenter(VECTOR point, uint angle);
|
||||
GBAVector rotateAsCenter(GBAVector point, FIXED angle);
|
||||
|
||||
// WHY all these inlines? performance reasons.
|
||||
inline static GBAVector up() { return GBAVector(0, int2fx(1), 0); }
|
||||
inline static FIXED dot(const GBAVector &left, const GBAVector &right) {
|
||||
return (fxmul(left.v.x, right.v.x) + fxmul(left.v.y, right.v.y) + fxmul(left.v.z, right.v.z));
|
||||
}
|
||||
inline static GBAVector cross(const GBAVector &left, const GBAVector &right) {
|
||||
FIXED x = fxmul(left.v.y, right.v.z) - fxmul(left.v.z, right.v.y);
|
||||
FIXED y = fxmul(left.v.z, right.v.x) - fxmul(left.v.x, right.v.z);
|
||||
FIXED z = fxmul(left.v.x, right.v.y) - fxmul(left.v.y, right.v.x);
|
||||
return GBAVector(x, y, z);
|
||||
}
|
||||
|
||||
inline friend GBAVector operator+(const GBAVector &one, const GBAVector &two) {
|
||||
return GBAVector(one.v.x + two.v.x, one.v.y + two.v.y, one.v.z + two.v.z);
|
||||
}
|
||||
inline friend GBAVector operator-(const GBAVector &one, const GBAVector &two) {
|
||||
return GBAVector(one.v.x - two.v.x, one.v.y - two.v.y, one.v.z - two.v.z);
|
||||
}
|
||||
inline friend GBAVector operator*(const GBAVector &one, const GBAVector &two) {
|
||||
return GBAVector(fxmul(one.v.x, two.v.x), fxmul(one.v.y, two.v.y), fxmul(one.v.z, two.v.z));
|
||||
}
|
||||
inline friend GBAVector operator/(const GBAVector &one, const GBAVector &two) {
|
||||
return GBAVector(fxdiv(one.v.x, two.v.x), fxdiv(one.v.y, two.v.y), fxdiv(one.v.z, two.v.z));
|
||||
}
|
||||
inline FIXED length() {
|
||||
FIXED toRoot = fxmul(v.x, v.x) + fxmul(v.y, v.y) + fxmul(v.z, v.z);
|
||||
return Sqrt(toRoot);
|
||||
}
|
||||
inline GBAVector negate() {
|
||||
return GBAVector(-v.x, -v.y, -v.z);
|
||||
}
|
||||
inline GBAVector scale(int scale) {
|
||||
FIXED fac = int2fx(scale);
|
||||
return GBAVector(fxmul(v.x, fac), fxmul(v.y, fac), fxmul(v.z, fac));
|
||||
}
|
||||
inline void normalize() {
|
||||
auto len = length();
|
||||
if(len == 0) return;
|
||||
FIXED num = fxdiv(int2fx(1), len);
|
||||
v.x = fxmul(v.x, num);
|
||||
v.y = fxmul(v.y, num);
|
||||
v.z = fxmul(v.z, num);
|
||||
}
|
||||
|
||||
inline FIXED x() const { return v.x; }
|
||||
inline float floatX() const { return fx2float(v.x); }
|
||||
inline FIXED y() const { return v.y; }
|
||||
inline float floatY() const { return fx2float(v.y); }
|
||||
inline FIXED z() const { return v.z; }
|
||||
inline float floatZ() const { return fx2float(v.z); }
|
||||
|
||||
std::string to_string() {
|
||||
return "(" + std::to_string(v.x) + "," + std::to_string(v.y) + ")";
|
||||
}
|
||||
};
|
||||
|
||||
#endif //GBA_SPRITE_ENGINE_PROJECT_MATH_H
|
||||
#endif
|
||||
|
@ -0,0 +1,30 @@
|
||||
//
|
||||
// Created by Wouter Groeneveld on 08/07/20.
|
||||
//
|
||||
|
||||
#ifndef GBA_BITMAP_ENGINE_PROJECT_MESH_H
|
||||
#define GBA_BITMAP_ENGINE_PROJECT_MESH_H
|
||||
|
||||
#include "gbavector.h"
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
class Mesh {
|
||||
private:
|
||||
GBAVector position;
|
||||
GBAVector rotation;
|
||||
|
||||
std::vector<std::unique_ptr<GBAVector>> verticesArr;
|
||||
|
||||
public:
|
||||
|
||||
void add(GBAVector v);
|
||||
inline std::vector<std::unique_ptr<GBAVector>> const& vertices() const {
|
||||
return verticesArr;
|
||||
}
|
||||
explicit Mesh() {}
|
||||
Mesh(const Mesh&) = delete;
|
||||
Mesh& operator=(const Mesh&) = delete;
|
||||
};
|
||||
|
||||
#endif //GBA_BITMAP_ENGINE_PROJECT_MESH_H
|
@ -0,0 +1,12 @@
|
||||
//
|
||||
// Created by Wouter Groeneveld on 08/07/20.
|
||||
//
|
||||
|
||||
#include <libgba-sprite-engine/mesh.h>
|
||||
#include <memory>
|
||||
|
||||
|
||||
void Mesh::add(GBAVector v) {
|
||||
verticesArr.push_back(std::unique_ptr<GBAVector>(new GBAVector(v)));
|
||||
}
|
||||
|
@ -0,0 +1,83 @@
|
||||
//
|
||||
// Created by Wouter Groeneveld on 08/07/20.
|
||||
//
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <math.h>
|
||||
#include <cmath>
|
||||
#include <libgba-sprite-engine/gba/tonc_math_stub.h>
|
||||
|
||||
class FpSuite : public ::testing::Test {
|
||||
protected:
|
||||
virtual void TearDown() {
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
}
|
||||
};
|
||||
|
||||
float rnd(float val) {
|
||||
return (float) ((std::floor(val * 100) + .5) / 100);
|
||||
}
|
||||
|
||||
float gr2rad(uint grad) {
|
||||
return grad*M_PI/180;
|
||||
}
|
||||
|
||||
FIXED gr2lut(uint grad) {
|
||||
return 65535 / (360 / grad);
|
||||
}
|
||||
|
||||
FIXED rad2lut(float rad) {
|
||||
return gr2lut(rad * 180 / M_PI);
|
||||
}
|
||||
|
||||
float fx12ToFloat(FIXED fx) {
|
||||
return fx / (float) (1<<12);
|
||||
}
|
||||
|
||||
FIXED fx12Tofx8(FIXED fx12) {
|
||||
return fx12 >> 4;
|
||||
}
|
||||
|
||||
|
||||
// from LUT doxygen:
|
||||
//! Look-up a cosine value (2π = 0x10000)
|
||||
/*! \param theta Angle in [0,FFFFh] range => 65535
|
||||
* \return .12f cosine value
|
||||
*/
|
||||
TEST_F(FpSuite, LUTValueTests) {
|
||||
float rad = gr2rad(90); // 1/4th halfway; 90; 360 / 4
|
||||
std::cout << "90 degrees is " << rad << " rads" << std::endl;
|
||||
auto sinR = sin(rad);
|
||||
ASSERT_EQ(rnd(sinR), 1.005f);
|
||||
|
||||
//FIXED angle = gr2lut(90); // 128 is a quarter circle now
|
||||
FIXED angle = rad2lut(rad); // this also works!
|
||||
FIXED sinLut = lu_sin(angle);
|
||||
float sinLutConv12 = fx12ToFloat(sinLut); // indeed, fx2float() gives me 15.995 instead of 0.995! shit.
|
||||
float sinLutConv8 = fx2float(fx12Tofx8(sinLut)); // this also works!
|
||||
|
||||
std::cout << angle << " lu_sin is " << sinLut << " .12f and conv: " << sinLutConv12 << std::endl;
|
||||
ASSERT_EQ(rnd(sinLutConv12), 0.995f);
|
||||
ASSERT_EQ(rnd(sinLutConv8), 0.995f);
|
||||
}
|
||||
|
||||
TEST_F(FpSuite, TanUtilityTests) {
|
||||
// 20 degrees is 0.34906577777777775 rad
|
||||
// Math.sin(0.3...) / Math.cos(0.3...) = 0.3420 / 0.9396 = 0.3639...
|
||||
auto rad = gr2rad(20);
|
||||
auto tanRef = sin(rad) / cos(rad);
|
||||
auto realTan = tan(rad);
|
||||
ASSERT_EQ(rnd(tanRef), 0.365f);
|
||||
ASSERT_EQ(rnd(realTan), 0.365f);
|
||||
|
||||
FIXED lutalpha = rad2lut(rad);
|
||||
FIXED lusin = lu_sin(lutalpha), lucos = lu_cos(lutalpha);
|
||||
|
||||
std::cout << "sin(14) is " << fx12ToFloat(lusin) << " and cos(14) is " << fx12ToFloat(lucos) << std::endl;
|
||||
|
||||
auto tanFakeLookupTables = fx2float(fxdiv(fx12Tofx8(lu_sin(lutalpha)), fx12Tofx8(lu_cos(lutalpha))));
|
||||
ASSERT_EQ(rnd(tanFakeLookupTables), 0.355f);
|
||||
}
|
||||
|
@ -0,0 +1,55 @@
|
||||
//
|
||||
// Created by Wouter Groeneveld on 08/07/20.
|
||||
//
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <math.h>
|
||||
#include <libgba-sprite-engine/gbamatrix.h>
|
||||
|
||||
class GBAMatrixSuite : public ::testing::Test {
|
||||
protected:
|
||||
virtual void TearDown() {
|
||||
}
|
||||
|
||||
virtual void SetUp() {
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(GBAMatrixSuite, TanUtilityTests) {
|
||||
// Math.sin(14) / Math.cos(14) = 0.99 / 0.13 = 7.2446
|
||||
auto tanRef = sin(14) / cos(14);
|
||||
auto realTan = tan(14);
|
||||
ASSERT_EQ((std::floor(tanRef * 100) + .5) / 100, 7.245);
|
||||
ASSERT_EQ((std::floor(realTan * 100) + .5) / 100, 7.245);
|
||||
|
||||
auto tanFakeLookupTables = ((lu_sin(14)) / (lu_cos(14))) << 4;
|
||||
ASSERT_EQ((std::floor(tanFakeLookupTables * 100) + .5) / 100, 7.245);
|
||||
|
||||
auto result = fx2float(GBAMatrix::tan(int2fx(14)));
|
||||
ASSERT_EQ(result, 7.2446);
|
||||
}
|
||||
|
||||
TEST_F(GBAMatrixSuite, PerspectiveFovLH_TestData) {
|
||||
/* IN:
|
||||
* fov 0.78, aspect 1.6, znear 0.01, zfar 1
|
||||
* OUT:
|
||||
0: 1.520478108791285
|
||||
1: 0
|
||||
2: 0
|
||||
3: 0
|
||||
4: 0
|
||||
5: 2.4327649740660564
|
||||
6: 0
|
||||
7: 0
|
||||
8: 0
|
||||
9: 0
|
||||
10: 1.0101010101010102
|
||||
11: 1
|
||||
12: 0
|
||||
13: 0
|
||||
14: -0.010101010101010102
|
||||
15: 0
|
||||
*/
|
||||
auto result = GBAMatrix::perspectiveFovLH(float2fx(0.78), float2fx(1.6), float2fx(0.01), float2fx(1));
|
||||
ASSERT_EQ(fx2float(result.mAt(0)), 1.52);
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
//
|
||||
// Created by Wouter Groeneveld on 08/07/20.
|
||||
//
|
||||
|
||||
#ifndef GBA_BITMAP_ENGINE_PROJECT_TONC_BIOS_STUB_H
|
||||
#define GBA_BITMAP_ENGINE_PROJECT_TONC_BIOS_STUB_H
|
||||
|
||||
|
||||
namespace externMath {
|
||||
|
||||
#include <math.h>
|
||||
|
||||
float root(float num) {
|
||||
return sqrt(num);
|
||||
return 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
u32 Sqrt(u32 num) {
|
||||
return float2fx(externMath::root(fx2float(num)));
|
||||
}
|
||||
|
||||
|
||||
#endif //GBA_BITMAP_ENGINE_PROJECT_TONC_BIOS_STUB_H
|
Loading…
Reference in new issue