gba-bitmap-engine/test/vectorfxtest.cpp

290 lines
8.0 KiB
C++

//
// Created by Wouter Groeneveld on 14/12/18.
//
#include <gtest/gtest.h>
#include <libgba-sprite-engine/vectorfx.h>
#include "tonc_bios_stub.h"
class VectorFxSuite : public ::testing::Test {
protected:
VectorFx vector;
virtual void TearDown() {
}
virtual void SetUp() {
vector = VectorFx({120, 80});
}
};
INLINE float rnd2(float val) {
return (float) ((std::floor(val * 10) + .5) / 10);
}
void assertVector(VectorFx expected, VectorFx actual) {
auto str = "[fx: " + actual.to_string() + ", fl: " + actual.to_stringfl() + "] , [fx: " + expected.to_string() + ", fl: " + expected.to_stringfl() + "]";
// WHY use rounding instead of checking fixed-point itself?
// because of a lot of rounding errors... -250 (-0.97) is supposed to be -256 (-1)...
ASSERT_EQ(rnd2(fx2float(actual.x())), rnd2(fx2float(expected.x()))) << "x incorrect: (act, exp) " << str;
ASSERT_EQ(rnd2(fx2float(actual.y())), rnd2(fx2float(actual.y()))) << "y incorrect: (act, exp) " << str;
ASSERT_EQ(rnd2(fx2float(actual.z())), rnd2(fx2float(actual.z()))) << "z incorrect: (act, exp) " << str;
}
TEST_F(VectorFxSuite, ToAndFromFixedIntWorks) {
auto zAxis = VectorFx::fromInt(0, 0, -10);
ASSERT_EQ(zAxis.y(), 0);
ASSERT_EQ(zAxis.z(), -2560);
auto toInt = zAxis.toInt();
ASSERT_EQ(toInt.y(), 0);
ASSERT_EQ(toInt.z(), -10);
}
TEST_F(VectorFxSuite, Normalize) {
// based on Babylon Math debugging examples
auto zAxis = VectorFx::fromInt(0, 0, -10);
auto l = zAxis.length();
auto expected = VectorFx::fromInt(0, 0, -1);
zAxis.normalize();
assertVector(expected, zAxis);
}
TEST_F(VectorFxSuite, MinDot) {
auto zAxis = VectorFx::fromInt(0, 0, -1);
auto eye = VectorFx::fromInt(0, 0, 10);
auto result = fx2int(-VectorFx::dot(zAxis, eye));
ASSERT_EQ(result, 10);
}
TEST_F(VectorFxSuite, Cross_AssertToInt) {
auto one = VectorFx::fromInt(0, 1, 0);
auto two = VectorFx::fromInt(0, 0, -1);
auto result = VectorFx::cross(one, two).toInt();
ASSERT_EQ(result.x(), -1);
ASSERT_EQ(result.y(), 0);
ASSERT_EQ(result.z(), 0);
}
TEST_F(VectorFxSuite, Cross_AssertFixed) {
auto one = VectorFx::fromInt(0, 1, 0);
auto two = VectorFx::fromInt(0, 0, -1);
auto result = VectorFx::cross(one, two);
auto expected = VectorFx::fromInt(-1, 0, 0);
ASSERT_EQ(result.x(), expected.x());
ASSERT_EQ(result.y(), expected.y());
ASSERT_EQ(result.z(), expected.z());
}
TEST_F(VectorFxSuite, AddTwoVectors) {
VectorFx one(1, 2, 3);
VectorFx two(4, 5, 6);
auto result = one + two;
ASSERT_EQ(result.x(), 5);
ASSERT_EQ(result.y(), 7);
ASSERT_EQ(result.z(), 9);
}
TEST_F(VectorFxSuite, SubstractTwoVectors) {
VectorFx one(1, 2, 3);
VectorFx two(4, 5, 6);
auto result = one - two;
ASSERT_EQ(result.x(), -3);
ASSERT_EQ(result.y(), -3);
ASSERT_EQ(result.z(), -3);
}
TEST_F(VectorFxSuite, LengthSqrtOfAllPowItself) {
auto one = VectorFx::fromInt(1, 2, 3); // 1*1 + 2*2 + 3*3 = 14
auto result = fx2float(one.length());
ASSERT_EQ(3.735, (std::floor(result * 100) + .5) / 100);
auto negative = VectorFx::fromInt(0, 0, -10);
int negResult = fx2int(negative.length());
ASSERT_EQ(fx2int(fxmul(int2fx(-10), int2fx(-10))), 100);
ASSERT_EQ(negResult, 10);
}
TEST_F(VectorFxSuite, DivideTwoVectors) {
auto one = VectorFx::fromInt(1, 2, 3);
auto two = VectorFx::fromInt(4, 10, 6);
auto result = (two / one).toInt();
ASSERT_EQ(result.x(), 4);
ASSERT_EQ(result.y(), 5);
ASSERT_EQ(result.z(), 2);
}
TEST_F(VectorFxSuite, MultiplyTwoVectors) {
auto one = VectorFx::fromInt(1, 2, 3);
auto two = VectorFx::fromInt(4, 10, 6);
auto result = (two * one).toInt();
ASSERT_EQ(result.x(), 4);
ASSERT_EQ(result.y(), 20);
ASSERT_EQ(result.z(), 18);
}
TEST_F(VectorFxSuite, ScaleAVector) {
auto one = VectorFx::fromInt(1, 2, 3);
auto result = one.scale(2).toInt();
ASSERT_EQ(result.x(), 2);
ASSERT_EQ(result.y(), 4);
ASSERT_EQ(result.z(), 6);
}
uint grad2rad(uint grad) {
//return float2fx(grad*M_PI/180);
return fxdiv(fxmul(int2fx(grad), float2fx(M_PI)), int2fx(180));
}
TEST_F(VectorFxSuite, Rotate_FromBottomHalf_0_Degrees) {
auto bottomHalf = VectorFx::fromInt(120, 200, 0);
auto vector = VectorFx::fromInt(120, 80, 0);
auto result = vector.rotateAsCenter(bottomHalf, grad2rad(0)).toInt();
ASSERT_EQ(120, result.x());
ASSERT_EQ(200, result.y());
}
TEST_F(VectorFxSuite, Rotate_FromBottomHalf_90_Degrees) {
auto bottomHalf = VectorFx::fromInt(120, 200, 0);
auto vector = VectorFx::fromInt(120, 80, 0);
auto result = vector.rotateAsCenter(bottomHalf, grad2rad(90)).toInt();
ASSERT_EQ(240, result.x());
ASSERT_EQ(80, result.y());
}
TEST_F(VectorFxSuite, Rotate_FromBottomHalf_180_Degrees) {
auto bottomHalf = VectorFx::fromInt(120, 200, 0);
auto vector = VectorFx::fromInt(120, 80, 0);
auto result = vector.rotateAsCenter(bottomHalf, grad2rad(180)).toInt();
ASSERT_EQ(120, result.x());
ASSERT_EQ(-40, result.y());
}
TEST_F(VectorFxSuite, Rotate_FromBottomHalf_270_Degrees) {
auto bottomHalf = VectorFx::fromInt(120, 200, 0);
auto vector = VectorFx::fromInt(120, 80, 0);
auto result = vector.rotateAsCenter(bottomHalf, grad2rad(270)).toInt();
ASSERT_EQ(0, result.x());
ASSERT_EQ(80, result.y());
}
// ---- //
TEST_F(VectorFxSuite, ToString) {
ASSERT_EQ(std::string("(120,80,0)"), vector.to_string());
}
TEST_F(VectorFxSuite, LineBetween_Diagonal_ToTopRightCorner) {
auto points = vector.bresenhamLineTo({240, 0});
ASSERT_EQ(121, points.size());
VECTOR pt;
// some sampling
pt = points.at(1);
ASSERT_EQ(121, pt.x);
ASSERT_EQ(79, pt.y);
pt = points.at(2);
ASSERT_EQ(122, pt.x);
ASSERT_EQ(79, pt.y);
pt = points.at(10);
ASSERT_EQ(130, pt.x);
ASSERT_EQ(73, pt.y);
pt = points.at(100);
ASSERT_EQ(220, pt.x);
ASSERT_EQ(13, pt.y);
}
TEST_F(VectorFxSuite, LineBetween_Diagonal_ToTopLeftCorner) {
auto points = vector.bresenhamLineTo({0, 0});
ASSERT_EQ(121, points.size());
VECTOR pt;
// some sampling
pt = points.at(1);
ASSERT_EQ(119, pt.x);
ASSERT_EQ(79, pt.y);
pt = points.at(2);
ASSERT_EQ(118, pt.x);
ASSERT_EQ(79, pt.y);
pt = points.at(10);
ASSERT_EQ(110, pt.x);
ASSERT_EQ(73, pt.y);
pt = points.at(100);
ASSERT_EQ(20, pt.x);
ASSERT_EQ(13, pt.y);
}
TEST_F(VectorFxSuite, LineBetween_Diagonal_ToBottomLeftCorner) {
auto points = vector.bresenhamLineTo({0, 160});
ASSERT_EQ(121, points.size());
VECTOR pt;
// some sampling
pt = points.at(1);
ASSERT_EQ(119, pt.x);
ASSERT_EQ(81, pt.y);
pt = points.at(2);
ASSERT_EQ(118, pt.x);
ASSERT_EQ(81, pt.y);
pt = points.at(10);
ASSERT_EQ(110, pt.x);
ASSERT_EQ(87, pt.y);
pt = points.at(100);
ASSERT_EQ(20, pt.x);
ASSERT_EQ(147, pt.y);
}
TEST_F(VectorFxSuite, LineBetween_Diagonal_ToBottomRightCorner) {
auto points = vector.bresenhamLineTo({240, 160});
ASSERT_EQ(121, points.size());
VECTOR pt;
// some sampling
pt = points.at(1);
ASSERT_EQ(121, pt.x);
ASSERT_EQ(81, pt.y);
pt = points.at(2);
ASSERT_EQ(122, pt.x);
ASSERT_EQ(81, pt.y);
pt = points.at(10);
ASSERT_EQ(130, pt.x);
ASSERT_EQ(87, pt.y);
pt = points.at(100);
ASSERT_EQ(220, pt.x);
ASSERT_EQ(147, pt.y);
}
TEST_F(VectorFxSuite, LineBetween_Horizontal_FromCenterToHalfYZeroX) {
auto points = vector.bresenhamLineTo({0, 80});
ASSERT_EQ(121, points.size());
for(int i = 0; i <= 120; i++) {
auto &vec = points.front();
ASSERT_EQ(80, vec.y);
ASSERT_EQ(120 - i, vec.x);
points.pop_front();
}
}
TEST_F(VectorFxSuite, LineBetween_Vertical_FromCenterToHalfXFullY) {
auto points = vector.bresenhamLineTo({120, 160});
ASSERT_EQ(81, points.size());
for(int i = 0; i <= (160 - 80); i++) {
auto &vec = points.front();
ASSERT_EQ(120, vec.x);
ASSERT_EQ(80 + i, vec.y);
points.pop_front();
}
}