Coroutinize ReimuB (#205)

This commit is contained in:
Andrei Alexeyev 2020-03-25 08:52:18 +02:00 committed by GitHub
parent b56f3eeb54
commit b6a6496c39
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 678 additions and 518 deletions

View file

@ -34,6 +34,8 @@ typedef enum DrawLayer {
// NOTE: you can bit-or a drawlayer_low_t value with one of the LAYER_x constants
// for sub-layer ordering.
typedef struct CustomEntity CustomEntity;
#define ENT_TYPES \
ENT_TYPE(Projectile, ENT_PROJECTILE) \
ENT_TYPE(Laser, ENT_LASER) \
@ -41,6 +43,7 @@ typedef enum DrawLayer {
ENT_TYPE(Boss, ENT_BOSS) \
ENT_TYPE(Player, ENT_PLAYER) \
ENT_TYPE(Item, ENT_ITEM) \
ENT_TYPE(CustomEntity, ENT_CUSTOM) \
typedef enum EntityType {
_ENT_TYPE_ENUM_BEGIN,
@ -111,7 +114,11 @@ struct EntityInterface {
ENTITY_INTERFACE_BASE(EntityInterface);
};
INLINE const char* ent_type_name(EntityType type) {
struct CustomEntity {
ENTITY_INTERFACE(CustomEntity);
};
INLINE const char *ent_type_name(EntityType type) {
switch(type) {
#define ENT_TYPE(typename, id) case id: return #id;
ENT_TYPES
@ -123,7 +130,7 @@ INLINE const char* ent_type_name(EntityType type) {
#define ENT_TYPE_ID(typename) (_ENT_TYPEID_##typename)
#ifdef USE_GNU_EXTENSIONS
#define ENT_CAST(ent, typename) (__extension__ ({ \
#define _internal_ENT_CAST(ent, typename, ent_type_id) (__extension__ ({ \
__auto_type _ent = ent; \
static_assert(__builtin_types_compatible_p(EntityInterface, __typeof__(*(_ent))), \
"Expression is not an EntityInterface pointer"); \
@ -131,15 +138,18 @@ INLINE const char* ent_type_name(EntityType type) {
#typename " doesn't implement EntityInterface"); \
static_assert(__builtin_offsetof(typename, entity_interface) == 0, \
"entity_interface has non-zero offset in " #typename); \
IF_DEBUG(if(_ent->type != _ENT_TYPEID_##typename) { \
IF_DEBUG(if(_ent->type != ent_type_id) { \
log_fatal("Invalid entity cast from %s to " #typename, ent_type_name(_ent->type)); \
}); \
CASTPTR_ASSUME_ALIGNED(_ent, typename); \
}))
#else
#define ENT_CAST(ent, typename) CASTPTR_ASSUME_ALIGNED(ent, typename)
#define _internal_ENT_CAST(ent, typename, ent_type_id) CASTPTR_ASSUME_ALIGNED(ent, typename)
#endif
#define ENT_CAST(ent, typename) _internal_ENT_CAST(ent, typename, ENT_TYPE_ID(typename))
#define ENT_CAST_CUSTOM(ent, typename) _internal_ENT_CAST(ent, typename, _ENT_TYPEID_CustomEntity)
void ent_init(void);
void ent_shutdown(void);
void ent_register(EntityInterface *ent, EntityType type) attr_nonnull(1);

View file

@ -55,8 +55,6 @@ void player_stage_post_init(Player *plr) {
assert(plr->mode != NULL);
// ensure the essential callbacks are there. other code tests only for the optional ones
assert(plr->mode->procs.shot != NULL);
assert(plr->mode->procs.bomb != NULL);
assert(plr->mode->procs.property != NULL);
assert(plr->mode->character != NULL);
assert(plr->mode->dialog != NULL);
@ -626,7 +624,9 @@ DEFINE_TASK(player_logic) {
if(player_should_shoot(plr, false)) {
coevent_signal(&plr->events.shoot);
plr->mode->procs.shot(plr);
if(plr->mode->procs.shot) {
plr->mode->procs.shot(plr);
}
}
if(global.frames == plr->deathtime) {
@ -655,7 +655,12 @@ static bool player_bomb(Player *plr) {
// player_cancel_powersurge(plr);
// stage_clear_hazards(CLEAR_HAZARDS_ALL);
plr->mode->procs.bomb(plr);
coevent_signal(&plr->events.bomb_used);
if(plr->mode->procs.bomb) {
plr->mode->procs.bomb(plr);
}
plr->bombs--;
if(plr->deathtime >= global.frames) {

View file

@ -118,7 +118,8 @@ struct Player {
COEVENTS_ARRAY(
shoot,
inputflags_changed,
power_changed
power_changed,
bomb_used
) events;
uint64_t points;

View file

@ -52,8 +52,17 @@ double reimu_common_property(Player *plr, PlrProperty prop) {
UNREACHABLE;
}
Projectile *reimu_common_ofuda_swawn_trail(Projectile *p, ProjectileList *dest) {
return PARTICLE(
TASK(reimu_ofuda_trail, { BoxedProjectile trail; }) {
Projectile *trail = TASK_BIND(ARGS.trail);
for(;;) {
trail->color.g *= 0.95;
YIELD;
}
}
Projectile *reimu_common_ofuda_swawn_trail(Projectile *p) {
Projectile *trail = PARTICLE(
// .sprite_ptr = p->sprite,
.sprite_ptr = get_sprite("proj/hghost"),
.color = &p->color,
@ -63,8 +72,11 @@ Projectile *reimu_common_ofuda_swawn_trail(Projectile *p, ProjectileList *dest)
.draw_rule = pdraw_timeout_scalefade(1, 2, 1, 0),
.layer = LAYER_PARTICLE_LOW,
.flags = PFLAG_NOREFLECT,
.dest = dest,
);
// TODO maybe replace this with something better looking and less task-hungry
INVOKE_TASK(reimu_ofuda_trail, ENT_BOX(trail));
return trail;
}
void reimu_common_draw_yinyang(Enemy *e, int t, const Color *c) {
@ -117,3 +129,22 @@ void reimu_common_bomb_buffer_init(void) {
cfg.tex_params.wrap.t = TEX_WRAP_MIRROR;
bomb_buffer = stage_add_background_framebuffer("Reimu bomb FB", 0.25, 1, 1, &cfg);
}
DEFINE_EXTERN_TASK(reimu_common_slave_expire) {
Enemy *e = TASK_BIND(ARGS.slave);
cotask_cancel(cotask_unbox(ARGS.slave_main_task));
cmplx pos0 = e->pos;
real retract_time = ARGS.retract_time;
e->move = (MoveParams) { 0 };
Player *plr;
for(int i = 1; i <= retract_time; ++i) {
YIELD;
plr = NOT_NULL(ENT_UNBOX(ARGS.player));
e->pos = clerp(pos0, plr->pos, i / retract_time);
}
delete_enemy(&plr->slaves, e);
}

View file

@ -20,9 +20,16 @@ extern PlayerMode plrmode_reimu_b;
double reimu_common_property(Player *plr, PlrProperty prop);
int reimu_common_ofuda(Projectile *p, int t);
Projectile *reimu_common_ofuda_swawn_trail(Projectile *p, ProjectileList *dest);
Projectile *reimu_common_ofuda_swawn_trail(Projectile *p);
void reimu_common_draw_yinyang(Enemy *e, int t, const Color *c);
void reimu_common_bomb_bg(Player *p, float alpha);
void reimu_common_bomb_buffer_init(void);
DECLARE_EXTERN_TASK(reimu_common_slave_expire, {
BoxedPlayer player;
BoxedEnemy slave;
BoxedTask slave_main_task;
int retract_time;
});
#endif // IGUARD_plrmodes_reimu_h

View file

@ -413,16 +413,7 @@ static void reimu_spirit_bomb_bg(Player *p) {
colorfill(0, 0.05 * alpha, 0.1 * alpha, alpha * 0.5);
}
TASK(reimu_spirit_ofuda_trail, { BoxedProjectile ofuda; }) {
Projectile *p = TASK_BIND_UNBOXED(reimu_common_ofuda_swawn_trail(NOT_NULL(ENT_UNBOX(ARGS.ofuda)), NULL));
for(;;) {
p->color.g *= 0.95;
YIELD;
}
}
TASK(reimu_spirit_ofuda, { cmplx pos; cmplx vel; real damage; }) {
TASK(reimu_spirit_ofuda, { cmplx pos; cmplx vel; real damage; ShaderProgram *shader; }) {
Projectile *ofuda = TASK_BIND_UNBOXED(PROJECTILE(
.proto = pp_ofuda,
.pos = ARGS.pos,
@ -430,11 +421,11 @@ TASK(reimu_spirit_ofuda, { cmplx pos; cmplx vel; real damage; }) {
.move = move_linear(ARGS.vel),
.type = PROJ_PLAYER,
.damage = ARGS.damage,
.shader = "sprite_particle",
.shader_ptr = ARGS.shader,
));
for(int t = 0;; ++t) {
INVOKE_TASK(reimu_spirit_ofuda_trail, ENT_BOX(ofuda));
reimu_common_ofuda_swawn_trail(ofuda);
YIELD;
}
}
@ -454,25 +445,9 @@ static void reimu_spirit_yinyang_unfocused_visual(Enemy *e, int t, bool render)
}
}
TASK(reimu_spirit_slave_expire, { ReimuAController *ctrl; BoxedEnemy e; BoxedTask main_task; }) {
Enemy *e = TASK_BIND(ARGS.e);
Player *plr = ARGS.ctrl->plr;
cotask_cancel(cotask_unbox(ARGS.main_task));
cmplx pos0 = e->pos;
real retract_time = ORB_RETRACT_TIME;
e->move = (MoveParams) { 0 };
for(int i = 1; i <= retract_time; ++i) {
YIELD;
e->pos = clerp(pos0, plr->pos, i / retract_time);
}
delete_enemy(&plr->slaves, e);
}
static Enemy *reimu_spirit_create_slave(ReimuAController *ctrl, EnemyVisualRule visual) {
Player *plr = ctrl->plr;
Enemy *e = create_enemy_p(
&plr->slaves,
plr->pos,
@ -480,8 +455,16 @@ static Enemy *reimu_spirit_create_slave(ReimuAController *ctrl, EnemyVisualRule
visual,
NULL, 0, 0, 0, 0
);
e->ent.draw_layer = LAYER_PLAYER_SLAVE;
INVOKE_TASK_WHEN(&ctrl->events.slaves_expired, reimu_spirit_slave_expire, ctrl, ENT_BOX(e), THIS_TASK);
INVOKE_TASK_WHEN(&ctrl->events.slaves_expired, reimu_common_slave_expire,
.player = ENT_BOX(plr),
.slave = ENT_BOX(e),
.slave_main_task = THIS_TASK,
.retract_time = ORB_RETRACT_TIME
);
return e;
}
@ -763,6 +746,7 @@ TASK(reimu_spirit_shot_forward, { ReimuAController *ctrl; }) {
ReimuAController *ctrl = ARGS.ctrl;
Player *plr = ctrl->plr;
real dir = 1;
ShaderProgram *shader = r_shader_get("sprite_particle");
for(;;) {
WAIT_EVENT_OR_DIE(&plr->events.shoot);
@ -770,7 +754,8 @@ TASK(reimu_spirit_shot_forward, { ReimuAController *ctrl; }) {
INVOKE_TASK(reimu_spirit_ofuda,
.pos = plr->pos + 10 * dir - 15.0*I,
.vel = -20*I,
.damage = SHOT_FORWARD_DMG
.damage = SHOT_FORWARD_DMG,
.shader = shader
);
dir = -dir;
WAIT(SHOT_FORWARD_DELAY);
@ -787,7 +772,6 @@ TASK(reimu_spirit_shot_volley_bullet, { Player *plr; cmplx offset; cmplx vel; re
.move = move_linear(ARGS.vel),
.type = PROJ_PLAYER,
.damage = ARGS.damage,
.shader = "sprite_particle",
.shader_ptr = ARGS.shader,
);
}
@ -807,7 +791,7 @@ TASK(reimu_spirit_shot_volley, { ReimuAController *ctrl; }) {
real spread = M_PI/32 * (1 + 0.35 * pwr);
INVOKE_SUBTASK_DELAYED(delay, reimu_spirit_shot_volley_bullet,
plr,
.plr = plr,
.offset = -I + 5,
.vel = -18 * I * cdir(spread),
.damage = damage,
@ -815,7 +799,7 @@ TASK(reimu_spirit_shot_volley, { ReimuAController *ctrl; }) {
);
INVOKE_SUBTASK_DELAYED(delay, reimu_spirit_shot_volley_bullet,
plr,
.plr = plr,
.offset = -I - 5,
.vel = -18 * I * cdir(-spread),
.damage = damage,

File diff suppressed because it is too large Load diff

View file

@ -60,6 +60,8 @@ static struct {
ManagedFramebufferGroup *mfb_group;
StageDrawEvents events;
#ifdef DEBUG
Sprite dummy;
#endif
@ -340,9 +342,12 @@ void stage_draw_init(void) {
events_register_handler(&(EventHandler) {
stage_draw_event, NULL, EPRIO_SYSTEM,
});
COEVENT_INIT_ARRAY(stagedraw.events);
}
void stage_draw_shutdown(void) {
COEVENT_CANCEL_ARRAY(stagedraw.events);
events_unregister_handler(stage_draw_event);
stage_draw_destroy_framebuffers();
}
@ -997,6 +1002,8 @@ void stage_draw_scene(StageInfo *stage) {
draw_framebuffer_tex(background->front, VIEWPORT_W, VIEWPORT_H);
r_state_pop();
coevent_signal(&stagedraw.events.background_drawn);
// draw bomb background
// FIXME: we need a more flexible and consistent way for entities to hook
// into the various stages of scene drawing code.
@ -1811,3 +1818,7 @@ void stage_display_clear_screen(const StageClearBonus *bonus) {
stagedraw.clear_screen.target_alpha = 1;
}
StageDrawEvents *stage_get_draw_events(void) {
return &stagedraw.events;
}

View file

@ -22,21 +22,29 @@ typedef enum StageFBPair {
NUM_FBPAIRS,
} StageFBPair;
typedef COEVENTS_ARRAY(
background_drawn
) StageDrawEvents;
void stage_draw_pre_init(void);
void stage_draw_init(void);
void stage_draw_shutdown(void);
StageDrawEvents *stage_get_draw_events(void);
void stage_draw_hud(void);
void stage_draw_viewport(void);
void stage_draw_overlay(void);
void stage_draw_scene(StageInfo *stage);
void stage_draw_bottom_text(void);
bool stage_should_draw_particle(Projectile *p);
void stage_display_clear_screen(const StageClearBonus *bonus);
void stage_draw_begin_noshake(void);
void stage_draw_end_noshake(void);
bool stage_should_draw_particle(Projectile *p);
void stage_display_clear_screen(const StageClearBonus *bonus);
FBPair *stage_get_fbpair(StageFBPair id) attr_returns_nonnull;
Framebuffer *stage_add_foreground_framebuffer(const char *label, float scale_worst, float scale_best, uint num_attachments, FBAttachmentConfig attachments[num_attachments]);
Framebuffer *stage_add_background_framebuffer(const char *label, float scale_worst, float scale_best, uint num_attachments, FBAttachmentConfig attachments[num_attachments]);

View file

@ -113,6 +113,13 @@ cmplx cclampabs(cmplx c, double maxabs) {
return c;
}
cmplx cwclamp(cmplx c, cmplx cmin, cmplx cmax) {
return CMPLX(
clamp(creal(c), creal(cmin), creal(cmax)),
clamp(cimag(c), cimag(cmin), cimag(cmax))
);
}
cmplx cdir(double angle) {
// this is faster than cexp(I*angle)
@ -133,6 +140,10 @@ cmplx32 cwmulf(cmplx32 c0, cmplx32 c1) {
return CMPLXF(crealf(c0)*crealf(c1), cimagf(c0)*cimagf(c1));
}
cmplx cswap(cmplx c) {
return CMPLX(cimag(c), creal(c));
}
double psin(double x) {
return 0.5 + 0.5 * sin(x);
}

View file

@ -42,9 +42,11 @@ float fapproach_asymptotic_p(float *val, float target, float rate, float epsilon
cmplx capproach_asymptotic_p(cmplx *val, cmplx target, double rate, double epsilon);
cmplx cnormalize(cmplx c) attr_const;
cmplx cclampabs(cmplx c, double maxabs) attr_const;
cmplx cwclamp(cmplx c, cmplx cmin, cmplx cmax) attr_const;
cmplx cdir(double angle) attr_const;
cmplx cwmul(cmplx c0, cmplx c1) attr_const;
cmplx32 cwmulf(cmplx32 c0, cmplx32 c1) attr_const;
cmplx cswap(cmplx c) attr_const;
double psin(double) attr_const;
double pcos(double) attr_const;
float psinf(float) attr_const;