Add geometry methods for point, vector, and rectangle.feature/data-structs
@@ -42,7 +42,8 @@ add_executable( | |||||
src/packages/game/input/IZ_keyboard.h | src/packages/game/input/IZ_keyboard.h | ||||
src/packages/game/IZ_config.c | src/packages/game/IZ_config.c | ||||
src/packages/game/IZ_config.h | 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( | target_link_libraries( | ||||
game | game | ||||
SDL2main | SDL2main | ||||
@@ -50,20 +51,18 @@ target_link_libraries( | |||||
) | ) | ||||
add_executable( | add_executable( | ||||
game-test-output | |||||
game-test-geometry | |||||
dependencies/bdd-for-c/bdd-for-c.h | dependencies/bdd-for-c/bdd-for-c.h | ||||
src/packages/test/IZ_mock.h | src/packages/test/IZ_mock.h | ||||
src/packages/test/IZ_test.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( | add_executable( | ||||
game-test-input | game-test-input | ||||
@@ -88,6 +87,23 @@ add_executable( | |||||
src/packages/game/input/input.test.c | 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) | if (WIN32) | ||||
add_custom_command(TARGET game POST_BUILD | add_custom_command(TARGET game POST_BUILD | ||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake - E copy_if_different..." | COMMAND ${CMAKE_COMMAND} -E copy_if_different # which executes "cmake - E copy_if_different..." | ||||
@@ -4,16 +4,21 @@ | |||||
#include "input/IZ_keyboard.h" | #include "input/IZ_keyboard.h" | ||||
#include "input/IZ_joystick.h" | #include "input/IZ_joystick.h" | ||||
#include "output/IZ_video.h" | #include "output/IZ_video.h" | ||||
#include "memory/IZ_pool.h" | |||||
#include "IZ_action.h" | #include "IZ_action.h" | ||||
typedef struct { | typedef struct { | ||||
IZ_VideoConfig video_config; | |||||
IZ_Action actions[PLAYERS]; | IZ_Action actions[PLAYERS]; | ||||
// input | |||||
IZ_KeyboardState keyboard_state[PLAYERS]; | IZ_KeyboardState keyboard_state[PLAYERS]; | ||||
IZ_JoystickState joystick_state[PLAYERS]; | IZ_JoystickState joystick_state[PLAYERS]; | ||||
// output, video state | |||||
IZ_VideoConfig video_config; | |||||
uint64_t video_update_at; | uint64_t video_update_at; | ||||
IZ_Pool memory_pool; | |||||
} IZ_App; | } IZ_App; | ||||
int IZ_InitializeApp(IZ_App*); | int IZ_InitializeApp(IZ_App*); | ||||
@@ -0,0 +1 @@ | |||||
#include "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 |
@@ -0,0 +1 @@ | |||||
#include "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 |
@@ -0,0 +1 @@ | |||||
#include "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 |
@@ -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, | |||||
}; | |||||
} |
@@ -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 |
@@ -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 | |||||
); | |||||
} |
@@ -0,0 +1,27 @@ | |||||
#ifndef IZ_RECT_H | |||||
#define IZ_RECT_H | |||||
#include <stdbool.h> | |||||
#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 |
@@ -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, | |||||
}; | |||||
} |
@@ -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 |
@@ -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."); | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -0,0 +1 @@ | |||||
#include "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 |