From b8f5131fb9c936dd46a621fa8918d6361b3b0244 Mon Sep 17 00:00:00 2001 From: TheoryOfNekomata Date: Mon, 23 May 2022 10:56:44 +0800 Subject: [PATCH] Implement geometry methods Add geometry methods for point, vector, and rectangle. --- CMakeLists.txt | 38 +++- src/packages/game/IZ_app.h | 9 +- src/packages/game/core/IZ_creature.c | 1 + src/packages/game/core/IZ_creature.h | 12 + src/packages/game/core/IZ_entity.c | 1 + src/packages/game/core/IZ_entity.h | 11 + src/packages/game/core/IZ_object.c | 1 + src/packages/game/core/IZ_object.h | 15 ++ src/packages/game/geometry/IZ_point2d.c | 8 + src/packages/game/geometry/IZ_point2d.h | 13 ++ src/packages/game/geometry/IZ_rect.c | 26 +++ src/packages/game/geometry/IZ_rect.h | 27 +++ src/packages/game/geometry/IZ_vector2d.c | 22 ++ src/packages/game/geometry/IZ_vector2d.h | 17 ++ src/packages/game/geometry/geometry.test.c | 244 +++++++++++++++++++++ src/packages/game/memory/IZ_pool.c | 1 + src/packages/game/memory/IZ_pool.h | 10 + 17 files changed, 443 insertions(+), 13 deletions(-) create mode 100644 src/packages/game/core/IZ_creature.c create mode 100644 src/packages/game/core/IZ_creature.h create mode 100644 src/packages/game/core/IZ_entity.c create mode 100644 src/packages/game/core/IZ_entity.h create mode 100644 src/packages/game/core/IZ_object.c create mode 100644 src/packages/game/core/IZ_object.h create mode 100644 src/packages/game/geometry/IZ_point2d.c create mode 100644 src/packages/game/geometry/IZ_point2d.h create mode 100644 src/packages/game/geometry/IZ_rect.c create mode 100644 src/packages/game/geometry/IZ_rect.h create mode 100644 src/packages/game/geometry/IZ_vector2d.c create mode 100644 src/packages/game/geometry/IZ_vector2d.h create mode 100644 src/packages/game/geometry/geometry.test.c create mode 100644 src/packages/game/memory/IZ_pool.c create mode 100644 src/packages/game/memory/IZ_pool.h diff --git a/CMakeLists.txt b/CMakeLists.txt index f27a422..887f487 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -42,7 +42,8 @@ add_executable( src/packages/game/input/IZ_keyboard.h src/packages/game/IZ_config.c src/packages/game/IZ_config.h -) + src/packages/game/geometry/IZ_point2d.c src/packages/game/geometry/IZ_point2d.h src/packages/game/geometry/IZ_vector2d.c src/packages/game/geometry/IZ_vector2d.h src/packages/game/geometry/IZ_rect.c src/packages/game/geometry/IZ_rect.h src/packages/game/core/IZ_object.c src/packages/game/core/IZ_object.h src/packages/game/core/IZ_creature.c src/packages/game/core/IZ_creature.h src/packages/game/core/IZ_entity.c src/packages/game/core/IZ_entity.h src/packages/game/memory/IZ_pool.c src/packages/game/memory/IZ_pool.h) + target_link_libraries( game SDL2main @@ -50,20 +51,18 @@ target_link_libraries( ) add_executable( - game-test-output + game-test-geometry dependencies/bdd-for-c/bdd-for-c.h src/packages/test/IZ_mock.h src/packages/test/IZ_test.h - __mocks__/minIni.mock.h - - src/packages/game/IZ_config.h - src/packages/game/__mocks__/IZ_config.mock.h - - src/packages/game/output/IZ_video.h - src/packages/game/output/IZ_video.c - src/packages/game/output/output.test.c -) + src/packages/game/geometry/IZ_point2d.h + src/packages/game/geometry/IZ_point2d.c + src/packages/game/geometry/IZ_rect.h + src/packages/game/geometry/IZ_rect.c + src/packages/game/geometry/IZ_vector2d.h + src/packages/game/geometry/IZ_vector2d.c + src/packages/game/geometry/geometry.test.c) add_executable( game-test-input @@ -88,6 +87,23 @@ add_executable( src/packages/game/input/input.test.c ) + +add_executable( + game-test-output + dependencies/bdd-for-c/bdd-for-c.h + src/packages/test/IZ_mock.h + src/packages/test/IZ_test.h + + __mocks__/minIni.mock.h + + src/packages/game/IZ_config.h + src/packages/game/__mocks__/IZ_config.mock.h + + src/packages/game/output/IZ_video.h + src/packages/game/output/IZ_video.c + src/packages/game/output/output.test.c +) + if (WIN32) add_custom_command(TARGET game POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake - E copy_if_different..." diff --git a/src/packages/game/IZ_app.h b/src/packages/game/IZ_app.h index 4a3eff0..3c6bdf9 100644 --- a/src/packages/game/IZ_app.h +++ b/src/packages/game/IZ_app.h @@ -4,16 +4,21 @@ #include "input/IZ_keyboard.h" #include "input/IZ_joystick.h" #include "output/IZ_video.h" +#include "memory/IZ_pool.h" #include "IZ_action.h" typedef struct { - IZ_VideoConfig video_config; - IZ_Action actions[PLAYERS]; + + // input IZ_KeyboardState keyboard_state[PLAYERS]; IZ_JoystickState joystick_state[PLAYERS]; + // output, video state + IZ_VideoConfig video_config; uint64_t video_update_at; + + IZ_Pool memory_pool; } IZ_App; int IZ_InitializeApp(IZ_App*); diff --git a/src/packages/game/core/IZ_creature.c b/src/packages/game/core/IZ_creature.c new file mode 100644 index 0000000..0dd54ca --- /dev/null +++ b/src/packages/game/core/IZ_creature.c @@ -0,0 +1 @@ +#include "IZ_creature.h" diff --git a/src/packages/game/core/IZ_creature.h b/src/packages/game/core/IZ_creature.h new file mode 100644 index 0000000..176f8d8 --- /dev/null +++ b/src/packages/game/core/IZ_creature.h @@ -0,0 +1,12 @@ +#ifndef IZ_CREATURE_H +#define IZ_CREATURE_H + +#include "IZ_object.h" + +typedef struct { + IZ_Object as_object; + + float hp; +} IZ_Creature; + +#endif diff --git a/src/packages/game/core/IZ_entity.c b/src/packages/game/core/IZ_entity.c new file mode 100644 index 0000000..b948af3 --- /dev/null +++ b/src/packages/game/core/IZ_entity.c @@ -0,0 +1 @@ +#include "IZ_entity.h" diff --git a/src/packages/game/core/IZ_entity.h b/src/packages/game/core/IZ_entity.h new file mode 100644 index 0000000..d522316 --- /dev/null +++ b/src/packages/game/core/IZ_entity.h @@ -0,0 +1,11 @@ +#ifndef IZ_ENTITY_H +#define IZ_ENTITY_H + +#include "../geometry/IZ_point2d.h" + +typedef struct { + IZ_Point2D pos; + // TODO object appearance (sprite, sprites contain bounding boxes, collisions contain bounding boxes) +} IZ_Entity; + +#endif diff --git a/src/packages/game/core/IZ_object.c b/src/packages/game/core/IZ_object.c new file mode 100644 index 0000000..6da7aca --- /dev/null +++ b/src/packages/game/core/IZ_object.c @@ -0,0 +1 @@ +#include "IZ_object.h" diff --git a/src/packages/game/core/IZ_object.h b/src/packages/game/core/IZ_object.h new file mode 100644 index 0000000..62de6d3 --- /dev/null +++ b/src/packages/game/core/IZ_object.h @@ -0,0 +1,15 @@ +#ifndef IZ_OBJECT_H +#define IZ_OBJECT_H + +#include "../geometry/IZ_vector2d.h" +#include "../geometry/IZ_rect.h" +#include "IZ_entity.h" + +typedef struct { + IZ_Entity as_entity; + + IZ_Rect collision_rect; + IZ_Vector2D speed; +} IZ_Object; + +#endif diff --git a/src/packages/game/geometry/IZ_point2d.c b/src/packages/game/geometry/IZ_point2d.c new file mode 100644 index 0000000..27b25bd --- /dev/null +++ b/src/packages/game/geometry/IZ_point2d.c @@ -0,0 +1,8 @@ +#include "IZ_point2d.h" + +IZ_Point2D IZ_PointTranslate(IZ_Point2D point, IZ_Coordinate translate_x, IZ_Coordinate translate_y) { + return (IZ_Point2D) { + .x = point.x + translate_x, + .y = point.y + translate_y, + }; +} diff --git a/src/packages/game/geometry/IZ_point2d.h b/src/packages/game/geometry/IZ_point2d.h new file mode 100644 index 0000000..5637653 --- /dev/null +++ b/src/packages/game/geometry/IZ_point2d.h @@ -0,0 +1,13 @@ +#ifndef IZ_POINT2D_H +#define IZ_POINT2D_H + +typedef float IZ_Coordinate; + +typedef struct { + IZ_Coordinate x; + IZ_Coordinate y; +} IZ_Point2D; + +IZ_Point2D IZ_PointTranslate(IZ_Point2D, IZ_Coordinate, IZ_Coordinate); + +#endif diff --git a/src/packages/game/geometry/IZ_rect.c b/src/packages/game/geometry/IZ_rect.c new file mode 100644 index 0000000..0b54800 --- /dev/null +++ b/src/packages/game/geometry/IZ_rect.c @@ -0,0 +1,26 @@ +#include "IZ_rect.h" + +IZ_Bounds IZ_RectGetBounds(IZ_Rect rect) { + return (IZ_Bounds) { + .left = rect.pos.x, + .top = rect.pos.y, + .right = rect.pos.x + rect.width, + .bottom = rect.pos.y + rect.height, + }; +} + +bool IZ_BoundsContainPoint(IZ_Bounds bounds, IZ_Point2D point) { + return ( + bounds.left <= point.x + && bounds.top <= point.y + && point.x <= bounds.right + && point.y <= bounds.bottom + ); +} + +bool IZ_BoundsCollide(IZ_Bounds a, IZ_Bounds b) { + return ( + b.left < a.right + && b.top < a.bottom + ); +} diff --git a/src/packages/game/geometry/IZ_rect.h b/src/packages/game/geometry/IZ_rect.h new file mode 100644 index 0000000..06e469a --- /dev/null +++ b/src/packages/game/geometry/IZ_rect.h @@ -0,0 +1,27 @@ +#ifndef IZ_RECT_H +#define IZ_RECT_H + +#include +#include "IZ_point2d.h" + +typedef struct { + IZ_Coordinate left; + IZ_Coordinate top; + IZ_Coordinate right; + IZ_Coordinate bottom; +} IZ_Bounds; + +typedef struct { + // top left + IZ_Point2D pos; + IZ_Coordinate width; + IZ_Coordinate height; +} IZ_Rect; + +IZ_Bounds IZ_RectGetBounds(IZ_Rect); + +bool IZ_BoundsContainPoint(IZ_Bounds, IZ_Point2D); + +bool IZ_BoundsCollide(IZ_Bounds, IZ_Bounds); + +#endif diff --git a/src/packages/game/geometry/IZ_vector2d.c b/src/packages/game/geometry/IZ_vector2d.c new file mode 100644 index 0000000..d320aa9 --- /dev/null +++ b/src/packages/game/geometry/IZ_vector2d.c @@ -0,0 +1,22 @@ +#include "IZ_vector2d.h" + +IZ_Vector2D IZ_VectorAdd(IZ_Vector2D addend, IZ_Vector2D augend) { + return (IZ_Vector2D) { + .right = addend.right + augend.right, + .up = addend.up + augend.up, + }; +} + +IZ_Vector2D IZ_VectorMultiply(IZ_Vector2D multiplicand, IZ_Vector2D multiplier) { + return (IZ_Vector2D) { + .right = multiplicand.right * multiplier.right, + .up = multiplicand.up * multiplier.up, + }; +} + +IZ_Vector2D IZ_VectorScale(IZ_Vector2D vector, IZ_VectorMagnitude scalar) { + return (IZ_Vector2D) { + .right = vector.right * scalar, + .up = vector.up * scalar, + }; +} diff --git a/src/packages/game/geometry/IZ_vector2d.h b/src/packages/game/geometry/IZ_vector2d.h new file mode 100644 index 0000000..ddf9b32 --- /dev/null +++ b/src/packages/game/geometry/IZ_vector2d.h @@ -0,0 +1,17 @@ +#ifndef IZ_VECTOR2D_H +#define IZ_VECTOR2D_H + +typedef float IZ_VectorMagnitude; + +typedef struct { + IZ_VectorMagnitude right; + IZ_VectorMagnitude up; +} IZ_Vector2D; + +IZ_Vector2D IZ_VectorAdd(IZ_Vector2D, IZ_Vector2D); + +IZ_Vector2D IZ_VectorMultiply(IZ_Vector2D, IZ_Vector2D); + +IZ_Vector2D IZ_VectorScale(IZ_Vector2D, IZ_VectorMagnitude); + +#endif diff --git a/src/packages/game/geometry/geometry.test.c b/src/packages/game/geometry/geometry.test.c new file mode 100644 index 0000000..0eee07e --- /dev/null +++ b/src/packages/game/geometry/geometry.test.c @@ -0,0 +1,244 @@ +#include "../../test/IZ_test.h" +#include "IZ_point2d.h" +#include "IZ_vector2d.h" +#include "IZ_rect.h" + +spec("geometry") { + describe("point2d") { + describe("PointTranslate") { + it("translates coordinates of a point") { + static IZ_Point2D input = { + .x = 420.f, + .y = 1337.f, + }; + + static IZ_Point2D expected = { + .x = 426.f, + .y = 1346.f, + }; + + static IZ_Point2D actual; + actual = IZ_PointTranslate(input, 6.f, 9.f); + + check(expected.x == actual.x, "X values do not match."); + check(expected.y == actual.y, "Y values do not match."); + } + } + } + + describe("vector2d") { + describe("VectorAdd") { + it("adds two vectors") { + static IZ_Vector2D addend = { + .right = 420.f, + .up = 1337.f, + }; + + static IZ_Vector2D augend = { + .right = 6.f, + .up = 9.f, + }; + + static IZ_Vector2D expected_sum = { + .right = 426.f, + .up = 1346.f, + }; + + static IZ_Vector2D actual_sum; + actual_sum = IZ_VectorAdd(addend, augend); + + check(expected_sum.right == actual_sum.right, "Right values do not match."); + check(expected_sum.up == actual_sum.up, "Up values do not match."); + } + } + + describe("VectorMultiply") { + it("multiplies two vectors") { + static IZ_Vector2D multiplicand = { + .right = 6.f, + .up = 9.f, + }; + + static IZ_Vector2D multiplier = { + .right = 3.f, + .up = 2.f, + }; + + static IZ_Vector2D expected_product = { + .right = 18.f, + .up = 18.f, + }; + + static IZ_Vector2D actual_product; + actual_product = IZ_VectorMultiply(multiplicand, multiplier); + + check(expected_product.right == actual_product.right, "Right values do not match."); + check(expected_product.up == actual_product.up, "Up values do not match."); + } + } + + describe("VectorScale") { + it("scales a vector") { + static IZ_Vector2D v = { + .right = 420.f, + .up = 69.f, + }; + + static IZ_VectorMagnitude s = 2.f; + + static IZ_Vector2D expected = { + .right = 840.f, + .up = 138.f, + }; + + static IZ_Vector2D actual; + actual = IZ_VectorScale(v, s); + + check(expected.right == actual.right, "Right values do not match."); + check(expected.up == actual.up, "Up values do not match."); + } + } + } + + describe("rect") { + describe("RectGetBounds") { + it("returns the bounds of a rectangle") { + static IZ_Rect r = { + .pos = { + .x = 50, + .y = 100, + }, + .width = 150, + .height = 200, + }; + + static IZ_Bounds expected = { + .left = 50, + .top = 100, + .right = 200, + .bottom = 300, + }; + + static IZ_Bounds actual; + actual = IZ_RectGetBounds(r); + + check(expected.left == actual.left, "Left values do not match."); + check(expected.top == actual.top, "Top values do not match."); + check(expected.right == actual.right, "Right values do not match."); + check(expected.bottom == actual.bottom, "Bottom values do not match."); + } + } + + describe("BoundsContainPoint") { + it("returns true for points inside bounds") { + static IZ_Bounds b = { + .left = 50, + .top = 100, + .right = 200, + .bottom = 300, + }; + + static IZ_Point2D p = { + .x = 75, + .y = 150, + }; + + check(IZ_BoundsContainPoint(b, p), "Point not found inside bounds."); + } + + it("returns true for points along bounds edge") { + static IZ_Bounds b = { + .left = 50, + .top = 100, + .right = 200, + .bottom = 300, + }; + + static IZ_Point2D p1 = { + .x = 50, + .y = 100, + }; + + static IZ_Point2D p2 = { + .x = 200, + .y = 300, + }; + + check(IZ_BoundsContainPoint(b, p1), "Point p1 not found inside bounds."); + check(IZ_BoundsContainPoint(b, p2), "Point p2 not found inside bounds."); + } + + it("returns false for points outside bounds") { + static IZ_Bounds b = { + .left = 50, + .top = 100, + .right = 200, + .bottom = 300, + }; + + static IZ_Point2D p = { + .x = 0, + .y = 0, + }; + + check(!IZ_BoundsContainPoint(b, p), "Point found inside bounds."); + } + } + + describe("BoundsCollide") { + it("returns true for bounds A inside bounds B") { + static IZ_Bounds a = { + .left = 100, + .top = 125, + .right = 150, + .bottom = 200, + }; + + static IZ_Bounds b = { + .left = 50, + .top = 75, + .right = 200, + .bottom = 250, + }; + + check(IZ_BoundsCollide(a, b), "Bounds not colliding."); + } + + it("returns true for bounds A intersecting bounds B") { + static IZ_Bounds a = { + .left = 0, + .top = 0, + .right = 150, + .bottom = 200, + }; + + static IZ_Bounds b = { + .left = 50, + .top = 75, + .right = 200, + .bottom = 250, + }; + + check(IZ_BoundsCollide(a, b), "Bounds not colliding."); + } + + it("returns true for bounds A outside bounds B") { + static IZ_Bounds a = { + .left = 50, + .top = 75, + .right = 200, + .bottom = 250, + }; + + static IZ_Bounds b = { + .left = 550, + .top = 575, + .right = 800, + .bottom = 850, + }; + + check(!IZ_BoundsCollide(a, b), "Bounds colliding."); + } + } + } +} diff --git a/src/packages/game/memory/IZ_pool.c b/src/packages/game/memory/IZ_pool.c new file mode 100644 index 0000000..dc2419a --- /dev/null +++ b/src/packages/game/memory/IZ_pool.c @@ -0,0 +1 @@ +#include "IZ_pool.h" diff --git a/src/packages/game/memory/IZ_pool.h b/src/packages/game/memory/IZ_pool.h new file mode 100644 index 0000000..7ee9eb0 --- /dev/null +++ b/src/packages/game/memory/IZ_pool.h @@ -0,0 +1,10 @@ +#ifndef IZ_POOL_H +#define IZ_POOL_H + +#define POOL_MAX_SIZE 256 + +typedef struct { + // TODO allocate and implement pool memory management! +} IZ_Pool; + +#endif