using System.Collections.Generic;
using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace SplashEdit.RuntimeCode
{
///
/// Collects all PSXCanvas hierarchies in the scene, bakes RectTransform
/// coordinates into PS1 pixel space, and produces
/// arrays ready for binary serialization.
///
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.
///
/// Target PS1 resolution (e.g. 320×240).
/// Output: collected custom font data (max 3).
/// Array of canvas data ready for binary writing.
public static PSXCanvasData[] CollectCanvases(Vector2 resolution, out PSXFontData[] fonts)
{
// Collect and deduplicate all custom fonts used by text elements
List uniqueFonts = new List();
#if UNITY_EDITOR
PSXCanvas[] canvases = Object.FindObjectsByType(FindObjectsSortMode.None);
#else
PSXCanvas[] canvases = Object.FindObjectsOfType();
#endif
if (canvases == null || canvases.Length == 0)
{
fonts = new PSXFontData[0];
return new PSXCanvasData[0];
}
// First pass: collect unique fonts
foreach (PSXCanvas canvas in canvases)
{
PSXUIText[] texts = canvas.GetComponentsInChildren(true);
foreach (PSXUIText txt in texts)
{
PSXFontAsset font = txt.GetEffectiveFont();
if (font != null && !uniqueFonts.Contains(font) && uniqueFonts.Count < 3)
uniqueFonts.Add(font);
}
}
// Build font data with VRAM positions.
// Each font gets its own texture page to avoid V-coordinate overflow.
// Font textures go at x=960:
// Font 1: y=0 (page 15,0) - 256px available
// Font 2: y=256 (page 15,1) - 208px available (system font at y=464)
// Font 3: not supported (would need different VRAM column)
// System font: (960, 464) in page (15,1), occupies y=464-511.
List fontDataList = new List();
ushort[] fontPageStarts = { 0, 256 }; // one per texture page
int fontPageIndex = 0;
foreach (PSXFontAsset fa in uniqueFonts)
{
byte[] pixelData = fa.ConvertTo4BPP();
if (pixelData == null) continue;
// Read advance widths directly from the font asset.
// These were computed during bitmap generation from the exact same
// CharacterInfo used to render the glyphs - guaranteed to match.
byte[] advances = fa.AdvanceWidths;
if (advances == null || advances.Length < 96)
{
Debug.LogWarning($"PSXUIExporter: Font '{fa.name}' has no stored advance widths. Using cell width as fallback.");
advances = new byte[96];
for (int i = 0; i < 96; i++) advances[i] = (byte)fa.GlyphWidth;
}
ushort texH = (ushort)fa.TextureHeight;
if (fontPageIndex >= fontPageStarts.Length)
{
Debug.LogError($"PSXUIExporter: Max 2 custom fonts supported (need separate texture pages). Skipping '{fa.name}'.");
continue;
}
ushort vramY = fontPageStarts[fontPageIndex];
int maxHeight = (fontPageIndex == 1) ? 208 : 256; // page 1 shares with system font
if (texH > maxHeight)
{
Debug.LogWarning($"PSXUIExporter: Font '{fa.name}' texture ({texH}px) exceeds page limit ({maxHeight}px). May be clipped.");
}
fontDataList.Add(new PSXFontData
{
Source = fa,
GlyphWidth = (byte)fa.GlyphWidth,
GlyphHeight = (byte)fa.GlyphHeight,
VramX = 960,
VramY = vramY,
TextureHeight = texH,
PixelData = pixelData,
AdvanceWidths = advances
});
fontPageIndex++;
}
fonts = fontDataList.ToArray();
// Second pass: collect canvases with font index assignment
List result = new List();
foreach (PSXCanvas canvas in canvases)
{
Canvas unityCanvas = canvas.GetComponent