浏览代码

Add more sprite logic

Demonstrate on-the-fly flip for sprites.
feature/data-structs
父节点
当前提交
b4cf53c181
共有 13 个文件被更改,包括 89 次插入109 次删除
  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 查看文件

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


+ 12
- 0
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, .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();


+ 10
- 3
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; 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?


+ 2
- 2
src/packages/game/core/IZ_entity.h 查看文件

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




+ 0
- 8
src/packages/game/geometry/IZ_point2d.c 查看文件

@@ -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 查看文件

@@ -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 查看文件

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


+ 3
- 3
src/packages/game/geometry/IZ_rect.h 查看文件

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




+ 6
- 6
src/packages/game/geometry/IZ_vector2d.c 查看文件

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

+ 3
- 3
src/packages/game/geometry/IZ_vector2d.h 查看文件

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


+ 26
- 49
src/packages/game/geometry/geometry.test.c 查看文件

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


+ 20
- 12
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) { 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;
}

+ 4
- 2
src/packages/game/output/video/IZ_video.h 查看文件

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

正在加载...
取消
保存