Deferred loading of resources.
TODO: deferred load of models, animations, dialog gfx TODO: work on deferred loading for spell stages
This commit is contained in:
parent
55c56e9bd6
commit
6258bf5828
11 changed files with 127 additions and 12 deletions
|
@ -26,7 +26,7 @@ void taisei_shutdown(void) {
|
|||
printf("\nshutdown:\n");
|
||||
|
||||
free_all_refs();
|
||||
free_resources();
|
||||
free_resources(0);
|
||||
audio_shutdown();
|
||||
video_shutdown();
|
||||
gamepad_shutdown();
|
||||
|
|
|
@ -37,6 +37,7 @@ static void register_handler(
|
|||
ResourceNameFunc name,
|
||||
ResourceFindFunc find,
|
||||
ResourceCheckFunc check,
|
||||
ResourceTransientFunc istransient,
|
||||
size_t tablesize)
|
||||
{
|
||||
assert(type >= 0 && type < RES_NUMTYPES);
|
||||
|
@ -48,6 +49,7 @@ static void register_handler(
|
|||
h->name = name;
|
||||
h->find = find;
|
||||
h->check = check;
|
||||
h->istransient = istransient;
|
||||
h->mapping = hashtable_new_stringkeys(tablesize);
|
||||
strcpy(h->subdir, subdir);
|
||||
}
|
||||
|
@ -163,31 +165,44 @@ Resource* get_resource(ResourceType type, const char *name, ResourceFlags flags)
|
|||
return res;
|
||||
}
|
||||
|
||||
bool istransient_filepath(const char *path) {
|
||||
char *fnstart = strrchr(path, '/');
|
||||
if (fnstart == NULL) return false;
|
||||
char *stgstart = strstr(path, "stage");
|
||||
return fnstart && stgstart && (stgstart < fnstart);
|
||||
}
|
||||
|
||||
bool istransient_filename(const char *path) {
|
||||
char *fnstart = strrchr(path, '/');
|
||||
if (fnstart == NULL) return false;
|
||||
return strstr(fnstart, "stage");
|
||||
}
|
||||
|
||||
void init_resources(void) {
|
||||
// hashtable sizes were carefully pulled out of my ass to reduce collisions a bit
|
||||
|
||||
register_handler(
|
||||
RES_TEXTURE, TEX_PATH_PREFIX, load_texture, (ResourceUnloadFunc)free_texture, NULL, texture_path, check_texture_path, 227
|
||||
RES_TEXTURE, TEX_PATH_PREFIX, load_texture, (ResourceUnloadFunc)free_texture, NULL, texture_path, check_texture_path, istransient_filepath, 227
|
||||
);
|
||||
|
||||
register_handler(
|
||||
RES_ANIM, ANI_PATH_PREFIX, load_animation, free, animation_name, animation_path, check_animation_path, 23
|
||||
RES_ANIM, ANI_PATH_PREFIX, load_animation, free, animation_name, animation_path, check_animation_path, NULL, 23
|
||||
);
|
||||
|
||||
register_handler(
|
||||
RES_SHADER, SHA_PATH_PREFIX, load_shader_file, unload_shader, NULL, shader_path, check_shader_path, 29
|
||||
RES_SHADER, SHA_PATH_PREFIX, load_shader_file, unload_shader, NULL, shader_path, check_shader_path, NULL, 29
|
||||
);
|
||||
|
||||
register_handler(
|
||||
RES_MODEL, MDL_PATH_PREFIX, load_model, unload_model, NULL, model_path, check_model_path, 17
|
||||
RES_MODEL, MDL_PATH_PREFIX, load_model, unload_model, NULL, model_path, check_model_path, NULL, 17
|
||||
);
|
||||
|
||||
register_handler(
|
||||
RES_SFX, SFX_PATH_PREFIX, load_sound, unload_sound, NULL, sound_path, check_sound_path, 16
|
||||
RES_SFX, SFX_PATH_PREFIX, load_sound, unload_sound, NULL, sound_path, check_sound_path, NULL, 16
|
||||
);
|
||||
|
||||
register_handler(
|
||||
RES_BGM, BGM_PATH_PREFIX, load_music, unload_music, NULL, music_path, check_music_path, 16
|
||||
RES_BGM, BGM_PATH_PREFIX, load_music, unload_music, NULL, music_path, check_music_path, istransient_filename, 16
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -234,7 +249,8 @@ static void recurse_dir(const char *path) {
|
|||
} else for(int rtype = 0; rtype < RES_NUMTYPES; ++rtype) {
|
||||
ResourceHandler *handler = get_handler(rtype);
|
||||
|
||||
if(handler->check(filepath)) {
|
||||
// NULL transient handler treats this resource type as permanent
|
||||
if((!handler->istransient || !handler->istransient(filepath)) && handler->check(filepath)) {
|
||||
load_resource(handler, filepath, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
@ -292,7 +308,7 @@ void load_resources(void) {
|
|||
init_fbo(&resources.fsec);
|
||||
}
|
||||
|
||||
void free_resources(void) {
|
||||
void free_resources(ResourceFlags flags) {
|
||||
for(ResourceType type = 0; type < RES_NUMTYPES; ++type) {
|
||||
ResourceHandler *handler = get_handler(type);
|
||||
|
||||
|
@ -303,12 +319,20 @@ void free_resources(void) {
|
|||
Resource *res;
|
||||
|
||||
for(HashtableIterator *i = hashtable_iter(handler->mapping); hashtable_iter_next(i, (void**)&name, (void**)&res);) {
|
||||
if ((flags & RESF_TRANSIENT) && !(res->flags & RESF_TRANSIENT)) continue;
|
||||
unload_resource(res);
|
||||
printf("Unloaded %s '%s'\n", resource_type_names[type], name);
|
||||
if (flags & RESF_TRANSIENT) hashtable_unset_deferred(handler->mapping, name);
|
||||
}
|
||||
|
||||
hashtable_free(handler->mapping);
|
||||
if (flags & RESF_TRANSIENT) {
|
||||
hashtable_unset_deferred_now(handler->mapping);
|
||||
}
|
||||
else {
|
||||
hashtable_free(handler->mapping);
|
||||
}
|
||||
}
|
||||
if (flags & RESF_TRANSIENT) return;
|
||||
|
||||
delete_vbo(&_vbo);
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ typedef enum ResourceType {
|
|||
typedef enum ResourceFlags {
|
||||
RESF_REQUIRED = 1,
|
||||
RESF_OVERRIDE = 2,
|
||||
// RESF_PERMANENT = 4;
|
||||
RESF_TRANSIENT = 4
|
||||
} ResourceFlags;
|
||||
|
||||
// All paths are relative to the current working directory, which can assumed to be the resources directory,
|
||||
|
@ -54,6 +54,9 @@ typedef char* (*ResourceFindFunc)(const char *name);
|
|||
// Tells whether the resource handler should attempt to load a file, specified by a path.
|
||||
typedef bool (*ResourceCheckFunc)(const char *path);
|
||||
|
||||
// Tells whether the resource specified by a path is transient.
|
||||
typedef bool (*ResourceTransientFunc)(const char *path);
|
||||
|
||||
// Loads a resource at path and returns a pointer to it.
|
||||
// Must return NULL and not crash the program on failure.
|
||||
typedef void* (*ResourceLoadFunc)(const char *path);
|
||||
|
@ -61,11 +64,18 @@ typedef void* (*ResourceLoadFunc)(const char *path);
|
|||
// Unloads a resource, freeing all allocated to it memory.
|
||||
typedef void (*ResourceUnloadFunc)(void *res);
|
||||
|
||||
// ResourceTransientFunc callback: resource treated as transient if its path contains "stage".
|
||||
bool istransient_filepath(const char *path);
|
||||
|
||||
// ResourceTransientFunc callback: resource treated as transient if its filename contains "stage".
|
||||
bool istransient_filename(const char *path);
|
||||
|
||||
typedef struct ResourceHandler {
|
||||
ResourceType type;
|
||||
ResourceNameFunc name;
|
||||
ResourceFindFunc find;
|
||||
ResourceCheckFunc check;
|
||||
ResourceTransientFunc istransient;
|
||||
ResourceLoadFunc load;
|
||||
ResourceUnloadFunc unload;
|
||||
Hashtable *mapping;
|
||||
|
@ -97,7 +107,7 @@ extern Resources resources;
|
|||
|
||||
void init_resources(void);
|
||||
void load_resources(void);
|
||||
void free_resources(void);
|
||||
void free_resources(ResourceFlags flags);
|
||||
|
||||
Resource* get_resource(ResourceType type, const char *name, ResourceFlags flags);
|
||||
Resource* insert_resource(ResourceType type, const char *name, void *data, ResourceFlags flags, const char *source);
|
||||
|
|
|
@ -626,6 +626,8 @@ static void stage_free(void) {
|
|||
free_boss(global.boss);
|
||||
global.boss = NULL;
|
||||
}
|
||||
|
||||
free_resources(RESF_TRANSIENT);
|
||||
}
|
||||
|
||||
static void stage_finalize(void *arg) {
|
||||
|
@ -691,6 +693,12 @@ void stage_loop(StageInfo *stage) {
|
|||
stg->playpos = 0;
|
||||
}
|
||||
|
||||
if (stage->procs->preload)
|
||||
{
|
||||
printf("Loading resources for stage:\n");
|
||||
stage->procs->preload();
|
||||
}
|
||||
|
||||
Enemy *e = global.plr.slaves, *tmp;
|
||||
short power = global.plr.power;
|
||||
global.plr.power = -1;
|
||||
|
|
|
@ -49,6 +49,7 @@ typedef struct StageProcs StageProcs;
|
|||
|
||||
struct StageProcs {
|
||||
StageProc begin;
|
||||
StageProc preload;
|
||||
StageProc end;
|
||||
StageProc draw;
|
||||
StageProc event;
|
||||
|
|
|
@ -159,6 +159,14 @@ void stage1_start(void) {
|
|||
bgcontext.cv[1] = 4;
|
||||
}
|
||||
|
||||
void stage1_preload(void) {
|
||||
get_resource(RES_BGM, "bgm_stage1", RESF_TRANSIENT);
|
||||
get_resource(RES_BGM, "bgm_stage1boss", RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage1/cirnobg", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage1/fog", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage1/snowlayer", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
}
|
||||
|
||||
void stage1_end(void) {
|
||||
free_stage3d(&bgcontext);
|
||||
}
|
||||
|
@ -180,6 +188,7 @@ ShaderRule stage1_shaders[] = { stage1_fog, NULL };
|
|||
|
||||
StageProcs stage1_procs = {
|
||||
.begin = stage1_start,
|
||||
.preload = stage1_preload,
|
||||
.end = stage1_end,
|
||||
.draw = stage1_draw,
|
||||
.event = stage1_events,
|
||||
|
|
|
@ -173,6 +173,17 @@ void stage2_start(void) {
|
|||
add_model(&bgcontext, stage2_bg_leaves_draw, stage2_bg_pos);
|
||||
}
|
||||
|
||||
void stage2_preload(void) {
|
||||
get_resource(RES_BGM, "bgm_stage2", RESF_TRANSIENT);
|
||||
get_resource(RES_BGM, "bgm_stage2boss", RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage2/border", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage2/leaves", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage2/roadgrass", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage2/roadstones", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage2/spellbg1", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage2/spellbg2", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
}
|
||||
|
||||
void stage2_end(void) {
|
||||
free_stage3d(&bgcontext);
|
||||
}
|
||||
|
@ -211,6 +222,7 @@ ShaderRule stage2_shaders[] = { stage2_fog, stage2_bloom, NULL };
|
|||
|
||||
StageProcs stage2_procs = {
|
||||
.begin = stage2_start,
|
||||
.preload = stage2_preload,
|
||||
.end = stage2_end,
|
||||
.draw = stage2_draw,
|
||||
.event = stage2_events,
|
||||
|
|
|
@ -116,6 +116,16 @@ void stage3_start(void) {
|
|||
// stgstate.fog_exp = 5.0;
|
||||
}
|
||||
|
||||
void stage3_preload(void) {
|
||||
get_resource(RES_BGM, "bgm_stage3", RESF_TRANSIENT);
|
||||
get_resource(RES_BGM, "bgm_stage3boss", RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage3/border", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage3/spellbg1", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage3/wspellbg", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage3/wspellclouds", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage3/wspellswarm", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
}
|
||||
|
||||
void stage3_end(void) {
|
||||
free_stage3d(&bgcontext);
|
||||
}
|
||||
|
@ -279,6 +289,7 @@ ShaderRule stage3_shaders[] = { stage3_fog, stage3_tunnel, NULL };
|
|||
|
||||
StageProcs stage3_procs = {
|
||||
.begin = stage3_start,
|
||||
.preload = stage3_preload,
|
||||
.end = stage3_end,
|
||||
.draw = stage3_draw,
|
||||
.event = stage3_events,
|
||||
|
|
|
@ -208,6 +208,18 @@ void stage4_start(void) {
|
|||
add_model(&bgcontext, stage4_corridor_draw, stage4_corridor_pos);
|
||||
}
|
||||
|
||||
void stage4_preload(void) {
|
||||
get_resource(RES_BGM, "bgm_stage4", RESF_TRANSIENT);
|
||||
get_resource(RES_BGM, "bgm_stage4boss", RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage2/border", RESF_REQUIRED | RESF_TRANSIENT); // Stage 2 is intentional!
|
||||
get_resource(RES_TEXTURE, "stage4/kurumibg1", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage4/kurumibg2", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage4/lake", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage4/mansion", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage4/planks", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage4/wall", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
}
|
||||
|
||||
void stage4_end(void) {
|
||||
free_stage3d(&bgcontext);
|
||||
}
|
||||
|
@ -247,6 +259,7 @@ ShaderRule stage4_shaders[] = { stage4_fog, NULL };
|
|||
|
||||
StageProcs stage4_procs = {
|
||||
.begin = stage4_start,
|
||||
.preload = stage4_preload,
|
||||
.end = stage4_end,
|
||||
.draw = stage4_draw,
|
||||
.event = stage4_events,
|
||||
|
|
|
@ -122,6 +122,16 @@ void stage5_start(void) {
|
|||
stagedata.rad = 2800;
|
||||
}
|
||||
|
||||
void stage5_preload(void) {
|
||||
get_resource(RES_BGM, "bgm_stage5", RESF_TRANSIENT);
|
||||
get_resource(RES_BGM, "bgm_stage5boss", RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage5/noise", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage5/spell_bg", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage5/spell_clouds", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage5/spell_lightning", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage5/tower", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
}
|
||||
|
||||
void stage5_end(void) {
|
||||
free_stage3d(&bgcontext);
|
||||
}
|
||||
|
@ -143,6 +153,7 @@ ShaderRule stage5_shaders[] = { NULL };
|
|||
|
||||
StageProcs stage5_procs = {
|
||||
.begin = stage5_start,
|
||||
.preload = stage5_preload,
|
||||
.end = stage5_end,
|
||||
.draw = stage5_draw,
|
||||
.event = stage5_events,
|
||||
|
|
|
@ -167,6 +167,21 @@ void stage6_start(void) {
|
|||
|
||||
}
|
||||
|
||||
void stage6_preload(void) {
|
||||
get_resource(RES_BGM, "bgm_stage6", RESF_TRANSIENT);
|
||||
get_resource(RES_BGM, "bgm_stage6boss", RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage6/baryon_connector", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage6/baryon", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage6/scythecircle", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage6/scythe", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage6/sky", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage6/spellbg_chalk", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage6/spellbg_classic", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage6/spellbg_modern", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage6/towertop", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
get_resource(RES_TEXTURE, "stage6/towerwall", RESF_REQUIRED | RESF_TRANSIENT);
|
||||
}
|
||||
|
||||
void stage6_end(void) {
|
||||
free_stage3d(&bgcontext);
|
||||
}
|
||||
|
@ -228,6 +243,7 @@ ShaderRule stage6_shaders[] = { NULL };
|
|||
|
||||
StageProcs stage6_procs = {
|
||||
.begin = stage6_start,
|
||||
.preload = stage6_preload,
|
||||
.end = stage6_end,
|
||||
.draw = stage6_draw,
|
||||
.event = stage6_events,
|
||||
|
|
Loading…
Reference in a new issue