From 224db2f9cc2df90b3cb615c32312de7d7b1a4ff8 Mon Sep 17 00:00:00 2001 From: kichikuou Date: Sat, 16 May 2026 12:40:05 +0900 Subject: [PATCH] Parts: Fix Z-order of 3DLayer and Movie parts 3DLayer and Movie parts use a SACT sprite as their render target (for SealEngine output or movie frames). That sprite was registered into the scene at z=0, so the content was drawn at z=0 instead of (or in addition to) the parts engine's render path at the parts' configured Z. Hide the bound SACT sprite from the scene so the parts engine is the sole renderer of its texture, and add a parts_render case for 3DLayer that composites the bound sprite's texture through parts_render_cg. --- src/parts/parts.c | 6 ++++++ src/parts/render.c | 24 +++++++++++++++++++++++- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/src/parts/parts.c b/src/parts/parts.c index 7ad11f6..dae8334 100644 --- a/src/parts/parts.c +++ b/src/parts/parts.c @@ -2185,6 +2185,9 @@ bool PE_init_parts_movie(int parts_no, int width, int height, int bg_r, int bg_g struct sact_sprite *sp = sact_create_sprite(sp_no, width, height, bg_r, bg_g, bg_b, 255); if (!sp) return false; + // The movie frames are composited by the parts engine via parts_render(), + // so hide the bound sprite from the scene to avoid double-drawing. + sprite_set_show(sp, false); struct texture *tex = sprite_get_texture(sp); movie->sprite_no = sp_no; @@ -2232,6 +2235,9 @@ bool PE_CreateParts3DLayerPluginID(int parts_no, int state) ReignEngine_ReleasePlugin(handle); return false; } + // The 3D content is composited by the parts engine via parts_render(), so + // hide the bound sprite from the scene to avoid double-drawing. + sprite_set_show(sp, false); l->plugin = handle; l->sprite_no = sp_no; diff --git a/src/parts/render.c b/src/parts/render.c index 575a546..e39944f 100644 --- a/src/parts/render.c +++ b/src/parts/render.c @@ -25,7 +25,9 @@ #include "system4/flat.h" #include "gfx/gfx.h" +#include "sact.h" #include "scene.h" +#include "sprite.h" #include "xsystem4.h" #include "parts_internal.h" @@ -329,6 +331,24 @@ static void parts_render_flat(struct parts *parts, struct parts_flat *f) f->flat->timelines, f->flat->nr_timelines, &ctx); } +static void parts_render_3dlayer(struct parts *parts, struct parts_3dlayer *l) +{ + if (l->sprite_no < 0) + return; + struct sact_sprite *sp = sact_try_get_sprite(l->sprite_no); + if (!sp) + return; + struct texture *tex = sprite_get_texture(sp); + if (!tex->handle) + return; + // The bound sprite's texture is recreated by RE_set_viewport, so + // refresh the parts_common's view of it each frame. + l->common.texture = *tex; + l->common.w = tex->w; + l->common.h = tex->h; + parts_render_cg(parts, &l->common); +} + static void parts_render_flash_shape(struct parts *parts, struct parts_flash *f, struct parts_flash_object *obj, struct swf_tag_define_shape *tag) { struct texture *src = ht_get_int(f->bitmaps, tag->fill_style.bitmap_id, NULL); @@ -449,7 +469,6 @@ void parts_render(struct parts *parts) case PARTS_UNINITIALIZED: case PARTS_RECT_DETECTION: case PARTS_LAYOUT_BOX: - case PARTS_3DLAYER: break; case PARTS_CG: case PARTS_ANIMATION: @@ -470,6 +489,9 @@ void parts_render(struct parts *parts) case PARTS_FLAT: parts_render_flat(parts, &state->flat); break; + case PARTS_3DLAYER: + parts_render_3dlayer(parts, &state->layer3d); + break; } }