Make use of sprite loading to streamline the sprite management process.feature/data-structs
@@ -118,6 +118,13 @@ IZ_AppResult IZ_AppRun(struct IZ_App* app, u8 argc, const char* argv[]) { | |||||
return IZ_APP_RESULT_INITIALIZATION_ERROR; | return IZ_APP_RESULT_INITIALIZATION_ERROR; | ||||
} | } | ||||
u16 sprite_slot_index = IZ_VideoGetNextFreeSpriteSlot(&app->video_state); | |||||
IZ_VideoLoadSprite(&app->video_state, (IZ_VideoLoadSpriteParams) { | |||||
.dir = "assets/default/weapon-servant", | |||||
.filename = "sprite.svg", | |||||
.priority = IZ_VIDEO_SPRITE_PRIORITY_MEDIUM, | |||||
}, &app->video_state.active_sprites[sprite_slot_index]); | |||||
while (true) { | while (true) { | ||||
app->ticks = SDL_GetTicks64(); | app->ticks = SDL_GetTicks64(); | ||||
@@ -104,8 +104,6 @@ void IZ_VideoUpdateForDebugNet(IZ_VideoState* video_state, IZ_NetClientState* ne | |||||
} | } | ||||
} | } | ||||
static f32 degrees = 0; | |||||
void IZ_VideoUpdate(IZ_VideoState* video_state) { | void IZ_VideoUpdate(IZ_VideoState* video_state) { | ||||
struct IZ_App* app = video_state->user_data; | struct IZ_App* app = video_state->user_data; | ||||
u64 ticks = IZ_AppGetTicks(app); | u64 ticks = IZ_AppGetTicks(app); | ||||
@@ -118,32 +116,22 @@ void IZ_VideoUpdate(IZ_VideoState* video_state) { | |||||
SDL_RenderClear(video_state->renderer); | SDL_RenderClear(video_state->renderer); | ||||
u16 sprite_index; | u16 sprite_index; | ||||
for (sprite_index = 0; sprite_index < MAX_ACTIVE_SPRITES; sprite_index += 1) { | for (sprite_index = 0; sprite_index < MAX_ACTIVE_SPRITES; sprite_index += 1) { | ||||
if (!video_state->active_sprites[sprite_index]) { | |||||
if (!video_state->active_sprites[sprite_index].sprite.texture) { | |||||
continue; | continue; | ||||
} | } | ||||
// TODO draw sprites | |||||
} | |||||
IZ_LoadedSprite loaded_sprite = { | |||||
.texture = NULL, | |||||
.original_width = 0, | |||||
.original_height = 0, | |||||
}; | |||||
IZ_VideoLoadTexture(video_state, "assets/default/weapon-servant", "sprite.svg", &loaded_sprite); | |||||
if (loaded_sprite.texture) { | |||||
f32 draw_width = loaded_sprite.original_width / 2; | |||||
f32 draw_height = loaded_sprite.original_height / 2; | |||||
SDL_RenderCopyExF(video_state->renderer, loaded_sprite.texture, NULL, &(SDL_FRect) { | |||||
IZ_Sprite* loaded_sprite = &video_state->active_sprites[sprite_index].sprite; | |||||
f32 draw_width = loaded_sprite->original_width * loaded_sprite->scale_factor; | |||||
f32 draw_height = loaded_sprite->original_height * loaded_sprite->scale_factor; | |||||
SDL_RenderCopyExF(video_state->renderer, loaded_sprite->texture, NULL, &(SDL_FRect) { | |||||
.x = 160, | .x = 160, | ||||
.y = 120, | .y = 120, | ||||
.w = draw_width, | .w = draw_width, | ||||
.h = draw_height, | .h = draw_height, | ||||
}, degrees++, &(SDL_FPoint) { | |||||
}, loaded_sprite->rotate_degrees++, &(SDL_FPoint) { | |||||
.x = draw_width / 2, | .x = draw_width / 2, | ||||
.y = draw_height / 2, | .y = draw_height / 2, | ||||
}, SDL_FLIP_NONE); | |||||
}, SDL_FLIP_HORIZONTAL); | |||||
IZ_VideoTeardownTexture(&loaded_sprite); | |||||
// 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? | ||||
} | } | ||||
@@ -66,6 +66,7 @@ IZ_ProcedureResult IZ_VideoInitializeConfig(IZ_VideoState* state, const char* c | |||||
IZ_ProcedureResult IZ_VideoInitialize(IZ_VideoState* state, void* user_data, const char* config_path, u8 argc, const char* argv[]) { | IZ_ProcedureResult IZ_VideoInitialize(IZ_VideoState* state, void* user_data, const char* config_path, u8 argc, const char* argv[]) { | ||||
SDL_memcpy(state, &IZ_VIDEO_DEFAULT_STATE, sizeof(IZ_VideoState)); | SDL_memcpy(state, &IZ_VIDEO_DEFAULT_STATE, sizeof(IZ_VideoState)); | ||||
memset(state->active_sprites, 0, sizeof(IZ_SpriteSlot) * MAX_ACTIVE_SPRITES); | |||||
if (IZ_VideoInitializeConfig(state, config_path, argc, argv) < 0) { | if (IZ_VideoInitializeConfig(state, config_path, argc, argv) < 0) { | ||||
return -2; | return -2; | ||||
} | } | ||||
@@ -94,25 +95,31 @@ void IZ_VideoTeardown(IZ_VideoState* state) { | |||||
SDL_DestroyWindow(state->window); | SDL_DestroyWindow(state->window); | ||||
} | } | ||||
void IZ_VideoLoadTexture(IZ_VideoState* state, const char* dir, const char* filename, IZ_LoadedSprite* out) { | |||||
u16 IZ_VideoGetNextFreeSpriteSlot(IZ_VideoState* state) { | |||||
return 0; | |||||
} | |||||
void IZ_VideoLoadSprite(IZ_VideoState* state, IZ_VideoLoadSpriteParams params, IZ_SpriteSlot* out) { | |||||
char full_path[2048]; | char full_path[2048]; | ||||
sprintf(full_path, "%s/%s", dir, filename); | |||||
sprintf(full_path, "%s/%s", params.dir, params.filename); | |||||
FILE* f = fopen(full_path, "r"); | FILE* f = fopen(full_path, "r"); | ||||
u32 sprite_length_bytes = ini_getl(dir, 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_ADD); | ||||
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) { | ||||
out->texture = SDL_CreateTextureFromSurface(state->renderer, test_surface); | |||||
out->original_width = test_surface->w; | |||||
out->original_height = test_surface->h; | |||||
out->sprite.texture = SDL_CreateTextureFromSurface(state->renderer, test_surface); | |||||
out->sprite.original_width = test_surface->w; | |||||
out->sprite.original_height = test_surface->h; | |||||
out->sprite.scale_factor = 1; | |||||
out->sprite.rotate_degrees = 0; | |||||
SDL_FreeSurface(test_surface); | SDL_FreeSurface(test_surface); | ||||
} | } | ||||
} | } | ||||
void IZ_VideoTeardownTexture(IZ_LoadedSprite* sprite) { | |||||
void IZ_VideoTeardownTexture(IZ_Sprite* sprite) { | |||||
if (!sprite->texture) { | if (!sprite->texture) { | ||||
return; | return; | ||||
} | } | ||||
@@ -34,28 +34,35 @@ typedef struct { | |||||
SDL_Texture* texture; | SDL_Texture* texture; | ||||
f32 original_width; | f32 original_width; | ||||
f32 original_height; | f32 original_height; | ||||
} IZ_LoadedSprite; | |||||
// TODO properly define sprites | |||||
typedef struct { | |||||
SDL_Texture* texture; | |||||
f32 scale_factor; | f32 scale_factor; | ||||
f32 rotate_degrees; | f32 rotate_degrees; | ||||
} IZ_Sprite; | } IZ_Sprite; | ||||
typedef struct { | |||||
const char* dir; | |||||
const char* filename; | |||||
IZ_VideoSpritePriority priority; | |||||
} IZ_VideoLoadSpriteParams; | |||||
typedef struct { | typedef struct { | ||||
u16 width; | u16 width; | ||||
u16 height; | u16 height; | ||||
u8 max_fps; | u8 max_fps; | ||||
} IZ_VideoConfig; | } IZ_VideoConfig; | ||||
typedef struct { | |||||
IZ_Sprite sprite; | |||||
u64 requested_at; | |||||
IZ_VideoSpritePriority priority; | |||||
} IZ_SpriteSlot; | |||||
typedef struct { | typedef struct { | ||||
void* user_data; | void* user_data; | ||||
IZ_VideoConfig config; | IZ_VideoConfig config; | ||||
u64 last_update_at; | u64 last_update_at; | ||||
SDL_Window* window; | SDL_Window* window; | ||||
SDL_Renderer* renderer; | SDL_Renderer* renderer; | ||||
IZ_Sprite* active_sprites[MAX_ACTIVE_SPRITES]; | |||||
IZ_SpriteSlot active_sprites[MAX_ACTIVE_SPRITES]; | |||||
} IZ_VideoState; | } IZ_VideoState; | ||||
static const IZ_VideoState IZ_VIDEO_DEFAULT_STATE = { | static const IZ_VideoState IZ_VIDEO_DEFAULT_STATE = { | ||||
@@ -75,10 +82,11 @@ IZ_ProcedureResult IZ_VideoInitialize(IZ_VideoState*, void*, const char*, u8, co | |||||
IZ_ProcedureResult IZ_VideoSaveConfig(IZ_VideoState*, const char*); | IZ_ProcedureResult IZ_VideoSaveConfig(IZ_VideoState*, const char*); | ||||
// TODO implement | |||||
void IZ_VideoLoadTexture(IZ_VideoState*, const char*, const char*, IZ_LoadedSprite*); | |||||
u16 IZ_VideoGetNextFreeSpriteSlot(IZ_VideoState*); | |||||
void IZ_VideoLoadSprite(IZ_VideoState*, IZ_VideoLoadSpriteParams, IZ_SpriteSlot*); | |||||
void IZ_VideoTeardownTexture(IZ_LoadedSprite*); | |||||
void IZ_VideoTeardownTexture(IZ_Sprite*); | |||||
void IZ_VideoTeardown(IZ_VideoState*); | void IZ_VideoTeardown(IZ_VideoState*); | ||||