resource: lifetime management redesign (WIP)

This commit is contained in:
Andrei Alexeyev 2023-03-22 23:41:32 +01:00
parent d7b1ecfd6f
commit 9dade8ad33
No known key found for this signature in database
GPG key ID: 72D26128040B9690
62 changed files with 627 additions and 345 deletions

View file

@ -1616,8 +1616,8 @@ void _begin_boss_attack_task(const BossAttackTaskArgs *args) {
WAIT_EVENT_OR_DIE(&args->attack->events.started);
}
void boss_preload(void) {
res_preload_multi(RES_SFX, RESF_OPTIONAL,
void boss_preload(ResourceGroup *rg) {
res_group_preload(rg, RES_SFX, RESF_OPTIONAL,
"charge_generic",
"charge_extra",
"spellend",
@ -1627,7 +1627,7 @@ void boss_preload(void) {
"bossdeath",
NULL);
res_preload_multi(RES_SPRITE, RESF_DEFAULT,
res_group_preload(rg, RES_SPRITE, RESF_DEFAULT,
"boss_circle",
"boss_indicator",
"boss_spellcircle0",
@ -1636,7 +1636,7 @@ void boss_preload(void) {
"spell",
NULL);
res_preload_multi(RES_SHADER_PROGRAM, RESF_DEFAULT,
res_group_preload(rg, RES_SHADER_PROGRAM, RESF_DEFAULT,
"boss_zoom",
"boss_death",
"spellcard_intro",
@ -1650,7 +1650,7 @@ void boss_preload(void) {
StageInfo *s = global.stage;
if(s->type != STAGE_SPELL || s->spell->type == AT_ExtraSpell) {
res_preload_multi(RES_TEXTURE, RESF_DEFAULT,
res_group_preload(rg, RES_TEXTURE, RESF_DEFAULT,
"stage3/wspellclouds",
"stage4/kurumibg2",
NULL);

View file

@ -16,6 +16,7 @@
#include "projectile.h"
#include "entity.h"
#include "coroutine.h"
#include "resource/resource.h"
#define BOSS_HURT_RADIUS 16
#define BOSS_MAX_ATTACKS 24
@ -226,7 +227,7 @@ void boss_death(Boss **boss) attr_nonnull(1);
void boss_reset_motion(Boss *boss) attr_nonnull(1);
void boss_preload(void);
void boss_preload(ResourceGroup *rg);
#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)

View file

@ -554,22 +554,22 @@ static void credits_free(void) {
stage3d_shutdown(&stage_3d_context);
}
void credits_preload(void) {
res_preload(RES_BGM, "credits", RESF_OPTIONAL);
res_preload_multi(RES_SHADER_PROGRAM, RESF_DEFAULT,
void credits_preload(ResourceGroup *rg) {
res_group_preload(rg, RES_BGM, RESF_OPTIONAL, "credits", NULL);
res_group_preload(rg, RES_SHADER_PROGRAM, RESF_DEFAULT,
"pbr",
"envmap_reflect",
"stage6_sky",
NULL);
res_preload(RES_SPRITE, "kyoukkuri", RESF_DEFAULT);
res_preload_multi(RES_TEXTURE, RESF_DEFAULT,
res_group_preload(rg, RES_SPRITE, RESF_DEFAULT, "kyoukkuri", NULL);
res_group_preload(rg, RES_TEXTURE, RESF_DEFAULT,
"loading", // for transition
"stage6/sky",
NULL);
res_preload_multi(RES_MATERIAL, RESF_DEFAULT,
res_group_preload(rg, RES_MATERIAL, RESF_DEFAULT,
"credits/tower",
NULL);
res_preload_multi(RES_MODEL, RESF_DEFAULT,
res_group_preload(rg, RES_MODEL, RESF_DEFAULT,
"credits/metal_columns",
"credits/tower",
"cube",
@ -603,7 +603,6 @@ static void credits_end_loop(void *ctx) {
}
void credits_enter(CallChain next) {
credits_preload();
credits_init();
credits.cc = next;
eventloop_enter(&credits, credits_logic_frame, credits_render_frame, credits_end_loop, FPS);

View file

@ -10,6 +10,7 @@
#include "taisei.h"
#include "util/callchain.h"
#include "resource/resource.h"
void credits_enter(CallChain next);
void credits_preload(void);
void credits_preload(ResourceGroup *rg);

View file

@ -49,6 +49,7 @@ typedef struct CutsceneState {
const CutscenePhase *phase;
const CutscenePhaseTextEntry *text_entry;
CallChain cc;
ResourceGroup rg;
CutsceneBGState bg_state;
LIST_ANCHOR(CutsceneTextVisual) text_visuals;
@ -393,6 +394,7 @@ static RenderFrameAction cutscene_render_frame(void *ctx) {
static void cutscene_end_loop(void *ctx) {
CutsceneState *st = ctx;
res_group_release(&st->rg);
for(CutsceneTextVisual *tv = st->text_visuals.first, *next; tv; tv = next) {
next = tv->next;
@ -406,20 +408,23 @@ static void cutscene_end_loop(void *ctx) {
run_call_chain(&cc, NULL);
}
static void cutscene_preload(const CutscenePhase phases[]) {
static void cutscene_preload(const CutscenePhase phases[], ResourceGroup *rg) {
for(const CutscenePhase *p = phases; p->background; ++p) {
if(*p->background) {
res_preload(RES_TEXTURE, p->background, RESF_DEFAULT);
res_group_preload(rg, RES_TEXTURE, RESF_DEFAULT, p->background, NULL);
}
}
}
static CutsceneState *cutscene_state_new(const CutscenePhase phases[]) {
cutscene_preload(phases);
auto st = ALLOC(CutsceneState, {
.phase = &phases[0],
.mfb_group = fbmgr_group_create(),
});
res_group_init(&st->rg);
cutscene_preload(phases, &st->rg);
switch_bg(st, st->phase->background);
reset_timers(st);

View file

@ -386,6 +386,6 @@ bool dialog_is_active(Dialog *d) {
return d && d->state != DIALOG_STATE_FADEOUT;
}
void dialog_preload(void) {
res_preload(RES_SHADER_PROGRAM, "text_dialog", RESF_DEFAULT);
void dialog_preload(ResourceGroup *rg) {
res_group_preload(rg, RES_SHADER_PROGRAM, RESF_DEFAULT, "text_dialog", NULL);
}

View file

@ -10,6 +10,7 @@
#include "taisei.h"
#include "color.h"
#include "resource/resource.h"
#include "resource/sprite.h"
#include "coroutine.h"
@ -130,6 +131,6 @@ bool dialog_page(Dialog *d)
bool dialog_is_active(Dialog *d);
void dialog_preload(void);
void dialog_preload(ResourceGroup *rg);
#include "dialog/dialog_interface.h"

View file

@ -10,6 +10,7 @@
#include "taisei.h"
#include "dialog.h"
#include "resource/resource.h"
#define DIALOG_SCRIPTS \
@ -35,6 +36,7 @@
_name##DialogEvents **out_events; \
int called_for_preload; \
ResourceFlags preload_rflags; \
ResourceGroup *preload_group; \
});
#define WITHOUT_EVENTS(_name) \

View file

@ -57,11 +57,11 @@
if(ARGS.called_for_preload)
#define PRELOAD_CHAR(name) \
portrait_preload_base_sprite(#name, NULL, ARGS.preload_rflags); \
portrait_preload_base_sprite(ARGS.preload_group, #name, NULL, ARGS.preload_rflags); \
for(const char *_charname = #name; _charname; _charname = NULL)
#define PRELOAD_VARIANT(variant) \
portrait_preload_base_sprite(_charname, #variant, ARGS.preload_rflags)
portrait_preload_base_sprite(ARGS.preload_group, _charname, #variant, ARGS.preload_rflags)
#define PRELOAD_FACE(face) \
portrait_preload_face_sprite(_charname, #face, ARGS.preload_rflags)
portrait_preload_face_sprite(ARGS.preload_group, _charname, #face, ARGS.preload_rflags)

View file

@ -54,8 +54,8 @@ const Color *difficulty_color(Difficulty diff) {
return d ? &d->color : &unknown_clr;
}
void difficulty_preload(void) {
void difficulty_preload(ResourceGroup *rg) {
for(Difficulty diff = D_Easy; diff < NUM_SELECTABLE_DIFFICULTIES + D_Easy; ++diff) {
res_preload(RES_SPRITE, difficulty_sprite_name(diff), RESF_PERMANENT);
res_group_preload(rg, RES_SPRITE, RESF_DEFAULT, difficulty_sprite_name(diff), NULL);
}
}

View file

@ -10,6 +10,7 @@
#include "taisei.h"
#include "color.h"
#include "resource/resource.h"
typedef enum {
D_Any = 0,
@ -31,7 +32,7 @@ const char *difficulty_sprite_name(Difficulty diff)
const Color *difficulty_color(Difficulty diff)
attr_pure attr_returns_nonnull;
void difficulty_preload(void);
void difficulty_preload(ResourceGroup *rg);
#define difficulty_value(easy, normal, hard, lunatic) ({ \
typeof((easy)+(normal)+(hard)+(lunatic)) val; \

View file

@ -344,8 +344,8 @@ void process_enemies(EnemyList *enemies) {
}
}
void enemies_preload(void) {
res_preload_multi(RES_ANIM, RESF_DEFAULT,
void enemies_preload(ResourceGroup *rg) {
res_group_preload(rg, RES_ANIM, RESF_DEFAULT,
"enemy/fairy_blue",
"enemy/fairy_red",
"enemy/bigfairy",
@ -353,14 +353,14 @@ void enemies_preload(void) {
"enemy/superfairy",
NULL);
res_preload_multi(RES_SPRITE, RESF_DEFAULT,
res_group_preload(rg, RES_SPRITE, RESF_DEFAULT,
"fairy_circle",
"fairy_circle_red",
"fairy_circle_big_and_mean",
"enemy/swirl",
NULL);
res_preload_multi(RES_SFX, RESF_OPTIONAL,
res_group_preload(rg, RES_SFX, RESF_OPTIONAL,
"enemydeath",
NULL);
}

View file

@ -15,6 +15,7 @@
#include "entity.h"
#include "coroutine.h"
#include "move.h"
#include "resource/resource.h"
#ifdef DEBUG
#define ENEMY_DEBUG
@ -132,4 +133,4 @@ cmplx enemy_visual_pos(Enemy *enemy);
void enemy_kill(Enemy *enemy);
void enemy_kill_all(EnemyList *enemies);
void enemies_preload(void);
void enemies_preload(ResourceGroup *rg);

View file

@ -387,16 +387,16 @@ void spawn_and_collect_items(cmplx pos, float collect_value, SpawnItemsArgs grou
spawn_items_internal(pos, collect_value, groups);
}
void items_preload(void) {
void items_preload(ResourceGroup *rg) {
for(ItemType i = ITEM_FIRST; i <= ITEM_LAST; ++i) {
res_preload(RES_SPRITE, item_sprite_name(i), RESF_PERMANENT);
res_group_preload(rg, RES_SPRITE, 0, item_sprite_name(i), NULL);
const char *indicator = item_indicator_sprite_name(i);
if(indicator != NULL) {
res_preload(RES_SPRITE, indicator, RESF_PERMANENT);
res_group_preload(rg, RES_SPRITE, 0, indicator, NULL);
}
}
res_preload_multi(RES_SFX, RESF_OPTIONAL,
res_group_preload(rg, RES_SFX, RESF_OPTIONAL,
"item_generic",
NULL);
}

View file

@ -10,6 +10,7 @@
#include "taisei.h"
#include "util.h"
#include "resource/resource.h"
#include "resource/texture.h"
#include "objectpool.h"
#include "entity.h"
@ -94,7 +95,7 @@ void spawn_and_collect_items(cmplx pos, float collect_value, SpawnItemsArgs grou
bool collect_item(Item *item, float value);
void collect_all_items(float value);
void items_preload(void);
void items_preload(ResourceGroup *rg);
#define POWER_VALUE 5
#define POWER_VALUE_MINI 1

View file

@ -250,8 +250,8 @@ static void create_pass2_resources(void) {
ldraw.pass2.quad.vertex_array = va;
}
void laserdraw_preload(void) {
res_preload_multi(RES_SHADER_PROGRAM, RESF_DEFAULT,
void laserdraw_preload(ResourceGroup *rg) {
res_group_preload(rg, RES_SHADER_PROGRAM, RESF_DEFAULT,
"lasers/sdf_apply",
"lasers/sdf_generate",
NULL);

View file

@ -10,8 +10,9 @@
#include "taisei.h"
#include "entity.h"
#include "resource/resource.h"
void laserdraw_preload(void);
void laserdraw_preload(ResourceGroup *rg);
void laserdraw_init(void);
void laserdraw_shutdown(void);

View file

@ -44,11 +44,13 @@ static void taisei_shutdown(void) {
progress_save();
}
r_release_resources();
res_shutdown();
demoplayer_shutdown();
progress_unload();
stage_objpools_shutdown();
gamemode_shutdown();
res_shutdown();
taskmgr_global_shutdown();
audio_shutdown();
video_shutdown();
@ -219,6 +221,7 @@ typedef struct MainContext {
Replay *replay_in;
Replay *replay_out;
SDL_RWops *replay_out_stream;
ResourceGroup rg;
int replay_idx;
uchar headless : 1;
} MainContext;
@ -242,6 +245,7 @@ static Replay *alloc_replay(void) {
}
static noreturn void main_quit(MainContext *ctx, int status) {
res_group_release(&ctx->rg);
free_cli_action(&ctx->cli);
cleanup_replay(&ctx->replay_in);
@ -375,11 +379,15 @@ static void main_post_vfsinit(CallChainResult ccr) {
filewatch_init();
res_init();
r_post_init();
res_group_init(&ctx->rg);
draw_loading_screen();
dynstage_init_monitoring();
audio_init();
res_post_init();
menu_preload(&ctx->rg);
gamepad_init();
progress_load();
video_post_init();
@ -459,7 +467,7 @@ static void main_singlestg_begin_game(CallChainResult ccr) {
global.plr.mode = ctx->plrmode;
}
stage_enter(ctx->stg, CALLCHAIN(main_singlestg_end_game, ctx));
stage_enter(ctx->stg, &mctx->rg, CALLCHAIN(main_singlestg_end_game, ctx));
}
static void main_singlestg_end_game(CallChainResult ccr) {
@ -476,6 +484,7 @@ static void main_singlestg_end_game(CallChainResult ccr) {
static void main_singlestg_cleanup(CallChainResult ccr) {
SingleStageContext *ctx = ccr.ctx;
MainContext *mctx = ctx->mctx;
res_group_release(&mctx->rg);
mem_free(ccr.ctx);
main_quit(mctx, 0);
}

View file

@ -359,16 +359,16 @@ static bool charprofile_input_handler(SDL_Event *event, void *arg) {
}
void preload_charprofile_menu(void) {
void preload_charprofile_menu(ResourceGroup *rg) {
for(int i = 0; i < NUM_PROFILES-1; i++) {
for(int f = 0; f < NUM_FACES; f++) {
if(!profiles[i].faces[f]) {
break;
}
portrait_preload_face_sprite(profiles[i].name, profiles[i].faces[f], RESF_PERMANENT);
portrait_preload_face_sprite(rg, profiles[i].name, profiles[i].faces[f], RESF_DEFAULT);
}
portrait_preload_base_sprite(profiles[i].name, NULL, RESF_PERMANENT);
res_preload(RES_TEXTURE, profiles[i].background, RESF_PERMANENT);
portrait_preload_base_sprite(rg, profiles[i].name, NULL, RESF_DEFAULT);
res_group_preload(rg, RES_TEXTURE, RESF_DEFAULT, profiles[i].background, NULL);
}
};
@ -382,8 +382,6 @@ static void charprofile_input(MenuData *m) {
MenuData *create_charprofile_menu(void) {
MenuData *m = alloc_menu();
preload_charprofile_menu();
m->input = charprofile_input;
m->draw = charprofile_draw;
m->logic = charprofile_logic;

View file

@ -10,7 +10,8 @@
#include "taisei.h"
#include "menu.h"
#include "resource/resource.h"
void preload_charprofile_menu(void);
void preload_charprofile_menu(ResourceGroup *rg);
MenuData *create_charprofile_menu(void);

View file

@ -378,16 +378,16 @@ static void char_menu_input(MenuData *menu) {
}, EFLAG_MENU);
}
void preload_char_menu(void) {
void preload_char_menu(ResourceGroup *rg) {
for(int i = 0; i < NUM_CHARACTERS; ++i) {
PlayerCharacter *pchar = plrchar_get(i);
portrait_preload_base_sprite(pchar->lower_name, NULL, RESF_PERMANENT);
res_preload(RES_TEXTURE, pchar->menu_texture_name, RESF_PERMANENT);
portrait_preload_base_sprite(rg, pchar->lower_name, NULL, RESF_DEFAULT);
res_group_preload(rg, RES_TEXTURE, RESF_DEFAULT, pchar->menu_texture_name, NULL);
}
char *p = (char*)facedefs;
for(int i = 0; i < sizeof(facedefs) / FACENAME_LEN; ++i) {
res_preload(RES_SPRITE, p + i * FACENAME_LEN, RESF_PERMANENT);
res_group_preload(rg, RES_SPRITE, RESF_DEFAULT, p + i * FACENAME_LEN, NULL);
}
}

View file

@ -10,7 +10,8 @@
#include "taisei.h"
#include "menu.h"
#include "resource/resource.h"
MenuData* create_char_menu(void);
MenuData *create_char_menu(void);
void draw_char_menu(MenuData *menu);
void preload_char_menu(void);
void preload_char_menu(ResourceGroup *rg);

View file

@ -29,6 +29,7 @@ typedef struct StartGameContext {
MenuData *char_menu;
Replay replay;
Difficulty difficulty;
ResourceGroup rg;
} StartGameContext;
static void start_game_do_pick_character(CallChainResult ccr);
@ -40,6 +41,7 @@ static void start_game_do_cleanup(CallChainResult ccr);
static void start_game_internal(MenuData *menu, StageInfo *info, bool difficulty_menu) {
auto ctx = ALLOC(StartGameContext);
res_group_init(&ctx->rg);
if(info == NULL) {
global.is_practice_mode = false;
@ -110,6 +112,11 @@ static void kill_aux_menus(StartGameContext *ctx) {
ctx->char_menu = ctx->diff_menu = NULL;
}
static void enter_stage_now(StartGameContext *ctx) {
res_group_release(&ctx->rg);
stage_enter(ctx->current_stage, &ctx->rg, CALLCHAIN(start_game_do_leave_stage, ctx));
}
static void start_game_do_enter_stage(CallChainResult ccr) {
StartGameContext *ctx = ccr.ctx;
MenuData *prev_menu = ccr.result;
@ -127,7 +134,7 @@ static void start_game_do_enter_stage(CallChainResult ccr) {
kill_aux_menus(ctx);
reset_game(ctx);
stage_enter(ctx->current_stage, CALLCHAIN(start_game_do_leave_stage, ctx));
enter_stage_now(ctx);
}
static void start_game_do_leave_stage(CallChainResult ccr) {
@ -135,7 +142,7 @@ static void start_game_do_leave_stage(CallChainResult ccr) {
if(global.gameover == GAMEOVER_RESTART) {
reset_game(ctx);
stage_enter(ctx->current_stage, CALLCHAIN(start_game_do_leave_stage, ctx));
enter_stage_now(ctx);
return;
}
@ -143,12 +150,14 @@ static void start_game_do_leave_stage(CallChainResult ccr) {
++ctx->current_stage;
if(ctx->current_stage->type == STAGE_STORY) {
stage_enter(ctx->current_stage, CALLCHAIN(start_game_do_leave_stage, ctx));
enter_stage_now(ctx);
} else {
CallChain cc;
if(global.gameover == GAMEOVER_WIN) {
credits_preload();
res_group_release(&ctx->rg);
res_purge();
credits_preload(&ctx->rg);
cc = CALLCHAIN(start_game_do_show_ending, ctx);
} else {
cc = CALLCHAIN(start_game_do_cleanup, ctx);
@ -184,8 +193,8 @@ static void start_game_do_cleanup(CallChainResult ccr) {
StartGameContext *ctx = ccr.ctx;
replay_reset(&ctx->replay);
kill_aux_menus(ctx);
res_group_release(&ctx->rg);
mem_free(ctx);
res_unload_all(false);
global.gameover = GAMEOVER_NONE;
replay_state_deinit(&global.replay.output);
main_menu_update_practice_menus();

View file

@ -241,8 +241,10 @@ void draw_main_menu(MenuData *menu) {
}
void draw_loading_screen(void) {
res_preload(RES_TEXTURE, "loading", RESF_DEFAULT);
res_preload(RES_SHADER_PROGRAM, "text_default", RESF_PERMANENT);
ResourceGroup rg;
res_group_init(&rg);
res_group_preload(&rg, RES_TEXTURE, RESF_DEFAULT, "loading", NULL);
res_group_preload(&rg, RES_SHADER_PROGRAM, RESF_DEFAULT, "text_default", NULL);
set_ortho(SCREEN_W, SCREEN_H);
fill_screen("loading");
@ -255,24 +257,25 @@ void draw_loading_screen(void) {
});
video_swap_buffers();
res_group_release(&rg);
}
void menu_preload(void) {
difficulty_preload();
void menu_preload(ResourceGroup *rg) {
difficulty_preload(rg);
res_preload_multi(RES_FONT, RESF_PERMANENT,
res_group_preload(rg, RES_FONT, RESF_DEFAULT,
"big",
"small",
NULL);
res_preload_multi(RES_TEXTURE, RESF_PERMANENT,
res_group_preload(rg, RES_TEXTURE, RESF_DEFAULT,
"abstract_brown",
"cell_noise",
"stage1/cirnobg",
"menu/mainmenubg",
NULL);
res_preload_multi(RES_SPRITE, RESF_PERMANENT,
res_group_preload(rg, RES_SPRITE, RESF_DEFAULT,
"part/smoke",
"part/petal",
"menu/logo",
@ -280,20 +283,20 @@ void menu_preload(void) {
"star",
NULL);
res_preload_multi(RES_SHADER_PROGRAM, RESF_PERMANENT,
res_group_preload(rg, RES_SHADER_PROGRAM, RESF_DEFAULT,
"mainmenubg",
"sprite_circleclipped_indicator",
NULL);
res_preload_multi(RES_SFX, RESF_PERMANENT | RESF_OPTIONAL,
res_group_preload(rg, RES_SFX, RESF_OPTIONAL,
"generic_shot",
"shot_special1",
"hit",
NULL);
res_preload_multi(RES_BGM, RESF_PERMANENT | RESF_OPTIONAL,
res_group_preload(rg, RES_BGM, RESF_OPTIONAL,
"menu",
NULL);
preload_char_menu();
preload_char_menu(rg);
}

View file

@ -10,10 +10,11 @@
#include "taisei.h"
#include "menu.h"
#include "resource/resource.h"
MenuData* create_main_menu(void);
MenuData *create_main_menu(void);
void draw_main_menu_bg(MenuData *m, double center_x, double center_y, double R, const char *tex1, const char *tex2);
void draw_main_menu(MenuData *m);
void main_menu_update_practice_menus(void);
void draw_loading_screen(void);
void menu_preload(void);
void menu_preload(ResourceGroup *rg);

View file

@ -35,13 +35,23 @@ static void draw_media_menu(MenuData *m) {
draw_menu_list(m, 100, 100, NULL, SCREEN_H, NULL);
}
MenuData *create_media_menu(void) {
MenuData *m = alloc_menu();
static void end_media_menu(MenuData *m) {
res_group_release(m->context);
mem_free(m->context);
}
MenuData *create_media_menu(void) {
auto rg = ALLOC(ResourceGroup);
res_group_init(rg);
preload_charprofile_menu(rg);
MenuData *m = alloc_menu();
m->draw = draw_media_menu;
m->logic = animate_menu_list;
m->flags = MF_Abortable;
m->transition = TransFadeBlack;
m->end = end_media_menu;
m->context = rg;
add_menu_entry(m, "Character Profiles", menu_action_enter_charprofileview, NULL);
add_menu_entry(m, "Music Room", menu_action_enter_musicroom, NULL);
@ -53,8 +63,9 @@ MenuData *create_media_menu(void) {
++m->cursor;
}
preload_charprofile_menu();
return m;
}
void preload_media_menu(ResourceGroup *rg) {
preload_charprofile_menu(rg);
}

View file

@ -10,5 +10,8 @@
#include "taisei.h"
#include "menu.h"
#include "resource/resource.h"
void preload_media_menu(ResourceGroup *rg);
MenuData *create_media_menu(void);

View file

@ -34,6 +34,10 @@ typedef struct MusicEntryParam {
uint8_t state;
} MusicEntryParam;
typedef struct MusicRoomContext {
ResourceGroup rg;
} MusicRoomContext;
static void musicroom_logic(MenuData *m) {
float prev_selector_x = m->drawdata[0];
float prev_selector_w = m->drawdata[1];
@ -216,11 +220,10 @@ static void action_play_bgm(MenuData *m, void *arg) {
}
static void add_bgm(MenuData *m, const char *bgm_name, bool preload) {
MusicRoomContext *ctx = m->context;
if(preload) {
// FIXME HACK: make this just RESF_OPTIONAL once we have proper refcounting for resources!
// Currently without RESF_PERMANENT we segfault after returning from demo playback,
// because transient resources get unloaded.
res_preload(RES_BGM, bgm_name, RESF_PERMANENT | RESF_OPTIONAL);
res_group_preload(&ctx->rg, RES_BGM, RESF_OPTIONAL, bgm_name, NULL);
return;
}
@ -245,18 +248,26 @@ static void add_bgm(MenuData *m, const char *bgm_name, bool preload) {
}
static void musicroom_free(MenuData *m) {
MusicRoomContext *ctx = m->context;
res_group_release(&ctx->rg);
mem_free(ctx);
dynarray_foreach_elem(&m->entries, MenuEntry *e, {
mem_free(e->arg);
});
}
MenuData* create_musicroom_menu(void) {
MenuData *create_musicroom_menu(void) {
auto ctx = ALLOC(MusicRoomContext);
res_group_init(&ctx->rg);
MenuData *m = alloc_menu();
m->logic = musicroom_logic;
m->draw = musicroom_draw;
m->end = musicroom_free;
m->transition = TransFadeBlack;
m->flags = MF_Abortable;
m->context = ctx;
for(int preload = 1; preload >= 0; --preload) {
add_bgm(m, "menu", preload);

View file

@ -11,4 +11,4 @@
#include "menu.h"
MenuData* create_musicroom_menu(void);
MenuData *create_musicroom_menu(void);

View file

@ -55,7 +55,6 @@ void player_stage_pre_init(Player *plr) {
plr->deathtime = -1;
plr->axis_lr = 0;
plr->axis_ud = 0;
plrmode_preload(plr->mode);
}
double player_property(Player *plr, PlrProperty prop) {
@ -1670,26 +1669,26 @@ uint64_t player_next_extralife_threshold(uint64_t step) {
return base * (step * step + step + 2) / 2;
}
void player_preload(void) {
void player_preload(ResourceGroup *rg) {
const int flags = RESF_DEFAULT;
res_preload_multi(RES_SHADER_PROGRAM, flags,
res_group_preload(rg, RES_SHADER_PROGRAM, flags,
"circle_distort",
"player_death",
NULL);
res_preload_multi(RES_TEXTURE, flags,
res_group_preload(rg, RES_TEXTURE, flags,
"static",
NULL);
res_preload_multi(RES_SPRITE, flags,
res_group_preload(rg, RES_SPRITE, flags,
"fairy_circle",
"focus",
"part/blast_huge_halo",
"part/powersurge_field",
NULL);
res_preload_multi(RES_SFX, flags | RESF_OPTIONAL,
res_group_preload(rg, RES_SFX, flags | RESF_OPTIONAL,
"death",
"extra_bomb",
"extra_life",

View file

@ -9,6 +9,17 @@
#pragma once
#include "taisei.h"
#include "util.h"
#include "enemy.h"
#include "gamepad.h"
#include "aniplayer.h"
#include "stats.h"
#include "resource/resource.h"
#include "resource/animation.h"
#include "entity.h"
#include "replay/state.h"
#include "replay/eventcodes.h"
#ifdef DEBUG
#define PLR_DPS_STATS
#endif
@ -19,16 +30,6 @@
#define IF_PLR_DPS_STATS(...)
#endif
#include "util.h"
#include "enemy.h"
#include "gamepad.h"
#include "aniplayer.h"
#include "stats.h"
#include "resource/animation.h"
#include "entity.h"
#include "replay/state.h"
#include "replay/eventcodes.h"
enum {
PLR_MAX_POWER_EFFECTIVE = 400,
PLR_MAX_POWER_STORED = 600,
@ -241,7 +242,7 @@ double player_get_bomb_progress(Player *plr);
void player_damage_hook(Player *plr, EntityInterface *target, DamageInfo *dmg);
void player_preload(void);
void player_preload(ResourceGroup *rg);
// FIXME: where should this be?
cmplx plrutil_homing_target(cmplx org, cmplx fallback);

View file

@ -40,14 +40,14 @@ PlayerCharacter *plrchar_get(CharacterID id) {
return pc;
}
void plrchar_preload(PlayerCharacter *pc) {
void plrchar_preload(PlayerCharacter *pc, ResourceGroup *rg) {
const char *name = pc->lower_name;
portrait_preload_base_sprite(name, NULL, RESF_DEFAULT);
portrait_preload_face_sprite(name, "normal", RESF_DEFAULT);
portrait_preload_base_sprite(rg, name, NULL, RESF_DEFAULT);
portrait_preload_face_sprite(rg, name, "normal", RESF_DEFAULT);
char buf[64];
plrchar_player_anim_name(pc, sizeof(buf), buf);
res_preload(RES_ANIM, buf, RESF_DEFAULT);
res_group_preload(rg, RES_ANIM, RESF_DEFAULT, buf, NULL);
}
void plrchar_render_bomb_portrait(PlayerCharacter *pc, Sprite *out_spr) {
@ -132,11 +132,11 @@ PlayerMode *plrmode_parse(const char *name) {
return plrmode_find(char_id, shot_id);
}
void plrmode_preload(PlayerMode *mode) {
void plrmode_preload(PlayerMode *mode, ResourceGroup *rg) {
assert(mode != NULL);
plrchar_preload(mode->character);
plrchar_preload(mode->character, rg);
if(mode->procs.preload) {
mode->procs.preload();
mode->procs.preload(rg);
}
}

View file

@ -74,7 +74,7 @@ typedef struct PlayerCharacter {
typedef void (*PlayerModeInitProc)(Player *plr);
typedef void (*PlayerModeFreeProc)(Player *plr);
typedef void (*PlayerModePreloadProc)(void);
typedef void (*PlayerModePreloadProc)(ResourceGroup *rg);
typedef double (*PlayerModePropertyProc)(Player *plr, PlrProperty prop);
typedef struct PlayerMode {
@ -97,7 +97,7 @@ enum {
};
PlayerCharacter *plrchar_get(CharacterID id);
void plrchar_preload(PlayerCharacter *pc);
void plrchar_preload(PlayerCharacter *pc, ResourceGroup *rg);
void plrchar_render_bomb_portrait(PlayerCharacter *pc, Sprite *out_spr);
int plrchar_player_anim_name(PlayerCharacter *pc, size_t bufsize, char buf[bufsize]);
Animation *plrchar_player_anim(PlayerCharacter *pc);
@ -105,6 +105,6 @@ Animation *plrchar_player_anim(PlayerCharacter *pc);
PlayerMode *plrmode_find(CharacterID charid, ShotModeID shotid);
int plrmode_repr(char *out, size_t outsize, PlayerMode *mode, bool internal);
PlayerMode *plrmode_parse(const char *name);
void plrmode_preload(PlayerMode *mode);
void plrmode_preload(PlayerMode *mode, ResourceGroup *rg);
double player_property(Player *plr, PlrProperty prop);

View file

@ -714,23 +714,23 @@ static double marisa_laser_property(Player *plr, PlrProperty prop) {
}
}
static void marisa_laser_preload(void) {
static void marisa_laser_preload(ResourceGroup *rg) {
const int flags = RESF_DEFAULT;
res_preload_multi(RES_SPRITE, flags,
res_group_preload(rg, RES_SPRITE, flags,
"proj/marisa",
"part/maristar_orbit",
"hakkero",
"masterspark_ring",
NULL);
res_preload_multi(RES_TEXTURE, flags,
res_group_preload(rg, RES_TEXTURE, flags,
"marisa_bombbg",
"part/marisa_laser0",
"part/marisa_laser1",
NULL);
res_preload_multi(RES_SHADER_PROGRAM, flags,
res_group_preload(rg, RES_SHADER_PROGRAM, flags,
"blur25",
"blur5",
"marisa_laser",
@ -739,11 +739,11 @@ static void marisa_laser_preload(void) {
"sprite_hakkero",
NULL);
res_preload_multi(RES_ANIM, flags,
res_group_preload(rg, RES_ANIM, flags,
"fire",
NULL);
res_preload_multi(RES_SFX, flags | RESF_OPTIONAL,
res_group_preload(rg, RES_SFX, flags | RESF_OPTIONAL,
"bomb_marisa_a",
NULL);
}

View file

@ -521,10 +521,10 @@ static double marisa_star_property(Player *plr, PlrProperty prop) {
}
}
static void marisa_star_preload(void) {
static void marisa_star_preload(ResourceGroup *rg) {
const int flags = RESF_DEFAULT;
res_preload_multi(RES_SPRITE, flags,
res_group_preload(rg, RES_SPRITE, flags,
"hakkero",
"masterspark_ring",
"part/maristar_orbit",
@ -533,17 +533,17 @@ static void marisa_star_preload(void) {
"proj/maristar",
NULL);
res_preload_multi(RES_TEXTURE, flags,
res_group_preload(rg, RES_TEXTURE, flags,
"marisa_bombbg",
NULL);
res_preload_multi(RES_SHADER_PROGRAM, flags,
res_group_preload(rg, RES_SHADER_PROGRAM, flags,
"masterspark",
"maristar_bombbg",
"sprite_hakkero",
NULL);
res_preload_multi(RES_SFX, flags | RESF_OPTIONAL,
res_group_preload(rg, RES_SFX, flags | RESF_OPTIONAL,
"bomb_marisa_b",
NULL);
}

View file

@ -42,10 +42,10 @@ DEFINE_ENTITY_TYPE(ReimuASlave, {
uint alive;
});
static void reimu_spirit_preload(void) {
static void reimu_spirit_preload(ResourceGroup *rg) {
const int flags = RESF_DEFAULT;
res_preload_multi(RES_SPRITE, flags,
res_group_preload(rg, RES_SPRITE, flags,
"yinyang",
"proj/ofuda",
"proj/needle",
@ -55,16 +55,16 @@ static void reimu_spirit_preload(void) {
"part/fantasyseal_impact",
NULL);
res_preload_multi(RES_TEXTURE, flags,
res_group_preload(rg, RES_TEXTURE, flags,
"runes",
NULL);
res_preload_multi(RES_SHADER_PROGRAM, flags,
res_group_preload(rg, RES_SHADER_PROGRAM, flags,
"sprite_yinyang",
"reimu_bomb_bg",
NULL);
res_preload_multi(RES_SFX, flags | RESF_OPTIONAL,
res_group_preload(rg, RES_SFX, flags | RESF_OPTIONAL,
"boom",
"bomb_reimu_a",
"bomb_marisa_b",

View file

@ -676,10 +676,10 @@ static void reimu_dream_init(Player *plr) {
INVOKE_TASK(reimu_dream_controller, ENT_BOX(plr));
}
static void reimu_dream_preload(void) {
static void reimu_dream_preload(ResourceGroup *rg) {
const int flags = RESF_DEFAULT;
res_preload_multi(RES_SPRITE, flags,
res_group_preload(rg, RES_SPRITE, flags,
"yinyang",
"proj/ofuda",
"proj/needle2",
@ -688,19 +688,19 @@ static void reimu_dream_preload(void) {
"part/stardust",
NULL);
res_preload_multi(RES_TEXTURE, flags,
res_group_preload(rg, RES_TEXTURE, flags,
"runes",
"gaplight",
NULL);
res_preload_multi(RES_SHADER_PROGRAM, flags,
res_group_preload(rg, RES_SHADER_PROGRAM, flags,
"sprite_yinyang",
"reimu_gap",
"reimu_gap_light",
"reimu_bomb_bg",
NULL);
res_preload_multi(RES_SFX, flags | RESF_OPTIONAL,
res_group_preload(rg, RES_SFX, flags | RESF_OPTIONAL,
"bomb_marisa_a",
"boon",
NULL);

View file

@ -616,10 +616,10 @@ static void youmu_mirror_init(Player *plr) {
INVOKE_TASK(youmu_mirror_controller, ENT_BOX(plr));
}
static void youmu_mirror_preload(void) {
static void youmu_mirror_preload(ResourceGroup *rg) {
const int flags = RESF_DEFAULT;
res_preload_multi(RES_SPRITE, flags,
res_group_preload(rg, RES_SPRITE, flags,
"part/arc",
"part/blast_huge_halo",
"part/myon",
@ -629,17 +629,17 @@ static void youmu_mirror_preload(void) {
"proj/youmu",
NULL);
res_preload_multi(RES_TEXTURE, flags,
res_group_preload(rg, RES_TEXTURE, flags,
"youmu_bombbg1",
NULL);
res_preload_multi(RES_SHADER_PROGRAM, flags,
res_group_preload(rg, RES_SHADER_PROGRAM, flags,
"sprite_youmu_myon_shot",
"youmu_bomb_bg",
"youmua_bomb",
NULL);
res_preload_multi(RES_SFX, flags | RESF_OPTIONAL,
res_group_preload(rg, RES_SFX, flags | RESF_OPTIONAL,
"bomb_youmu_b",
NULL);
}

View file

@ -595,19 +595,19 @@ static void youmu_haunting_init(Player *plr) {
INVOKE_TASK(youmu_haunting_controller, ENT_BOX(plr));
}
static void youmu_haunting_preload(void) {
static void youmu_haunting_preload(ResourceGroup *rg) {
const int flags = RESF_DEFAULT;
res_preload_multi(RES_SPRITE, flags,
res_group_preload(rg, RES_SPRITE, flags,
"proj/youmu",
"part/youmu_slice",
NULL);
res_preload_multi(RES_TEXTURE, flags,
res_group_preload(rg, RES_TEXTURE, flags,
"youmu_bombbg1",
NULL);
res_preload_multi(RES_SFX, flags | RESF_OPTIONAL,
res_group_preload(rg, RES_SFX, flags | RESF_OPTIONAL,
"bomb_youmu_b",
NULL);
}

View file

@ -32,10 +32,10 @@ Sprite *portrait_get_base_sprite(const char *charname, const char *variant) {
return res_sprite(buf);
}
void portrait_preload_base_sprite(const char *charname, const char *variant, ResourceFlags rflags) {
void portrait_preload_base_sprite(ResourceGroup *rg, const char *charname, const char *variant, ResourceFlags rflags) {
char buf[BUFFER_SIZE];
portrait_get_base_sprite_name(charname, variant, sizeof(buf), buf);
res_preload(RES_SPRITE, buf, rflags);
res_group_preload(rg, RES_SPRITE, rflags, buf, NULL);
}
int portrait_get_face_sprite_name(const char *charname, const char *face, size_t bufsize, char buf[bufsize]) {
@ -48,10 +48,10 @@ Sprite *portrait_get_face_sprite(const char *charname, const char *face) {
return res_sprite(buf);
}
void portrait_preload_face_sprite(const char *charname, const char *face, ResourceFlags rflags) {
void portrait_preload_face_sprite(ResourceGroup *rg, const char *charname, const char *face, ResourceFlags