WIP transition from resource scanning to manual preloading
This commit is contained in:
parent
b8fb9f6ade
commit
c82928a8da
41 changed files with 371 additions and 167 deletions
16
src/boss.c
16
src/boss.c
|
@ -245,3 +245,19 @@ Attack* boss_add_attack_from_info(Boss *boss, AttackInfo *info, char move) {
|
|||
a->info = info;
|
||||
return a;
|
||||
}
|
||||
|
||||
void boss_preload(void) {
|
||||
preload_resources(RES_SFX, RESF_OPTIONAL,
|
||||
"charge_generic",
|
||||
NULL);
|
||||
|
||||
preload_resources(RES_TEXTURE, RESF_DEFAULT,
|
||||
"boss_spellcircle0",
|
||||
"boss_circle",
|
||||
"boss_indicator",
|
||||
NULL);
|
||||
|
||||
preload_resources(RES_SHADER, RESF_DEFAULT,
|
||||
"boss_zoom",
|
||||
NULL);
|
||||
}
|
||||
|
|
|
@ -101,6 +101,8 @@ Attack* boss_add_attack_from_info(Boss *boss, AttackInfo *info, char move);
|
|||
|
||||
void boss_death(Boss **boss);
|
||||
|
||||
void boss_preload(void);
|
||||
|
||||
#define BOSS_DEFAULT_SPAWN_POS (VIEWPORT_W * 0.5 - I * VIEWPORT_H * 0.5)
|
||||
#define BOSS_DEFAULT_GO_POS (VIEWPORT_W * 0.5 + 200.0*I)
|
||||
#define BOSS_NOMOVE (-3142-39942.0*I)
|
||||
|
|
|
@ -253,7 +253,18 @@ void credits_free(void) {
|
|||
free(credits.entries);
|
||||
}
|
||||
|
||||
void credits_preload(void) {
|
||||
preload_resource(RES_BGM, "bgm_credits", RESF_OPTIONAL);
|
||||
preload_resource(RES_SHADER, "tower_wall", RESF_DEFAULT);
|
||||
preload_resources(RES_TEXTURE, RESF_DEFAULT,
|
||||
"stage6/sky",
|
||||
"stage6/towerwall",
|
||||
"yukkureimu",
|
||||
NULL);
|
||||
}
|
||||
|
||||
void credits_loop(void) {
|
||||
credits_preload();
|
||||
credits_init();
|
||||
while(credits.end) {
|
||||
handle_events(NULL, 0, NULL);
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
void credits_loop(void);
|
||||
void credits_add(char*, int);
|
||||
void credits_preload(void);
|
||||
|
||||
#define CREDITS_ENTRY_FADEIN 200.0
|
||||
#define CREDITS_ENTRY_FADEOUT 100.0
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
*/
|
||||
|
||||
#include "difficulty.h"
|
||||
#include "resource/resource.h"
|
||||
|
||||
const char* difficulty_name(Difficulty diff) {
|
||||
switch(diff) {
|
||||
|
@ -40,3 +41,9 @@ Color difficulty_color(Difficulty diff) {
|
|||
default: return rgb(0.5, 0.5, 0.5);
|
||||
}
|
||||
}
|
||||
|
||||
void difficulty_preload(void) {
|
||||
for(Difficulty diff = D_Easy; diff < NUM_SELECTABLE_DIFFICULTIES + D_Easy; ++diff) {
|
||||
preload_resource(RES_TEXTURE, difficulty_tex(diff), RESF_PERMANENT);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,5 +27,6 @@ typedef enum {
|
|||
const char* difficulty_name(Difficulty diff);
|
||||
const char* difficulty_tex(Difficulty diff);
|
||||
Color difficulty_color(Difficulty diff);
|
||||
void difficulty_preload(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -121,8 +121,14 @@ void ending_draw(Ending *e) {
|
|||
draw_and_update_transition();
|
||||
}
|
||||
|
||||
void ending_preload(void) {
|
||||
preload_resource(RES_BGM, "bgm_ending", RESF_OPTIONAL);
|
||||
}
|
||||
|
||||
void ending_loop(void) {
|
||||
Ending e;
|
||||
|
||||
ending_preload();
|
||||
create_ending(&e);
|
||||
|
||||
global.frames = 0;
|
||||
|
|
|
@ -38,5 +38,6 @@ void add_ending_entry(Ending *e, int time, char *msg, char *tex);
|
|||
void create_ending(Ending *e);
|
||||
void ending_loop(void);
|
||||
void free_ending(Ending *e);
|
||||
void ending_preload(void);
|
||||
|
||||
#endif
|
||||
|
|
15
src/enemy.c
15
src/enemy.c
|
@ -224,3 +224,18 @@ void process_enemies(Enemy **enemies) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void enemies_preload(void) {
|
||||
preload_resources(RES_ANIM, RESF_DEFAULT,
|
||||
"fairy",
|
||||
"bigfairy",
|
||||
NULL);
|
||||
|
||||
preload_resources(RES_TEXTURE, RESF_DEFAULT,
|
||||
"swirl",
|
||||
NULL);
|
||||
|
||||
preload_resources(RES_SFX, RESF_OPTIONAL,
|
||||
"enemydeath",
|
||||
NULL);
|
||||
}
|
||||
|
|
|
@ -64,4 +64,6 @@ void BigFairy(Enemy*, int t);
|
|||
int enemy_flare(Projectile *p, int t);
|
||||
void EnemyFlareShrink(Projectile *p, int t);
|
||||
|
||||
void enemies_preload(void);
|
||||
|
||||
#endif
|
||||
|
|
14
src/item.c
14
src/item.c
|
@ -148,3 +148,17 @@ void spawn_items(complex pos, int point, int power, int bomb, int life) {
|
|||
for(i = 0; i < life; i++)
|
||||
spawn_item(pos, Life);
|
||||
}
|
||||
|
||||
void items_preload(void) {
|
||||
preload_resources(RES_TEXTURE, RESF_PERMANENT,
|
||||
"items/power",
|
||||
"items/point",
|
||||
"items/life",
|
||||
"items/bomb",
|
||||
"items/bullet_point",
|
||||
NULL);
|
||||
|
||||
preload_resources(RES_SFX, RESF_OPTIONAL,
|
||||
"item_generic",
|
||||
NULL);
|
||||
}
|
||||
|
|
|
@ -46,6 +46,8 @@ void process_items(void);
|
|||
void spawn_item(complex pos, Type type);
|
||||
void spawn_items(complex pos, int point, int power, int bomb, int life);
|
||||
|
||||
void items_preload(void);
|
||||
|
||||
#define POWER_VALUE 3
|
||||
|
||||
#endif
|
||||
|
|
|
@ -165,7 +165,32 @@ void draw_main_menu(MenuData *menu) {
|
|||
}
|
||||
|
||||
void draw_loading_screen(void) {
|
||||
preload_resource(RES_TEXTURE, "loading", RESF_PERMANENT);
|
||||
set_ortho();
|
||||
draw_texture(SCREEN_W/2, SCREEN_H/2, "loading");
|
||||
SDL_GL_SwapWindow(video.window);
|
||||
}
|
||||
|
||||
void menu_preload(void) {
|
||||
difficulty_preload();
|
||||
|
||||
preload_resources(RES_TEXTURE, RESF_PERMANENT,
|
||||
"mainmenu/mainmenubg",
|
||||
"mainmenu/logo",
|
||||
"part/smoke",
|
||||
"part/petal",
|
||||
"dialog/marisa",
|
||||
"dialog/youmu",
|
||||
"charselect_arrow",
|
||||
NULL);
|
||||
|
||||
preload_resources(RES_SFX, RESF_PERMANENT | RESF_OPTIONAL,
|
||||
"generic_shot",
|
||||
"shot_special1",
|
||||
"hit",
|
||||
NULL);
|
||||
|
||||
preload_resources(RES_BGM, RESF_PERMANENT | RESF_OPTIONAL,
|
||||
"bgm_menu",
|
||||
NULL);
|
||||
}
|
||||
|
|
|
@ -15,5 +15,6 @@ void draw_main_menu_bg(MenuData *m);
|
|||
void draw_main_menu(MenuData *m);
|
||||
void main_menu_update_spellpractice(void);
|
||||
void draw_loading_screen(void);
|
||||
void menu_preload(void);
|
||||
|
||||
#endif
|
||||
|
|
23
src/player.c
23
src/player.c
|
@ -422,3 +422,26 @@ void player_graze(Player *plr, complex pos, int pts) {
|
|||
create_particle2c("flare", pos, 0, Shrink, timeout_linear, 5 + 5 * afrand(2), (1+afrand(0)*5)*cexp(I*tsrand_a(1)))->type=PlrProj;
|
||||
}
|
||||
}
|
||||
|
||||
void player_preload(void) {
|
||||
const int flags = RESF_DEFAULT;
|
||||
|
||||
preload_resources(RES_TEXTURE, flags,
|
||||
"focus",
|
||||
"fairy_circle",
|
||||
"masterspark",
|
||||
"masterspark_ring",
|
||||
NULL);
|
||||
|
||||
preload_resources(RES_SFX, flags | RESF_OPTIONAL,
|
||||
"graze",
|
||||
"death",
|
||||
"shot",
|
||||
"masterspark",
|
||||
NULL);
|
||||
|
||||
preload_resources(RES_ANIM, flags,
|
||||
"youmu",
|
||||
"marisa",
|
||||
NULL);
|
||||
}
|
||||
|
|
|
@ -110,4 +110,6 @@ void player_event(Player* plr, int type, int key);
|
|||
void player_applymovement(Player* plr);
|
||||
void player_input_workaround(Player *plr);
|
||||
|
||||
void player_preload(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -419,3 +419,39 @@ void petal_explosion(int n, complex pos) {
|
|||
create_particle4c("petal", pos, rgba(0.6,1-afrand(0)*0.4,0.5,1-0.5*afrand(1)), Petal, asymptotic, (3+5*afrand(2))*cexp(I*M_PI*2*afrand(3)), 5, afrand(4) + afrand(5)*I, afrand(6) + 360.0*I*afrand(7));
|
||||
}
|
||||
}
|
||||
|
||||
void projectiles_preload(void) {
|
||||
preload_resources(RES_TEXTURE, RESF_PERMANENT,
|
||||
"part/blast",
|
||||
"part/boss_shadow",
|
||||
"part/flare",
|
||||
"part/lasercurve",
|
||||
"part/marilaser_part0",
|
||||
"part/maristar_orbit",
|
||||
"part/petal",
|
||||
"part/smoke",
|
||||
"part/stain",
|
||||
"part/youmu_slice",
|
||||
"proj/ball",
|
||||
"proj/bigball",
|
||||
"proj/bullet",
|
||||
"proj/card",
|
||||
"proj/crystal",
|
||||
"proj/flea",
|
||||
"proj/hghost",
|
||||
"proj/marilaser",
|
||||
"proj/marisa",
|
||||
"proj/maristar",
|
||||
"proj/plainball",
|
||||
"proj/rice",
|
||||
"proj/soul",
|
||||
"proj/thickrice",
|
||||
"proj/wave",
|
||||
"proj/youhoming",
|
||||
"proj/youmu",
|
||||
NULL);
|
||||
|
||||
preload_resources(RES_SHADER, RESF_PERMANENT,
|
||||
"bullet_color",
|
||||
NULL);
|
||||
}
|
||||
|
|
|
@ -98,4 +98,6 @@ int timeout_linear(Projectile *p, int t);
|
|||
void Petal(Projectile *p, int t);
|
||||
void petal_explosion(int n, complex pos);
|
||||
|
||||
void projectiles_preload(void);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -59,7 +59,7 @@ char* animation_name(const char *filename) {
|
|||
return newname;
|
||||
}
|
||||
|
||||
void* load_animation(const char *filename) {
|
||||
void* load_animation(const char *filename, unsigned int flags) {
|
||||
Animation *ani = malloc(sizeof(Animation));
|
||||
|
||||
char *basename = resource_util_basename(ANI_PATH_PREFIX, filename);
|
||||
|
@ -87,7 +87,7 @@ void* load_animation(const char *filename) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
ani->tex = get_tex(basename);
|
||||
ani->tex = get_resource(RES_TEXTURE, basename, flags)->texture;
|
||||
|
||||
if(!ani->tex) {
|
||||
warnx("load_animation(): couldn't get texture '%s'", basename);
|
||||
|
|
|
@ -26,7 +26,7 @@ typedef struct Animation {
|
|||
|
||||
char* animation_path(const char *name);
|
||||
bool check_animation_path(const char *path);
|
||||
void* load_animation(const char *filename);
|
||||
void* load_animation(const char *filename, unsigned int flags);
|
||||
char* animation_name(const char *filename);
|
||||
|
||||
Animation *get_ani(const char *name);
|
||||
|
|
|
@ -17,7 +17,7 @@ typedef struct Music {
|
|||
|
||||
char* music_path(const char *name);
|
||||
bool check_music_path(const char *path);
|
||||
void* load_music(const char *path);
|
||||
void* load_music(const char *path, unsigned int flags);
|
||||
void unload_music(void *snd);
|
||||
|
||||
#define BGM_PATH_PREFIX "bgm/"
|
||||
|
|
|
@ -22,7 +22,7 @@ bool check_music_path(const char *path) {
|
|||
return strstartswith(path, BGM_PATH_PREFIX) && audio_mixer_check_sound_path(path, true);
|
||||
}
|
||||
|
||||
void* load_music(const char *path) {
|
||||
void* load_music(const char *path, unsigned int flags) {
|
||||
Mix_Music *music = Mix_LoadMUS(path);
|
||||
|
||||
if(!music) {
|
||||
|
|
|
@ -4,5 +4,5 @@
|
|||
|
||||
char* music_path(const char *name) { return NULL; }
|
||||
bool check_music_path(const char *path) { return NULL; }
|
||||
void* load_music(const char *path) { return NULL; }
|
||||
void* load_music(const char *path, unsigned int flags) { return NULL; }
|
||||
void unload_music(void *vmus) { }
|
||||
|
|
|
@ -28,7 +28,7 @@ bool check_model_path(const char *path) {
|
|||
return strendswith(path, MDL_EXTENSION);
|
||||
}
|
||||
|
||||
void* load_model(const char *path) {
|
||||
void* load_model(const char *path, unsigned int flags) {
|
||||
Model *m = malloc(sizeof(Model));
|
||||
|
||||
ObjFileData data;
|
||||
|
|
|
@ -37,7 +37,7 @@ typedef struct Model {
|
|||
|
||||
char* model_path(const char *name);
|
||||
bool check_model_path(const char *path);
|
||||
void* load_model(const char *path);
|
||||
void* load_model(const char *path, unsigned int flags);
|
||||
void unload_model(void*); // Does not delete elements from the VBO, so doing this at runtime is leaking VBO space
|
||||
|
||||
Model* get_model(const char *name);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include "config.h"
|
||||
#include "taisei_err.h"
|
||||
#include "video.h"
|
||||
#include "menu/mainmenu.h"
|
||||
|
||||
Resources resources;
|
||||
|
||||
|
@ -37,7 +38,6 @@ static void register_handler(
|
|||
ResourceNameFunc name,
|
||||
ResourceFindFunc find,
|
||||
ResourceCheckFunc check,
|
||||
ResourceTransientFunc istransient,
|
||||
size_t tablesize)
|
||||
{
|
||||
assert(type >= 0 && type < RES_NUMTYPES);
|
||||
|
@ -49,7 +49,6 @@ 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);
|
||||
}
|
||||
|
@ -83,7 +82,9 @@ Resource* insert_resource(ResourceType type, const char *name, void *data, Resou
|
|||
|
||||
hashtable_set_string(handler->mapping, name, res);
|
||||
|
||||
printf("Loaded %s '%s' from '%s'\n", resource_type_names[handler->type], name, source);
|
||||
printf("Loaded %s '%s' from '%s' (%s)\n", resource_type_names[handler->type], name, source,
|
||||
(flags & RESF_PERMANENT) ? "permanent" : "transient");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -133,7 +134,7 @@ static Resource* load_resource(ResourceHandler *handler, const char *path, const
|
|||
}
|
||||
}
|
||||
|
||||
raw = handler->load(path);
|
||||
raw = handler->load(path, flags);
|
||||
|
||||
if(!raw) {
|
||||
name = name ? name : "<name unknown>";
|
||||
|
@ -164,10 +165,20 @@ Resource* get_resource(ResourceType type, const char *name, ResourceFlags flags)
|
|||
Resource *res = hashtable_get_string(handler->mapping, name);
|
||||
|
||||
if(!res || flags & RESF_OVERRIDE) {
|
||||
if(!(flags & (RESF_PRELOAD | RESF_OVERRIDE))) {
|
||||
warnx("get_resource(): %s '%s' was not preloaded", resource_type_names[type], name);
|
||||
|
||||
if(!(flags & RESF_OPTIONAL) && getenvint("TAISEI_PRELOAD_REQUIRED")) {
|
||||
warnx("Aborting due to TAISEI_PRELOAD_REQUIRED");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
res = load_resource(handler, NULL, name, flags);
|
||||
}
|
||||
|
||||
if(flags & RESF_PERMANENT) {
|
||||
if(res && flags & RESF_PERMANENT && !(res->flags & RESF_PERMANENT)) {
|
||||
printf("Promoted %s '%s' to permanent\n", resource_type_names[type], name);
|
||||
res->flags |= RESF_PERMANENT;
|
||||
}
|
||||
|
||||
|
@ -175,47 +186,47 @@ Resource* get_resource(ResourceType type, const char *name, ResourceFlags flags)
|
|||
}
|
||||
|
||||
void preload_resource(ResourceType type, const char *name, ResourceFlags flags) {
|
||||
get_resource(type, name, flags);
|
||||
if(!getenvint("TAISEI_NOPRELOAD")) {
|
||||
get_resource(type, name, flags | RESF_PRELOAD);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
void preload_resources(ResourceType type, ResourceFlags flags, const char *firstname, ...) {
|
||||
va_list args;
|
||||
va_start(args, firstname);
|
||||
|
||||
bool istransient_filename(const char *path) {
|
||||
char *fnstart = strrchr(path, '/');
|
||||
if (fnstart == NULL) return false;
|
||||
return strstr(fnstart, "stage");
|
||||
for(const char *name = firstname; name; name = va_arg(args, const char*)) {
|
||||
preload_resource(type, name, flags);
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
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, istransient_filepath, 227
|
||||
RES_TEXTURE, TEX_PATH_PREFIX, load_texture, (ResourceUnloadFunc)free_texture, NULL, texture_path, check_texture_path, 227
|
||||
);
|
||||
|
||||
register_handler(
|
||||
RES_ANIM, ANI_PATH_PREFIX, load_animation, free, animation_name, animation_path, check_animation_path, NULL, 23
|
||||
RES_ANIM, ANI_PATH_PREFIX, load_animation, free, animation_name, animation_path, check_animation_path, 23
|
||||
);
|
||||
|
||||
register_handler(
|
||||
RES_SHADER, SHA_PATH_PREFIX, load_shader_file, unload_shader, NULL, shader_path, check_shader_path, NULL, 29
|
||||
RES_SHADER, SHA_PATH_PREFIX, load_shader_file, unload_shader, NULL, shader_path, check_shader_path, 29
|
||||
);
|
||||
|
||||
register_handler(
|
||||
RES_MODEL, MDL_PATH_PREFIX, load_model, unload_model, NULL, model_path, check_model_path, NULL, 17
|
||||
RES_MODEL, MDL_PATH_PREFIX, load_model, unload_model, NULL, model_path, check_model_path, 17
|
||||
);
|
||||
|
||||
register_handler(
|
||||
RES_SFX, SFX_PATH_PREFIX, load_sound, unload_sound, NULL, sound_path, check_sound_path, NULL, 16
|
||||
RES_SFX, SFX_PATH_PREFIX, load_sound, unload_sound, NULL, sound_path, check_sound_path, 16
|
||||
);
|
||||
|
||||
register_handler(
|
||||
RES_BGM, BGM_PATH_PREFIX, load_music, unload_music, NULL, music_path, check_music_path, istransient_filename, 16
|
||||
RES_BGM, BGM_PATH_PREFIX, load_music, unload_music, NULL, music_path, check_music_path, 16
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -244,78 +255,15 @@ const char* resource_util_filename(const char *path) {
|
|||
return path;
|
||||
}
|
||||
|
||||
static void recurse_dir(const char *path) {
|
||||
DIR *dir = opendir(path);
|
||||
if(dir == NULL)
|
||||
errx(-1, "Can't open directory '%s'", path);
|
||||
|
||||
struct dirent *dp;
|
||||
|
||||
while((dp = readdir(dir)) != NULL) {
|
||||
char *filepath = strjoin(path, "/", dp->d_name, NULL);
|
||||
struct stat statbuf;
|
||||
|
||||
stat(filepath, &statbuf);
|
||||
|
||||
if(S_ISDIR(statbuf.st_mode) && *dp->d_name != '.') {
|
||||
recurse_dir(filepath);
|
||||
} else for(int rtype = 0; rtype < RES_NUMTYPES; ++rtype) {
|
||||
ResourceHandler *handler = get_handler(rtype);
|
||||
|
||||
// NULL transient handler treats this resource type as permanent
|
||||
if((!handler->istransient || !handler->istransient(filepath)) && handler->check(filepath)) {
|
||||
load_resource(handler, filepath, NULL, 0);
|
||||
}
|
||||
}
|
||||
|
||||
free(filepath);
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
static void recurse_dir_rel(const char *relpath) {
|
||||
char *path = strdup(relpath);
|
||||
strip_trailing_slashes(path);
|
||||
recurse_dir(path);
|
||||
free(path);
|
||||
}
|
||||
|
||||
static void scan_resources(void) {
|
||||
ListContainer *visited = NULL;
|
||||
|
||||
for(ResourceType type = 0; type < RES_NUMTYPES; ++type) {
|
||||
ResourceHandler *handler = get_handler(type);
|
||||
ListContainer *c;
|
||||
bool skip = false;
|
||||
|
||||
for(c = visited; c; c = c->next) {
|
||||
if(!strcmp((char*)c->data, handler->subdir)) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!skip) {
|
||||
recurse_dir_rel(handler->subdir);
|
||||
create_container(&visited)->data = handler->subdir;
|
||||
}
|
||||
}
|
||||
|
||||
delete_all_elements((void**)&visited, delete_element);
|
||||
}
|
||||
|
||||
void load_resources(void) {
|
||||
if(!getenvint("TAISEI_NOSCAN")) {
|
||||
scan_resources();
|
||||
}
|
||||
|
||||
init_fonts();
|
||||
|
||||
if(glext.draw_instanced) {
|
||||
load_shader_snippets("shader/laser_snippets", "laser_");
|
||||
load_shader_snippets("shader/laser_snippets", "laser_", RESF_PERMANENT);
|
||||
}
|
||||
|
||||
menu_preload();
|
||||
|
||||
init_fbo(&resources.fbg[0]);
|
||||
init_fbo(&resources.fbg[1]);
|
||||
init_fbo(&resources.fsec);
|
||||
|
@ -335,8 +283,11 @@ void free_resources(bool all) {
|
|||
if(!all && res->flags & RESF_PERMANENT)
|
||||
continue;
|
||||
|
||||
ResourceFlags flags = res->flags;
|
||||
unload_resource(res);
|
||||
printf("Unloaded %s '%s'\n", resource_type_names[type], name);
|
||||
printf("Unloaded %s '%s' (%s)\n", resource_type_names[type], name,
|
||||
(flags & RESF_PERMANENT) ? "permanent" : "transient"
|
||||
);
|
||||
|
||||
if(!all) {
|
||||
hashtable_unset_deferred(handler->mapping, name);
|
||||
|
|
|
@ -35,6 +35,7 @@ typedef enum ResourceFlags {
|
|||
RESF_OVERRIDE = 1,
|
||||
RESF_OPTIONAL = 2,
|
||||
RESF_PERMANENT = 4,
|
||||
RESF_PRELOAD = 8,
|
||||
} ResourceFlags;
|
||||
|
||||
#define RESF_DEFAULT 0
|
||||
|
@ -56,28 +57,18 @@ 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);
|
||||
typedef void* (*ResourceLoadFunc)(const char *path, unsigned int flags);
|
||||
|
||||
// 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;
|
||||
|
@ -114,6 +105,7 @@ void free_resources(bool all);
|
|||
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);
|
||||
void preload_resource(ResourceType type, const char *name, ResourceFlags flags);
|
||||
void preload_resources(ResourceType type, ResourceFlags flags, const char *firstname, ...) __attribute__((sentinel));
|
||||
|
||||
void resource_util_strip_ext(char *path);
|
||||
char* resource_util_basename(const char *prefix, const char *path);
|
||||
|
|
|
@ -17,7 +17,7 @@ typedef struct Sound {
|
|||
|
||||
char* sound_path(const char *name);
|
||||
bool check_sound_path(const char *path);
|
||||
void* load_sound(const char *path);
|
||||
void* load_sound(const char *path, unsigned int flags);
|
||||
void unload_sound(void *snd);
|
||||
|
||||
#define SFX_PATH_PREFIX "sfx/"
|
||||
|
|
|
@ -22,7 +22,7 @@ bool check_sound_path(const char *path) {
|
|||
return strstartswith(path, SFX_PATH_PREFIX) && audio_mixer_check_sound_path(path, false);
|
||||
}
|
||||
|
||||
void* load_sound(const char *path) {
|
||||
void* load_sound(const char *path, unsigned int flags) {
|
||||
Mix_Chunk *sound = Mix_LoadWAV(path);
|
||||
|
||||
if(!sound) {
|
||||
|
|
|
@ -4,5 +4,5 @@
|
|||
|
||||
char* sound_path(const char *name) { return NULL; }
|
||||
bool check_sound_path(const char *path) { return NULL; }
|
||||
void* load_sound(const char *path) { return NULL; }
|
||||
void* load_sound(const char *path, unsigned int flags) { return NULL; }
|
||||
void unload_sound(void *vmus) { }
|
||||
|
|
|
@ -39,7 +39,7 @@ bool check_shader_path(const char *path) {
|
|||
|
||||
static Shader* load_shader(const char *vheader, const char *fheader, const char *vtext, const char *ftext);
|
||||
|
||||
void* load_shader_file(const char *path) {
|
||||
void* load_shader_file(const char *path, unsigned int flags) {
|
||||
char *text, *vtext, *ftext, *delim;
|
||||
|
||||
text = read_all(path, NULL);
|
||||
|
@ -81,7 +81,7 @@ static char* get_snippet_header(void) {
|
|||
}
|
||||
}
|
||||
|
||||
void load_shader_snippets(const char *filename, const char *prefix) {
|
||||
void load_shader_snippets(const char *filename, const char *prefix, unsigned int flags) {
|
||||
int size, vhsize = 0, vfsize = 0, fhsize = 0, ffsize = 0, ssize, prefixlen;
|
||||
char *text, *vhead, *vfoot, *fhead, *ffoot;
|
||||
char *sec, *name, *nend, *send;
|
||||
|
@ -160,7 +160,7 @@ void load_shader_snippets(const char *filename, const char *prefix) {
|
|||
nbuf[nend-name+prefixlen] = 0;
|
||||
|
||||
Shader *sha = load_shader(get_snippet_header(), NULL, vtext, ftext);
|
||||
insert_resource(RES_SHADER, nbuf, sha, 0, filename);
|
||||
insert_resource(RES_SHADER, nbuf, sha, flags, filename);
|
||||
|
||||
free(nbuf);
|
||||
free(vtext);
|
||||
|
|
|
@ -19,10 +19,10 @@ typedef struct Shader {
|
|||
|
||||
char* shader_path(const char *name);
|
||||
bool check_shader_path(const char *path);
|
||||
void* load_shader_file(const char *path);
|
||||
void* load_shader_file(const char *path, unsigned int flags);
|
||||
void unload_shader(void *vsha);
|
||||
|
||||
void load_shader_snippets(const char *filename, const char *prefix);
|
||||
void load_shader_snippets(const char *filename, const char *prefix, unsigned int flags);
|
||||
Shader* get_shader(const char *name);
|
||||
|
||||
int uniloc(Shader *sha, const char *name);
|
||||
|
|
|
@ -25,7 +25,7 @@ bool check_texture_path(const char *path) {
|
|||
return strendswith(path, TEX_EXTENSION);
|
||||
}
|
||||
|
||||
void* load_texture(const char *path) {
|
||||
void* load_texture(const char *path, unsigned int flags) {
|
||||
SDL_Surface *surface = load_png(path);
|
||||
|
||||
if(surface == NULL) {
|
||||
|
|
|
@ -21,7 +21,7 @@ struct Texture {
|
|||
};
|
||||
|
||||
char* texture_path(const char *name);
|
||||
void* load_texture(const char *path);
|
||||
void* load_texture(const char *path, unsigned int flags);
|
||||
bool check_texture_path(const char *path);
|
||||
|
||||
void load_sdl_surf(SDL_Surface *surface, Texture *texture);
|
||||
|
|
26
src/stage.c
26
src/stage.c
|
@ -638,6 +638,30 @@ void stage_finish(int gameover) {
|
|||
set_transition_callback(TransFadeBlack, FADE_TIME, FADE_TIME*2, stage_finalize, (void*)(intptr_t)gameover);
|
||||
}
|
||||
|
||||
static void stage_preload(void) {
|
||||
difficulty_preload();
|
||||
projectiles_preload();
|
||||
player_preload();
|
||||
items_preload();
|
||||
boss_preload();
|
||||
|
||||
if(global.stage->type != STAGE_SPELL)
|
||||
enemies_preload();
|
||||
|
||||
global.stage->procs->preload();
|
||||
|
||||
preload_resources(RES_TEXTURE, RESF_PERMANENT,
|
||||
"hud",
|
||||
"star",
|
||||
"titletransition",
|
||||
NULL);
|
||||
|
||||
preload_resources(RES_SHADER, RESF_PERMANENT,
|
||||
"stagetitle",
|
||||
"ingame_menu",
|
||||
NULL);
|
||||
}
|
||||
|
||||
void stage_loop(StageInfo *stage) {
|
||||
assert(stage);
|
||||
assert(stage->procs);
|
||||
|
@ -657,7 +681,7 @@ void stage_loop(StageInfo *stage) {
|
|||
// I really want to separate all of the game state from the global struct sometime
|
||||
global.stage = stage;
|
||||
|
||||
stage->procs->preload();
|
||||
stage_preload();
|
||||
|
||||
uint32_t seed = (uint32_t)time(0);
|
||||
tsrand_switch(&global.rand_game);
|
||||
|
|
|
@ -160,11 +160,22 @@ void stage1_start(void) {
|
|||
}
|
||||
|
||||
void stage1_preload(void) {
|
||||
preload_resource(RES_BGM, "bgm_stage1", RESF_OPTIONAL);
|
||||
preload_resource(RES_BGM, "bgm_stage1boss", RESF_OPTIONAL);
|
||||
preload_resource(RES_TEXTURE, "stage1/cirnobg", RESF_DEFAULT);
|
||||
preload_resource(RES_TEXTURE, "stage1/fog", RESF_DEFAULT);
|
||||
preload_resource(RES_TEXTURE, "stage1/snowlayer", RESF_DEFAULT);
|
||||
preload_resources(RES_BGM, RESF_OPTIONAL, "bgm_stage1", "bgm_stage1boss", NULL);
|
||||
preload_resources(RES_TEXTURE, RESF_DEFAULT,
|
||||
"stage1/cirnobg",
|
||||
"stage1/fog",
|
||||
"stage1/snowlayer",
|
||||
"dialog/cirno",
|
||||
NULL);
|
||||
preload_resources(RES_MODEL, RESF_DEFAULT,
|
||||
"reeds",
|
||||
NULL);
|
||||
preload_resources(RES_SHADER, RESF_DEFAULT,
|
||||
"zbuf_fog",
|
||||
NULL);
|
||||
preload_resources(RES_ANIM, RESF_DEFAULT,
|
||||
"cirno",
|
||||
NULL);
|
||||
}
|
||||
|
||||
void stage1_end(void) {
|
||||
|
|
|
@ -174,14 +174,26 @@ void stage2_start(void) {
|
|||
}
|
||||
|
||||
void stage2_preload(void) {
|
||||
preload_resource(RES_BGM, "bgm_stage2", RESF_OPTIONAL);
|
||||
preload_resource(RES_BGM, "bgm_stage2boss", RESF_OPTIONAL);
|
||||
preload_resource(RES_TEXTURE, "stage2/border", RESF_DEFAULT);
|
||||
preload_resource(RES_TEXTURE, "stage2/leaves", RESF_DEFAULT);
|
||||
preload_resource(RES_TEXTURE, "stage2/roadgrass", RESF_DEFAULT);
|
||||
preload_resource(RES_TEXTURE, "stage2/roadstones", RESF_DEFAULT);
|
||||
preload_resource(RES_TEXTURE, "stage2/spellbg1", RESF_DEFAULT);
|
||||
preload_resource(RES_TEXTURE, "stage2/spellbg2", RESF_DEFAULT);
|
||||
preload_resources(RES_BGM, RESF_OPTIONAL, "bgm_stage2", "bgm_stage2boss", NULL);
|
||||
preload_resources(RES_TEXTURE, RESF_DEFAULT,
|
||||
"stage2/border",
|
||||
"stage2/leaves",
|
||||
"stage2/roadgrass",
|
||||
"stage2/roadstones",
|
||||
"stage2/spellbg1",
|
||||
"stage2/spellbg2",
|
||||
"dialog/hina",
|
||||
NULL);
|
||||
preload_resources(RES_SHADER, RESF_DEFAULT,
|
||||
"bloom",
|
||||
"zbuf_fog",
|
||||
"alpha_depth",
|
||||
NULL);
|
||||
preload_resources(RES_ANIM, RESF_DEFAULT,
|
||||
"wriggle",
|
||||
"hina",
|
||||
"fire",
|
||||
NULL);
|
||||
}
|
||||
|
||||
void stage2_end(void) {
|
||||
|
|
|
@ -117,13 +117,24 @@ void stage3_start(void) {
|
|||
}
|
||||
|
||||
void stage3_preload(void) {
|
||||
preload_resource(RES_BGM, "bgm_stage3", RESF_OPTIONAL);
|
||||
preload_resource(RES_BGM, "bgm_stage3boss", RESF_OPTIONAL);
|
||||
preload_resource(RES_TEXTURE, "stage3/border", RESF_DEFAULT);
|
||||
preload_resource(RES_TEXTURE, "stage3/spellbg1", RESF_DEFAULT);
|
||||
preload_resource(RES_TEXTURE, "stage3/wspellbg", RESF_DEFAULT);
|
||||
preload_resource(RES_TEXTURE, "stage3/wspellclouds", RESF_DEFAULT);
|
||||
preload_resource(RES_TEXTURE, "stage3/wspellswarm", RESF_DEFAULT);
|
||||
preload_resources(RES_BGM, RESF_OPTIONAL, "bgm_stage3", "bgm_stage3boss", NULL);
|
||||
preload_resources(RES_TEXTURE, RESF_DEFAULT,
|
||||
"stage3/border",
|
||||
"stage3/spellbg1",
|
||||
"stage3/spellbg2",
|
||||
"stage3/wspellbg",
|
||||
"stage3/wspellclouds",
|
||||
"stage3/wspellswarm",
|
||||
"dialog/wriggle",
|
||||
NULL);
|
||||
preload_resources(RES_SHADER, RESF_DEFAULT,
|
||||
"tunnel",
|
||||
"zbuf_fog",
|
||||
NULL);
|
||||
preload_resources(RES_ANIM, RESF_DEFAULT,
|
||||
"scuttle",
|
||||
"wriggleex",
|
||||
NULL);
|
||||
}
|
||||
|
||||
void stage3_end(void) {
|
||||
|
|
|
@ -209,15 +209,27 @@ void stage4_start(void) {
|
|||
}
|
||||
|
||||
void stage4_preload(void) {
|
||||
preload_resource(RES_BGM, "bgm_stage4", RESF_OPTIONAL);
|
||||
preload_resource(RES_BGM, "bgm_stage4boss", RESF_OPTIONAL);
|
||||
preload_resource(RES_TEXTURE, "stage2/border", RESF_DEFAULT); // Stage 2 is intentional!
|
||||
preload_resource(RES_TEXTURE, "stage4/kurumibg1", RESF_DEFAULT);
|
||||
preload_resource(RES_TEXTURE, "stage4/kurumibg2", RESF_DEFAULT);
|
||||
preload_resource(RES_TEXTURE, "stage4/lake", RESF_DEFAULT);
|
||||
preload_resource(RES_TEXTURE, "stage4/mansion", RESF_DEFAULT);
|
||||
preload_resource(RES_TEXTURE, "stage4/planks", RESF_DEFAULT);
|
||||
preload_resource(RES_TEXTURE, "stage4/wall", RESF_DEFAULT);
|
||||
preload_resources(RES_BGM, RESF_OPTIONAL, "bgm_stage4", "bgm_stage4boss", NULL);
|
||||
preload_resources(RES_TEXTURE, RESF_DEFAULT,
|
||||
"stage2/border", // Stage 2 is intentional!
|
||||
"stage4/kurumibg1",
|
||||
"stage4/kurumibg2",
|
||||
"stage4/lake",
|
||||
"stage4/mansion",
|
||||
"stage4/planks",
|
||||
"stage4/wall",
|
||||
"dialog/kurumi",
|
||||
NULL);
|
||||
preload_resources(RES_SHADER, RESF_DEFAULT,
|
||||
"zbuf_fog",
|
||||
NULL);
|
||||
preload_resources(RES_ANIM, RESF_DEFAULT,
|
||||
"kurumi",
|
||||
NULL);
|
||||
preload_resources(RES_MODEL, RESF_DEFAULT,
|
||||
"mansion",
|
||||
"lake",
|
||||
NULL);
|
||||
}
|
||||
|
||||
void stage4_end(void) {
|
||||
|
|
|
@ -123,13 +123,24 @@ void stage5_start(void) {
|
|||
}
|
||||
|
||||
void stage5_preload(void) {
|
||||
preload_resource(RES_BGM, "bgm_stage5", RESF_OPTIONAL);
|
||||
preload_resource(RES_BGM, "bgm_stage5boss", RESF_OPTIONAL);
|
||||
preload_resource(RES_TEXTURE, "stage5/noise", RESF_DEFAULT);
|
||||
preload_resource(RES_TEXTURE, "stage5/spell_bg", RESF_DEFAULT);
|
||||
preload_resource(RES_TEXTURE, "stage5/spell_clouds", RESF_DEFAULT);
|
||||
preload_resource(RES_TEXTURE, "stage5/spell_lightning", RESF_DEFAULT);
|
||||
preload_resource(RES_TEXTURE, "stage5/tower", RESF_DEFAULT);
|
||||
preload_resources(RES_BGM, RESF_OPTIONAL, "bgm_stage5", "bgm_stage5boss", NULL);
|
||||
preload_resources(RES_TEXTURE, RESF_DEFAULT,
|
||||
"stage5/noise",
|
||||
"stage5/spell_bg",
|
||||
"stage5/spell_clouds",
|
||||
"stage5/spell_lightning",
|
||||
"stage5/tower",
|
||||
"dialog/iku",
|
||||
NULL);
|
||||
preload_resources(RES_SHADER, RESF_DEFAULT,
|
||||
"tower_light",
|
||||
NULL);
|
||||
preload_resources(RES_ANIM, RESF_DEFAULT,
|
||||
"iku",
|
||||
NULL);
|
||||
preload_resources(RES_MODEL, RESF_DEFAULT,
|
||||
"tower",
|
||||
NULL);
|
||||
}
|
||||
|
||||
void stage5_end(void) {
|
||||
|
|
|
@ -168,18 +168,31 @@ void stage6_start(void) {
|
|||
}
|
||||
|
||||
void stage6_preload(void) {
|
||||
preload_resource(RES_BGM, "bgm_stage6", RESF_OPTIONAL);
|
||||
preload_resource(RES_BGM, "bgm_stage6boss", RESF_OPTIONAL);
|
||||
preload_resource(RES_TEXTURE, "stage6/baryon_connector", RESF_DEFAULT);
|
||||
preload_resource(RES_TEXTURE, "stage6/baryon", RESF_DEFAULT);
|
||||
preload_resource(RES_TEXTURE, "stage6/scythecircle", RESF_DEFAULT);
|
||||
preload_resource(RES_TEXTURE, "stage6/scythe", RESF_DEFAULT);
|
||||
preload_resource(RES_TEXTURE, "stage6/sky", RESF_DEFAULT);
|
||||
preload_resource(RES_TEXTURE, "stage6/spellbg_chalk", RESF_DEFAULT);
|
||||
preload_resource(RES_TEXTURE, "stage6/spellbg_classic", RESF_DEFAULT);
|
||||
preload_resource(RES_TEXTURE, "stage6/spellbg_modern", RESF_DEFAULT);
|
||||
preload_resource(RES_TEXTURE, "stage6/towertop", RESF_DEFAULT);
|
||||
preload_resource(RES_TEXTURE, "stage6/towerwall", RESF_DEFAULT);
|
||||
preload_resources(RES_BGM, RESF_OPTIONAL, "bgm_stage6", "bgm_stage6boss", NULL);
|
||||
preload_resources(RES_TEXTURE, RESF_DEFAULT,
|
||||
"stage6/baryon_connector",
|
||||
"stage6/baryon",
|
||||
"stage6/scythecircle",
|
||||
"stage6/scythe",
|
||||
"stage6/sky",
|
||||
"stage6/spellbg_chalk",
|
||||
"stage6/spellbg_classic",
|
||||
"stage6/spellbg_modern",
|
||||
"stage6/towertop",
|
||||
"stage6/towerwall",
|
||||
"dialog/elly",
|
||||
NULL);
|
||||
preload_resources(RES_SHADER, RESF_DEFAULT,
|
||||
"tower_wall",
|
||||
NULL);
|
||||
preload_resources(RES_ANIM, RESF_DEFAULT,
|
||||
"elly",
|
||||
NULL);
|
||||
preload_resources(RES_MODEL, RESF_DEFAULT,
|
||||
"towerwall",
|
||||
"towertop",
|
||||
"skysphere",
|
||||
NULL);
|
||||
}
|
||||
|
||||
void stage6_end(void) {
|
||||
|
|
Loading…
Reference in a new issue