Browse Source

Add more sprite logic

Demonstrate on-the-fly flip for sprites.
feature/data-structs
TheoryOfNekomata 1 year ago
parent
commit
b4cf53c181
13 changed files with 89 additions and 109 deletions
  1. +2
    -6
      CMakeLists.txt
  2. +12
    -0
      src/packages/game/IZ_app.c
  3. +10
    -3
      src/packages/game/IZ_app_video.c
  4. +2
    -2
      src/packages/game/core/IZ_entity.h
  5. +0
    -8
      src/packages/game/geometry/IZ_point2d.c
  6. +0
    -14
      src/packages/game/geometry/IZ_point2d.h
  7. +1
    -1
      src/packages/game/geometry/IZ_rect.c
  8. +3
    -3
      src/packages/game/geometry/IZ_rect.h
  9. +6
    -6
      src/packages/game/geometry/IZ_vector2d.c
  10. +3
    -3
      src/packages/game/geometry/IZ_vector2d.h
  11. +26
    -49
      src/packages/game/geometry/geometry.test.c
  12. +20
    -12
      src/packages/game/output/video/IZ_video.c
  13. +4
    -2
      src/packages/game/output/video/IZ_video.h

+ 2
- 6
CMakeLists.txt View File

@@ -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


+ 12
- 0
src/packages/game/IZ_app.c View File

@@ -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();


+ 10
- 3
src/packages/game/IZ_app_video.c View File

@@ -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?


+ 2
- 2
src/packages/game/core/IZ_entity.h View File

@@ -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;



+ 0
- 8
src/packages/game/geometry/IZ_point2d.c View File

@@ -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,
};
}

+ 0
- 14
src/packages/game/geometry/IZ_point2d.h View File

@@ -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

+ 1
- 1
src/packages/game/geometry/IZ_rect.c View File

@@ -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


+ 3
- 3
src/packages/game/geometry/IZ_rect.h View File

@@ -2,7 +2,7 @@
#define IZ_RECT_H

#include <stdbool.h>
#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);



+ 6
- 6
src/packages/game/geometry/IZ_vector2d.c View File

@@ -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,
};
}

+ 3
- 3
src/packages/game/geometry/IZ_vector2d.h View File

@@ -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);


+ 26
- 49
src/packages/game/geometry/geometry.test.c View File

@@ -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,
};


+ 20
- 12
src/packages/game/output/video/IZ_video.c View File

@@ -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;
}

+ 4
- 2
src/packages/game/output/video/IZ_video.h View File

@@ -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

Loading…
Cancel
Save