Fixed UI ordering

This commit is contained in:
2026-03-28 14:35:35 +01:00
parent 132ab479c2
commit 275b4e891d

View File

@@ -164,19 +164,12 @@ namespace SplashEdit.RuntimeCode
Debug.Log($"[UIExporter] Canvas '{canvas.CanvasName}' on '{canvas.gameObject.name}' " +
$"canvasW={canvasW} canvasH={canvasH} childCount={canvas.transform.childCount}");
// Log what each collector finds
int prevCount = elements.Count;
CollectImages(canvas.transform, canvasRect, scaleX, scaleY, resolution, elements);
Debug.Log($"[UIExporter] Images: {elements.Count - prevCount}");
prevCount = elements.Count;
CollectBoxes(canvas.transform, canvasRect, scaleX, scaleY, resolution, elements);
Debug.Log($"[UIExporter] Boxes: {elements.Count - prevCount}");
prevCount = elements.Count;
CollectTexts(canvas.transform, canvasRect, scaleX, scaleY, resolution, elements, uniqueFonts);
Debug.Log($"[UIExporter] Texts: {elements.Count - prevCount}");
prevCount = elements.Count;
CollectProgressBars(canvas.transform, canvasRect, scaleX, scaleY, resolution, elements);
Debug.Log($"[UIExporter] ProgressBars: {elements.Count - prevCount}");
// Collect all UI elements in hierarchy order (depth-first, sibling index).
// GetComponentsInChildren returns top-of-hierarchy first, but the C++
// renderer draws index 0 first (back). Reverse so that top-of-hierarchy
// elements are rendered last (on top), matching Unity's visual stacking.
CollectAllElementsInHierarchyOrder(canvas.transform, canvasRect, scaleX, scaleY, resolution, elements, uniqueFonts);
elements.Reverse();
Debug.Log($"[UIExporter] TOTAL elements: {elements.Count}");
string name = canvas.CanvasName ?? "canvas";
@@ -258,6 +251,214 @@ namespace SplashEdit.RuntimeCode
// ─── Collectors ───
/// <summary>
/// Walk the hierarchy depth-first in sibling order, collecting every
/// PSX UI component into <paramref name="elements"/> so that draw order
/// matches the Unity scene tree (top-to-bottom = back-to-front).
/// </summary>
private static void CollectAllElementsInHierarchyOrder(
Transform root, RectTransform canvasRect,
float scaleX, float scaleY, Vector2 resolution,
List<PSXUIElementData> elements,
List<PSXFontAsset> uniqueFonts)
{
// GetComponentsInChildren iterates depth-first in sibling order —
// exactly the hierarchy ordering we want.
Transform[] allTransforms = root.GetComponentsInChildren<Transform>(true);
foreach (Transform t in allTransforms)
{
if (t == root) continue; // skip the canvas root itself
// Check each supported component type on this transform.
// A single GameObject should only have one PSX UI component,
// but we check all to be safe.
PSXUIImage img = t.GetComponent<PSXUIImage>();
if (img != null)
{
CollectSingleImage(img, canvasRect, scaleX, scaleY, resolution, elements);
continue;
}
PSXUIBox box = t.GetComponent<PSXUIBox>();
if (box != null)
{
CollectSingleBox(box, canvasRect, scaleX, scaleY, resolution, elements);
continue;
}
PSXUIText txt = t.GetComponent<PSXUIText>();
if (txt != null)
{
CollectSingleText(txt, canvasRect, scaleX, scaleY, resolution, elements, uniqueFonts);
continue;
}
PSXUIProgressBar bar = t.GetComponent<PSXUIProgressBar>();
if (bar != null)
{
CollectSingleProgressBar(bar, canvasRect, scaleX, scaleY, resolution, elements);
continue;
}
}
}
private static void CollectSingleImage(
PSXUIImage img, RectTransform canvasRect,
float scaleX, float scaleY, Vector2 resolution,
List<PSXUIElementData> elements)
{
RectTransform rt = img.GetComponent<RectTransform>();
if (rt == null) return;
BakeLayout(rt, canvasRect, scaleX, scaleY, resolution,
out short x, out short y, out short w, out short h,
out byte amin_x, out byte amin_y, out byte amax_x, out byte amax_y);
var data = new PSXUIElementData
{
Type = PSXUIElementType.Image,
StartVisible = img.StartVisible,
Name = TruncateName(img.ElementName),
X = x, Y = y, W = w, H = h,
AnchorMinX = amin_x, AnchorMinY = amin_y,
AnchorMaxX = amax_x, AnchorMaxY = amax_y,
ColorR = (byte)Mathf.Clamp(Mathf.RoundToInt(img.TintColor.r * 255f), 0, 255),
ColorG = (byte)Mathf.Clamp(Mathf.RoundToInt(img.TintColor.g * 255f), 0, 255),
ColorB = (byte)Mathf.Clamp(Mathf.RoundToInt(img.TintColor.b * 255f), 0, 255),
};
if (img.PackedTexture != null)
{
PSXTexture2D tex = img.PackedTexture;
int expander = 16 / (int)tex.BitDepth;
data.TexpageX = tex.TexpageX;
data.TexpageY = tex.TexpageY;
data.ClutX = (ushort)tex.ClutPackingX;
data.ClutY = (ushort)tex.ClutPackingY;
data.U0 = (byte)(tex.PackingX * expander);
data.V0 = (byte)tex.PackingY;
data.U1 = (byte)(tex.PackingX * expander + tex.Width - 1);
data.V1 = (byte)(tex.PackingY + tex.Height - 1);
data.BitDepthIndex = tex.BitDepth switch
{
PSXBPP.TEX_4BIT => 0,
PSXBPP.TEX_8BIT => 1,
PSXBPP.TEX_16BIT => 2,
_ => 2
};
Debug.Log($"[UIImage] '{img.ElementName}' src='{(tex.OriginalTexture ? tex.OriginalTexture.name : "null")}' " +
$"bpp={(int)tex.BitDepth} W={tex.Width} H={tex.Height} QW={tex.QuantizedWidth} " +
$"packXY=({tex.PackingX},{tex.PackingY}) tpage=({tex.TexpageX},{tex.TexpageY}) " +
$"clutXY=({tex.ClutPackingX},{tex.ClutPackingY}) " +
$"UV=({data.U0},{data.V0})->({data.U1},{data.V1}) expander={expander} bitIdx={data.BitDepthIndex}");
}
else
{
Debug.LogWarning($"[UIImage] '{img.ElementName}' has NULL PackedTexture!");
}
elements.Add(data);
}
private static void CollectSingleBox(
PSXUIBox box, RectTransform canvasRect,
float scaleX, float scaleY, Vector2 resolution,
List<PSXUIElementData> elements)
{
RectTransform rt = box.GetComponent<RectTransform>();
if (rt == null) return;
BakeLayout(rt, canvasRect, scaleX, scaleY, resolution,
out short x, out short y, out short w, out short h,
out byte amin_x, out byte amin_y, out byte amax_x, out byte amax_y);
elements.Add(new PSXUIElementData
{
Type = PSXUIElementType.Box,
StartVisible = box.StartVisible,
Name = TruncateName(box.ElementName),
X = x, Y = y, W = w, H = h,
AnchorMinX = amin_x, AnchorMinY = amin_y,
AnchorMaxX = amax_x, AnchorMaxY = amax_y,
ColorR = (byte)Mathf.Clamp(Mathf.RoundToInt(box.BoxColor.r * 255f), 0, 255),
ColorG = (byte)Mathf.Clamp(Mathf.RoundToInt(box.BoxColor.g * 255f), 0, 255),
ColorB = (byte)Mathf.Clamp(Mathf.RoundToInt(box.BoxColor.b * 255f), 0, 255),
});
}
private static void CollectSingleText(
PSXUIText txt, RectTransform canvasRect,
float scaleX, float scaleY, Vector2 resolution,
List<PSXUIElementData> elements,
List<PSXFontAsset> uniqueFonts)
{
RectTransform rt = txt.GetComponent<RectTransform>();
if (rt == null) return;
BakeLayout(rt, canvasRect, scaleX, scaleY, resolution,
out short x, out short y, out short w, out short h,
out byte amin_x, out byte amin_y, out byte amax_x, out byte amax_y);
string defaultText = txt.DefaultText ?? "";
if (defaultText.Length > 63) defaultText = defaultText.Substring(0, 63);
byte fontIndex = 0;
PSXFontAsset effectiveFont = txt.GetEffectiveFont();
if (effectiveFont != null && uniqueFonts != null)
{
int idx = uniqueFonts.IndexOf(effectiveFont);
if (idx >= 0) fontIndex = (byte)(idx + 1);
}
elements.Add(new PSXUIElementData
{
Type = PSXUIElementType.Text,
StartVisible = txt.StartVisible,
Name = TruncateName(txt.ElementName),
X = x, Y = y, W = w, H = h,
AnchorMinX = amin_x, AnchorMinY = amin_y,
AnchorMaxX = amax_x, AnchorMaxY = amax_y,
ColorR = (byte)Mathf.Clamp(Mathf.RoundToInt(txt.TextColor.r * 255f), 0, 255),
ColorG = (byte)Mathf.Clamp(Mathf.RoundToInt(txt.TextColor.g * 255f), 0, 255),
ColorB = (byte)Mathf.Clamp(Mathf.RoundToInt(txt.TextColor.b * 255f), 0, 255),
DefaultText = defaultText,
FontIndex = fontIndex,
});
}
private static void CollectSingleProgressBar(
PSXUIProgressBar bar, RectTransform canvasRect,
float scaleX, float scaleY, Vector2 resolution,
List<PSXUIElementData> elements)
{
RectTransform rt = bar.GetComponent<RectTransform>();
if (rt == null) return;
BakeLayout(rt, canvasRect, scaleX, scaleY, resolution,
out short x, out short y, out short w, out short h,
out byte amin_x, out byte amin_y, out byte amax_x, out byte amax_y);
elements.Add(new PSXUIElementData
{
Type = PSXUIElementType.Progress,
StartVisible = bar.StartVisible,
Name = TruncateName(bar.ElementName),
X = x, Y = y, W = w, H = h,
AnchorMinX = amin_x, AnchorMinY = amin_y,
AnchorMaxX = amax_x, AnchorMaxY = amax_y,
ColorR = (byte)Mathf.Clamp(Mathf.RoundToInt(bar.FillColor.r * 255f), 0, 255),
ColorG = (byte)Mathf.Clamp(Mathf.RoundToInt(bar.FillColor.g * 255f), 0, 255),
ColorB = (byte)Mathf.Clamp(Mathf.RoundToInt(bar.FillColor.b * 255f), 0, 255),
BgR = (byte)Mathf.Clamp(Mathf.RoundToInt(bar.BackgroundColor.r * 255f), 0, 255),
BgG = (byte)Mathf.Clamp(Mathf.RoundToInt(bar.BackgroundColor.g * 255f), 0, 255),
BgB = (byte)Mathf.Clamp(Mathf.RoundToInt(bar.BackgroundColor.b * 255f), 0, 255),
ProgressValue = (byte)bar.InitialValue,
});
}
// ─── Legacy per-type collectors (kept for reference, no longer called) ───
private static void CollectImages(
Transform root, RectTransform canvasRect,
float scaleX, float scaleY, Vector2 resolution,