From dd985a37691dc8d82f299da18d7b9f59e98aaf6a Mon Sep 17 00:00:00 2001 From: Nunuhara Cabbage Date: Fri, 21 May 2021 18:56:33 -0700 Subject: [PATCH] Refactor sprite/scene management code Create a separate interface for managing the scene. The sact_sprite interface is implemented on top of this, as is GoatGUIEngine (which is now independent of sact_sprite). This will allow more specialized graphics interfaces to be implemented without adding to the complexity of the sact_sprite interace. (For example, GoatGUIEngine needs to store multiple textures per sprite for button states; this is not supported by sact_sprite.) --- include/sact.h | 6 +- include/scene.h | 82 ++++++++++++++++++++++ include/sprite.h | 57 +++------------- src/effect.c | 4 +- src/hll/GoatGUIEngine.c | 94 ++++++++++++++++---------- src/hll/SACT2.c | 9 +-- src/meson.build | 1 + src/scene.c | 139 ++++++++++++++++++++++++++++++++++++++ src/sprite.c | 146 +++++----------------------------------- 9 files changed, 316 insertions(+), 222 deletions(-) create mode 100644 include/scene.h create mode 100644 src/scene.c diff --git a/include/sact.h b/include/sact.h index 7b456b0..65c50d9 100644 --- a/include/sact.h +++ b/include/sact.h @@ -25,8 +25,8 @@ struct sact_sprite *sact_try_get_sprite(int sp); struct sact_sprite *sact_create_sprite(int sp_no, int width, int height, int r, int g, int b, int a); void sact_ModuleFini(void); int sact_Init(void *_, int cg_cache_size); -#define sact_SetWP sprite_set_wp -#define sact_SetWP_Color sprite_set_wp_color +#define sact_SetWP scene_set_wp +#define sact_SetWP_Color scene_set_wp_color int sact_GetScreenWidth(void); int sact_GetScreenHeight(void); int sact_GetMainSurfaceNumber(void); @@ -35,7 +35,7 @@ int sact_Effect(int type, int time, int key); int sact_SP_GetUnuseNum(int min); int sact_SP_Count(void); int sact_SP_Enum(struct page **array); -#define sact_SP_GetMaxZ sprite_get_max_z +#define sact_SP_GetMaxZ scene_get_max_z int sact_SP_SetCG(int sp, int cg); int sact_SP_Create(int sp, int width, int height, int r, int g, int b, int a); int sact_SP_CreatePixelOnly(int sp, int width, int height); diff --git a/include/scene.h b/include/scene.h new file mode 100644 index 0000000..4e912f5 --- /dev/null +++ b/include/scene.h @@ -0,0 +1,82 @@ +/* Copyright (C) 2019 Nunuhara Cabbage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#ifndef SYSTEM4_SCENE_H +#define SYSTEM4_SCENE_H + +#include +#include "queue.h" + +struct sprite { + TAILQ_ENTRY(sprite) entry; + // The Z-layer of the sprite within the scene + int z; + // The secondary Z-layer (for GoatGUIEngine) + int z2; + // If a sprite does not have pixel data, it will not be added to the scene. + bool has_pixel; + bool has_alpha; + // When a sprite is hidden, it is removed from the scene. + bool hidden; + // 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; + // The rendering function. + void (*render)(struct sprite*); +}; + +extern bool scene_is_dirty; + +void scene_register_sprite(struct sprite *sp); +void scene_unregister_sprite(struct sprite *sp); +void scene_render(void); +void scene_flip(void); +int scene_set_wp(int cg_no); +int scene_set_wp_color(int r, int g, int b); +int scene_get_max_z(void); +void scene_set_sprite_z(struct sprite *sp, int z); +void scene_set_sprite_z2(struct sprite *sp, int z, int z2); + +static inline void scene_sprite_dirty(struct sprite *sp) +{ + if (!sp) + return; + scene_is_dirty = true; + if (sp->hidden) { + scene_unregister_sprite(sp); + } else if (sp->has_pixel) { + scene_register_sprite(sp); + } +} + +static inline void scene_dirty(void) +{ + scene_is_dirty = true; +} + +static inline void scene_set_sprite_show(struct sprite *sp, bool show) +{ + sp->hidden = !show; + scene_sprite_dirty(sp); +} + +static inline bool scene_get_sprite_show(struct sprite *sp) +{ + return !sp->hidden; +} + +#endif /* SYSTEM4_SCENE_H */ diff --git a/include/sprite.h b/include/sprite.h index f7885c8..00c9605 100644 --- a/include/sprite.h +++ b/include/sprite.h @@ -21,12 +21,14 @@ #include #include "queue.h" #include "gfx/gfx.h" +#include "scene.h" struct string; struct page; union vm_value; struct sact_sprite { + struct sprite sp; TAILQ_ENTRY(sact_sprite) entry; // The sprite's texture (CG or solid color). Initialized lazily. struct texture texture; @@ -44,79 +46,40 @@ struct sact_sprite { int char_space; int line_space; } text; - // The Z-layer of the sprite within the scene. - int z; - // The secondary Z-layer (for GoatGUIEngine) - int z2; - // This flag indicates that pixel data has been attached to a sprite; it - // does NOT guarantee that the texture is initialized. - bool has_pixel; - bool has_alpha; - // 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; - // The rendering function - void (*render)(struct sact_sprite*); }; -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) - 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) -{ - sact_dirty = true; + scene_sprite_dirty(&sp->sp); } void sprite_free(struct sact_sprite *sp); -void sprite_render_scene(void); -void sprite_flip(void); struct texture *sprite_get_texture(struct sact_sprite *sp); -int sprite_set_wp(int cg_no); -int sprite_set_wp_color(int r, int g, int b); int sprite_set_cg(struct sact_sprite *sp, int cg_no); int sprite_set_cg_from_file(struct sact_sprite *sp, const char *path); void sprite_init(struct sact_sprite *sp, int w, int h, int r, int g, int b, int a); -int sprite_get_max_z(void); void sprite_set_pos(struct sact_sprite *sp, int x, int y); void sprite_set_x(struct sact_sprite *sp, int x); void sprite_set_y(struct sact_sprite *sp, int y); -void sprite_set_z(struct sact_sprite *sp, int z); -void sprite_set_z2(struct sact_sprite *sp, int z, int z2); +static inline void sprite_set_z(struct sact_sprite *sp, int z) { scene_set_sprite_z(&sp->sp, z); } +static inline void sprite_set_z2(struct sact_sprite *sp, int z, int z2) { scene_set_sprite_z2(&sp->sp, z, z2); } int sprite_get_blend_rate(struct sact_sprite *sp); void sprite_set_blend_rate(struct sact_sprite *sp, int rate); -void sprite_set_show(struct sact_sprite *sp, bool show); +static inline void sprite_set_show(struct sact_sprite *sp, bool show) { scene_set_sprite_show(&sp->sp, show); } int sprite_set_draw_method(struct sact_sprite *sp, int method); int sprite_get_draw_method(struct sact_sprite *sp); -int sprite_exists_alpha(struct sact_sprite *sp); +static inline int sprite_exists_alpha(struct sact_sprite *sp) { return sp->sp.has_alpha; } static inline int sprite_get_pos_x(struct sact_sprite *sp) { return sp->rect.x; } 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_z2(struct sact_sprite *sp) { return sp->z2; } -static inline int sprite_get_show(struct sact_sprite *sp) { return !sp->hidden; } +static inline int sprite_get_z(struct sact_sprite *sp) { return sp->sp.z; } +static inline int sprite_get_z2(struct sact_sprite *sp) { return sp->sp.z2; } +static inline int sprite_get_show(struct sact_sprite *sp) { return !sp->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/effect.c b/src/effect.c index fdccaa6..95fb680 100644 --- a/src/effect.c +++ b/src/effect.c @@ -105,7 +105,7 @@ int sact_Effect(int type, possibly_unused int time, possibly_unused int key) // get old & new scene textures Texture old, new; gfx_copy_main_surface(&old); - sprite_render_scene(); + scene_render(); gfx_copy_main_surface(&new); effect_callback effect = effects[type]; @@ -143,7 +143,7 @@ int sact_TRANS_Begin(int type) trans.on = true; trans.type = type; gfx_copy_main_surface(&trans.old); - sprite_render_scene(); + scene_render(); gfx_copy_main_surface(&trans.new); return 1; } diff --git a/src/hll/GoatGUIEngine.c b/src/hll/GoatGUIEngine.c index 78c0e96..13d0a00 100644 --- a/src/hll/GoatGUIEngine.c +++ b/src/hll/GoatGUIEngine.c @@ -16,13 +16,15 @@ #include +#include "system4/cg.h" #include "system4/hashtable.h" #include +#include "asset_manager.h" #include "gfx/gfx.h" #include "input.h" #include "queue.h" -#include "sprite.h" +#include "scene.h" #include "xsystem4.h" #include "hll.h" @@ -71,7 +73,9 @@ struct parts_motion { }; struct parts { - struct sact_sprite sp; + struct sprite sp; + Texture texture; + unsigned cg_no; TAILQ_ENTRY(parts) parts_list_entry; int no; int sprite_deform; @@ -80,6 +84,7 @@ struct parts { int on_cursor_sound; int on_click_sound; int origin_mode; + Rectangle rect; // The actual hitbox of the sprite (accounting for origin-mode, scale, etc) Rectangle pos; struct { float x, y; } scale; @@ -87,7 +92,7 @@ struct parts { TAILQ_HEAD(, parts_motion) motion; }; -static void parts_render(struct sact_sprite *sp); +static void parts_render(struct sprite *sp); static struct hash_table *parts_table = NULL; static TAILQ_HEAD(listhead, parts) parts_list = TAILQ_HEAD_INITIALIZER(parts_list); @@ -167,7 +172,8 @@ static void parts_clear_motion(struct parts *parts) static void parts_clear(struct parts *parts) { parts_clear_motion(parts); - sprite_free(&parts->sp); + scene_unregister_sprite(&parts->sp); + gfx_delete_texture(&parts->texture); } static void parts_release(int parts_no) @@ -285,48 +291,56 @@ static void origin_mode_translate(mat4 dst, int mode, int w, int h) static void parts_recalculate_pos(struct parts *parts) { int x, y; - origin_mode_offset(parts->origin_mode, parts->sp.rect.w, parts->sp.rect.h, &x, &y); + origin_mode_offset(parts->origin_mode, parts->rect.w, parts->rect.h, &x, &y); parts->pos = (Rectangle) { - .x = parts->sp.rect.x + x, - .y = parts->sp.rect.y + y, - .w = parts->sp.rect.w, - .h = parts->sp.rect.h, + .x = parts->rect.x + x, + .y = parts->rect.y + y, + .w = parts->rect.w, + .h = parts->rect.h, }; } static void parts_set_pos(struct parts *parts, Point pos) { - sprite_set_pos(&parts->sp, pos.x, pos.y); + parts->rect.x = pos.x; + parts->rect.y = pos.y; parts_recalculate_pos(parts); + scene_sprite_dirty(&parts->sp); } static void parts_set_scale_x(struct parts *parts, float mag) { parts->scale.x = mag; parts_recalculate_pos(parts); - sprite_dirty(&parts->sp); + scene_sprite_dirty(&parts->sp); } static void parts_set_scale_y(struct parts *parts, float mag) { parts->scale.y = mag; parts_recalculate_pos(parts); - sprite_dirty(&parts->sp); + scene_sprite_dirty(&parts->sp); } static void parts_set_rotation_z(struct parts *parts, float rot) { parts->rotation.z = rot; - sprite_dirty(&parts->sp); + scene_sprite_dirty(&parts->sp); } -static void parts_render(struct sact_sprite *sp) +static void parts_set_alpha(struct parts *parts, int alpha) +{ + parts->texture.alpha_mod = max(0, min(255, alpha)); + scene_sprite_dirty(&parts->sp); +} + +static void parts_render(struct sprite *sp) { struct parts *parts = (struct parts*)sp; - if (!parts->sp.cg_no) + if (!parts->cg_no) return; - Rectangle *d = &parts->sp.rect; + Rectangle *d = &parts->rect; mat4 mw_transform = GLM_MAT4_IDENTITY_INIT; glm_translate(mw_transform, (vec3) { d->x, d->y, 0 }); // FIXME: need perspective for 3D rotate @@ -341,10 +355,10 @@ static void parts_render(struct sact_sprite *sp) struct gfx_render_job job = { .shader = NULL, // default shader - .texture = parts->sp.texture.handle, + .texture = parts->texture.handle, .world_transform = mw_transform[0], .view_transform = wv_transform[0], - .data = &parts->sp.texture, + .data = &parts->texture, }; gfx_render(&job); @@ -357,7 +371,7 @@ static void parts_update_with_motion(struct parts *parts, struct parts_motion *m parts_set_pos(parts, motion_calculate_point(motion, motion_t)); break; case PARTS_MOTION_ALPHA: - sprite_set_blend_rate(&parts->sp, motion_calculate_i(motion, motion_t)); + parts_set_alpha(parts, motion_calculate_i(motion, motion_t)); break; case PARTS_MOTION_MAG_X: parts_set_scale_x(parts, motion_calculate_f(motion, motion_t)); @@ -472,15 +486,26 @@ static void GoatGUIEngine_Update(possibly_unused int passed_time, possibly_unuse static bool GoatGUIEngine_SetPartsCG(int parts_no, int cg_no, possibly_unused int sprite_deform, possibly_unused int state) { struct parts *parts = parts_get(parts_no); - if (!sprite_set_cg(&parts->sp, cg_no)) + struct cg *cg = asset_cg_load(cg_no); + if (!cg) return false; + gfx_delete_texture(&parts->texture); + gfx_init_texture_with_cg(&parts->texture, cg); + parts->rect.w = cg->metrics.w; + parts->rect.h = cg->metrics.h; + parts->cg_no = cg_no; + parts->sp.has_pixel = true; + parts->sp.has_alpha = cg->metrics.has_alpha; + parts->sp.render = parts_render; parts_recalculate_pos(parts); + scene_sprite_dirty(&parts->sp); + cg_free(cg); return true; } static int GoatGUIEngine_GetPartsCGNumber(int parts_no, possibly_unused int state) { - return parts_get(parts_no)->sp.cg_no; + return parts_get(parts_no)->cg_no; } bool GoatGUIEngine_SetLoopCG(int PartsNumber, int CGNumber, int NumofCG, int TimePerCG, int State); @@ -548,9 +573,7 @@ static void GoatGUIEngine_ReleaseAllPartsWithoutSystem(void) static void GoatGUIEngine_SetPos(int parts_no, int x, int y) { - struct parts *parts = parts_get(parts_no); - sprite_set_pos(&parts->sp, x, y); - parts_recalculate_pos(parts); + parts_set_pos(parts_get(parts_no), (Point){ x, y }); } /* @@ -561,52 +584,49 @@ static void GoatGUIEngine_SetPos(int parts_no, int x, int y) */ static void GoatGUIEngine_SetZ(int parts_no, int z) { - sprite_set_z2(&parts_get(parts_no)->sp, 0, z+1); + scene_set_sprite_z2(&parts_get(parts_no)->sp, 0, z+1); } static void GoatGUIEngine_SetShow(int parts_no, bool show) { - struct parts *parts = parts_get(parts_no); - sprite_set_show(&parts->sp, show); + scene_set_sprite_show(&parts_get(parts_no)->sp, show); } static void GoatGUIEngine_SetAlpha(int parts_no, int alpha) { - struct parts *parts = parts_get(parts_no); - sprite_set_blend_rate(&parts->sp, alpha); + parts_set_alpha(parts_get(parts_no), alpha); } void GoatGUIEngine_SetPartsDrawFilter(int PartsNumber, int DrawFilter); static void GoatGUIEngine_SetClickable(int parts_no, bool clickable) { - struct parts *parts = parts_get(parts_no); - parts->clickable = !!clickable; + parts_get(parts_no)->clickable = !!clickable; } static int GoatGUIEngine_GetPartsX(int parts_no) { - return sprite_get_pos_x(&parts_get(parts_no)->sp); + return parts_get(parts_no)->rect.x; } static int GoatGUIEngine_GetPartsY(int parts_no) { - return sprite_get_pos_y(&parts_get(parts_no)->sp); + return parts_get(parts_no)->rect.y; } static int GoatGUIEngine_GetPartsZ(int parts_no) { - return sprite_get_z2(&parts_get(parts_no)->sp) - 1; + return parts_get(parts_no)->sp.z2 - 1; } static bool GoatGUIEngine_GetPartsShow(int parts_no) { - return sprite_get_show(&parts_get(parts_no)->sp); + return scene_get_sprite_show(&parts_get(parts_no)->sp); } static int GoatGUIEngine_GetPartsAlpha(int parts_no) { - return sprite_get_blend_rate(&parts_get(parts_no)->sp); + return parts_get(parts_no)->texture.alpha_mod; } static bool GoatGUIEngine_GetPartsClickable(int parts_no) @@ -619,7 +639,7 @@ static void GoatGUIEngine_SetPartsOriginPosMode(int parts_no, int origin_pos_mod struct parts *parts = parts_get(parts_no); parts->origin_mode = origin_pos_mode; parts_recalculate_pos(parts); - sprite_dirty(&parts->sp); + scene_sprite_dirty(&parts->sp); } static int GoatGUIEngine_GetPartsOriginPosMode(int parts_no) diff --git a/src/hll/SACT2.c b/src/hll/SACT2.c index ab4f911..dabddb9 100644 --- a/src/hll/SACT2.c +++ b/src/hll/SACT2.c @@ -29,6 +29,7 @@ #include "queue.h" #include "gfx/gfx.h" #include "sact.h" +#include "scene.h" #include "vm/page.h" #include "dungeon/dungeon.h" #include "xsystem4.h" @@ -135,9 +136,9 @@ int sact_Update(void) { handle_events(); dungeon_update(); - if (sact_dirty) { - sprite_render_scene(); - sprite_flip(); + if (scene_is_dirty) { + scene_render(); + scene_flip(); } return 1; } @@ -577,7 +578,7 @@ int sact_SP_GetAMapValue(int sp_no, int x, int y) if (!sp) return -1; if (x < 0 || x >= sp->rect.w || y < 0 || y >= sp->rect.h) return -1; - if (!sp->has_alpha) + if (!sp->sp.has_alpha) return -1; return sprite_get_amap_value(sp, x, y); } diff --git a/src/meson.build b/src/meson.build index 8bb94ba..1d8ebf5 100644 --- a/src/meson.build +++ b/src/meson.build @@ -12,6 +12,7 @@ xsystem4 = ['audio.c', 'page.c', 'resume.c', 'savedata.c', + 'scene.c', 'sprite.c', 'system4.c', 'text.c', diff --git a/src/scene.c b/src/scene.c new file mode 100644 index 0000000..50c3817 --- /dev/null +++ b/src/scene.c @@ -0,0 +1,139 @@ +/* Copyright (C) 2019 Nunuhara Cabbage + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + */ + +#include +#include + +#include "system4.h" +#include "system4/cg.h" + +#include "asset_manager.h" +#include "gfx/gfx.h" +#include "queue.h" +#include "scene.h" + +bool scene_is_dirty = true; + +static TAILQ_HEAD(listhead, sprite) sprite_list = TAILQ_HEAD_INITIALIZER(sprite_list); + +static Texture wp = {0}; + +void scene_register_sprite(struct sprite *sp) +{ + if (sp->in_scene) + return; + + struct sprite *p; + TAILQ_FOREACH(p, &sprite_list, entry) { + if (p->z == sp->z) { + if (p->z2 > sp->z2) { + TAILQ_INSERT_BEFORE(p, sp, entry); + sp->in_scene = true; + return; + } + } else if (p->z > sp->z) { + TAILQ_INSERT_BEFORE(p, sp, entry); + sp->in_scene = true; + return; + } + } + TAILQ_INSERT_TAIL(&sprite_list, sp, entry); + sp->in_scene = true; + scene_dirty(); +} + +void scene_unregister_sprite(struct sprite *sp) +{ + if (!sp->in_scene) + return; + TAILQ_REMOVE(&sprite_list, sp, entry); + sp->in_scene = false; + scene_dirty(); +} + +void scene_render(void) +{ + gfx_clear(); + if (wp.handle) { + Rectangle r = RECT(0, 0, wp.w, wp.h); + gfx_render_texture(&wp, &r); + } + + struct sprite *sp; + TAILQ_FOREACH(sp, &sprite_list, entry) { + if (sp->render) + sp->render(sp); + else + WARNING("sprite in scene without render function"); + } +} + +void scene_flip(void) +{ + gfx_swap(); + scene_is_dirty = false; +} + +int scene_set_wp(int cg_no) { + if (!cg_no) { + gfx_delete_texture(&wp); + scene_dirty(); + return 1; + } + + struct cg *cg = asset_cg_load(cg_no); + if (!cg) + return 0; + + gfx_delete_texture(&wp); + gfx_init_texture_with_cg(&wp, cg); + cg_free(cg); + scene_dirty(); + return 1; +} + +int scene_set_wp_color(int r, int g, int b) +{ + gfx_set_clear_color(r, g, b, 255); + scene_dirty(); + return 1; +} + +int scene_get_max_z(void) +{ + if (TAILQ_EMPTY(&sprite_list)) + return 0; + return TAILQ_LAST(&sprite_list, listhead)->z; +} + +void scene_set_sprite_z(struct sprite *sp, int z) +{ + sp->z = z; + if (sp->in_scene) { + scene_unregister_sprite(sp); + scene_register_sprite(sp); + } +} + +void scene_set_sprite_z2(struct sprite *sp, int z, int z2) +{ + sp->z = z; + sp->z2 = z2; + if (sp->in_scene) { + scene_unregister_sprite(sp); + scene_register_sprite(sp); + } +} diff --git a/src/sprite.c b/src/sprite.c index ed3888c..b32bc91 100644 --- a/src/sprite.c +++ b/src/sprite.c @@ -33,47 +33,12 @@ bool sact_dirty = true; -static struct sact_sprite wp; - TAILQ_HEAD(listhead, sact_sprite) sprite_list = TAILQ_HEAD_INITIALIZER(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) { - if (p->z2 > sp->z2) { - TAILQ_INSERT_BEFORE(p, sp, entry); - sp->in_scene = true; - return; - } - } else if (p->z > sp->z) { - TAILQ_INSERT_BEFORE(p, sp, entry); - sp->in_scene = true; - return; - } - } - TAILQ_INSERT_TAIL(&sprite_list, sp, entry); - sp->in_scene = true; - scene_dirty(); -} - -void sprite_unregister(struct sact_sprite *sp) -{ - if (!sp->in_scene) - return; - TAILQ_REMOVE(&sprite_list, sp, entry); - sp->in_scene = false; - scene_dirty(); -} - void sprite_free(struct sact_sprite *sp) { - sprite_unregister(sp); + scene_unregister_sprite(&sp->sp); gfx_delete_texture(&sp->texture); gfx_delete_texture(&sp->text.texture); memset(sp, 0, sizeof(struct sact_sprite)); @@ -82,38 +47,21 @@ void sprite_free(struct sact_sprite *sp) static void sprite_init_texture(struct sact_sprite *sp) { if (!sp->texture.handle) { - if (sp->has_alpha) + if (sp->sp.has_alpha) gfx_init_texture_rgba(&sp->texture, sp->rect.w, sp->rect.h, sp->color); else gfx_init_texture_rgb(&sp->texture, sp->rect.w, sp->rect.h, sp->color); } } -void sprite_render_scene(void) +static void sprite_render(struct sprite *_sp) { - gfx_clear(); - if (wp.texture.handle) { - Rectangle r = RECT(0, 0, wp.texture.w, wp.texture.h); - gfx_render_texture(&wp.texture, &r); + struct sact_sprite *sp = (struct sact_sprite*)_sp; + sprite_init_texture(sp); + gfx_render_texture(&sp->texture, &sp->rect); + if (sp->text.texture.handle) { + gfx_render_texture(&sp->text.texture, &sp->rect); } - struct sact_sprite *p; - TAILQ_FOREACH(p, &sprite_list, entry) { - if (p->render) { - p->render(p); - } else { - sprite_init_texture(p); - gfx_render_texture(&p->texture, &p->rect); - if (p->text.texture.handle) { - gfx_render_texture(&p->text.texture, &p->rect); - } - } - } -} - -void sprite_flip(void) -{ - gfx_swap(); - sact_dirty = false; } struct texture *sprite_get_texture(struct sact_sprite *sp) @@ -122,32 +70,6 @@ struct texture *sprite_get_texture(struct sact_sprite *sp) return &sp->texture; } -int sprite_set_wp(int cg_no) -{ - if (!cg_no) { - gfx_delete_texture(&wp.texture); - return 1; - } - - struct cg *cg = asset_cg_load(cg_no); - if (!cg) - return 0; - - gfx_delete_texture(&wp.texture); - gfx_init_texture_with_cg(&wp.texture, cg); - cg_free(cg); - scene_dirty(); - return 1; -} - -int sprite_set_wp_color(int r, int g, int b) -{ - gfx_set_clear_color(r, g, b, 255); - scene_dirty(); - return 1; -} - - int sprite_set_cg(struct sact_sprite *sp, int cg_no) { struct cg *cg = asset_cg_load(cg_no); @@ -158,8 +80,9 @@ int sprite_set_cg(struct sact_sprite *sp, int cg_no) sp->rect.w = cg->metrics.w; sp->rect.h = cg->metrics.h; sp->cg_no = cg_no; - sp->has_pixel = true; - sp->has_alpha = cg->metrics.has_alpha; + sp->sp.has_pixel = true; + sp->sp.has_alpha = cg->metrics.has_alpha; + sp->sp.render = sprite_render; sprite_dirty(sp); cg_free(cg); return 1; @@ -174,8 +97,9 @@ int sprite_set_cg_from_file(struct sact_sprite *sp, const char *path) gfx_init_texture_with_cg(&sp->texture, cg); sp->rect.w = cg->metrics.w; sp->rect.h = cg->metrics.h; - sp->has_pixel = true; - sp->has_alpha = cg->metrics.has_alpha; + sp->sp.has_pixel = true; + sp->sp.has_alpha = cg->metrics.has_alpha; + sp->sp.render = sprite_render; sprite_dirty(sp); cg_free(cg); return 1; @@ -191,18 +115,12 @@ void sprite_init(struct sact_sprite *sp, int w, int h, int r, int g, int b, int sp->rect.h = h; gfx_delete_texture(&sp->texture); - sp->has_pixel = true; - sp->has_alpha = a >= 0; + sp->sp.has_pixel = true; + sp->sp.has_alpha = a >= 0; + sp->sp.render = sprite_render; sprite_dirty(sp); } -int sprite_get_max_z(void) -{ - if (TAILQ_EMPTY(&sprite_list)) - return 0; - return TAILQ_LAST(&sprite_list, listhead)->z; -} - void sprite_set_pos(struct sact_sprite *sp, int x, int y) { sp->rect.x = x; @@ -222,25 +140,6 @@ void sprite_set_y(struct sact_sprite *sp, int y) sprite_dirty(sp); } -void sprite_set_z(struct sact_sprite *sp, int z) -{ - sp->z = z; - if (sp->in_scene) { - sprite_unregister(sp); - sprite_register(sp); - } -} - -void sprite_set_z2(struct sact_sprite *sp, int z, int z2) -{ - sp->z = z; - sp->z2 = z2; - if (sp->in_scene) { - sprite_unregister(sp); - sprite_register(sp); - } -} - int sprite_get_blend_rate(struct sact_sprite *sp) { return sprite_get_texture(sp)->alpha_mod; @@ -252,12 +151,6 @@ void sprite_set_blend_rate(struct sact_sprite *sp, int rate) sprite_dirty(sp); } -void sprite_set_show(struct sact_sprite *sp, bool show) -{ - sp->hidden = !show; - sprite_dirty(sp); -} - int sprite_set_draw_method(struct sact_sprite *sp, int method) { if (method < 0 || method >= NR_DRAW_METHODS) { @@ -274,11 +167,6 @@ int sprite_get_draw_method(struct sact_sprite *sp) return sprite_get_texture(sp)->draw_method; } -int sprite_exists_alpha(struct sact_sprite *sp) -{ - return sp->has_alpha; -} - void sprite_set_text_home(struct sact_sprite *sp, int x, int y) { sp->text.home = (Point) { .x = x, .y = y };