You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

220 lines
7.9 KiB

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

//
// Created by Wouter Groeneveld on 08/07/20.
//
#include <gtest/gtest.h>
#include <math.h>
#include <libgba-bitmap-engine/matrixfx.h>
#include <libgba-bitmap-engine/math.h>
#include <libgba-bitmap-engine/mesh.h>
#include <libgba-bitmap-engine/camera.h>
#include <libgba-bitmap-engine/renderer/gba_engine.h>
#include <libgba-bitmap-engine/gba/toolbox.h>
class MatrixFxSuite : public ::testing::Test {
protected:
virtual void TearDown() {
}
virtual void SetUp() {
}
};
INLINE float rnd2(float val) {
return (float) ((std::floor(val * 10) + .5) / 10);
}
void assertMatrix(MatrixFx expected, MatrixFx actual, std::string matrixName) {
for(int i = 0; i < MATRIX_DIMENSION; i++) {
auto expect = expected.mAt(i);
auto act = actual.mAt(i);
// WHY check the rounded floats instead of fixed numbers? conversion issues. -256 and -257 should be 'equal'
float expectFl = rnd2(fx2float(expect));
float actFl = rnd2(fx2float(act));
ASSERT_EQ(expectFl, actFl) << matrixName << "[" << i << "] does not match: (exp, act) " << expect << ", " << act << " - floats: " << expectFl << ", " << actFl;
}
}
TEST_F(MatrixFxSuite, RotationMatriches) {
auto result = MatrixFx::rotationZ(0);
auto expectedIdMatrix = MatrixFx(float2fx(1.0), 0, 0, 0, 0, float2fx(1.0), 0, 0, 0, 0, float2fx(1.0), 0, 0, 0, 0, float2fx(1.0));
assertMatrix(expectedIdMatrix, result, "rotz");
}
TEST_F(MatrixFxSuite, RotationYawPitchRoll_WithoutRotations) {
auto expectedIdMatrix = MatrixFx(float2fx(1.0), 0, 0, 0, 0, float2fx(1.0), 0, 0, 0, 0, float2fx(1.0), 0, 0, 0, 0, float2fx(1.0));
auto rotYwaPitchRoll = MatrixFx::rotationYawPitchRoll(0, 0, 0);
assertMatrix(expectedIdMatrix, rotYwaPitchRoll, "rotywa");
}
TEST_F(MatrixFxSuite, RotationYawPitchRoll_WithRotations) {
auto expectedMatrix = MatrixFx::fromFloat(
0.9074467814501962, 0, -0.4201670368266409, 0,
0.17654033883567982, 0.9074467814501962, 0.38127922523980134, 0,
0.38127922523980134, -0.4201670368266409, 0.8234596611643201, 0,
0, 0, 0, 1);
auto rotYwaPitchRoll = MatrixFx::rotationYawPitchRoll(int2fx(13), int2fx(13), 0);
assertMatrix(expectedMatrix, rotYwaPitchRoll, "rotywa");
}
TEST_F(MatrixFxSuite, TransformCoordinates) {
// test data taken from Babylon, first coord of cube to be transformed with calculated transfomatrix
auto transformation = MatrixFx::fromFloat(
-1.6218433160440375,
0,
0,
0,
0,
2.4327649740660564,
0,
0,
0,
0,
-1.0101010101010102,
-1,
0,
0,
10.090909090909092,
10);
auto result = MatrixFx::transformCoordinates(VectorFx::fromInt(-1, 1, 1), transformation);
// expected result: Vector3 {x: 0.18020481289378196, y: 0.2703072193406729, z: 1.0089786756453423}
ASSERT_FLOAT_EQ(fx2float(result.x()), 0.1796875);
ASSERT_FLOAT_EQ(fx2float(result.y()), 0.26953125);
ASSERT_FLOAT_EQ(fx2float(result.z()), 1.0078125);
result = MatrixFx::transformCoordinates(VectorFx::fromInt(-1, -1, -1), transformation);
// expected result: Vector3 {x: 0.14744030145854886, y: -0.22116045218782332, z: 1.0091827364554637}
ASSERT_FLOAT_EQ(fx2float(result.x()), 0.14453125);
ASSERT_FLOAT_EQ(fx2float(result.y()), -0.21875);
ASSERT_FLOAT_EQ(fx2float(result.z()), 1.0078125);
}
TEST_F(MatrixFxSuite, MeshToTransformMatrix_IntegrationTest) {
// source:
Mesh cube;
cube.add(VectorFx(-1, 1, 1));
cube.add(VectorFx(1, 1, 1));
cube.add(VectorFx(-1, -1, 1));
cube.add(VectorFx(-1, -1, -1));
cube.add(VectorFx(-1, 1, -1));
cube.add(VectorFx(1, 1, -1));
cube.add(VectorFx(1, -1, 1));
cube.add(VectorFx(-1, -1, -1));
auto currentCamera = Camera(VectorFx::fromInt(0, 0, 10), VectorFx::fromInt(0, 0, 0));
auto viewMatrix = MatrixFx::lookAtLH(currentCamera.getPosition(), currentCamera.getTarget(), VectorFx::up());
auto projectionMatrix = MatrixFx::perspectiveFovLH(float2fx(0.78), fxdiv(GBA_SCREEN_WIDTH_FX, GBA_SCREEN_HEIGHT_FX), float2fx(0.01), ONE);
auto expectedProjectionMatrix = MatrixFx(float2fx(1.64f), 0, 0, 0, 0, float2fx(2.55f), 0, 0, 0, 0, float2fx(1.05), float2fx(1.05), 0, 0, float2fx(-0.05), 0);
assertMatrix(expectedProjectionMatrix, projectionMatrix, "project");
auto expectedIdMatrix = MatrixFx(float2fx(1.0), 0, 0, 0, 0, float2fx(1.0), 0, 0, 0, 0, float2fx(1.0), 0, 0, 0, 0, float2fx(1.0));
auto rotYwaPitchRoll = MatrixFx::rotationYawPitchRoll(cube.roty(), cube.rotx(), cube.rotz());
assertMatrix(expectedIdMatrix, rotYwaPitchRoll, "rotywa");
auto translatedPos = MatrixFx::translation(cube.position());
assertMatrix(expectedIdMatrix, translatedPos, "translpos");
auto worldMatrix = rotYwaPitchRoll * translatedPos;
assertMatrix(expectedIdMatrix, worldMatrix, "worldmatrix");
auto transformMatrix = worldMatrix * viewMatrix * projectionMatrix;
auto expectedTransformMatrix = MatrixFx(float2fx(-1.67), 0, 0, 0, 0, float2fx(2.55), 0, 0, 0, 0, float2fx(-1.0), float2fx(-1.0), 0, 0, float2fx(9.85), float2fx(9.75));
assertMatrix(expectedTransformMatrix, transformMatrix, "transfomatrix");
auto coord = *cube.vertices()[0].get();
auto point = MatrixFx::transformCoordinates(coord, transformMatrix);
ASSERT_FLOAT_EQ(fx2float(point.x()), 0);
ASSERT_FLOAT_EQ(fx2float(point.y()), 0);
ASSERT_FLOAT_EQ(fx2float(point.z()), 1.0039062);
auto x = fxmul(point.x(), GBA_SCREEN_WIDTH_FX) + fxdiv(GBA_SCREEN_WIDTH_FX, int2fx(2));
auto y = fxmul(-point.y(), GBA_SCREEN_HEIGHT_FX) + fxdiv(GBA_SCREEN_HEIGHT_FX, int2fx(2));
ASSERT_EQ(fx2float(x), 120);
ASSERT_EQ(fx2float(y), 80);
// dest in Babylon - dest according to for loop below - dest printed using TextStream (should print something roughly similar)
/*
* 0 163, 36 - 150,40 - 165, 34
* 1 76, 36 - 60,40 - 75, 34
* 2 163, 123 - 150,140 - 165, 125
* 3 155, 115 - 93,26 - 75, 34 (same as 0)
* 4 155, 44 - 93,115 - 75, 125
* 5 84, 44 - 172,115 - 165, 125 (same as 2)
* 6 76, 123 - 60,140 - 75, 125 (same as 4)
* 7 84, 115 - 93,26 - 165, 34 (same as 0)
*
*/
for(auto& vertex : cube.vertices()) {
auto point = MatrixFx::transformCoordinates(*vertex.get(), transformMatrix);
auto x = fxmul(point.x(), GBA_SCREEN_WIDTH_FX) + fxdiv(GBA_SCREEN_WIDTH_FX, int2fx(2));
auto y = fxmul(-point.y(), GBA_SCREEN_HEIGHT_FX) + fxdiv(GBA_SCREEN_HEIGHT_FX, int2fx(2));
std::cout << "plotting (" << fx2int(x) << "," << fx2int(y) << ")" << std::endl;
}
}
TEST_F(MatrixFxSuite, lookAtLH_TestData) {
/*
* IN:
* eye 0, 0, 10
* taget: 0, 0, 0
* up: 0, 1, 0
* OUT:
0: -1
1: 0
2: 0
3: 0
4: 0
5: 1
6: 0
7: 0
8: 0
9: 0
10: -1
11: 0
12: -0
13: -0
14: 10
15: 1
*/
auto eye = VectorFx::fromInt(0, 0, 10);
auto target = VectorFx::fromInt(0, 0, 0);
auto up = VectorFx::up();
auto result = MatrixFx::lookAtLH(eye, target, up);
auto expected = MatrixFx(-257, 0, 0, 0, 0, 256, 0, 0, 0, 0, -250, 0, 0, 0, 2500, 256);
assertMatrix(expected, result, "M");
}
TEST_F(MatrixFxSuite, 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 = MatrixFx::perspectiveFovLH(float2fx(0.78), float2fx(1.6), float2fx(0.01), float2fx(1));
auto expected = MatrixFx::fromFloat(1.565f, 0, 0, 0, 0, 2.505f, 0, 0, 0, 0, 1.005f, 1, 0, 0, -0.005f, 0);
assertMatrix(expected, result, "M");
}