From 1dd10ecc45ff9b03dd81da54ef12ed09b0c61215 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sat, 3 May 2025 11:13:03 +0900 Subject: [PATCH] SACTDX/Stoat/Chipmunk: render sprites in correct order for same Z In SACT2, if two sprites have the same Z value, they are rendered in increasing order of their sprite numbers. This behavior is documented in the SDK manual. However, in later versions of the sprite engine (SACTDX, StoatSpriteEngine, ChipmunkSpriteEngine), sprites are drawn in the order they were created. This fixes an issue in Rance Quest Magnum which relies on this behavior. --- include/sact.h | 10 +++++++++- src/hll/ChipmunkSpriteEngine.c | 4 ++-- src/hll/SACT2.c | 33 ++++++++++++++++++++++++--------- src/hll/StoatSpriteEngine.c | 2 +- src/parts/parts.c | 2 +- 5 files changed, 37 insertions(+), 14 deletions(-) diff --git a/include/sact.h b/include/sact.h index 2bc8b42..a157bbf 100644 --- a/include/sact.h +++ b/include/sact.h @@ -20,11 +20,19 @@ #include #include "sprite.h" +enum sprite_engine_type { + UNINITIALIZED_SPRITE_ENGINE, + SACT2_SPRITE_ENGINE, + SACTDX_SPRITE_ENGINE, + STOAT_SPRITE_ENGINE, + CHIPMUNK_SPRITE_ENGINE, +}; + struct sact_sprite *sact_get_sprite(int sp); 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(int cg_cache_size, bool chipmunk); +int sact_init(int cg_cache_size, enum sprite_engine_type engine); #define sact_SetWP scene_set_wp #define sact_SetWP_Color scene_set_wp_color int sact_GetScreenWidth(void); diff --git a/src/hll/ChipmunkSpriteEngine.c b/src/hll/ChipmunkSpriteEngine.c index 82ede6b..29c4ad7 100644 --- a/src/hll/ChipmunkSpriteEngine.c +++ b/src/hll/ChipmunkSpriteEngine.c @@ -40,12 +40,12 @@ static void ChipmunkSpriteEngine_ModuleFini(void) static int ChipmunkSpriteEngine_Init(possibly_unused void *imain_system) { - return sact_init(16, true); + return sact_init(16, CHIPMUNK_SPRITE_ENGINE); } static int ChipmunkSpriteEngine_Init_with_size(possibly_unused void *imain_system, int cg_cache_size) { - return sact_init(cg_cache_size, true); + return sact_init(cg_cache_size, CHIPMUNK_SPRITE_ENGINE); } static int ChipmunkSpriteEngine_SP_SetCG(int sp_no, struct string *cg_name) diff --git a/src/hll/SACT2.c b/src/hll/SACT2.c index fe8ddd0..e32f1c4 100644 --- a/src/hll/SACT2.c +++ b/src/hll/SACT2.c @@ -38,16 +38,18 @@ #include "dungeon/dungeon.h" #include "xsystem4.h" +static enum sprite_engine_type engine_type = UNINITIALIZED_SPRITE_ENGINE; static struct sact_sprite **sprites = NULL; static int nr_sprites = 0; static int view_mode; static bool use_power2_texture; +static int next_z2 = 0; static struct sact_sprite *sact_alloc_sprite(int sp) { sprites[sp] = xcalloc(1, sizeof(struct sact_sprite)); sprites[sp]->no = sp; - sprites[sp]->sp.z2 = sp; + sprites[sp]->sp.z2 = engine_type == SACT2_SPRITE_ENGINE ? sp : ++next_z2; sprite_init(sprites[sp]); sprite_dirty(sprites[sp]); return sprites[sp]; @@ -95,11 +97,15 @@ struct sact_sprite *sact_try_get_sprite(int sp) return sprites[sp]; } -int sact_init(possibly_unused int cg_cache_size, bool chipmunk) +int sact_init(possibly_unused int cg_cache_size, enum sprite_engine_type engine) { - // already initialized - if (sprites) + if (engine_type != UNINITIALIZED_SPRITE_ENGINE) { + if (engine_type != engine) + VM_ERROR("sact_init() called with different engine type: %d != %d", engine_type, engine); + // already initialized return 1; + } + engine_type = engine; gfx_init(); gfx_font_init(); @@ -118,7 +124,7 @@ int sact_init(possibly_unused int cg_cache_size, bool chipmunk) sprites++; // initialize sprite renderer - if (chipmunk) + if (engine == CHIPMUNK_SPRITE_ENGINE) sprite_init_chipmunk(); else sprite_init_sact(); @@ -126,9 +132,14 @@ int sact_init(possibly_unused int cg_cache_size, bool chipmunk) return 1; } -static int sact_Init(possibly_unused void *imain_system, int cg_cache_size) +static int SACT2_Init(possibly_unused void *imain_system, int cg_cache_size) { - return sact_init(cg_cache_size, false); + return sact_init(cg_cache_size, SACT2_SPRITE_ENGINE); +} + +static int SACTDX_Init(possibly_unused void *imain_system, int cg_cache_size) +{ + return sact_init(cg_cache_size, SACTDX_SPRITE_ENGINE); } void sact_ModuleFini(void) @@ -344,6 +355,7 @@ int sact_SP_DeleteAll(void) sact_free_sprite(sprites[i]); } } + next_z2 = 0; return 1; } @@ -838,7 +850,6 @@ int SACT2_SP_GetBrightness(int sp_no) #define SACT_EXPORTS \ HLL_EXPORT(_ModuleFini, sact_ModuleFini), \ - HLL_EXPORT(Init, sact_Init), \ HLL_TODO_EXPORT(Error, SACT2_Error), \ HLL_EXPORT(SetWP, sact_SetWP), \ HLL_EXPORT(SetWP_Color, sact_SetWP_Color), \ @@ -1033,7 +1044,11 @@ void sact_DX_SetUsePower2Texture(bool use) use_power2_texture = use; } +#define SACT2_EXPORTS \ + HLL_EXPORT(Init, SACT2_Init) + #define SACTDX_EXPORTS \ + HLL_EXPORT(Init, SACTDX_Init), \ HLL_EXPORT(SetVolumeMixerMasterGroupNum, SACTDX_SetVolumeMixerMasterGroupNum), \ HLL_EXPORT(SetVolumeMixerSEGroupNum, SACTDX_SetVolumeMixerSEGroupNum), \ HLL_EXPORT(SetVolumeMixerBGMGroupNum, SACTDX_SetVolumeMixerBGMGroupNum), \ @@ -1055,5 +1070,5 @@ void sact_DX_SetUsePower2Texture(bool use) HLL_EXPORT(DX_GetUsePower2Texture, sact_DX_GetUsePower2Texture), \ HLL_EXPORT(DX_SetUsePower2Texture, sact_DX_SetUsePower2Texture) -HLL_LIBRARY(SACT2, SACT_EXPORTS); +HLL_LIBRARY(SACT2, SACT_EXPORTS, SACT2_EXPORTS); HLL_LIBRARY(SACTDX, SACT_EXPORTS, SACTDX_EXPORTS); diff --git a/src/hll/StoatSpriteEngine.c b/src/hll/StoatSpriteEngine.c index cf283ec..6fb8f85 100644 --- a/src/hll/StoatSpriteEngine.c +++ b/src/hll/StoatSpriteEngine.c @@ -313,7 +313,7 @@ static void multisprite_reset_cg(struct multisprite *sp) static int StoatSpriteEngine_Init(void *imain_system, int cg_cache_size) { - sact_init(cg_cache_size, false); + sact_init(cg_cache_size, STOAT_SPRITE_ENGINE); for (int i = 0; i < NR_SP_TYPES; i++) { sp_types[i].nr_sprites = 16; sp_types[i].sprites = xcalloc(16, sizeof(struct multisprite*)); diff --git a/src/parts/parts.c b/src/parts/parts.c index 6f9ffda..4402a07 100644 --- a/src/parts/parts.c +++ b/src/parts/parts.c @@ -913,7 +913,7 @@ bool PE_Init(void) if (parts_engine_initialized) return true; // XXX: Oyako Rankan doesn't call ChipmunkSpriteEngine.Init - sact_init(16, true); + sact_init(16, CHIPMUNK_SPRITE_ENGINE); parts_table = ht_create(1024); parts_render_init(); parts_debug_init();