bunch of portrait and dialog-related shuffling around
This commit is contained in:
parent
ea90164f3a
commit
9f10dfef21
32 changed files with 321 additions and 199 deletions
10
src/boss.c
10
src/boss.c
|
@ -15,6 +15,7 @@
|
|||
#include "stagedraw.h"
|
||||
#include "entity.h"
|
||||
#include "util/glm.h"
|
||||
#include "portrait.h"
|
||||
|
||||
static void ent_draw_boss(EntityInterface *ent);
|
||||
static DamageResult ent_damage_boss(EntityInterface *ent, const DamageInfo *dmg);
|
||||
|
@ -60,17 +61,18 @@ Boss* create_boss(char *name, char *ani, cmplx pos) {
|
|||
return boss;
|
||||
}
|
||||
|
||||
void boss_set_portrait(Boss *boss, Sprite *base, Sprite *face) {
|
||||
void boss_set_portrait(Boss *boss, const char *name, const char *variant, const char *face) {
|
||||
if(boss->portrait.tex != NULL) {
|
||||
r_texture_destroy(boss->portrait.tex);
|
||||
boss->portrait.tex = NULL;
|
||||
}
|
||||
|
||||
if(base != NULL) {
|
||||
if(name != NULL) {
|
||||
assume(face != NULL);
|
||||
render_character_portrait(base, face, &boss->portrait);
|
||||
portrait_render_byname(name, variant, face, &boss->portrait);
|
||||
} else {
|
||||
assume(face == NULL);
|
||||
assume(variant == NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1304,7 +1306,7 @@ void free_boss(Boss *boss) {
|
|||
}
|
||||
|
||||
ent_unregister(&boss->ent);
|
||||
boss_set_portrait(boss, NULL, NULL);
|
||||
boss_set_portrait(boss, NULL, NULL, NULL);
|
||||
aniplayer_free(&boss->ani);
|
||||
free(boss->name);
|
||||
free(boss);
|
||||
|
|
|
@ -190,7 +190,7 @@ Attack* boss_add_attack_from_info(Boss *boss, AttackInfo *info, char move)
|
|||
attr_nonnull(1, 2) attr_returns_nonnull;
|
||||
void boss_set_attack_bonus(Attack *a, int rank) attr_nonnull(1);
|
||||
|
||||
void boss_set_portrait(Boss *boss, Sprite *base, Sprite *face) attr_nonnull(1);
|
||||
void boss_set_portrait(Boss *boss, const char *name, const char *variant, const char *face) attr_nonnull(1);
|
||||
|
||||
void boss_start_attack(Boss *b, Attack *a) attr_nonnull(1, 2);
|
||||
void boss_finish_current_attack(Boss *boss) attr_nonnull(1);
|
||||
|
|
41
src/dialog.c
41
src/dialog.c
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "dialog.h"
|
||||
#include "global.h"
|
||||
#include "portrait.h"
|
||||
|
||||
void dialog_init(Dialog *d) {
|
||||
memset(d, 0, sizeof(*d));
|
||||
|
@ -222,50 +223,12 @@ static void dialog_actor_update_composite(DialogActor *a) {
|
|||
|
||||
log_debug("%s (%p) is dirty; face=%s; variant=%s", a->name, (void*)a, a->face, a->variant);
|
||||
|
||||
Sprite *spr_base, *spr_face;
|
||||
|
||||
size_t name_len = strlen(a->name);
|
||||
size_t face_len = strlen(a->face);
|
||||
size_t variant_len;
|
||||
bool have_variant = a->variant;
|
||||
|
||||
size_t lenfull_base = sizeof("dialog/") + name_len - 1;
|
||||
size_t lenfull_face = lenfull_base + sizeof("_face_") + face_len - 1;
|
||||
|
||||
if(have_variant) {
|
||||
variant_len = strlen(a->variant);
|
||||
lenfull_base += sizeof("_variant_") + variant_len - 1;
|
||||
}
|
||||
|
||||
char buf[imax(lenfull_base, lenfull_face) + 1];
|
||||
char *dst = buf;
|
||||
dst = memcpy(dst, "dialog/", sizeof("dialog/") - 1);
|
||||
dst = memcpy(dst + sizeof("dialog/") - 1, a->name, name_len + 1);
|
||||
|
||||
if(have_variant) {
|
||||
char *tmp = dst;
|
||||
dst = memcpy(dst + name_len, "_variant_", sizeof("_variant_") - 1);
|
||||
dst = memcpy(dst + sizeof("_variant_") - 1, a->variant, variant_len + 1);
|
||||
dst = tmp;
|
||||
}
|
||||
|
||||
spr_base = get_sprite(buf);
|
||||
log_debug("base: %s", buf);
|
||||
assume(spr_base != NULL);
|
||||
|
||||
dst = memcpy(dst + name_len, "_face_", sizeof("_face_") - 1);
|
||||
dst = memcpy(dst + sizeof("_face_") - 1, a->face, face_len + 1);
|
||||
|
||||
spr_face = get_sprite(buf);
|
||||
log_debug("face: %s", buf);
|
||||
assume(spr_face != NULL);
|
||||
|
||||
if(a->composite.tex != NULL) {
|
||||
log_debug("destroyed texture at %p", (void*)a->composite.tex);
|
||||
r_texture_destroy(a->composite.tex);
|
||||
}
|
||||
|
||||
render_character_portrait(spr_base, spr_face, &a->composite);
|
||||
portrait_render_byname(a->name, a->variant, a->face, &a->composite);
|
||||
log_debug("created texture at %p", (void*)a->composite.tex);
|
||||
a->composite_dirty = false;
|
||||
}
|
||||
|
|
|
@ -33,7 +33,11 @@
|
|||
|
||||
#define WITH_EVENTS(_name, _events) \
|
||||
typedef COEVENTS_ARRAY _events _name##DialogEvents; \
|
||||
DEFINE_TASK_INTERFACE(_name##Dialog, { _name##DialogEvents **out_events; });
|
||||
DEFINE_TASK_INTERFACE(_name##Dialog, { \
|
||||
_name##DialogEvents **out_events; \
|
||||
int called_for_preload; \
|
||||
ResourceFlags preload_rflags; \
|
||||
});
|
||||
|
||||
#define WITHOUT_EVENTS(_name) \
|
||||
WITH_EVENTS(_name, (_dummy_fake_event_))
|
||||
|
@ -59,21 +63,14 @@ typedef struct PlayerDialogTasks {
|
|||
#undef WITH_EVENTS
|
||||
#undef WITHOUT_EVENTS
|
||||
|
||||
// FIXME: might not be the best place for this
|
||||
typedef struct PlayerDialogProcs {
|
||||
void (*stage1_pre_boss)(Dialog *d);
|
||||
void (*stage1_post_boss)(Dialog *d);
|
||||
void (*stage2_pre_boss)(Dialog *d);
|
||||
void (*stage2_post_boss)(Dialog *d);
|
||||
void (*stage3_pre_boss)(Dialog *d);
|
||||
void (*stage3_post_boss)(Dialog *d);
|
||||
void (*stage4_pre_boss)(Dialog *d);
|
||||
void (*stage4_post_boss)(Dialog *d);
|
||||
void (*stage5_post_midboss)(Dialog *d);
|
||||
void (*stage5_pre_boss)(Dialog *d);
|
||||
void (*stage5_post_boss)(Dialog *d);
|
||||
void (*stage6_pre_boss)(Dialog *d);
|
||||
void (*stage6_pre_final)(Dialog *d);
|
||||
} PlayerDialogProcs;
|
||||
// FIXME: not used yet, because stage preload procs don't have reliable access to initialized player
|
||||
#define DIALOG_PRELOAD(_player, _dialog_name, _preload_rflags) do { \
|
||||
TASK_INDIRECT_TYPE(_dialog_name##Dialog) _dialog_ref = (_player)->mode->dialog->_dialog_name; \
|
||||
TASK_IFACE_ARGS_TYPE(_dialog_name##Dialog) _dialog_args = { \
|
||||
.called_for_preload = 1, \
|
||||
.preload_rflags = (_preload_rflags), \
|
||||
}; \
|
||||
_dialog_ref._cotask_##_dialog_name##Dialog##_thunk(&_dialog_args); \
|
||||
} while(0)
|
||||
|
||||
#endif // IGUARD_dialog_dialog_interface_h
|
||||
|
|
|
@ -13,8 +13,15 @@
|
|||
|
||||
#include "dialog.h"
|
||||
#include "stage.h"
|
||||
#include "portrait.h"
|
||||
|
||||
#define DIALOG_BEGIN(_interface) \
|
||||
if(ARGS.called_for_preload) { \
|
||||
if(ARGS.called_for_preload > 0) { \
|
||||
log_warn("preload was not handled"); \
|
||||
} \
|
||||
return; \
|
||||
} \
|
||||
Dialog dialog; \
|
||||
stage_begin_dialog(&dialog); \
|
||||
_interface##DialogEvents events = { 0 }; \
|
||||
|
@ -47,4 +54,18 @@
|
|||
#define DIALOG_TASK(_protag, _interface) \
|
||||
TASK_WITH_INTERFACE(_protag##_##_interface##Dialog, _interface##Dialog)
|
||||
|
||||
#define PRELOAD \
|
||||
if(ARGS.called_for_preload) ARGS.called_for_preload = -1; \
|
||||
if(ARGS.called_for_preload)
|
||||
|
||||
#define PRELOAD_CHAR(name) \
|
||||
portrait_preload_base_sprite(#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)
|
||||
|
||||
#define PRELOAD_FACE(face) \
|
||||
portrait_preload_face_sprite(_charname, #face, ARGS.preload_rflags)
|
||||
|
||||
#endif // IGUARD_dialog_dialog_macros_h
|
||||
|
|
|
@ -15,7 +15,20 @@
|
|||
*/
|
||||
|
||||
DIALOG_TASK(reimu, Stage1PreBoss) {
|
||||
// Initialization, must be at the very top.
|
||||
PRELOAD {
|
||||
PRELOAD_CHAR(reimu) {
|
||||
PRELOAD_FACE(normal);
|
||||
PRELOAD_FACE(unamused);
|
||||
PRELOAD_FACE(sigh);
|
||||
}
|
||||
|
||||
PRELOAD_CHAR(cirno) {
|
||||
PRELOAD_FACE(normal);
|
||||
PRELOAD_FACE(angry);
|
||||
}
|
||||
}
|
||||
|
||||
// Initialization, must be at the very top (after PRELOAD).
|
||||
DIALOG_BEGIN(Stage1PreBoss);
|
||||
|
||||
ACTOR_LEFT(reimu);
|
||||
|
@ -40,9 +53,9 @@ DIALOG_TASK(reimu, Stage1PreBoss) {
|
|||
// MSG() makes the actor say a line, and then waits an unspecified amount of time (skippable).
|
||||
// The timeout is determined by the dialog_util_estimate_wait_timeout_from_text() function in dialog.c
|
||||
// MSG() also implies FOCUS()
|
||||
MSG(reimu, "Unseasonable snow? I wonder if it’s that ’Secret God’ again…");
|
||||
MSG(reimu, "Unseasonable snow? I wonder if it’s that ‘Secret God’ again…");
|
||||
|
||||
MSG(cirno, "’Secret God’?");
|
||||
MSG(cirno, "‘Secret God’?");
|
||||
|
||||
// EVENT()s are handled by stage code.
|
||||
// You can find the list of events per dialogue in dialog_interface.h
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "global.h"
|
||||
#include "video.h"
|
||||
#include "util/glm.h"
|
||||
#include "portrait.h"
|
||||
|
||||
#define SELECTED_SUBSHOT(m) (((CharMenuContext*)(m)->context)->subshot)
|
||||
#define DESCRIPTION_WIDTH (SCREEN_W / 3 + 40)
|
||||
|
@ -31,25 +32,25 @@ enum {
|
|||
#define FACENAME_LEN 32
|
||||
static const char facedefs[NUM_CHARACTERS][NUM_FACES][FACENAME_LEN] = {
|
||||
[PLR_CHAR_REIMU] = {
|
||||
[F_HAPPY] = "dialog/reimu_face_happy",
|
||||
[F_NORMAL] = "dialog/reimu_face_normal",
|
||||
[F_SMUG] = "dialog/reimu_face_smug",
|
||||
[F_SURPRISED] = "dialog/reimu_face_surprised",
|
||||
[F_UNAMUSED] = "dialog/reimu_face_unamused",
|
||||
[F_HAPPY] = PORTRAIT_STATIC_FACE_SPRITE_NAME(reimu, happy),
|
||||
[F_NORMAL] = PORTRAIT_STATIC_FACE_SPRITE_NAME(reimu, normal),
|
||||
[F_SMUG] = PORTRAIT_STATIC_FACE_SPRITE_NAME(reimu, smug),
|
||||
[F_SURPRISED] = PORTRAIT_STATIC_FACE_SPRITE_NAME(reimu, surprised),
|
||||
[F_UNAMUSED] = PORTRAIT_STATIC_FACE_SPRITE_NAME(reimu, unamused),
|
||||
},
|
||||
[PLR_CHAR_MARISA] = {
|
||||
[F_HAPPY] = "dialog/marisa_face_happy",
|
||||
[F_NORMAL] = "dialog/marisa_face_normal",
|
||||
[F_SMUG] = "dialog/marisa_face_smug",
|
||||
[F_SURPRISED] = "dialog/marisa_face_surprised",
|
||||
[F_UNAMUSED] = "dialog/marisa_face_unamused",
|
||||
[F_HAPPY] = PORTRAIT_STATIC_FACE_SPRITE_NAME(marisa, happy),
|
||||
[F_NORMAL] = PORTRAIT_STATIC_FACE_SPRITE_NAME(marisa, normal),
|
||||
[F_SMUG] = PORTRAIT_STATIC_FACE_SPRITE_NAME(marisa, smug),
|
||||
[F_SURPRISED] = PORTRAIT_STATIC_FACE_SPRITE_NAME(marisa, surprised),
|
||||
[F_UNAMUSED] = PORTRAIT_STATIC_FACE_SPRITE_NAME(marisa, unamused),
|
||||
},
|
||||
[PLR_CHAR_YOUMU] = {
|
||||
[F_HAPPY] = "dialog/youmu_face_happy",
|
||||
[F_NORMAL] = "dialog/youmu_face_normal",
|
||||
[F_SMUG] = "dialog/youmu_face_smug",
|
||||
[F_SURPRISED] = "dialog/youmu_face_surprised",
|
||||
[F_UNAMUSED] = "dialog/youmu_face_unamused",
|
||||
[F_HAPPY] = PORTRAIT_STATIC_FACE_SPRITE_NAME(youmu, happy),
|
||||
[F_NORMAL] = PORTRAIT_STATIC_FACE_SPRITE_NAME(youmu, normal),
|
||||
[F_SMUG] = PORTRAIT_STATIC_FACE_SPRITE_NAME(youmu, smug),
|
||||
[F_SURPRISED] = PORTRAIT_STATIC_FACE_SPRITE_NAME(youmu, surprised),
|
||||
[F_UNAMUSED] = PORTRAIT_STATIC_FACE_SPRITE_NAME(youmu, unamused),
|
||||
},
|
||||
};
|
||||
|
||||
|
@ -173,7 +174,7 @@ void draw_char_menu(MenuData *menu) {
|
|||
assert(pchar != NULL);
|
||||
assert(pchar->id == i);
|
||||
|
||||
Sprite *spr = get_sprite(pchar->dialog_base_sprite_name);
|
||||
Sprite *spr = portrait_get_base_sprite(pchar->lower_name, NULL); // TODO cache this
|
||||
const char *name = pchar->full_name;
|
||||
const char *title = pchar->title;
|
||||
|
||||
|
@ -377,6 +378,11 @@ static void char_menu_input(MenuData *menu) {
|
|||
}
|
||||
|
||||
void preload_char_menu(void) {
|
||||
for(int i = 0; i < NUM_CHARACTERS; ++i) {
|
||||
PlayerCharacter *pchar = plrchar_get(i);
|
||||
portrait_preload_base_sprite(pchar->lower_name, NULL, RESF_PERMANENT);
|
||||
}
|
||||
|
||||
char *p = (char*)facedefs;
|
||||
|
||||
for(int i = 0; i < sizeof(facedefs) / FACENAME_LEN; ++i) {
|
||||
|
|
|
@ -292,10 +292,5 @@ void menu_preload(void) {
|
|||
"menu",
|
||||
NULL);
|
||||
|
||||
for(int i = 0; i < NUM_CHARACTERS; ++i) {
|
||||
PlayerCharacter *pchar = plrchar_get(i);
|
||||
preload_resource(RES_SPRITE, pchar->dialog_base_sprite_name, RESF_PERMANENT);
|
||||
}
|
||||
|
||||
preload_char_menu();
|
||||
}
|
||||
|
|
|
@ -82,6 +82,7 @@ taisei_src = files(
|
|||
'move.c',
|
||||
'player.c',
|
||||
'plrmodes.c',
|
||||
'portrait.c',
|
||||
'progress.c',
|
||||
'projectile.c',
|
||||
'projectile_prototypes.c',
|
||||
|
|
|
@ -70,8 +70,8 @@ void player_stage_post_init(Player *plr) {
|
|||
assert(plr->mode->character != NULL);
|
||||
assert(plr->mode->dialog != NULL);
|
||||
|
||||
plrchar_make_bomb_portrait(plr->mode->character, &plr->bomb_portrait);
|
||||
aniplayer_create(&plr->ani, get_ani(plr->mode->character->player_sprite_name), "main");
|
||||
plrchar_render_bomb_portrait(plr->mode->character, &plr->bomb_portrait);
|
||||
aniplayer_create(&plr->ani, plrchar_player_anim(plr->mode->character), "main");
|
||||
|
||||
plr->ent.draw_layer = LAYER_PLAYER;
|
||||
plr->ent.draw_func = ent_draw_player;
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
#include "player.h"
|
||||
#include "global.h"
|
||||
#include "stage.h"
|
||||
#include "portrait.h"
|
||||
|
||||
#include "plrmodes.h"
|
||||
#include "plrmodes/marisa.h"
|
||||
|
@ -32,7 +33,7 @@ static PlayerMode *player_modes[] = {
|
|||
&plrmode_youmu_b,
|
||||
};
|
||||
|
||||
PlayerCharacter* plrchar_get(CharacterID id) {
|
||||
PlayerCharacter *plrchar_get(CharacterID id) {
|
||||
assert((unsigned)id < NUM_CHARACTERS);
|
||||
PlayerCharacter *pc = player_characters[id];
|
||||
assert(pc->id == id);
|
||||
|
@ -40,27 +41,32 @@ PlayerCharacter* plrchar_get(CharacterID id) {
|
|||
}
|
||||
|
||||
void plrchar_preload(PlayerCharacter *pc) {
|
||||
preload_resource(RES_ANIM, pc->player_sprite_name, RESF_DEFAULT);
|
||||
preload_resource(RES_SPRITE, pc->dialog_base_sprite_name, RESF_DEFAULT);
|
||||
}
|
||||
const char *name = pc->lower_name;
|
||||
portrait_preload_base_sprite(name, NULL, RESF_DEFAULT);
|
||||
portrait_preload_face_sprite(name, "normal", RESF_DEFAULT);
|
||||
|
||||
void plrchar_make_bomb_portrait(PlayerCharacter *pc, Sprite *out_spr) {
|
||||
Sprite *s_base = get_sprite(pc->dialog_base_sprite_name);
|
||||
Sprite *s_face = plrchar_face_sprite(pc, "normal");
|
||||
render_character_portrait(s_base, s_face, out_spr);
|
||||
}
|
||||
|
||||
int plrchar_face_spritename(PlayerCharacter *pc, const char *face, char *buf, size_t bufsize) {
|
||||
const char *basename = pc->dialog_base_sprite_name;
|
||||
static const char face_suffix[] = "_face_normal";
|
||||
assert(bufsize >= strlen(basename) + sizeof(face_suffix) + 1);
|
||||
return snprintf(buf, bufsize, "%s%s", basename, face_suffix);
|
||||
}
|
||||
|
||||
Sprite *plrchar_face_sprite(PlayerCharacter *pc, const char *face) {
|
||||
char buf[64];
|
||||
plrchar_face_spritename(pc, face, buf, sizeof(buf));
|
||||
return get_sprite(buf);
|
||||
plrchar_player_anim_name(pc, sizeof(buf), buf);
|
||||
preload_resource(RES_ANIM, buf, RESF_DEFAULT);
|
||||
}
|
||||
|
||||
void plrchar_render_bomb_portrait(PlayerCharacter *pc, Sprite *out_spr) {
|
||||
const char *name = pc->lower_name;
|
||||
Sprite *s_base = portrait_get_base_sprite(name, NULL);
|
||||
Sprite *s_face = portrait_get_face_sprite(name, "normal");
|
||||
portrait_render(s_base, s_face, out_spr);
|
||||
}
|
||||
|
||||
int plrchar_player_anim_name(PlayerCharacter *pc, size_t bufsize, char buf[bufsize]) {
|
||||
const char *name = pc->lower_name;
|
||||
assert(bufsize >= strlen("player/") + strlen(name) + 1);
|
||||
return snprintf(buf, bufsize, "player/%s", name);
|
||||
}
|
||||
|
||||
Animation *plrchar_player_anim(PlayerCharacter *pc) {
|
||||
char buf[64];
|
||||
plrchar_player_anim_name(pc, sizeof(buf), buf);
|
||||
return get_ani(buf);
|
||||
}
|
||||
|
||||
int plrmode_repr(char *out, size_t outsize, PlayerMode *mode, bool internal) {
|
||||
|
@ -73,7 +79,7 @@ int plrmode_repr(char *out, size_t outsize, PlayerMode *mode, bool internal) {
|
|||
);
|
||||
}
|
||||
|
||||
PlayerMode* plrmode_find(CharacterID char_id, ShotModeID shot_id) {
|
||||
PlayerMode *plrmode_find(CharacterID char_id, ShotModeID shot_id) {
|
||||
for(int i = 0; i < NUM_PLAYER_MODES; ++i) {
|
||||
PlayerMode *mode = player_modes[i];
|
||||
|
||||
|
@ -85,7 +91,7 @@ PlayerMode* plrmode_find(CharacterID char_id, ShotModeID shot_id) {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
PlayerMode* plrmode_parse(const char *name) {
|
||||
PlayerMode *plrmode_parse(const char *name) {
|
||||
CharacterID char_id = (CharacterID)-1;
|
||||
ShotModeID shot_id = (ShotModeID)-1;
|
||||
char buf[strlen(name) + 1];
|
||||
|
|
|
@ -63,8 +63,6 @@ typedef struct PlayerCharacter {
|
|||
const char *proper_name;
|
||||
const char *full_name;
|
||||
const char *title;
|
||||
const char *dialog_base_sprite_name;
|
||||
const char *player_sprite_name;
|
||||
const char *menu_texture_name;
|
||||
|
||||
struct {
|
||||
|
@ -109,15 +107,15 @@ enum {
|
|||
NUM_PLAYER_MODES = NUM_CHARACTERS * NUM_SHOT_MODES_PER_CHARACTER,
|
||||
};
|
||||
|
||||
PlayerCharacter* plrchar_get(CharacterID id);
|
||||
PlayerCharacter *plrchar_get(CharacterID id);
|
||||
void plrchar_preload(PlayerCharacter *pc);
|
||||
void plrchar_make_bomb_portrait(PlayerCharacter *pc, Sprite *out_spr);
|
||||
int plrchar_face_spritename(PlayerCharacter *pc, const char *face, char *buf, size_t bufsize);
|
||||
Sprite *plrchar_face_sprite(PlayerCharacter *pc, const char *face);
|
||||
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);
|
||||
|
||||
PlayerMode* plrmode_find(CharacterID charid, ShotModeID shotid);
|
||||
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);
|
||||
PlayerMode *plrmode_parse(const char *name);
|
||||
void plrmode_preload(PlayerMode *mode);
|
||||
|
||||
double player_property(Player *plr, PlrProperty prop);
|
||||
|
|
|
@ -19,8 +19,6 @@ PlayerCharacter character_marisa = {
|
|||
.proper_name = "Marisa",
|
||||
.full_name = "Kirisame Marisa",
|
||||
.title = "Unbelievably Ordinary Magician",
|
||||
.dialog_base_sprite_name = "dialog/marisa",
|
||||
.player_sprite_name = "player/marisa",
|
||||
.menu_texture_name = "marisa_bombbg",
|
||||
.ending = {
|
||||
.good = good_ending_marisa,
|
||||
|
|
|
@ -21,8 +21,6 @@ PlayerCharacter character_reimu = {
|
|||
.proper_name = "Reimu",
|
||||
.full_name = "Hakurei Reimu",
|
||||
.title = "Shrine Maiden of Fantasy",
|
||||
.dialog_base_sprite_name = "dialog/reimu",
|
||||
.player_sprite_name = "player/reimu",
|
||||
.menu_texture_name = "reimubg",
|
||||
.ending = {
|
||||
.good = good_ending_reimu,
|
||||
|
|
|
@ -19,8 +19,6 @@ PlayerCharacter character_youmu = {
|
|||
.proper_name = "Yōmu",
|
||||
.full_name = "Konpaku Yōmu",
|
||||
.title = "Swordswoman Between Worlds",
|
||||
.dialog_base_sprite_name = "dialog/youmu",
|
||||
.player_sprite_name = "player/youmu",
|
||||
.menu_texture_name = "youmu_bombbg1",
|
||||
.ending = {
|
||||
.good = good_ending_youmu,
|
||||
|
|
121
src/portrait.c
Normal file
121
src/portrait.c
Normal file
|
@ -0,0 +1,121 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT License.
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
|
||||
*/
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "portrait.h"
|
||||
#include "renderer/api.h"
|
||||
#include "config.h"
|
||||
|
||||
#define RETURN_RESOURCE_NAME(name1, suffix, name2) \
|
||||
assert(bufsize >= strlen(PORTRAIT_PREFIX) + strlen(name1) + strlen(suffix) + strlen(name2) + 1); \
|
||||
return snprintf(buf, bufsize, PORTRAIT_PREFIX "%s" suffix "%s", name1, name2)
|
||||
|
||||
#define BUFFER_SIZE 128
|
||||
|
||||
int portrait_get_base_sprite_name(const char *charname, const char *variant, size_t bufsize, char buf[bufsize]) {
|
||||
if(variant == NULL) {
|
||||
RETURN_RESOURCE_NAME(charname, "", "");
|
||||
} else {
|
||||
RETURN_RESOURCE_NAME(charname, PORTRAIT_VARIANT_SUFFIX, variant);
|
||||
}
|
||||
}
|
||||
|
||||
Sprite *portrait_get_base_sprite(const char *charname, const char *variant) {
|
||||
char buf[BUFFER_SIZE];
|
||||
portrait_get_base_sprite_name(charname, variant, sizeof(buf), buf);
|
||||
return get_sprite(buf);
|
||||
}
|
||||
|
||||
void portrait_preload_base_sprite(const char *charname, const char *variant, ResourceFlags rflags) {
|
||||
char buf[BUFFER_SIZE];
|
||||
portrait_get_base_sprite_name(charname, variant, sizeof(buf), buf);
|
||||
preload_resource(RES_SPRITE, buf, rflags);
|
||||
}
|
||||
|
||||
int portrait_get_face_sprite_name(const char *charname, const char *face, size_t bufsize, char buf[bufsize]) {
|
||||
RETURN_RESOURCE_NAME(charname, PORTRAIT_FACE_SUFFIX, face);
|
||||
}
|
||||
|
||||
Sprite *portrait_get_face_sprite(const char *charname, const char *face) {
|
||||
char buf[BUFFER_SIZE];
|
||||
portrait_get_face_sprite_name(charname, face, sizeof(buf), buf);
|
||||
return get_sprite(buf);
|
||||
}
|
||||
|
||||
void portrait_preload_face_sprite(const char *charname, const char *face, ResourceFlags rflags) {
|
||||
char buf[BUFFER_SIZE];
|
||||
portrait_get_face_sprite_name(charname, face, sizeof(buf), buf);
|
||||
preload_resource(RES_SPRITE, buf, rflags);
|
||||
}
|
||||
|
||||
void portrait_render(Sprite *s_base, Sprite *s_face, Sprite *s_out) {
|
||||
r_state_push();
|
||||
|
||||
IntRect itc = sprite_denormalized_int_tex_coords(s_base);
|
||||
|
||||
uint tex_w = itc.w;
|
||||
uint tex_h = itc.h;
|
||||
uint spr_w = s_base->extent.w;
|
||||
uint spr_h = s_base->extent.h;
|
||||
|
||||
Texture *ptex = r_texture_create(&(TextureParams) {
|
||||
.type = TEX_TYPE_RGBA_8,
|
||||
.width = tex_w,
|
||||
.height = tex_h,
|
||||
.filter.min = TEX_FILTER_LINEAR_MIPMAP_LINEAR,
|
||||
.filter.mag = TEX_FILTER_LINEAR,
|
||||
.wrap.s = TEX_WRAP_CLAMP,
|
||||
.wrap.t = TEX_WRAP_CLAMP,
|
||||
.mipmap_mode = TEX_MIPMAP_AUTO,
|
||||
.mipmaps = 3,
|
||||
});
|
||||
|
||||
Framebuffer *fb = r_framebuffer_create();
|
||||
r_framebuffer_attach(fb, ptex, 0, FRAMEBUFFER_ATTACH_COLOR0);
|
||||
r_framebuffer_viewport(fb, 0, 0, tex_w, tex_h);
|
||||
r_framebuffer(fb);
|
||||
r_framebuffer_clear(fb, CLEAR_COLOR, RGBA(0, 0, 0, 0), 1);
|
||||
|
||||
r_mat_proj_push_ortho(spr_w, spr_h);
|
||||
r_mat_mv_push_identity();
|
||||
|
||||
SpriteParams sp = { 0 };
|
||||
sp.sprite_ptr = s_base;
|
||||
sp.blend = BLEND_NONE;
|
||||
sp.pos.x = spr_w * 0.5f - sprite_padded_offset_x(s_base);
|
||||
sp.pos.y = spr_h * 0.5f - sprite_padded_offset_y(s_base);
|
||||
sp.color = RGBA(1, 1, 1, 1);
|
||||
sp.shader_ptr = r_shader_get("sprite_default"),
|
||||
r_draw_sprite(&sp);
|
||||
sp.blend = BLEND_PREMUL_ALPHA;
|
||||
sp.sprite_ptr = s_face;
|
||||
r_draw_sprite(&sp);
|
||||
r_flush_sprites();
|
||||
|
||||
r_mat_mv_pop();
|
||||
r_mat_proj_pop();
|
||||
r_state_pop();
|
||||
r_framebuffer_destroy(fb);
|
||||
|
||||
Sprite s = { 0 };
|
||||
s.tex = ptex;
|
||||
s.extent = s_base->extent;
|
||||
s.padding = s_base->padding;
|
||||
s.tex_area.w = 1.0f;
|
||||
s.tex_area.h = 1.0f;
|
||||
*s_out = s;
|
||||
}
|
||||
|
||||
void portrait_render_byname(const char *charname, const char *variant, const char *face, Sprite *s_out) {
|
||||
portrait_render(
|
||||
portrait_get_base_sprite(charname, variant),
|
||||
portrait_get_face_sprite(charname, face),
|
||||
s_out
|
||||
);
|
||||
}
|
50
src/portrait.h
Normal file
50
src/portrait.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* This software is licensed under the terms of the MIT License.
|
||||
* See COPYING for further information.
|
||||
* ---
|
||||
* Copyright (c) 2011-2019, Lukas Weber <laochailan@web.de>.
|
||||
* Copyright (c) 2012-2019, Andrei Alexeyev <akari@taisei-project.org>.
|
||||
*/
|
||||
|
||||
#ifndef IGUARD_portrait_h
|
||||
#define IGUARD_portrait_h
|
||||
|
||||
#include "taisei.h"
|
||||
|
||||
#include "resource/sprite.h"
|
||||
|
||||
#define PORTRAIT_PREFIX "dialog/"
|
||||
#define PORTRAIT_VARIANT_SUFFIX "_variant_"
|
||||
#define PORTRAIT_FACE_SUFFIX "_face_"
|
||||
|
||||
#define PORTRAIT_STATIC_FACE_SPRITE_NAME(charname, face) \
|
||||
PORTRAIT_PREFIX #charname PORTRAIT_FACE_SUFFIX #face
|
||||
|
||||
#define PORTRAIT_STATIC_VARIANT_SPRITE_NAME(charname, face) \
|
||||
PORTRAIT_PREFIX #charname PORTRAIT_VARIANT_SUFFIX #face
|
||||
|
||||
int portrait_get_base_sprite_name(const char *charname, const char *variant, size_t bufsize, char buf[bufsize])
|
||||
attr_nonnull(1, 4);
|
||||
|
||||
Sprite *portrait_get_base_sprite(const char *charname, const char *variant)
|
||||
attr_nonnull(1) attr_returns_nonnull;
|
||||
|
||||
void portrait_preload_base_sprite(const char *charname, const char *variant, ResourceFlags rflags)
|
||||
attr_nonnull(1);
|
||||
|
||||
int portrait_get_face_sprite_name(const char *charname, const char *face, size_t bufsize, char buf[bufsize])
|
||||
attr_nonnull(1, 2, 4);
|
||||
|
||||
void portrait_preload_face_sprite(const char *charname, const char *variant, ResourceFlags rflags)
|
||||
attr_nonnull(1, 2);
|
||||
|
||||
Sprite *portrait_get_face_sprite(const char *charname, const char *face)
|
||||
attr_nonnull(1, 2) attr_returns_nonnull;
|
||||
|
||||
void portrait_render(Sprite *s_base, Sprite *s_face, Sprite *s_out)
|
||||
attr_nonnull_all;
|
||||
|
||||
void portrait_render_byname(const char *charname, const char *variant, const char *face, Sprite *s_out)
|
||||
attr_nonnull(1, 3, 4);
|
||||
|
||||
#endif // IGUARD_portrait_h
|
|
@ -18,6 +18,7 @@
|
|||
#include "resource/model.h"
|
||||
#include "util/glm.h"
|
||||
#include "common_tasks.h"
|
||||
#include "portrait.h"
|
||||
|
||||
/*
|
||||
* See the definition of AttackInfo in boss.h for information on how to set up the idmaps.
|
||||
|
@ -464,13 +465,15 @@ static void stage1_start(void) {
|
|||
}
|
||||
|
||||
static void stage1_preload(void) {
|
||||
// DIALOG_PRELOAD(&global.plr, Stage1PreBoss, RESF_DEFAULT);
|
||||
portrait_preload_base_sprite("cirno", NULL, RESF_DEFAULT);
|
||||
portrait_preload_face_sprite("cirno", "normal", RESF_DEFAULT);
|
||||
preload_resources(RES_BGM, RESF_OPTIONAL, "stage1", "stage1boss", NULL);
|
||||
preload_resources(RES_SPRITE, RESF_DEFAULT,
|
||||
"stage1/cirnobg",
|
||||
"stage1/fog",
|
||||
"stage1/snowlayer",
|
||||
"stage1/waterplants",
|
||||
"dialog/cirno",
|
||||
NULL);
|
||||
preload_resources(RES_TEXTURE, RESF_DEFAULT,
|
||||
"stage1/horizon",
|
||||
|
|
|
@ -43,7 +43,7 @@ void cirno_pfreeze_bg(Boss *c, int time) {
|
|||
|
||||
Boss *stage1_spawn_cirno(cmplx pos) {
|
||||
Boss *cirno = create_boss("Cirno", "cirno", pos);
|
||||
boss_set_portrait(cirno, get_sprite("dialog/cirno"), get_sprite("dialog/cirno_face_normal"));
|
||||
boss_set_portrait(cirno, "cirno", NULL, "normal");
|
||||
cirno->shadowcolor = *RGBA_MUL_ALPHA(0.6, 0.7, 1.0, 0.25);
|
||||
cirno->glowcolor = *RGB(0.2, 0.35, 0.5);
|
||||
return cirno;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "global.h"
|
||||
#include "stage.h"
|
||||
#include "stageutils.h"
|
||||
#include "portrait.h"
|
||||
|
||||
PRAGMA(message "Remove when this stage is modernized")
|
||||
DIAGNOSTIC(ignored "-Wdeprecated-declarations")
|
||||
|
@ -171,6 +172,8 @@ static void stage2_start(void) {
|
|||
}
|
||||
|
||||
static void stage2_preload(void) {
|
||||
portrait_preload_base_sprite("hina", NULL, RESF_DEFAULT);
|
||||
portrait_preload_face_sprite("hina", "normal", RESF_DEFAULT);
|
||||
preload_resources(RES_BGM, RESF_OPTIONAL, "stage2", "stage2boss", NULL);
|
||||
preload_resources(RES_SPRITE, RESF_DEFAULT,
|
||||
"stage2/border",
|
||||
|
@ -179,7 +182,6 @@ static void stage2_preload(void) {
|
|||
"stage2/roadstones",
|
||||
"stage2/spellbg1",
|
||||
"stage2/spellbg2",
|
||||
"dialog/hina",
|
||||
NULL);
|
||||
preload_resources(RES_SHADER_PROGRAM, RESF_DEFAULT,
|
||||
"bloom",
|
||||
|
|
|
@ -864,7 +864,7 @@ void hina_spell_bg(Boss *h, int time) {
|
|||
|
||||
Boss* stage2_spawn_hina(cmplx pos) {
|
||||
Boss *hina = create_boss("Kagiyama Hina", "hina", pos);
|
||||
boss_set_portrait(hina, get_sprite("dialog/hina"), get_sprite("dialog/hina_face_normal"));
|
||||
boss_set_portrait(hina, "hina", NULL, "normal");
|
||||
hina->glowcolor = *RGBA_MUL_ALPHA(0.7, 0.2, 0.3, 0.5);
|
||||
hina->shadowcolor = hina->glowcolor;
|
||||
return hina;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include "global.h"
|
||||
#include "stage.h"
|
||||
#include "stageutils.h"
|
||||
#include "portrait.h"
|
||||
|
||||
PRAGMA(message "Remove when this stage is modernized")
|
||||
DIAGNOSTIC(ignored "-Wdeprecated-declarations")
|
||||
|
@ -161,6 +162,10 @@ static void stage3_start(void) {
|
|||
}
|
||||
|
||||
static void stage3_preload(void) {
|
||||
portrait_preload_base_sprite("wriggle", NULL, RESF_DEFAULT);
|
||||
portrait_preload_face_sprite("wriggle", "proud", RESF_DEFAULT);
|
||||
portrait_preload_base_sprite("scuttle", NULL, RESF_DEFAULT);
|
||||
portrait_preload_face_sprite("scuttle", "normal", RESF_DEFAULT);
|
||||
preload_resources(RES_BGM, RESF_OPTIONAL, "stage3", "stage3boss", NULL);
|
||||
preload_resources(RES_SPRITE, RESF_DEFAULT,
|
||||
"stage3/border",
|
||||
|
@ -169,8 +174,6 @@ static void stage3_preload(void) {
|
|||
"stage3/wspellbg",
|
||||
"stage3/wspellclouds",
|
||||
"stage3/wspellswarm",
|
||||
"dialog/wriggle",
|
||||
"dialog/scuttle",
|
||||
NULL);
|
||||
preload_resources(RES_SHADER_PROGRAM, RESF_DEFAULT,
|
||||
"tunnel",
|
||||
|
|
|
@ -735,7 +735,7 @@ void wriggle_spellbg(Boss *b, int time) {
|
|||
|
||||
Boss* stage3_spawn_scuttle(cmplx pos) {
|
||||
Boss *scuttle = create_boss("Scuttle", "scuttle", pos);
|
||||
boss_set_portrait(scuttle, get_sprite("dialog/scuttle"), get_sprite("dialog/scuttle_face_normal"));
|
||||
boss_set_portrait(scuttle, "scuttle", NULL, "normal");
|
||||
scuttle->glowcolor = *RGB(0.5, 0.6, 0.3);
|
||||
scuttle->shadowcolor = *RGBA_MUL_ALPHA(0.7, 0.3, 0.1, 0.5);
|
||||
return scuttle;
|
||||
|
@ -1420,7 +1420,7 @@ static void stage3_boss_intro(Boss *boss, int time) {
|
|||
|
||||
Boss* stage3_spawn_wriggle_ex(cmplx pos) {
|
||||
Boss *wriggle = create_boss("Wriggle EX", "wriggleex", pos);
|
||||
boss_set_portrait(wriggle, get_sprite("dialog/wriggle"), get_sprite("dialog/wriggle_face_proud"));
|
||||
boss_set_portrait(wriggle, "wriggle", NULL, "proud");
|
||||
wriggle->glowcolor = *RGBA_MUL_ALPHA(0.2, 0.4, 0.5, 0.5);
|
||||
wriggle->shadowcolor = *RGBA_MUL_ALPHA(0.4, 0.2, 0.6, 0.5);
|
||||
return wriggle;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "stageutils.h"
|
||||
#include "util/glm.h"
|
||||
#include "resource/model.h"
|
||||
#include "portrait.h"
|
||||
|
||||
PRAGMA(message "Remove when this stage is modernized")
|
||||
DIAGNOSTIC(ignored "-Wdeprecated-declarations")
|
||||
|
@ -218,6 +219,8 @@ static void stage4_start(void) {
|
|||
}
|
||||
|
||||
static void stage4_preload(void) {
|
||||
portrait_preload_base_sprite("kurumi", NULL, RESF_DEFAULT);
|
||||
portrait_preload_face_sprite("kurumi", "normal", RESF_DEFAULT);
|
||||
preload_resources(RES_BGM, RESF_OPTIONAL, "stage4", "stage4boss", NULL);
|
||||
preload_resources(RES_SPRITE, RESF_DEFAULT,
|
||||
"stage2/border", // Stage 2 is intentional!
|
||||
|
@ -227,7 +230,6 @@ static void stage4_preload(void) {
|
|||
"stage4/mansion",
|
||||
"stage4/planks",
|
||||
"stage4/wall",
|
||||
"dialog/kurumi",
|
||||
NULL);
|
||||
preload_resources(RES_SPRITE, RESF_DEFAULT,
|
||||
"stage6/scythe", // Stage 6 is also intentional
|
||||
|
|
|
@ -554,7 +554,7 @@ static void kurumi_global_rule(Boss *b, int time) {
|
|||
|
||||
Boss* stage4_spawn_kurumi(cmplx pos) {
|
||||
Boss* b = create_boss("Kurumi", "kurumi", pos);
|
||||
boss_set_portrait(b, get_sprite("dialog/kurumi"), get_sprite("dialog/kurumi_face_normal"));
|
||||
boss_set_portrait(b, "kurumi", NULL, "normal");
|
||||
b->glowcolor = *RGB(0.5, 0.1, 0.0);
|
||||
b->global_rule = kurumi_global_rule;
|
||||
return b;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "stageutils.h"
|
||||
#include "global.h"
|
||||
#include "resource/model.h"
|
||||
#include "portrait.h"
|
||||
|
||||
PRAGMA(message "Remove when this stage is modernized")
|
||||
DIAGNOSTIC(ignored "-Wdeprecated-declarations")
|
||||
|
@ -153,9 +154,10 @@ static void stage5_start(void) {
|
|||
}
|
||||
|
||||
static void stage5_preload(void) {
|
||||
portrait_preload_base_sprite("iku", NULL, RESF_DEFAULT);
|
||||
portrait_preload_face_sprite("iku", "normal", RESF_DEFAULT);
|
||||
preload_resources(RES_BGM, RESF_OPTIONAL, "stage5", "stage5boss", NULL);
|
||||
preload_resources(RES_SPRITE, RESF_DEFAULT,
|
||||
"dialog/iku",
|
||||
"part/blast_huge_halo",
|
||||
"part/blast_huge_rays",
|
||||
"stage5/noise",
|
||||
|
|
|
@ -1269,7 +1269,7 @@ void iku_extra(Boss *b, int t) {
|
|||
|
||||
Boss* stage5_spawn_iku(cmplx pos) {
|
||||
Boss *b = create_boss("Nagae Iku", "iku", pos);
|
||||
boss_set_portrait(b, get_sprite("dialog/iku"), get_sprite("dialog/iku_face_normal"));
|
||||
boss_set_portrait(b, "iku", NULL, "normal");
|
||||
b->glowcolor = *RGBA_MUL_ALPHA(0.2, 0.4, 0.5, 0.5);
|
||||
b->shadowcolor = *RGBA_MUL_ALPHA(0.65, 0.2, 0.75, 0.5);
|
||||
return b;
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "global.h"
|
||||
#include "resource/model.h"
|
||||
#include "stagedraw.h"
|
||||
#include "portrait.h"
|
||||
|
||||
PRAGMA(message "Remove when this stage is modernized")
|
||||
DIAGNOSTIC(ignored "-Wdeprecated-declarations")
|
||||
|
@ -275,6 +276,10 @@ static void stage6_start(void) {
|
|||
}
|
||||
|
||||
static void stage6_preload(void) {
|
||||
portrait_preload_base_sprite("elly", NULL, RESF_DEFAULT);
|
||||
portrait_preload_face_sprite("elly", "normal", RESF_DEFAULT);
|
||||
portrait_preload_base_sprite("elly", "beaten", RESF_DEFAULT);
|
||||
portrait_preload_face_sprite("elly", "shouting", RESF_DEFAULT);
|
||||
preload_resources(RES_BGM, RESF_OPTIONAL,
|
||||
"stage6",
|
||||
"stage6boss_phase1",
|
||||
|
@ -286,7 +291,6 @@ static void stage6_preload(void) {
|
|||
"stage6/towerwall",
|
||||
NULL);
|
||||
preload_resources(RES_SPRITE, RESF_DEFAULT,
|
||||
"dialog/elly",
|
||||
"part/blast_huge_halo",
|
||||
"part/blast_huge_rays",
|
||||
"part/myon",
|
||||
|
|
|
@ -2636,7 +2636,7 @@ static void elly_toe_laser_logic(Laser *l, int t) {
|
|||
void elly_theory(Boss *b, int time) {
|
||||
if(time == EVENT_BIRTH) {
|
||||
global.shake_view = 10;
|
||||
boss_set_portrait(b, get_sprite("dialog/elly_variant_beaten"), get_sprite("dialog/elly_face_shouting"));
|
||||
boss_set_portrait(b, "elly", "beaten", "shouting");
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2946,7 +2946,7 @@ static void elly_global_rule(Boss *b, int time) {
|
|||
|
||||
Boss* stage6_spawn_elly(cmplx pos) {
|
||||
Boss *b = create_boss("Elly", "elly", pos);
|
||||
boss_set_portrait(b, get_sprite("dialog/elly"), get_sprite("dialog/elly_face_normal"));
|
||||
boss_set_portrait(b, "elly", NULL, "normal");
|
||||
b->global_rule = elly_global_rule;
|
||||
return b;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
|
||||
#include "taisei.h"
|
||||
|
||||
|
||||
#include "stats.h"
|
||||
|
||||
#include "global.h"
|
||||
|
|
|
@ -186,61 +186,3 @@ void draw_framebuffer_attachment(Framebuffer *fb, double width, double height, F
|
|||
void draw_framebuffer_tex(Framebuffer *fb, double width, double height) {
|
||||
draw_framebuffer_attachment(fb, width, height, FRAMEBUFFER_ATTACH_COLOR0);
|
||||
}
|
||||
|
||||
void render_character_portrait(Sprite *s_base, Sprite *s_face, Sprite *s_out) {
|
||||
r_state_push();
|
||||
|
||||
IntRect itc = sprite_denormalized_int_tex_coords(s_base);
|
||||
|
||||
uint tex_w = itc.w;
|
||||
uint tex_h = itc.h;
|
||||
uint spr_w = s_base->extent.w;
|
||||
uint spr_h = s_base->extent.h;
|
||||
|
||||
Texture *ptex = r_texture_create(&(TextureParams) {
|
||||
.type = TEX_TYPE_RGBA_8,
|
||||
.width = tex_w,
|
||||
.height = tex_h,
|
||||
.filter.min = TEX_FILTER_LINEAR_MIPMAP_LINEAR,
|
||||
.filter.mag = TEX_FILTER_LINEAR,
|
||||
.wrap.s = TEX_WRAP_CLAMP,
|
||||
.wrap.t = TEX_WRAP_CLAMP,
|
||||
.mipmap_mode = TEX_MIPMAP_AUTO,
|
||||
.mipmaps = 3,
|
||||
});
|
||||
|
||||
Framebuffer *fb = r_framebuffer_create();
|
||||
r_framebuffer_attach(fb, ptex, 0, FRAMEBUFFER_ATTACH_COLOR0);
|
||||
r_framebuffer_viewport(fb, 0, 0, tex_w, tex_h);
|
||||
r_framebuffer(fb);
|
||||
r_framebuffer_clear(fb, CLEAR_COLOR, RGBA(0, 0, 0, 0), 1);
|
||||
|
||||
r_mat_proj_push_ortho(spr_w, spr_h);
|
||||
r_mat_mv_push_identity();
|
||||
|
||||
SpriteParams sp = { 0 };
|
||||
sp.sprite_ptr = s_base;
|
||||
sp.blend = BLEND_NONE;
|
||||
sp.pos.x = spr_w * 0.5f - sprite_padded_offset_x(s_base);
|
||||
sp.pos.y = spr_h * 0.5f - sprite_padded_offset_y(s_base);
|
||||
sp.color = RGBA(1, 1, 1, 1);
|
||||
sp.shader_ptr = r_shader_get("sprite_default"),
|
||||
r_draw_sprite(&sp);
|
||||
sp.blend = BLEND_PREMUL_ALPHA;
|
||||
sp.sprite_ptr = s_face;
|
||||
r_draw_sprite(&sp);
|
||||
r_flush_sprites();
|
||||
|
||||
r_mat_mv_pop();
|
||||
r_mat_proj_pop();
|
||||
r_state_pop();
|
||||
r_framebuffer_destroy(fb);
|
||||
|
||||
Sprite s = { 0 };
|
||||
s.tex = ptex;
|
||||
s.extent = s_base->extent;
|
||||
s.padding = s_base->padding;
|
||||
s.tex_area.w = 1.0f;
|
||||
s.tex_area.h = 1.0f;
|
||||
*s_out = s;
|
||||
}
|
||||
|
|
|
@ -54,6 +54,4 @@ double draw_fraction(double value, Alignment a, double pos_x, double pos_y, Font
|
|||
void draw_framebuffer_tex(Framebuffer *fb, double width, double height);
|
||||
void draw_framebuffer_attachment(Framebuffer *fb, double width, double height, FramebufferAttachment attachment);
|
||||
|
||||
void render_character_portrait(Sprite *s_base, Sprite *s_face, Sprite *s_out);
|
||||
|
||||
#endif // IGUARD_util_graphics_h
|
||||
|
|
Loading…
Reference in a new issue