Impl 3d_helpers, unit tests, basic 3D demo
3d_helpers facilitate usage of transformation matrices. Unit tests ensure the 3d_helpers are correct. Currently, the program rotates a Cube mesh in x, y, and z axes.
This commit is contained in:
parent
1feefc5d9b
commit
c99407a474
9 changed files with 765 additions and 10 deletions
17
Makefile
17
Makefile
|
@ -13,25 +13,38 @@ SOURCES = \
|
|||
src/main.cc \
|
||||
src/game.cc \
|
||||
src/screen.cc \
|
||||
src/screen_test.cc
|
||||
src/screen_test.cc \
|
||||
src/screen_trunner.cc \
|
||||
src/3d_helpers.cc
|
||||
|
||||
HEADERS = \
|
||||
src/game.h \
|
||||
src/screen.h \
|
||||
src/screen_test.h
|
||||
src/screen_test.h \
|
||||
src/screen_trunner.h \
|
||||
src/3d_helpers.h
|
||||
|
||||
OBJECTS = $(addprefix ${OBJDIR}/,$(subst .cc,.cc.o,${SOURCES}))
|
||||
|
||||
TEST_SOURCES = \
|
||||
src/test/test.cc
|
||||
|
||||
TEST_OBJECTS = $(addprefix ${OBJDIR}/,$(subst .cc,.cc.o,${TEST_SOURCES}))
|
||||
|
||||
all: | format demo_0
|
||||
|
||||
demo_0: ${OBJECTS}
|
||||
${CXX} ${CXX_FLAGS} ${LINKER_FLAGS} -o $@ $^
|
||||
|
||||
test: $(filter-out ${OBJDIR}/src/main.cc.o,${OBJECTS}) ${TEST_OBJECTS}
|
||||
${CXX} ${CXX_FLAGS} ${LINKER_FLAGS} -o $@ $^
|
||||
|
||||
.PHONY: clean format
|
||||
|
||||
clean:
|
||||
rm -rf ${OBJDIR}
|
||||
rm -f demo_0
|
||||
rm -f test
|
||||
|
||||
format:
|
||||
clang-format -i --style=google ${HEADERS} ${SOURCES}
|
||||
|
|
128
src/3d_helpers.cc
Normal file
128
src/3d_helpers.cc
Normal file
|
@ -0,0 +1,128 @@
|
|||
#include "3d_helpers.h"
|
||||
|
||||
// standard library includes
|
||||
#include <cmath>
|
||||
|
||||
Matrix get_identity_matrix() {
|
||||
return Matrix{1.0F, 0.0F, 0.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F,
|
||||
0.0F, 0.0F, 1.0F, 0.0F, 0.0F, 0.0F, 0.0F, 1.0F};
|
||||
}
|
||||
|
||||
// Rotation is
|
||||
// cos, -sin,
|
||||
// sin, cos
|
||||
// probably?
|
||||
//
|
||||
// About z-axis:
|
||||
// cos, -sin, 0, 0,
|
||||
// sin, cos, 0, 0,
|
||||
// 0, 0, 1, 0,
|
||||
// 0, 0, 0, 1
|
||||
|
||||
Matrix get_rotation_matrix_about_z(float radians) {
|
||||
// OpenGL is column-major.
|
||||
return Matrix{std::cos(radians),
|
||||
std::sin(radians),
|
||||
0.0F,
|
||||
0.0F,
|
||||
-std::sin(radians),
|
||||
std::cos(radians),
|
||||
0.0F,
|
||||
0.0F,
|
||||
0.0F,
|
||||
0.0F,
|
||||
1.0F,
|
||||
0.0F,
|
||||
0.0F,
|
||||
0.0F,
|
||||
0.0F,
|
||||
1.0F};
|
||||
}
|
||||
|
||||
// About y-axis
|
||||
// cos, 0, sin, 0,
|
||||
// 0, 1, 0, 0,
|
||||
// -sin, 0, cos, 0,
|
||||
// 0, 0, 0, 1
|
||||
|
||||
Matrix get_rotation_matrix_about_y(float radians) {
|
||||
// OpenGL is column-major.
|
||||
return Matrix{std::cos(radians),
|
||||
0.0F,
|
||||
-std::sin(radians),
|
||||
0.0F,
|
||||
0.0F,
|
||||
1.0F,
|
||||
0.0F,
|
||||
0.0F,
|
||||
std::sin(radians),
|
||||
0.0F,
|
||||
std::cos(radians),
|
||||
0.0F,
|
||||
0.0F,
|
||||
0.0F,
|
||||
0.0F,
|
||||
1.0F};
|
||||
}
|
||||
|
||||
// About x-axis
|
||||
// 1, 0, 0, 0
|
||||
// 0, cos, -sin, 0
|
||||
// 0, sin, cos, 0
|
||||
// 0, 0, 0, 1
|
||||
|
||||
Matrix get_rotation_matrix_about_x(float radians) {
|
||||
// OpenGL is column-major.
|
||||
return Matrix{1.0F,
|
||||
0.0F,
|
||||
0.0F,
|
||||
0.0F,
|
||||
0.0F,
|
||||
std::cos(radians),
|
||||
std::sin(radians),
|
||||
0.0F,
|
||||
0.0F,
|
||||
-std::sin(radians),
|
||||
std::cos(radians),
|
||||
0.0F,
|
||||
0.0F,
|
||||
0.0F,
|
||||
0.0F,
|
||||
1.0F};
|
||||
}
|
||||
|
||||
Matrix translate_matrix_z(float distance) {
|
||||
return Matrix{1.0F, 0.0F, 0.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F,
|
||||
0.0F, 0.0F, 1.0F, distance, 0.0F, 0.0F, 0.0F, 1.0F};
|
||||
}
|
||||
|
||||
Matrix operator*(const Matrix &a, const Matrix &b) {
|
||||
return Matrix{a.m0 * b.m0 + a.m1 * b.m4 + a.m2 * b.m8 + a.m3 * b.m12,
|
||||
a.m4 * b.m0 + a.m5 * b.m4 + a.m6 * b.m8 + a.m7 * b.m12,
|
||||
a.m8 * b.m0 + a.m9 * b.m4 + a.m10 * b.m8 + a.m11 * b.m12,
|
||||
a.m12 * b.m0 + a.m13 * b.m4 + a.m14 * b.m8 + a.m15 * b.m12,
|
||||
|
||||
a.m0 * b.m1 + a.m1 * b.m5 + a.m2 * b.m9 + a.m3 * b.m13,
|
||||
a.m4 * b.m1 + a.m5 * b.m5 + a.m6 * b.m9 + a.m7 * b.m13,
|
||||
a.m8 * b.m1 + a.m9 * b.m5 + a.m10 * b.m9 + a.m11 * b.m13,
|
||||
a.m12 * b.m1 + a.m13 * b.m5 + a.m14 * b.m9 + a.m15 * b.m13,
|
||||
|
||||
a.m0 * b.m2 + a.m1 * b.m6 + a.m2 * b.m10 + a.m3 * b.m14,
|
||||
a.m4 * b.m2 + a.m5 * b.m6 + a.m6 * b.m10 + a.m7 * b.m14,
|
||||
a.m8 * b.m2 + a.m9 * b.m6 + a.m10 * b.m10 + a.m11 * b.m14,
|
||||
a.m12 * b.m2 + a.m13 * b.m6 + a.m14 * b.m10 + a.m15 * b.m14,
|
||||
|
||||
a.m0 * b.m3 + a.m1 * b.m7 + a.m2 * b.m11 + a.m3 * b.m15,
|
||||
a.m4 * b.m3 + a.m5 * b.m7 + a.m6 * b.m11 + a.m7 * b.m15,
|
||||
a.m8 * b.m3 + a.m9 * b.m7 + a.m10 * b.m11 + a.m11 * b.m15,
|
||||
a.m12 * b.m3 + a.m13 * b.m7 + a.m14 * b.m11 + a.m15 * b.m15};
|
||||
}
|
||||
|
||||
Vector4 operator*(const Matrix &m, const Vector4 &v) {
|
||||
return Vector4{
|
||||
m.m0 * v.x + m.m1 * v.y + m.m2 * v.z + m.m3 * v.w,
|
||||
m.m4 * v.x + m.m5 * v.y + m.m6 * v.z + m.m7 * v.w,
|
||||
m.m8 * v.x + m.m9 * v.y + m.m10 * v.z + m.m11 * v.w,
|
||||
m.m12 * v.x + m.m13 * v.y + m.m14 * v.z + m.m15 * v.w,
|
||||
};
|
||||
}
|
17
src/3d_helpers.h
Normal file
17
src/3d_helpers.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef JUMPARTIFACT_DOT_COM_DEMO_0_3D_HELPERS_H_
|
||||
#define JUMPARTIFACT_DOT_COM_DEMO_0_3D_HELPERS_H_
|
||||
|
||||
// third party includes
|
||||
#include <raylib.h>
|
||||
|
||||
extern Matrix get_identity_matrix();
|
||||
extern Matrix get_rotation_matrix_about_z(float radians);
|
||||
extern Matrix get_rotation_matrix_about_y(float radians);
|
||||
extern Matrix get_rotation_matrix_about_x(float radians);
|
||||
|
||||
extern Matrix translate_matrix_z(float distance);
|
||||
|
||||
extern Matrix operator*(const Matrix &a, const Matrix &b);
|
||||
extern Vector4 operator*(const Matrix &m, const Vector4 &v);
|
||||
|
||||
#endif
|
|
@ -1,11 +1,13 @@
|
|||
#include "game.h"
|
||||
|
||||
// local includes
|
||||
#include "screen_test.h"
|
||||
#include "screen_trunner.h"
|
||||
|
||||
Game::Game()
|
||||
: screen_stack(ScreenStack::new_instance()),
|
||||
prev_time(std::chrono::steady_clock::now()) {}
|
||||
prev_time(std::chrono::steady_clock::now()) {
|
||||
screen_stack->push_screen<TRunnerScreen>();
|
||||
}
|
||||
|
||||
void Game::update() {
|
||||
auto next_time = std::chrono::steady_clock::now();
|
||||
|
|
11
src/main.cc
11
src/main.cc
|
@ -39,9 +39,9 @@ void jumpartifact_demo_update(void *ud) {
|
|||
int main() {
|
||||
InitWindow(800, 800, "Demo");
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
Game game{};
|
||||
|
||||
#ifdef __EMSCRIPTEN__
|
||||
SetWindowSize(call_js_get_canvas_width(), call_js_get_canvas_height());
|
||||
|
||||
emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, &game, false,
|
||||
|
@ -49,10 +49,13 @@ int main() {
|
|||
|
||||
emscripten_set_main_loop_arg(jumpartifact_demo_update, &game, 0, 1);
|
||||
#else
|
||||
SetTargetFPS(60);
|
||||
{
|
||||
Game game{};
|
||||
SetTargetFPS(60);
|
||||
|
||||
while (!WindowShouldClose()) {
|
||||
jumpartifact_demo_update(&game);
|
||||
while (!WindowShouldClose()) {
|
||||
jumpartifact_demo_update(&game);
|
||||
}
|
||||
}
|
||||
|
||||
CloseAudioDevice();
|
||||
|
|
119
src/screen_trunner.cc
Normal file
119
src/screen_trunner.cc
Normal file
|
@ -0,0 +1,119 @@
|
|||
#include "screen_trunner.h"
|
||||
|
||||
// standard library includes
|
||||
#include <raylib.h>
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
|
||||
// local includes
|
||||
#include "3d_helpers.h"
|
||||
|
||||
TRunnerScreen::TRunnerScreen(std::weak_ptr<ScreenStack> stack)
|
||||
: Screen(stack),
|
||||
camera{Vector3{0.0F, 0.0F, 0.0F}, Vector3{0.0F, 0.0F, -1.0F},
|
||||
Vector3{0.0F, 1.0F, 0.0F}, 80.0F, CAMERA_PERSPECTIVE},
|
||||
flags(),
|
||||
TEMP_cube(GenMeshCube(2.0F, 2.0F, 2.0F)),
|
||||
TEMP_default_material(LoadMaterialDefault()),
|
||||
TEMP_matrix(get_identity_matrix()),
|
||||
TEMP_offset_matrix(translate_matrix_z(-4.0F)),
|
||||
grid_spacing(1.0F),
|
||||
grid_spacing_modifier(0.0F) {}
|
||||
|
||||
TRunnerScreen::~TRunnerScreen() {
|
||||
UnloadMesh(TEMP_cube);
|
||||
UnloadMaterial(TEMP_default_material);
|
||||
}
|
||||
|
||||
bool TRunnerScreen::update(float dt) {
|
||||
// grid_spacing_modifier += dt * GRID_SPACING_RATE;
|
||||
// if (grid_spacing_modifier > 2.0F * PI) {
|
||||
// grid_spacing_modifier -= 2.0F * PI;
|
||||
// }
|
||||
// grid_spacing = std::sin(grid_spacing_modifier) + GRID_SPACING_OFFSET;
|
||||
TEMP_matrix = get_rotation_matrix_about_z(dt) *
|
||||
get_rotation_matrix_about_y(dt * 1.2F) *
|
||||
get_rotation_matrix_about_x(dt * 1.4F) * TEMP_matrix;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool TRunnerScreen::draw() {
|
||||
BeginDrawing();
|
||||
ClearBackground(PixelToColor(Pixel::PIXEL_SKY));
|
||||
BeginMode3D(camera);
|
||||
|
||||
DrawMesh(TEMP_cube, TEMP_default_material, TEMP_matrix * TEMP_offset_matrix);
|
||||
|
||||
// for (unsigned int i = 11; i-- > 1;) {
|
||||
// // upper
|
||||
// DrawRay(Ray{Vector3{0.0F, 2.0F, -(0.5F + grid_spacing * (float)i)},
|
||||
// Vector3{1.0F, 0.0F, 0.0F}},
|
||||
// BLACK);
|
||||
// DrawRay(Ray{Vector3{0.0F, 2.0F, -(0.5F + grid_spacing * (float)i)},
|
||||
// Vector3{-1.0F, 0.0F, 0.0F}},
|
||||
// BLACK);
|
||||
//
|
||||
// // lower
|
||||
// DrawRay(Ray{Vector3{0.0F, -2.0F, -(0.5F + grid_spacing * (float)i)},
|
||||
// Vector3{1.0F, 0.0F, 0.0F}},
|
||||
// BLACK);
|
||||
// DrawRay(Ray{Vector3{0.0F, -2.0F, -(0.5F + grid_spacing * (float)i)},
|
||||
// Vector3{-1.0F, 0.0F, 0.0F}},
|
||||
// BLACK);
|
||||
//
|
||||
// // left
|
||||
// DrawRay(Ray{Vector3{-2.0F, 0.0F, -(0.5F + grid_spacing * (float)i)},
|
||||
// Vector3{0.0F, 1.0F, 0.0F}},
|
||||
// BLACK);
|
||||
// DrawRay(Ray{Vector3{-2.0F, 0.0F, -(0.5F + grid_spacing * (float)i)},
|
||||
// Vector3{0.0F, -1.0F, 0.0F}},
|
||||
// BLACK);
|
||||
//
|
||||
// // right
|
||||
// DrawRay(Ray{Vector3{2.0F, 0.0F, -(0.5F + grid_spacing * (float)i)},
|
||||
// Vector3{0.0F, 1.0F, 0.0F}},
|
||||
// BLACK);
|
||||
// DrawRay(Ray{Vector3{2.0F, 0.0F, -(0.5F + grid_spacing * (float)i)},
|
||||
// Vector3{0.0F, -1.0F, 0.0F}},
|
||||
// BLACK);
|
||||
// }
|
||||
EndMode3D();
|
||||
EndDrawing();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
Color TRunnerScreen::PixelToColor(Pixel p) {
|
||||
switch (p) {
|
||||
case PIXEL_BLANK:
|
||||
return Color{0, 0, 0, 0};
|
||||
case PIXEL_BLACK:
|
||||
return Color{0, 0, 0, 255};
|
||||
case PIXEL_RED:
|
||||
return Color{255, 50, 50, 255};
|
||||
case PIXEL_GREEN:
|
||||
return Color{50, 255, 50, 255};
|
||||
case PIXEL_BLUE:
|
||||
return Color{50, 50, 255, 255};
|
||||
case PIXEL_YELLOW:
|
||||
return Color{255, 255, 0, 255};
|
||||
case PIXEL_CYAN:
|
||||
return Color{0, 255, 255, 255};
|
||||
case PIXEL_MAGENTA:
|
||||
return Color{255, 0, 255, 255};
|
||||
case PIXEL_ORANGE:
|
||||
return Color{255, 200, 0, 255};
|
||||
case PIXEL_BROWN:
|
||||
return Color{180, 130, 0, 255};
|
||||
case PIXEL_TURQUOISE:
|
||||
return Color{0, 255, 200, 255};
|
||||
case PIXEL_SKY:
|
||||
return Color{168, 178, 255, 255};
|
||||
case PIXEL_WHITE:
|
||||
return Color{255, 255, 255, 255};
|
||||
default:
|
||||
assert(!"unreachable");
|
||||
return Color{0, 0, 0, 255};
|
||||
}
|
||||
}
|
53
src/screen_trunner.h
Normal file
53
src/screen_trunner.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
#ifndef JUMPARTIFACT_DOT_COM_DEMO_0_TANK_RUNNER_H_
|
||||
#define JUMPARTIFACT_DOT_COM_DEMO_0_TANK_RUNNER_H_
|
||||
|
||||
#include "screen.h"
|
||||
|
||||
// standard library includes
|
||||
#include <array>
|
||||
#include <bitset>
|
||||
|
||||
// third party includes
|
||||
#include <raylib.h>
|
||||
|
||||
constexpr float GRID_SPACING_RATE = 1.0F;
|
||||
constexpr float GRID_SPACING_OFFSET = 1.5F;
|
||||
|
||||
class TRunnerScreen : public Screen {
|
||||
public:
|
||||
TRunnerScreen(std::weak_ptr<ScreenStack> stack);
|
||||
~TRunnerScreen() override;
|
||||
|
||||
bool update(float dt) override;
|
||||
bool draw() override;
|
||||
|
||||
private:
|
||||
enum Pixel : unsigned char {
|
||||
PIXEL_BLANK,
|
||||
PIXEL_BLACK,
|
||||
PIXEL_RED,
|
||||
PIXEL_GREEN,
|
||||
PIXEL_BLUE,
|
||||
PIXEL_YELLOW,
|
||||
PIXEL_CYAN,
|
||||
PIXEL_MAGENTA,
|
||||
PIXEL_ORANGE,
|
||||
PIXEL_BROWN,
|
||||
PIXEL_TURQUOISE,
|
||||
PIXEL_SKY,
|
||||
PIXEL_WHITE
|
||||
};
|
||||
|
||||
static Color PixelToColor(Pixel p);
|
||||
|
||||
const Camera3D camera;
|
||||
std::bitset<64> flags;
|
||||
Mesh TEMP_cube;
|
||||
Material TEMP_default_material;
|
||||
Matrix TEMP_matrix;
|
||||
Matrix TEMP_offset_matrix;
|
||||
float grid_spacing;
|
||||
float grid_spacing_modifier;
|
||||
};
|
||||
|
||||
#endif
|
416
src/test/test.cc
Normal file
416
src/test/test.cc
Normal file
|
@ -0,0 +1,416 @@
|
|||
// standard library includes
|
||||
#include <iostream>
|
||||
|
||||
// local includes
|
||||
#include "../3d_helpers.h"
|
||||
|
||||
#define ASSERT_TRUE(v) \
|
||||
if (!(v)) { \
|
||||
std::cerr << "False in ASSERT_TRUE at line " << __LINE__ << "!\n"; \
|
||||
}
|
||||
|
||||
#define ASSERT_FALSE(v) \
|
||||
if (v) { \
|
||||
std::cerr << "True in ASSERT_FALSE at line " << __LINE__ << "!\n"; \
|
||||
}
|
||||
|
||||
#define ASSERT_FLOAT_EQUALS(f, v) \
|
||||
if ((f) < (v) - 0.1F || (f) > (v) + 0.1F) { \
|
||||
std::cerr << "ASSERT_FLOAT_EQUALS: " << (f) << " is not (roughly) equal to " << (v) << " at line " << __LINE__ << "!\n"; \
|
||||
}
|
||||
|
||||
|
||||
int main() {
|
||||
std::cout << "Testing 3d_helpers...\n";
|
||||
{
|
||||
auto identity = get_identity_matrix();
|
||||
ASSERT_TRUE(identity.m0 == 1.0F);
|
||||
ASSERT_TRUE(identity.m1 == 0.0F);
|
||||
ASSERT_TRUE(identity.m2 == 0.0F);
|
||||
ASSERT_TRUE(identity.m3 == 0.0F);
|
||||
|
||||
ASSERT_TRUE(identity.m4 == 0.0F);
|
||||
ASSERT_TRUE(identity.m5 == 1.0F);
|
||||
ASSERT_TRUE(identity.m6 == 0.0F);
|
||||
ASSERT_TRUE(identity.m7 == 0.0F);
|
||||
|
||||
ASSERT_TRUE(identity.m8 == 0.0F);
|
||||
ASSERT_TRUE(identity.m9 == 0.0F);
|
||||
ASSERT_TRUE(identity.m10 == 1.0F);
|
||||
ASSERT_TRUE(identity.m11 == 0.0F);
|
||||
|
||||
ASSERT_TRUE(identity.m12 == 0.0F);
|
||||
ASSERT_TRUE(identity.m13 == 0.0F);
|
||||
ASSERT_TRUE(identity.m14 == 0.0F);
|
||||
ASSERT_TRUE(identity.m15 == 1.0F);
|
||||
|
||||
identity = identity * get_identity_matrix();
|
||||
ASSERT_FLOAT_EQUALS(identity.m0, 1.0F);
|
||||
ASSERT_FLOAT_EQUALS(identity.m1, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(identity.m2, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(identity.m3, 0.0F);
|
||||
|
||||
ASSERT_FLOAT_EQUALS(identity.m4, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(identity.m5, 1.0F);
|
||||
ASSERT_FLOAT_EQUALS(identity.m6, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(identity.m7, 0.0F);
|
||||
|
||||
ASSERT_FLOAT_EQUALS(identity.m8, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(identity.m9, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(identity.m10, 1.0F);
|
||||
ASSERT_FLOAT_EQUALS(identity.m11, 0.0F);
|
||||
|
||||
ASSERT_FLOAT_EQUALS(identity.m12, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(identity.m13, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(identity.m14, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(identity.m15, 1.0F);
|
||||
|
||||
{
|
||||
auto v = Vector4{1.0F, 0.0F, 0.0F, 1.0F};
|
||||
auto v_result = identity * v;
|
||||
ASSERT_FLOAT_EQUALS(v_result.x, 1.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.y, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.z, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.w, 1.0F);
|
||||
}
|
||||
{
|
||||
auto v = Vector4{0.0F, 1.0F, 0.0F, 1.0F};
|
||||
auto v_result = identity * v;
|
||||
ASSERT_FLOAT_EQUALS(v_result.x, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.y, 1.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.z, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.w, 1.0F);
|
||||
}
|
||||
{
|
||||
auto v = Vector4{0.0F, 0.0F, 1.0F, 1.0F};
|
||||
auto v_result = identity * v;
|
||||
ASSERT_FLOAT_EQUALS(v_result.x, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.y, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.z, 1.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.w, 1.0F);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// 90 degree rotation and identity matrix.
|
||||
auto m = get_rotation_matrix_about_z(PI / 2.0F) * get_identity_matrix();
|
||||
ASSERT_FLOAT_EQUALS(m.m0, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m1, -1.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m2, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m3, 0.0F);
|
||||
|
||||
ASSERT_FLOAT_EQUALS(m.m4, 1.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m5, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m6, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m7, 0.0F);
|
||||
|
||||
ASSERT_FLOAT_EQUALS(m.m8, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m9, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m10, 1.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m11, 0.0F);
|
||||
|
||||
ASSERT_FLOAT_EQUALS(m.m12, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m13, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m14, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m15, 1.0F);
|
||||
|
||||
{
|
||||
auto v = Vector4{1.0F, 0.0F, 0.0F, 1.0F};
|
||||
auto v_result = m * v;
|
||||
ASSERT_FLOAT_EQUALS(v_result.x, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.y, 1.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.z, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.w, 1.0F);
|
||||
}
|
||||
{
|
||||
auto v = Vector4{0.0F, 1.0F, 0.0F, 1.0F};
|
||||
auto v_result = m * v;
|
||||
ASSERT_FLOAT_EQUALS(v_result.x, -1.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.y, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.z, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.w, 1.0F);
|
||||
}
|
||||
{
|
||||
auto v = Vector4{-1.0F, 0.0F, 0.0F, 1.0F};
|
||||
auto v_result = m * v;
|
||||
ASSERT_FLOAT_EQUALS(v_result.x, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.y, -1.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.z, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.w, 1.0F);
|
||||
}
|
||||
{
|
||||
auto v = Vector4{0.0F, -1.0F, 0.0F, 1.0F};
|
||||
auto v_result = m * v;
|
||||
ASSERT_FLOAT_EQUALS(v_result.x, 1.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.y, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.z, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.w, 1.0F);
|
||||
}
|
||||
}
|
||||
{
|
||||
// Double 90 degree rotation about z.
|
||||
auto m = get_rotation_matrix_about_z(PI/2.0F) * get_rotation_matrix_about_z(PI/2.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m0, -1.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m1, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m2, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m3, 0.0F);
|
||||
|
||||
ASSERT_FLOAT_EQUALS(m.m4, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m5, -1.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m6, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m7, 0.0F);
|
||||
|
||||
ASSERT_FLOAT_EQUALS(m.m8, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m9, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m10, 1.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m11, 0.0F);
|
||||
|
||||
ASSERT_FLOAT_EQUALS(m.m12, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m13, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m14, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m15, 1.0F);
|
||||
{
|
||||
auto v = Vector4{1.0F, 0.0F, 0.0F, 1.0F};
|
||||
auto v_result = m * v;
|
||||
ASSERT_FLOAT_EQUALS(v_result.x, -1.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.y, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.z, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.w, 1.0F);
|
||||
}
|
||||
{
|
||||
auto v = Vector4{0.0F, 1.0F, 0.0F, 1.0F};
|
||||
auto v_result = m * v;
|
||||
ASSERT_FLOAT_EQUALS(v_result.x, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.y, -1.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.z, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.w, 1.0F);
|
||||
}
|
||||
{
|
||||
auto v = Vector4{-1.0F, 0.0F, 0.0F, 1.0F};
|
||||
auto v_result = m * v;
|
||||
ASSERT_FLOAT_EQUALS(v_result.x, 1.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.y, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.z, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.w, 1.0F);
|
||||
}
|
||||
{
|
||||
auto v = Vector4{0.0F, -1.0F, 0.0F, 1.0F};
|
||||
auto v_result = m * v;
|
||||
ASSERT_FLOAT_EQUALS(v_result.x, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.y, 1.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.z, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.w, 1.0F);
|
||||
}
|
||||
// Rotate back 90 degrees.
|
||||
m = get_rotation_matrix_about_z(-PI/2.0F) * m;
|
||||
ASSERT_FLOAT_EQUALS(m.m0, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m1, -1.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m2, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m3, 0.0F);
|
||||
|
||||
ASSERT_FLOAT_EQUALS(m.m4, 1.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m5, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m6, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m7, 0.0F);
|
||||
|
||||
ASSERT_FLOAT_EQUALS(m.m8, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m9, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m10, 1.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m11, 0.0F);
|
||||
|
||||
ASSERT_FLOAT_EQUALS(m.m12, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m13, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m14, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m15, 1.0F);
|
||||
}
|
||||
{
|
||||
// Rotate about y-axis 90 degrees.
|
||||
auto m = get_rotation_matrix_about_y(PI/2.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m0, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m1, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m2, 1.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m3, 0.0F);
|
||||
|
||||
ASSERT_FLOAT_EQUALS(m.m4, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m5, 1.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m6, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m7, 0.0F);
|
||||
|
||||
ASSERT_FLOAT_EQUALS(m.m8, -1.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m9, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m10, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m11, 0.0F);
|
||||
|
||||
ASSERT_FLOAT_EQUALS(m.m12, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m13, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m14, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m15, 1.0F);
|
||||
|
||||
{
|
||||
auto v = Vector4{1.0F, 0.0F, 0.0F, 1.0F};
|
||||
auto v_result = m * v;
|
||||
ASSERT_FLOAT_EQUALS(v_result.x, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.y, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.z, -1.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.w, 1.0F);
|
||||
}
|
||||
{
|
||||
auto v = Vector4{0.0F, 0.0F, -1.0F, 1.0F};
|
||||
auto v_result = m * v;
|
||||
ASSERT_FLOAT_EQUALS(v_result.x, -1.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.y, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.z, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.w, 1.0F);
|
||||
}
|
||||
{
|
||||
auto v = Vector4{-1.0F, 0.0F, 0.0F, 1.0F};
|
||||
auto v_result = m * v;
|
||||
ASSERT_FLOAT_EQUALS(v_result.x, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.y, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.z, 1.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.w, 1.0F);
|
||||
}
|
||||
{
|
||||
auto v = Vector4{0.0F, 0.0F, 1.0F, 1.0F};
|
||||
auto v_result = m * v;
|
||||
ASSERT_FLOAT_EQUALS(v_result.x, 1.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.y, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.z, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.w, 1.0F);
|
||||
}
|
||||
|
||||
// additional 90 degrees.
|
||||
m = get_rotation_matrix_about_y(PI/2.0F) * m;
|
||||
ASSERT_FLOAT_EQUALS(m.m0, -1.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m1, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m2, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m3, 0.0F);
|
||||
|
||||
ASSERT_FLOAT_EQUALS(m.m4, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m5, 1.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m6, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m7, 0.0F);
|
||||
|
||||
ASSERT_FLOAT_EQUALS(m.m8, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m9, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m10, -1.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m11, 0.0F);
|
||||
|
||||
ASSERT_FLOAT_EQUALS(m.m12, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m13, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m14, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m15, 1.0F);
|
||||
{
|
||||
auto v = Vector4{1.0F, 0.0F, 0.0F, 1.0F};
|
||||
auto v_result = m * v;
|
||||
ASSERT_FLOAT_EQUALS(v_result.x, -1.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.y, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.z, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.w, 1.0F);
|
||||
}
|
||||
{
|
||||
auto v = Vector4{0.0F, 0.0F, -1.0F, 1.0F};
|
||||
auto v_result = m * v;
|
||||
ASSERT_FLOAT_EQUALS(v_result.x, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.y, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.z, 1.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.w, 1.0F);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
// About x-axis 90 degrees.
|
||||
auto m = get_rotation_matrix_about_x(PI/2.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m0, 1.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m1, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m2, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m3, 0.0F);
|
||||
|
||||
ASSERT_FLOAT_EQUALS(m.m4, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m5, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m6, -1.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m7, 0.0F);
|
||||
|
||||
ASSERT_FLOAT_EQUALS(m.m8, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m9, 1.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m10, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m11, 0.0F);
|
||||
|
||||
ASSERT_FLOAT_EQUALS(m.m12, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m13, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m14, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m15, 1.0F);
|
||||
{
|
||||
auto v = Vector4{0.0F, 1.0F, 0.0F, 1.0F};
|
||||
auto v_result = m * v;
|
||||
ASSERT_FLOAT_EQUALS(v_result.x, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.y, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.z, 1.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.w, 1.0F);
|
||||
}
|
||||
{
|
||||
auto v = Vector4{0.0F, 0.0F, 1.0F, 1.0F};
|
||||
auto v_result = m * v;
|
||||
ASSERT_FLOAT_EQUALS(v_result.x, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.y, -1.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.z, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.w, 1.0F);
|
||||
}
|
||||
{
|
||||
auto v = Vector4{0.0F, -1.0F, 0.0F, 1.0F};
|
||||
auto v_result = m * v;
|
||||
ASSERT_FLOAT_EQUALS(v_result.x, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.y, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.z, -1.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.w, 1.0F);
|
||||
}
|
||||
{
|
||||
auto v = Vector4{0.0F, 0.0F, -1.0F, 1.0F};
|
||||
auto v_result = m * v;
|
||||
ASSERT_FLOAT_EQUALS(v_result.x, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.y, 1.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.z, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.w, 1.0F);
|
||||
}
|
||||
// Additional 90 degrees.
|
||||
m = get_rotation_matrix_about_x(PI/2.0F) * m;
|
||||
ASSERT_FLOAT_EQUALS(m.m0, 1.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m1, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m2, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m3, 0.0F);
|
||||
|
||||
ASSERT_FLOAT_EQUALS(m.m4, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m5, -1.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m6, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m7, 0.0F);
|
||||
|
||||
ASSERT_FLOAT_EQUALS(m.m8, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m9, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m10, -1.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m11, 0.0F);
|
||||
|
||||
ASSERT_FLOAT_EQUALS(m.m12, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m13, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m14, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(m.m15, 1.0F);
|
||||
{
|
||||
auto v = Vector4{0.0F, 1.0F, 0.0F, 1.0F};
|
||||
auto v_result = m * v;
|
||||
ASSERT_FLOAT_EQUALS(v_result.x, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.y, -1.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.z, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.w, 1.0F);
|
||||
}
|
||||
{
|
||||
auto v = Vector4{0.0F, 0.0F, 1.0F, 1.0F};
|
||||
auto v_result = m * v;
|
||||
ASSERT_FLOAT_EQUALS(v_result.x, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.y, 0.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.z, -1.0F);
|
||||
ASSERT_FLOAT_EQUALS(v_result.w, 1.0F);
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << "Finished tests.\n";
|
||||
return 0;
|
||||
}
|
|
@ -9,13 +9,17 @@ SOURCES = \
|
|||
../src/ems.cc \
|
||||
../src/game.cc \
|
||||
../src/screen.cc \
|
||||
../src/screen_test.cc
|
||||
../src/screen_test.cc \
|
||||
../src/screen_trunner.cc \
|
||||
../src/3d_helpers.cc
|
||||
|
||||
HEADERS = \
|
||||
../src/ems.h \
|
||||
../src/game.h \
|
||||
../src/screen.h \
|
||||
../src/screen_test.h
|
||||
../src/screen_test.h \
|
||||
../src/screen_trunner.h \
|
||||
../src/3d_helpers.h
|
||||
|
||||
CXX = source ${HOME}/git/emsdk/emsdk_env.sh && em++
|
||||
|
||||
|
|
Loading…
Reference in a new issue