PerspectiveFovLH with fx2lut impl

This commit is contained in:
wgroeneveld 2020-07-08 20:54:56 +02:00
parent aedb3cdfcb
commit c6374b6e59
7 changed files with 110 additions and 49 deletions

View File

@ -9,6 +9,7 @@ add_library(${PROJECT_NAME}
src/gba/sin_lut.s
src/gba/tonc_bios.s
src/gba_engine.cpp
src/math.cpp
src/sound_control.cpp src/scene.cpp src/timer.cpp src/gbavector.cpp src/mesh.cpp)
target_include_directories(${PROJECT_NAME} PUBLIC

View File

@ -6,6 +6,7 @@
#define GBA_BITMAP_ENGINE_PROJECT_GBAMATRIX_H
#define MATRIX_DIMENSION 16
#include <libgba-sprite-engine/math.h>
#ifdef CODE_COMPILED_AS_PART_OF_TEST
#include <libgba-sprite-engine/gba/tonc_math_stub.h>
@ -13,20 +14,11 @@
#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 {
@ -57,7 +49,7 @@ public:
inline static GBAMatrix perspectiveFovLH(FIXED fov, FIXED aspect, FIXED znear, FIXED zfar) {
auto matrix = GBAMatrix::zero();
FIXED tanResult = fxdiv(ONE, tan(fxmul(fov, HALF)));
FIXED tanResult = fxdiv(ONE, fxtan(fxmul(fov, HALF)));
matrix.m[0] = fxdiv(tanResult, aspect);
matrix.m[1] = matrix.m[2] = matrix.m[3] = 0;
matrix.m[5] = tanResult;

View File

@ -0,0 +1,68 @@
//
// Created by Wouter Groeneveld on 08/07/20.
//
#ifndef GBA_BITMAP_ENGINE_PROJECT_MATH_H
#define GBA_BITMAP_ENGINE_PROJECT_MATH_H
#include <libgba-sprite-engine/gba/tonc_types.h>
#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 point math things that were missing from TONC
extern FIXED HALF;
extern FIXED ONE;
// -----
INLINE float gr2rad(uint grad);
INLINE FIXED gr2lut(uint grad);
INLINE FIXED rad2lut(float rad);
INLINE FIXED fxrad2lut(FIXED rad);
INLINE float fx12ToFloat(FIXED fx);
INLINE FIXED fx12Tofx8(FIXED fx12);
INLINE FIXED fxtan(FIXED fxrad);
INLINE float rnd(float val);
// ---- impl
INLINE float rnd(float val) {
return (float) ((std::floor(val * 100) + .5) / 100);
}
INLINE float gr2rad(uint grad) {
return grad*M_PI/180;
}
INLINE FIXED gr2lut(uint grad) {
return 65535 / (360 / grad);
}
INLINE FIXED rad2lut(float rad) {
return gr2lut(rad * 180 / M_PI);
}
INLINE FIXED fxrad2lut(FIXED rad) {
// TODO NOT good; too much divisions, but hey, fuck it
return rad2lut(fx2float(rad));
}
INLINE float fx12ToFloat(FIXED fx) {
return fx / (float) (1<<12);
}
INLINE FIXED fx12Tofx8(FIXED fx12) {
return fx12 >> 4;
}
INLINE FIXED fxtan(FIXED fxrad) {
FIXED theta = fxrad2lut(fxrad);
FIXED sin = fx12Tofx8(lu_sin(theta));
FIXED cos = fx12Tofx8(lu_cos(theta));
return fxdiv(sin, cos);
}
#endif //GBA_BITMAP_ENGINE_PROJECT_MATH_H

8
engine/src/math.cpp Normal file
View File

@ -0,0 +1,8 @@
//
// Created by Wouter Groeneveld on 08/07/20.
//
#include <libgba-sprite-engine/math.h>
FIXED HALF = float2fx(0.5);
FIXED ONE = int2fx(1);

View File

@ -33,6 +33,7 @@ add_executable(unittest
../engine/src/palette/palette_manager.cpp
../engine/src/palette/combined_palette.cpp
../engine/src/timer.cpp
../engine/src/math.cpp
../engine/src/gbavector.cpp
timertest.cpp gbavectortest.cpp gbamatrixtest.cpp fixedpoinmathtest.cpp)

View File

@ -6,6 +6,7 @@
#include <math.h>
#include <cmath>
#include <libgba-sprite-engine/gba/tonc_math_stub.h>
#include <libgba-sprite-engine/math.h>
class FpSuite : public ::testing::Test {
protected:
@ -16,30 +17,6 @@ protected:
}
};
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&#960; = 0x10000)
@ -63,6 +40,25 @@ TEST_F(FpSuite, LUTValueTests) {
ASSERT_EQ(rnd(sinLutConv8), 0.995f);
}
TEST_F(FpSuite, TanFromFixedPointRadian) {
// 20 degrees is 0.34906577777777775 rad
// will be stored as .8f as input val
FIXED angle = float2fx(0.34906577777777775f);
float result = fx2float(fxtan(angle));
ASSERT_EQ(rnd(result), 0.355f);
}
TEST_F(FpSuite, SinFromFixedPointRadInput) {
// 20 degrees is 0.34906577777777775 rad
FIXED angle = float2fx(0.34906577777777775f);
FIXED lusin = lu_sin(fxrad2lut(angle));
float result = fx12ToFloat(lusin);
ASSERT_EQ(rnd(result), 0.335f);
}
TEST_F(FpSuite, TanUtilityTests) {
// 20 degrees is 0.34906577777777775 rad
// Math.sin(0.3...) / Math.cos(0.3...) = 0.3420 / 0.9396 = 0.3639...
@ -75,7 +71,7 @@ TEST_F(FpSuite, TanUtilityTests) {
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;
std::cout << "sin(20) is " << fx12ToFloat(lusin) << " and cos(20) is " << fx12ToFloat(lucos) << std::endl;
auto tanFakeLookupTables = fx2float(fxdiv(fx12Tofx8(lu_sin(lutalpha)), fx12Tofx8(lu_cos(lutalpha))));
ASSERT_EQ(rnd(tanFakeLookupTables), 0.355f);

View File

@ -5,6 +5,7 @@
#include <gtest/gtest.h>
#include <math.h>
#include <libgba-sprite-engine/gbamatrix.h>
#include <libgba-sprite-engine/math.h>
class GBAMatrixSuite : public ::testing::Test {
protected:
@ -15,19 +16,6 @@ protected:
}
};
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:
@ -51,5 +39,12 @@ TEST_F(GBAMatrixSuite, PerspectiveFovLH_TestData) {
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);
// hmm... is this correct? rounding issues aside?
ASSERT_EQ(rnd(fx2float(result.mAt(0))), 1.565f);
ASSERT_EQ(fx2float(result.mAt(1)), 0);
ASSERT_EQ(rnd(fx2float(result.mAt(5))), 2.505f);
ASSERT_EQ(rnd(fx2float(result.mAt(10))), 1.005f);
ASSERT_EQ(rnd(fx2float(result.mAt(14))), -0.005f);
ASSERT_EQ(fx2float(result.mAt(15)), 0);
}