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; | |||
} | |||
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) { | |||
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) { | |||
struct IZ_App* app = video_state->user_data; | |||
u64 ticks = IZ_AppGetTicks(app); | |||
@@ -118,32 +116,22 @@ void IZ_VideoUpdate(IZ_VideoState* video_state) { | |||
SDL_RenderClear(video_state->renderer); | |||
u16 sprite_index; | |||
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; | |||
} | |||
// 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, | |||
.y = 120, | |||
.w = draw_width, | |||
.h = draw_height, | |||
}, degrees++, &(SDL_FPoint) { | |||
}, loaded_sprite->rotate_degrees++, &(SDL_FPoint) { | |||
.x = draw_width / 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. | |||
// 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[]) { | |||
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) { | |||
return -2; | |||
} | |||
@@ -94,25 +95,31 @@ void IZ_VideoTeardown(IZ_VideoState* state) { | |||
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]; | |||
sprintf(full_path, "%s/%s", dir, filename); | |||
sprintf(full_path, "%s/%s", params.dir, params.filename); | |||
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); | |||
fread(sprite, 1, sprite_length_bytes, f); | |||
SDL_SetRenderDrawBlendMode(state->renderer, SDL_BLENDMODE_ADD); | |||
SDL_Surface* test_surface = IMG_LoadSVG_RW(SDL_RWFromConstMem(sprite, sprite_length_bytes)); | |||
free(sprite); | |||
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); | |||
} | |||
} | |||
void IZ_VideoTeardownTexture(IZ_LoadedSprite* sprite) { | |||
void IZ_VideoTeardownTexture(IZ_Sprite* sprite) { | |||
if (!sprite->texture) { | |||
return; | |||
} | |||
@@ -34,28 +34,35 @@ typedef struct { | |||
SDL_Texture* texture; | |||
f32 original_width; | |||
f32 original_height; | |||
} IZ_LoadedSprite; | |||
// TODO properly define sprites | |||
typedef struct { | |||
SDL_Texture* texture; | |||
f32 scale_factor; | |||
f32 rotate_degrees; | |||
} IZ_Sprite; | |||
typedef struct { | |||
const char* dir; | |||
const char* filename; | |||
IZ_VideoSpritePriority priority; | |||
} IZ_VideoLoadSpriteParams; | |||
typedef struct { | |||
u16 width; | |||
u16 height; | |||
u8 max_fps; | |||
} IZ_VideoConfig; | |||
typedef struct { | |||
IZ_Sprite sprite; | |||
u64 requested_at; | |||
IZ_VideoSpritePriority priority; | |||
} IZ_SpriteSlot; | |||
typedef struct { | |||
void* user_data; | |||
IZ_VideoConfig config; | |||
u64 last_update_at; | |||
SDL_Window* window; | |||
SDL_Renderer* renderer; | |||
IZ_Sprite* active_sprites[MAX_ACTIVE_SPRITES]; | |||
IZ_SpriteSlot active_sprites[MAX_ACTIVE_SPRITES]; | |||
} IZ_VideoState; | |||
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*); | |||
// 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*); | |||