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/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..." | |||
@@ -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*); | |||
@@ -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 |