diff --git a/include/sprite.h b/include/sprite.h index ea9a3f8..55633f3 100644 --- a/include/sprite.h +++ b/include/sprite.h @@ -28,9 +28,14 @@ union vm_value; struct sact_sprite { TAILQ_ENTRY(sact_sprite) entry; + // The sprite's texture (CG or solid color). Initialized lazily. struct texture texture; + // If no CG is attached to the sprite, the solid color to fill with. SDL_Color color; + // The position and dimensions of the sprite. Rectangle rect; + // Arbitrary text can be attached to the sprite. This is rendered on a + // separate texture and overlayed. struct { struct string *str; struct texture texture; @@ -39,18 +44,39 @@ struct sact_sprite { int char_space; int line_space; } text; + // The Z-layer of the sprite within the scene. int z; - bool show; + // This flag indicates that pixel data has been attached to a sprite; it + // does NOT guarantee that the texture is initialized. + bool has_pixel; + // This flag indicates whether or not the sprite is included in the + // the current scene. A sprite should be in the scene if there is pixel + // or text data attached to it and it is not hidden. + bool in_scene; + // When a sprite is hidden, it is removed from the scene. Attaching new + // pixel data does not alter the state of this flag. + bool hidden; + // The sprite handle. int no; + // The CG number attached to the sprite. int cg_no; }; extern bool sact_dirty; +void sprite_register(struct sact_sprite *sp); +void sprite_unregister(struct sact_sprite *sp); + static inline void sprite_dirty(struct sact_sprite *sp) { - if (sp && sp->show) - sact_dirty = true; + if (!sp) + return; + sact_dirty = true; + if (sp->hidden) { + sprite_unregister(sp); + } else if (sp->has_pixel || sp->text.texture.handle) { + sprite_register(sp); + } } static inline void scene_dirty(void) @@ -58,9 +84,6 @@ static inline void scene_dirty(void) sact_dirty = true; } - -void sprite_register(struct sact_sprite *sp); -void sprite_unregister(struct sact_sprite *sp); void sprite_free(struct sact_sprite *sp); void sprite_render_scene(void); void sprite_flip(void); @@ -85,7 +108,7 @@ static inline int sprite_get_pos_y(struct sact_sprite *sp) { return sp->rect.y; static inline int sprite_get_width(struct sact_sprite *sp) { return sp->rect.w; } static inline int sprite_get_height(struct sact_sprite *sp) { return sp->rect.h; } static inline int sprite_get_z(struct sact_sprite *sp) { return sp->z; } -static inline int sprite_get_show(struct sact_sprite *sp) { return sp->show; } +static inline int sprite_get_show(struct sact_sprite *sp) { return !sp->hidden; } void sprite_set_text_home(struct sact_sprite *sp, int x, int y); void sprite_set_text_line_space(struct sact_sprite *sp, int px); void sprite_set_text_char_space(struct sact_sprite *sp, int px); diff --git a/src/hll/SACT2.c b/src/hll/SACT2.c index fe490f2..b46b035 100644 --- a/src/hll/SACT2.c +++ b/src/hll/SACT2.c @@ -35,14 +35,6 @@ static struct sact_sprite **sprites = NULL; static int nr_sprites = 0; -// NOTE: Used externally by DrawGraph and SengokuRanceFont -struct sact_sprite *sact_get_sprite(int sp) -{ - if (sp < -1 || sp >= nr_sprites) - return NULL; - return sprites[sp]; -} - static struct sact_sprite *sact_alloc_sprite(int sp) { sprites[sp] = xcalloc(1, sizeof(struct sact_sprite)); @@ -71,6 +63,19 @@ static void realloc_sprite_table(int n) memset(sprites + old_nr_sprites, 0, sizeof(struct sact_sprite*) * (nr_sprites - old_nr_sprites)); } +// NOTE: Used externally by DrawGraph and SengokuRanceFont +struct sact_sprite *sact_get_sprite(int sp) +{ + if (sp < -1) + return NULL; + if (sp >= nr_sprites) + realloc_sprite_table(sp+256); + if (!sprites[sp]) { + return sact_alloc_sprite(sp); + } + return sprites[sp]; +} + int sact_Init(possibly_unused void *_, possibly_unused int cg_cache_size) { // already initialized diff --git a/src/sprite.c b/src/sprite.c index 189927c..2c0ae8d 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -39,29 +39,34 @@ TAILQ_HEAD(listhead, sact_sprite) sprite_list = void sprite_register(struct sact_sprite *sp) { + if (sp->in_scene) + return; + struct sact_sprite *p; TAILQ_FOREACH(p, &sprite_list, entry) { if (p->z > sp->z) { TAILQ_INSERT_BEFORE(p, sp, entry); + sp->in_scene = true; return; } } TAILQ_INSERT_TAIL(&sprite_list, sp, entry); - if (sp->show) - scene_dirty(); + sp->in_scene = true; + scene_dirty(); } void sprite_unregister(struct sact_sprite *sp) { + if (!sp->in_scene) + return; TAILQ_REMOVE(&sprite_list, sp, entry); - if (sp->show) - scene_dirty(); + sp->in_scene = false; + scene_dirty(); } void sprite_free(struct sact_sprite *sp) { - if (sp->show) - sprite_unregister(sp); + sprite_unregister(sp); gfx_delete_texture(&sp->texture); gfx_delete_texture(&sp->text.texture); } @@ -135,20 +140,23 @@ int sprite_set_cg(struct sact_sprite *sp, int cg_no) sp->rect.h = cg->metrics.h; sp->cg_no = cg_no; cg_free(cg); + + sp->has_pixel = true; sprite_dirty(sp); return 1; } +/* + * Attach pixel data to a sprite. The texture is initialized lazily. + */ void sprite_init(struct sact_sprite *sp, int w, int h, int r, int g, int b, int a) { sp->color = (SDL_Color) { .r = r, .g = g, .b = b, .a = (a >= 0 ? a : 255) }; sp->rect.w = w; sp->rect.h = h; - if (!sp->show) { - sp->show = true; - sprite_register(sp); - } gfx_delete_texture(&sp->texture); + + sp->has_pixel = true; sprite_dirty(sp); } @@ -181,7 +189,7 @@ void sprite_set_y(struct sact_sprite *sp, int y) void sprite_set_z(struct sact_sprite *sp, int z) { sp->z = z; - if (sp->show) { + if (sp->in_scene) { sprite_unregister(sp); sprite_register(sp); } @@ -200,14 +208,8 @@ void sprite_set_blend_rate(struct sact_sprite *sp, int rate) void sprite_set_show(struct sact_sprite *sp, bool show) { - if (show == sp->show) - return; - sp->show = show; + sp->hidden = !show; sprite_dirty(sp); - if (show) - sprite_register(sp); - else - sprite_unregister(sp); } int sprite_set_draw_method(struct sact_sprite *sp, int method)