From a8aa674a9c45502c7cd2bb5f71c30d0b3b0b4971 Mon Sep 17 00:00:00 2001 From: Jan Racek Date: Thu, 26 Mar 2026 17:27:10 +0100 Subject: [PATCH] Fixed up textures in UI --- Runtime/PSXUIExporter.cs | 7 +++++-- Runtime/TexturePacker.cs | 24 ++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/Runtime/PSXUIExporter.cs b/Runtime/PSXUIExporter.cs index d31f53b..d4e2de8 100644 --- a/Runtime/PSXUIExporter.cs +++ b/Runtime/PSXUIExporter.cs @@ -13,7 +13,7 @@ namespace SplashEdit.RuntimeCode /// public static class PSXUIExporter { - /// + /// /// Collect all PSXCanvas components and their child UI elements, /// converting RectTransform coordinates to PS1 pixel space. /// Also collects and deduplicates custom fonts. @@ -242,6 +242,8 @@ namespace SplashEdit.RuntimeCode if (img.PackedTexture != null) { PSXTexture2D tex = img.PackedTexture; + // Convert PackingX from VRAM halfwords to texture-pixel U coords. + // 4bpp: 4 pixels per halfword, 8bpp: 2, 16bpp: 1 int expander = 16 / (int)tex.BitDepth; data.TexpageX = tex.TexpageX; data.TexpageY = tex.TexpageY; @@ -249,7 +251,8 @@ namespace SplashEdit.RuntimeCode data.ClutY = (ushort)tex.ClutPackingY; data.U0 = (byte)(tex.PackingX * expander); data.V0 = (byte)tex.PackingY; - data.U1 = (byte)(tex.PackingX * expander + tex.Width * expander / ((int)tex.BitDepth / (int)PSXBPP.TEX_4BIT)); + // Width is already in source pixels = texture-pixel units + data.U1 = (byte)(tex.PackingX * expander + tex.Width); data.V1 = (byte)(tex.PackingY + tex.Height); data.BitDepthIndex = tex.BitDepth switch { diff --git a/Runtime/TexturePacker.cs b/Runtime/TexturePacker.cs index 8598193..3aeb1c4 100644 --- a/Runtime/TexturePacker.cs +++ b/Runtime/TexturePacker.cs @@ -82,6 +82,8 @@ namespace SplashEdit.RuntimeCode // List to track unique textures and their indices List uniqueTextures = new List(); Dictionary<(int, PSXBPP), int> textureToIndexMap = new Dictionary<(int, PSXBPP), int>(); + // Track duplicates so we can propagate packing data after placement + List<(PSXTexture2D duplicate, int uniqueIndex)> duplicates = new List<(PSXTexture2D, int)>(); // Group textures by bit depth (highest first). var texturesByBitDepth = allTextures @@ -112,7 +114,8 @@ namespace SplashEdit.RuntimeCode // Check if we've already processed this texture if (textureToIndexMap.TryGetValue(textureKey, out int existingIndex)) { - // This texture is a duplicate, skip packing but remember the mapping + // This texture is a duplicate, skip packing but track for later fixup + duplicates.Add((texture, existingIndex)); continue; } @@ -196,6 +199,21 @@ namespace SplashEdit.RuntimeCode AllocateCLUTs(); // Build the final VRAM pixel array from placed textures and CLUTs. BuildVram(); + + // Propagate packing coordinates to duplicate textures (e.g. UI images + // sharing the same source texture as a 3D object). Without this, the + // duplicate's PackingX/Y/TexpageX/Y/ClutPackingX/Y stay at zero. + foreach (var (dup, idx) in duplicates) + { + var unique = uniqueTextures[idx]; + dup.PackingX = unique.PackingX; + dup.PackingY = unique.PackingY; + dup.TexpageX = unique.TexpageX; + dup.TexpageY = unique.TexpageY; + dup.ClutPackingX = unique.ClutPackingX; + dup.ClutPackingY = unique.ClutPackingY; + } + return (objects, _finalizedAtlases.ToArray(), _vramPixels); } @@ -345,9 +363,11 @@ namespace SplashEdit.RuntimeCode // For non-16-bit textures, copy the color palette into VRAM. if (texture.BitDepth != PSXBPP.TEX_16BIT) { + // ClutPackingX is pre-divided by 16, multiply back for VRAM pixel position + int clutPixelX = texture.ClutPackingX * 16; for (int x = 0; x < texture.ColorPalette.Count; x++) { - _vramPixels[x + texture.ClutPackingX, texture.ClutPackingY] = texture.ColorPalette[x]; + _vramPixels[clutPixelX + x, texture.ClutPackingY] = texture.ColorPalette[x]; } } }