@@ -67,9 +67,7 @@ add_executable( | |||||
src/packages/game/input/IZ_keyboard.h | src/packages/game/input/IZ_keyboard.h | ||||
src/packages/config/IZ_config.c | src/packages/config/IZ_config.c | ||||
src/packages/config/IZ_config.h | src/packages/config/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.c | |||||
src/packages/game/geometry/IZ_vector2d.h | src/packages/game/geometry/IZ_vector2d.h | ||||
src/packages/game/geometry/IZ_rect.c | src/packages/game/geometry/IZ_rect.c | ||||
src/packages/game/geometry/IZ_rect.h | src/packages/game/geometry/IZ_rect.h | ||||
@@ -115,9 +113,7 @@ add_executable( | |||||
src/packages/test/IZ_mock.h | src/packages/test/IZ_mock.h | ||||
src/packages/test/IZ_test.h | src/packages/test/IZ_test.h | ||||
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.h | |||||
src/packages/game/geometry/IZ_rect.c | src/packages/game/geometry/IZ_rect.c | ||||
src/packages/game/geometry/IZ_vector2d.h | src/packages/game/geometry/IZ_vector2d.h | ||||
src/packages/game/geometry/IZ_vector2d.c | src/packages/game/geometry/IZ_vector2d.c | ||||
@@ -127,6 +127,18 @@ IZ_AppResult IZ_AppRun(struct IZ_App* app, u8 argc, const char* argv[]) { | |||||
.priority = IZ_VIDEO_SPRITE_PRIORITY_MEDIUM, | .priority = IZ_VIDEO_SPRITE_PRIORITY_MEDIUM, | ||||
}, &app->video_state.active_sprites[sprite_slot_index]); | }, &app->video_state.active_sprites[sprite_slot_index]); | ||||
app->video_state.active_sprites[sprite_slot_index].sprite.scale_factor = 0.25f; | app->video_state.active_sprites[sprite_slot_index].sprite.scale_factor = 0.25f; | ||||
app->video_state.active_sprites[sprite_slot_index].sprite.position = (IZ_Vector2D) { 100.f, 100.f }; | |||||
IZ_AssetResolveDir("weapon-specialist", asset_dir); | |||||
sprite_slot_index = IZ_VideoGetNextFreeSpriteSlot(&app->video_state); | |||||
IZ_VideoLoadSprite(&app->video_state, (IZ_VideoLoadSpriteParams) { | |||||
.dir = asset_dir, | |||||
.filename = "sprite.svg", | |||||
.priority = IZ_VIDEO_SPRITE_PRIORITY_MEDIUM, | |||||
}, &app->video_state.active_sprites[sprite_slot_index]); | |||||
app->video_state.active_sprites[sprite_slot_index].sprite.scale_factor = 0.25f; | |||||
app->video_state.active_sprites[sprite_slot_index].sprite.position = (IZ_Vector2D) { 50.f, 50.f }; | |||||
app->video_state.active_sprites[sprite_slot_index].sprite.flip_x = true; | |||||
while (true) { | while (true) { | ||||
app->ticks = SDL_GetTicks64(); | app->ticks = SDL_GetTicks64(); | ||||
@@ -123,16 +123,23 @@ void IZ_VideoUpdate(IZ_VideoState* video_state) { | |||||
IZ_Sprite* sprite = &video_state->active_sprites[sprite_index].sprite; | IZ_Sprite* sprite = &video_state->active_sprites[sprite_index].sprite; | ||||
f32 draw_width = sprite->original_width * sprite->scale_factor; | f32 draw_width = sprite->original_width * sprite->scale_factor; | ||||
f32 draw_height = sprite->original_height * sprite->scale_factor; | f32 draw_height = sprite->original_height * sprite->scale_factor; | ||||
u8 flip_flag = 0; | |||||
if (sprite->flip_x) { | |||||
flip_flag |= SDL_FLIP_HORIZONTAL; | |||||
} | |||||
if (sprite->flip_y) { | |||||
flip_flag |= SDL_FLIP_VERTICAL; | |||||
} | |||||
SDL_RenderCopyExF(video_state->renderer, sprite->texture, NULL, &(SDL_FRect) { | SDL_RenderCopyExF(video_state->renderer, sprite->texture, NULL, &(SDL_FRect) { | ||||
// TODO honor each sprite's location in the world for calculation in the screen. | // TODO honor each sprite's location in the world for calculation in the screen. | ||||
.x = 100, | |||||
.y = 100, | |||||
.x = sprite->position.x, | |||||
.y = sprite->position.y, | |||||
.w = draw_width, | .w = draw_width, | ||||
.h = draw_height, | .h = draw_height, | ||||
}, sprite->rotate_degrees++, &(SDL_FPoint) { | }, sprite->rotate_degrees++, &(SDL_FPoint) { | ||||
.x = draw_width / 2, | .x = draw_width / 2, | ||||
.y = draw_height / 2, | .y = draw_height / 2, | ||||
}, SDL_FLIP_NONE); | |||||
}, flip_flag); | |||||
// our goal is to render the svg files and apply custom transforms to some SVG groups if ever. | // our goal is to render the svg files and apply custom transforms to some SVG groups if ever. | ||||
// TODO perhaps we can parse the SVG for easier transforms? | // TODO perhaps we can parse the SVG for easier transforms? | ||||
@@ -1,10 +1,10 @@ | |||||
#ifndef IZ_ENTITY_H | #ifndef IZ_ENTITY_H | ||||
#define IZ_ENTITY_H | #define IZ_ENTITY_H | ||||
#include "../geometry/IZ_point2d.h" | |||||
#include "../geometry/IZ_vector2d.h" | |||||
typedef struct { | typedef struct { | ||||
IZ_Point2D pos; | |||||
IZ_Vector2D pos; | |||||
// TODO object appearance (sprite, sprites contain bounding boxes, collisions contain bounding boxes) | // TODO object appearance (sprite, sprites contain bounding boxes, collisions contain bounding boxes) | ||||
} IZ_Entity; | } IZ_Entity; | ||||
@@ -1,8 +0,0 @@ | |||||
#include "IZ_point2d.h" | |||||
IZ_Point2D IZ_Point2DTranslate(IZ_Point2D point, f32 translate_x, f32 translate_y) { | |||||
return (IZ_Point2D) { | |||||
.x = point.x + translate_x, | |||||
.y = point.y + translate_y, | |||||
}; | |||||
} |
@@ -1,14 +0,0 @@ | |||||
#ifndef IZ_POINT2D_H | |||||
#define IZ_POINT2D_H | |||||
#include "../../common/IZ_common.h" | |||||
// TODO: unify with vector2d | |||||
typedef struct { | |||||
f32 x; | |||||
f32 y; | |||||
} IZ_Point2D; | |||||
IZ_Point2D IZ_Point2DTranslate(IZ_Point2D, f32, f32); | |||||
#endif |
@@ -9,7 +9,7 @@ IZ_Bounds IZ_RectGetBounds(IZ_Rect rect) { | |||||
}; | }; | ||||
} | } | ||||
bool IZ_RectBoundsContainPoint(IZ_Bounds bounds, IZ_Point2D point) { | |||||
bool IZ_RectBoundsContainPoint(IZ_Bounds bounds, IZ_Vector2D point) { | |||||
return ( | return ( | ||||
bounds.left <= point.x | bounds.left <= point.x | ||||
&& bounds.top <= point.y | && bounds.top <= point.y | ||||
@@ -2,7 +2,7 @@ | |||||
#define IZ_RECT_H | #define IZ_RECT_H | ||||
#include <stdbool.h> | #include <stdbool.h> | ||||
#include "IZ_point2d.h" | |||||
#include "IZ_vector2d.h" | |||||
typedef struct { | typedef struct { | ||||
f32 left; | f32 left; | ||||
@@ -13,14 +13,14 @@ typedef struct { | |||||
typedef struct { | typedef struct { | ||||
// top left | // top left | ||||
IZ_Point2D pos; | |||||
IZ_Vector2D pos; | |||||
f32 width; | f32 width; | ||||
f32 height; | f32 height; | ||||
} IZ_Rect; | } IZ_Rect; | ||||
IZ_Bounds IZ_RectGetBounds(IZ_Rect); | IZ_Bounds IZ_RectGetBounds(IZ_Rect); | ||||
bool IZ_RectBoundsContainPoint(IZ_Bounds, IZ_Point2D); | |||||
bool IZ_RectBoundsContainPoint(IZ_Bounds, IZ_Vector2D); | |||||
bool IZ_RectBoundsCollide(IZ_Bounds, IZ_Bounds); | bool IZ_RectBoundsCollide(IZ_Bounds, IZ_Bounds); | ||||
@@ -2,21 +2,21 @@ | |||||
IZ_Vector2D IZ_Vector2DAdd(IZ_Vector2D addend, IZ_Vector2D augend) { | IZ_Vector2D IZ_Vector2DAdd(IZ_Vector2D addend, IZ_Vector2D augend) { | ||||
return (IZ_Vector2D) { | return (IZ_Vector2D) { | ||||
.right = addend.right + augend.right, | |||||
.up = addend.up + augend.up, | |||||
.x = addend.x + augend.x, | |||||
.y = addend.y + augend.y, | |||||
}; | }; | ||||
} | } | ||||
IZ_Vector2D IZ_Vector2DMultiply(IZ_Vector2D multiplicand, IZ_Vector2D multiplier) { | IZ_Vector2D IZ_Vector2DMultiply(IZ_Vector2D multiplicand, IZ_Vector2D multiplier) { | ||||
return (IZ_Vector2D) { | return (IZ_Vector2D) { | ||||
.right = multiplicand.right * multiplier.right, | |||||
.up = multiplicand.up * multiplier.up, | |||||
.x = multiplicand.x * multiplier.x, | |||||
.y = multiplicand.y * multiplier.y, | |||||
}; | }; | ||||
} | } | ||||
IZ_Vector2D IZ_Vector2DScale(IZ_Vector2D vector, f32 scalar) { | IZ_Vector2D IZ_Vector2DScale(IZ_Vector2D vector, f32 scalar) { | ||||
return (IZ_Vector2D) { | return (IZ_Vector2D) { | ||||
.right = vector.right * scalar, | |||||
.up = vector.up * scalar, | |||||
.x = vector.x * scalar, | |||||
.y = vector.y * scalar, | |||||
}; | }; | ||||
} | } |
@@ -1,11 +1,11 @@ | |||||
#ifndef IZ_VECTOR2D_H | #ifndef IZ_VECTOR2D_H | ||||
#define IZ_VECTOR2D_H | #define IZ_VECTOR2D_H | ||||
#include "IZ_point2d.h" | |||||
#include "../../common/IZ_common.h" | |||||
typedef struct { | typedef struct { | ||||
f32 right; | |||||
f32 up; | |||||
f32 x; | |||||
f32 y; | |||||
} IZ_Vector2D; | } IZ_Vector2D; | ||||
IZ_Vector2D IZ_Vector2DAdd(IZ_Vector2D, IZ_Vector2D); | IZ_Vector2D IZ_Vector2DAdd(IZ_Vector2D, IZ_Vector2D); | ||||
@@ -1,101 +1,78 @@ | |||||
#include "../../test/IZ_test.h" | #include "../../test/IZ_test.h" | ||||
#include "IZ_point2d.h" | |||||
#include "IZ_vector2d.h" | #include "IZ_vector2d.h" | ||||
#include "IZ_rect.h" | #include "IZ_rect.h" | ||||
spec("geometry") { | spec("geometry") { | ||||
describe("point2d") { | |||||
describe("Translate") { | |||||
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_Point2DTranslate(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("vector2d") { | ||||
describe("Add") { | describe("Add") { | ||||
it("adds two vectors") { | it("adds two vectors") { | ||||
static IZ_Vector2D addend = { | static IZ_Vector2D addend = { | ||||
.right = 420.f, | |||||
.up = 1337.f, | |||||
.x = 420.f, | |||||
.y = 1337.f, | |||||
}; | }; | ||||
static IZ_Vector2D augend = { | static IZ_Vector2D augend = { | ||||
.right = 6.f, | |||||
.up = 9.f, | |||||
.x = 6.f, | |||||
.y = 9.f, | |||||
}; | }; | ||||
static IZ_Vector2D expected_sum = { | static IZ_Vector2D expected_sum = { | ||||
.right = 426.f, | |||||
.up = 1346.f, | |||||
.x = 426.f, | |||||
.y = 1346.f, | |||||
}; | }; | ||||
static IZ_Vector2D actual_sum; | static IZ_Vector2D actual_sum; | ||||
actual_sum = IZ_Vector2DAdd(addend, augend); | actual_sum = IZ_Vector2DAdd(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."); | |||||
check(expected_sum.x == actual_sum.x, "Right values do not match."); | |||||
check(expected_sum.y == actual_sum.y, "Up values do not match."); | |||||
} | } | ||||
} | } | ||||
describe("Multiply") { | describe("Multiply") { | ||||
it("multiplies two vectors") { | it("multiplies two vectors") { | ||||
static IZ_Vector2D multiplicand = { | static IZ_Vector2D multiplicand = { | ||||
.right = 6.f, | |||||
.up = 9.f, | |||||
.x = 6.f, | |||||
.y = 9.f, | |||||
}; | }; | ||||
static IZ_Vector2D multiplier = { | static IZ_Vector2D multiplier = { | ||||
.right = 3.f, | |||||
.up = 2.f, | |||||
.x = 3.f, | |||||
.y = 2.f, | |||||
}; | }; | ||||
static IZ_Vector2D expected_product = { | static IZ_Vector2D expected_product = { | ||||
.right = 18.f, | |||||
.up = 18.f, | |||||
.x = 18.f, | |||||
.y = 18.f, | |||||
}; | }; | ||||
static IZ_Vector2D actual_product; | static IZ_Vector2D actual_product; | ||||
actual_product = IZ_Vector2DMultiply(multiplicand, multiplier); | actual_product = IZ_Vector2DMultiply(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."); | |||||
check(expected_product.x == actual_product.x, "Right values do not match."); | |||||
check(expected_product.y == actual_product.y, "Up values do not match."); | |||||
} | } | ||||
} | } | ||||
describe("Scale") { | describe("Scale") { | ||||
it("scales a vector") { | it("scales a vector") { | ||||
static IZ_Vector2D v = { | static IZ_Vector2D v = { | ||||
.right = 420.f, | |||||
.up = 69.f, | |||||
.x = 420.f, | |||||
.y = 69.f, | |||||
}; | }; | ||||
static f32 s = 2.f; | static f32 s = 2.f; | ||||
static IZ_Vector2D expected = { | static IZ_Vector2D expected = { | ||||
.right = 840.f, | |||||
.up = 138.f, | |||||
.x = 840.f, | |||||
.y = 138.f, | |||||
}; | }; | ||||
static IZ_Vector2D actual; | static IZ_Vector2D actual; | ||||
actual = IZ_Vector2DScale(v, s); | actual = IZ_Vector2DScale(v, s); | ||||
check(expected.right == actual.right, "Right values do not match."); | |||||
check(expected.up == actual.up, "Up values do not match."); | |||||
check(expected.x == actual.x, "Right values do not match."); | |||||
check(expected.y == actual.y, "Up values do not match."); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
@@ -138,7 +115,7 @@ spec("geometry") { | |||||
.bottom = 300, | .bottom = 300, | ||||
}; | }; | ||||
static IZ_Point2D p = { | |||||
static IZ_Vector2D p = { | |||||
.x = 75, | .x = 75, | ||||
.y = 150, | .y = 150, | ||||
}; | }; | ||||
@@ -154,12 +131,12 @@ spec("geometry") { | |||||
.bottom = 300, | .bottom = 300, | ||||
}; | }; | ||||
static IZ_Point2D p1 = { | |||||
static IZ_Vector2D p1 = { | |||||
.x = 50, | .x = 50, | ||||
.y = 100, | .y = 100, | ||||
}; | }; | ||||
static IZ_Point2D p2 = { | |||||
static IZ_Vector2D p2 = { | |||||
.x = 200, | .x = 200, | ||||
.y = 300, | .y = 300, | ||||
}; | }; | ||||
@@ -176,7 +153,7 @@ spec("geometry") { | |||||
.bottom = 300, | .bottom = 300, | ||||
}; | }; | ||||
static IZ_Point2D p = { | |||||
static IZ_Vector2D p = { | |||||
.x = 0, | .x = 0, | ||||
.y = 0, | .y = 0, | ||||
}; | }; | ||||
@@ -92,6 +92,14 @@ IZ_ProcedureResult IZ_VideoInitialize(IZ_VideoState* state, void* user_data, con | |||||
} | } | ||||
void IZ_VideoTeardown(IZ_VideoState* state) { | void IZ_VideoTeardown(IZ_VideoState* state) { | ||||
for (u16 i = 0; i < MAX_ACTIVE_SPRITES; i += 1) { | |||||
if (state->active_sprites[i].sprite.texture) { | |||||
SDL_DestroyTexture(state->active_sprites[i].sprite.texture); | |||||
state->active_sprites[i].sprite.texture = NULL; | |||||
state->active_sprites[i].requested_at = 0; | |||||
} | |||||
} | |||||
SDL_DestroyWindow(state->window); | SDL_DestroyWindow(state->window); | ||||
} | } | ||||
@@ -100,8 +108,14 @@ u16 IZ_VideoGetNextFreeSpriteSlot(IZ_VideoState* state) { | |||||
// 1. Run through all sprites in the active sprites array | // 1. Run through all sprites in the active sprites array | ||||
// 2. Check each sprite's priority and requested_at (for eviction policy) | // 2. Check each sprite's priority and requested_at (for eviction policy) | ||||
// 3. Return that new slot. (prefer returning empty slots) | // 3. Return that new slot. (prefer returning empty slots) | ||||
// 4. Return the max value for u16 if there's not slot left) | |||||
return 0; | |||||
// 4. Return MAX_ACTIVE_SPRITES if there's no slot left) | |||||
for (u16 i = 0; i < MAX_ACTIVE_SPRITES; i += 1) { | |||||
if (!state->active_sprites[i].sprite.texture) { | |||||
return i; | |||||
} | |||||
} | |||||
return MAX_ACTIVE_SPRITES; | |||||
} | } | ||||
void IZ_VideoLoadSprite(IZ_VideoState* state, IZ_VideoLoadSpriteParams params, IZ_SpriteSlot* out) { | void IZ_VideoLoadSprite(IZ_VideoState* state, IZ_VideoLoadSpriteParams params, IZ_SpriteSlot* out) { | ||||
@@ -111,7 +125,7 @@ void IZ_VideoLoadSprite(IZ_VideoState* state, IZ_VideoLoadSpriteParams params, I | |||||
u32 sprite_length_bytes = ini_getl(params.dir, params.filename, 0, "assets.ini"); | u32 sprite_length_bytes = ini_getl(params.dir, params.filename, 0, "assets.ini"); | ||||
u8* sprite = malloc(sprite_length_bytes + 1); | u8* sprite = malloc(sprite_length_bytes + 1); | ||||
fread(sprite, 1, sprite_length_bytes, f); | fread(sprite, 1, sprite_length_bytes, f); | ||||
SDL_SetRenderDrawBlendMode(state->renderer, SDL_BLENDMODE_ADD); | |||||
SDL_SetRenderDrawBlendMode(state->renderer, SDL_BLENDMODE_BLEND); | |||||
SDL_Surface* test_surface = IMG_LoadSVG_RW(SDL_RWFromConstMem(sprite, sprite_length_bytes)); | SDL_Surface* test_surface = IMG_LoadSVG_RW(SDL_RWFromConstMem(sprite, sprite_length_bytes)); | ||||
free(sprite); | free(sprite); | ||||
if (test_surface) { | if (test_surface) { | ||||
@@ -120,15 +134,9 @@ void IZ_VideoLoadSprite(IZ_VideoState* state, IZ_VideoLoadSpriteParams params, I | |||||
out->sprite.original_height = test_surface->h; | out->sprite.original_height = test_surface->h; | ||||
out->sprite.scale_factor = 1; | out->sprite.scale_factor = 1; | ||||
out->sprite.rotate_degrees = 0; | out->sprite.rotate_degrees = 0; | ||||
out->sprite.position = (IZ_Vector2D) { 0, 0 }; | |||||
out->sprite.flip_x = false; | |||||
out->sprite.flip_y = false; | |||||
SDL_FreeSurface(test_surface); | SDL_FreeSurface(test_surface); | ||||
} | } | ||||
} | } | ||||
void IZ_VideoTeardownTexture(IZ_Sprite* sprite) { | |||||
if (!sprite->texture) { | |||||
return; | |||||
} | |||||
SDL_DestroyTexture(sprite->texture); | |||||
sprite->original_width = 0; | |||||
sprite->original_height = 0; | |||||
} |
@@ -9,6 +9,7 @@ | |||||
#include "../../../net/IZ_net_client.h" | #include "../../../net/IZ_net_client.h" | ||||
#include "../../../config/IZ_config.h" | #include "../../../config/IZ_config.h" | ||||
#include "../../../common/IZ_common.h" | #include "../../../common/IZ_common.h" | ||||
#include "../../geometry/IZ_vector2d.h" | |||||
#include "../../input/IZ_input.h" | #include "../../input/IZ_input.h" | ||||
#define MAX_ACTIVE_SPRITES 512u | #define MAX_ACTIVE_SPRITES 512u | ||||
@@ -32,10 +33,13 @@ typedef enum { | |||||
typedef struct { | typedef struct { | ||||
SDL_Texture* texture; | SDL_Texture* texture; | ||||
IZ_Vector2D position; | |||||
f32 original_width; | f32 original_width; | ||||
f32 original_height; | f32 original_height; | ||||
f32 scale_factor; | f32 scale_factor; | ||||
f32 rotate_degrees; | f32 rotate_degrees; | ||||
bool flip_x; | |||||
bool flip_y; | |||||
} IZ_Sprite; | } IZ_Sprite; | ||||
typedef struct { | typedef struct { | ||||
@@ -86,8 +90,6 @@ u16 IZ_VideoGetNextFreeSpriteSlot(IZ_VideoState*); | |||||
void IZ_VideoLoadSprite(IZ_VideoState*, IZ_VideoLoadSpriteParams, IZ_SpriteSlot*); | void IZ_VideoLoadSprite(IZ_VideoState*, IZ_VideoLoadSpriteParams, IZ_SpriteSlot*); | ||||
void IZ_VideoTeardownTexture(IZ_Sprite*); | |||||
void IZ_VideoTeardown(IZ_VideoState*); | void IZ_VideoTeardown(IZ_VideoState*); | ||||
#endif | #endif |