From b4cf53c181064a382ec1206872983a25c705b001 Mon Sep 17 00:00:00 2001 From: TheoryOfNekomata Date: Sat, 17 Sep 2022 18:41:41 +0800 Subject: [PATCH] Add more sprite logic Demonstrate on-the-fly flip for sprites. --- CMakeLists.txt | 8 +-- src/packages/game/IZ_app.c | 12 ++++ src/packages/game/IZ_app_video.c | 13 +++- src/packages/game/core/IZ_entity.h | 4 +- src/packages/game/geometry/IZ_point2d.c | 8 --- src/packages/game/geometry/IZ_point2d.h | 14 ---- src/packages/game/geometry/IZ_rect.c | 2 +- src/packages/game/geometry/IZ_rect.h | 6 +- src/packages/game/geometry/IZ_vector2d.c | 12 ++-- src/packages/game/geometry/IZ_vector2d.h | 6 +- src/packages/game/geometry/geometry.test.c | 75 ++++++++-------------- src/packages/game/output/video/IZ_video.c | 32 +++++---- src/packages/game/output/video/IZ_video.h | 6 +- 13 files changed, 89 insertions(+), 109 deletions(-) delete mode 100644 src/packages/game/geometry/IZ_point2d.c delete mode 100644 src/packages/game/geometry/IZ_point2d.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b72e50a..3777294 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -67,9 +67,7 @@ add_executable( src/packages/game/input/IZ_keyboard.h src/packages/config/IZ_config.c 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_rect.c src/packages/game/geometry/IZ_rect.h @@ -115,9 +113,7 @@ add_executable( src/packages/test/IZ_mock.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_vector2d.h src/packages/game/geometry/IZ_vector2d.c diff --git a/src/packages/game/IZ_app.c b/src/packages/game/IZ_app.c index ae1ccbe..220228e 100644 --- a/src/packages/game/IZ_app.c +++ b/src/packages/game/IZ_app.c @@ -127,6 +127,18 @@ IZ_AppResult IZ_AppRun(struct IZ_App* app, u8 argc, const char* argv[]) { .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) { 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) { app->ticks = SDL_GetTicks64(); diff --git a/src/packages/game/IZ_app_video.c b/src/packages/game/IZ_app_video.c index 1d11da6..cdda642 100644 --- a/src/packages/game/IZ_app_video.c +++ b/src/packages/game/IZ_app_video.c @@ -123,16 +123,23 @@ void IZ_VideoUpdate(IZ_VideoState* video_state) { IZ_Sprite* sprite = &video_state->active_sprites[sprite_index].sprite; f32 draw_width = sprite->original_width * 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) { // 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, .h = draw_height, }, sprite->rotate_degrees++, &(SDL_FPoint) { .x = draw_width / 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. // TODO perhaps we can parse the SVG for easier transforms? diff --git a/src/packages/game/core/IZ_entity.h b/src/packages/game/core/IZ_entity.h index d522316..f5cf831 100644 --- a/src/packages/game/core/IZ_entity.h +++ b/src/packages/game/core/IZ_entity.h @@ -1,10 +1,10 @@ #ifndef IZ_ENTITY_H #define IZ_ENTITY_H -#include "../geometry/IZ_point2d.h" +#include "../geometry/IZ_vector2d.h" typedef struct { - IZ_Point2D pos; + IZ_Vector2D pos; // TODO object appearance (sprite, sprites contain bounding boxes, collisions contain bounding boxes) } IZ_Entity; diff --git a/src/packages/game/geometry/IZ_point2d.c b/src/packages/game/geometry/IZ_point2d.c deleted file mode 100644 index 4be59b2..0000000 --- a/src/packages/game/geometry/IZ_point2d.c +++ /dev/null @@ -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, - }; -} diff --git a/src/packages/game/geometry/IZ_point2d.h b/src/packages/game/geometry/IZ_point2d.h deleted file mode 100644 index 3908bec..0000000 --- a/src/packages/game/geometry/IZ_point2d.h +++ /dev/null @@ -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 diff --git a/src/packages/game/geometry/IZ_rect.c b/src/packages/game/geometry/IZ_rect.c index 6926d5e..cea4f0c 100644 --- a/src/packages/game/geometry/IZ_rect.c +++ b/src/packages/game/geometry/IZ_rect.c @@ -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 ( bounds.left <= point.x && bounds.top <= point.y diff --git a/src/packages/game/geometry/IZ_rect.h b/src/packages/game/geometry/IZ_rect.h index 3733005..07bd217 100644 --- a/src/packages/game/geometry/IZ_rect.h +++ b/src/packages/game/geometry/IZ_rect.h @@ -2,7 +2,7 @@ #define IZ_RECT_H #include -#include "IZ_point2d.h" +#include "IZ_vector2d.h" typedef struct { f32 left; @@ -13,14 +13,14 @@ typedef struct { typedef struct { // top left - IZ_Point2D pos; + IZ_Vector2D pos; f32 width; f32 height; } 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); diff --git a/src/packages/game/geometry/IZ_vector2d.c b/src/packages/game/geometry/IZ_vector2d.c index f33247c..d576082 100644 --- a/src/packages/game/geometry/IZ_vector2d.c +++ b/src/packages/game/geometry/IZ_vector2d.c @@ -2,21 +2,21 @@ IZ_Vector2D IZ_Vector2DAdd(IZ_Vector2D addend, IZ_Vector2D augend) { 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) { 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) { return (IZ_Vector2D) { - .right = vector.right * scalar, - .up = vector.up * scalar, + .x = vector.x * scalar, + .y = vector.y * scalar, }; } diff --git a/src/packages/game/geometry/IZ_vector2d.h b/src/packages/game/geometry/IZ_vector2d.h index 53676be..def46b1 100644 --- a/src/packages/game/geometry/IZ_vector2d.h +++ b/src/packages/game/geometry/IZ_vector2d.h @@ -1,11 +1,11 @@ #ifndef IZ_VECTOR2D_H #define IZ_VECTOR2D_H -#include "IZ_point2d.h" +#include "../../common/IZ_common.h" typedef struct { - f32 right; - f32 up; + f32 x; + f32 y; } IZ_Vector2D; IZ_Vector2D IZ_Vector2DAdd(IZ_Vector2D, IZ_Vector2D); diff --git a/src/packages/game/geometry/geometry.test.c b/src/packages/game/geometry/geometry.test.c index 287b830..fd6f59c 100644 --- a/src/packages/game/geometry/geometry.test.c +++ b/src/packages/game/geometry/geometry.test.c @@ -1,101 +1,78 @@ #include "../../test/IZ_test.h" -#include "IZ_point2d.h" #include "IZ_vector2d.h" #include "IZ_rect.h" 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("Add") { it("adds two vectors") { static IZ_Vector2D addend = { - .right = 420.f, - .up = 1337.f, + .x = 420.f, + .y = 1337.f, }; static IZ_Vector2D augend = { - .right = 6.f, - .up = 9.f, + .x = 6.f, + .y = 9.f, }; static IZ_Vector2D expected_sum = { - .right = 426.f, - .up = 1346.f, + .x = 426.f, + .y = 1346.f, }; static IZ_Vector2D actual_sum; 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") { it("multiplies two vectors") { static IZ_Vector2D multiplicand = { - .right = 6.f, - .up = 9.f, + .x = 6.f, + .y = 9.f, }; static IZ_Vector2D multiplier = { - .right = 3.f, - .up = 2.f, + .x = 3.f, + .y = 2.f, }; static IZ_Vector2D expected_product = { - .right = 18.f, - .up = 18.f, + .x = 18.f, + .y = 18.f, }; static IZ_Vector2D actual_product; 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") { it("scales a vector") { static IZ_Vector2D v = { - .right = 420.f, - .up = 69.f, + .x = 420.f, + .y = 69.f, }; static f32 s = 2.f; static IZ_Vector2D expected = { - .right = 840.f, - .up = 138.f, + .x = 840.f, + .y = 138.f, }; static IZ_Vector2D actual; 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, }; - static IZ_Point2D p = { + static IZ_Vector2D p = { .x = 75, .y = 150, }; @@ -154,12 +131,12 @@ spec("geometry") { .bottom = 300, }; - static IZ_Point2D p1 = { + static IZ_Vector2D p1 = { .x = 50, .y = 100, }; - static IZ_Point2D p2 = { + static IZ_Vector2D p2 = { .x = 200, .y = 300, }; @@ -176,7 +153,7 @@ spec("geometry") { .bottom = 300, }; - static IZ_Point2D p = { + static IZ_Vector2D p = { .x = 0, .y = 0, }; diff --git a/src/packages/game/output/video/IZ_video.c b/src/packages/game/output/video/IZ_video.c index eea3416..b2c2910 100644 --- a/src/packages/game/output/video/IZ_video.c +++ b/src/packages/game/output/video/IZ_video.c @@ -92,6 +92,14 @@ IZ_ProcedureResult IZ_VideoInitialize(IZ_VideoState* state, void* user_data, con } 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); } @@ -100,8 +108,14 @@ u16 IZ_VideoGetNextFreeSpriteSlot(IZ_VideoState* state) { // 1. Run through all sprites in the active sprites array // 2. Check each sprite's priority and requested_at (for eviction policy) // 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) { @@ -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"); u8* sprite = malloc(sprite_length_bytes + 1); 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)); free(sprite); 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.scale_factor = 1; 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); } } - -void IZ_VideoTeardownTexture(IZ_Sprite* sprite) { - if (!sprite->texture) { - return; - } - SDL_DestroyTexture(sprite->texture); - sprite->original_width = 0; - sprite->original_height = 0; -} diff --git a/src/packages/game/output/video/IZ_video.h b/src/packages/game/output/video/IZ_video.h index 1ccc4be..ada7e71 100644 --- a/src/packages/game/output/video/IZ_video.h +++ b/src/packages/game/output/video/IZ_video.h @@ -9,6 +9,7 @@ #include "../../../net/IZ_net_client.h" #include "../../../config/IZ_config.h" #include "../../../common/IZ_common.h" +#include "../../geometry/IZ_vector2d.h" #include "../../input/IZ_input.h" #define MAX_ACTIVE_SPRITES 512u @@ -32,10 +33,13 @@ typedef enum { typedef struct { SDL_Texture* texture; + IZ_Vector2D position; f32 original_width; f32 original_height; f32 scale_factor; f32 rotate_degrees; + bool flip_x; + bool flip_y; } IZ_Sprite; typedef struct { @@ -86,8 +90,6 @@ u16 IZ_VideoGetNextFreeSpriteSlot(IZ_VideoState*); void IZ_VideoLoadSprite(IZ_VideoState*, IZ_VideoLoadSpriteParams, IZ_SpriteSlot*); -void IZ_VideoTeardownTexture(IZ_Sprite*); - void IZ_VideoTeardown(IZ_VideoState*); #endif