ITS BROKEN

This commit is contained in:
Jan Racek
2026-03-29 16:14:30 +02:00
parent 61fbca17a7
commit 01b636f3e2
10 changed files with 114 additions and 127 deletions

View File

@@ -1,46 +1,87 @@
using UnityEngine;
using UnityEditor;
using SplashEdit.RuntimeCode;
using System.Linq;
namespace SplashEdit.EditorCode
{
// --- Scene Preview Gizmos ---
// These draw filled rectangles in the Scene view for WYSIWYG UI preview.
// A single canvas-level gizmo draws all children in hierarchy order
// so depth stacking is correct (last child in hierarchy renders on top).
public static class PSXUIGizmos
{
[DrawGizmo(GizmoType.NonSelected | GizmoType.Selected)]
static void DrawBoxGizmo(PSXUIBox box, GizmoType gizmoType)
static void DrawCanvasGizmo(PSXCanvas canvas, GizmoType gizmoType)
{
RectTransform canvasRt = canvas.GetComponent<RectTransform>();
if (canvasRt == null) return;
bool canvasSelected = (gizmoType & GizmoType.Selected) != 0;
// Canvas border
Vector3[] canvasCorners = new Vector3[4];
canvasRt.GetWorldCorners(canvasCorners);
Color border = canvasSelected ? Color.yellow : new Color(1, 1, 0, 0.3f);
Handles.DrawSolidRectangleWithOutline(canvasCorners, Color.clear, border);
// Draw all children in hierarchy order (first child = back, last child = front)
var children = canvas.GetComponentsInChildren<Transform>(true).Reverse();
foreach (var child in children)
{
if (child == canvas.transform) continue;
bool childSelected = Selection.Contains(child.gameObject);
var box = child.GetComponent<PSXUIBox>();
if (box != null) { DrawBox(box, childSelected); continue; }
var image = child.GetComponent<PSXUIImage>();
if (image != null) { DrawImage(image, childSelected); continue; }
var text = child.GetComponent<PSXUIText>();
if (text != null) { DrawText(text, childSelected); continue; }
var bar = child.GetComponent<PSXUIProgressBar>();
if (bar != null) { DrawProgressBar(bar, childSelected); continue; }
}
// Canvas label when selected
if (canvasSelected)
{
Vector2 res = PSXCanvas.PSXResolution;
Vector3 topMid = (canvasCorners[1] + canvasCorners[2]) * 0.5f;
string label = $"PSX Canvas: {canvas.CanvasName} ({res.x}x{res.y})";
GUIStyle style = new GUIStyle(EditorStyles.boldLabel);
style.normal.textColor = Color.yellow;
Handles.Label(topMid, label, style);
}
}
static void DrawBox(PSXUIBox box, bool selected)
{
RectTransform rt = box.GetComponent<RectTransform>();
if (rt == null) return;
Vector3[] corners = new Vector3[4];
rt.GetWorldCorners(corners);
Color fill = box.BoxColor;
fill.a = (gizmoType & GizmoType.Selected) != 0 ? 0.8f : 0.5f;
Color border = Color.white;
border.a = (gizmoType & GizmoType.Selected) != 0 ? 1f : 0.4f;
Handles.DrawSolidRectangleWithOutline(corners, fill, border);
fill.a = selected ? 1f : 0.9f;
Color borderColor = selected ? Color.white : new Color(1, 1, 1, 0.5f);
Handles.DrawSolidRectangleWithOutline(corners, fill, borderColor);
}
[DrawGizmo(GizmoType.NonSelected | GizmoType.Selected)]
static void DrawImageGizmo(PSXUIImage image, GizmoType gizmoType)
static void DrawImage(PSXUIImage image, bool selected)
{
RectTransform rt = image.GetComponent<RectTransform>();
if (rt == null) return;
Vector3[] corners = new Vector3[4];
rt.GetWorldCorners(corners);
bool selected = (gizmoType & GizmoType.Selected) != 0;
// Draw texture preview if available
if (image.SourceTexture != null)
{
Color tint = image.TintColor;
tint.a = selected ? 0.9f : 0.6f;
tint.a = selected ? 1f : 0.9f;
Handles.DrawSolidRectangleWithOutline(corners, tint * 0.3f, tint);
// Draw texture in GUI overlay
Handles.BeginGUI();
Vector2 min = HandleUtility.WorldToGUIPoint(corners[0]);
Vector2 max = HandleUtility.WorldToGUIPoint(corners[2]);
@@ -49,7 +90,7 @@ namespace SplashEdit.EditorCode
Mathf.Abs(max.x - min.x), Mathf.Abs(max.y - min.y));
if (screenRect.width > 2 && screenRect.height > 2)
{
GUI.color = new Color(tint.r, tint.g, tint.b, selected ? 0.9f : 0.5f);
GUI.color = new Color(tint.r, tint.g, tint.b, selected ? 1f : 0.9f);
GUI.DrawTexture(screenRect, image.SourceTexture, ScaleMode.StretchToFill);
GUI.color = Color.white;
}
@@ -57,27 +98,23 @@ namespace SplashEdit.EditorCode
}
else
{
Color fill = new Color(0.4f, 0.4f, 0.8f, selected ? 0.4f : 0.2f);
Color fill = new Color(0.4f, 0.4f, 0.8f, selected ? 0.8f : 0.6f);
Handles.DrawSolidRectangleWithOutline(corners, fill, Color.cyan);
}
}
[DrawGizmo(GizmoType.NonSelected | GizmoType.Selected)]
static void DrawTextGizmo(PSXUIText text, GizmoType gizmoType)
static void DrawText(PSXUIText text, bool selected)
{
RectTransform rt = text.GetComponent<RectTransform>();
if (rt == null) return;
Vector3[] corners = new Vector3[4];
rt.GetWorldCorners(corners);
bool selected = (gizmoType & GizmoType.Selected) != 0;
Color border = text.TextColor;
border.a = selected ? 1f : 0.5f;
Color fill = new Color(0, 0, 0, selected ? 0.3f : 0.1f);
Handles.DrawSolidRectangleWithOutline(corners, fill, border);
Color borderColor = text.TextColor;
borderColor.a = selected ? 1f : 0.7f;
Color fill = new Color(0, 0, 0, selected ? 0.6f : 0.4f);
Handles.DrawSolidRectangleWithOutline(corners, fill, borderColor);
// Pixel-perfect preview: render each glyph from the actual font bitmap
// at PS1 scale, using advance widths for proportional positioning.
string label = string.IsNullOrEmpty(text.DefaultText) ? "[empty]" : text.DefaultText;
PSXFontAsset font = text.GetEffectiveFont();
@@ -98,18 +135,14 @@ namespace SplashEdit.EditorCode
float guiH = Mathf.Abs(botRight.y - topLeft.y);
Color tintColor = text.TextColor;
tintColor.a = selected ? 1f : 0.7f;
tintColor.a = selected ? 1f : 0.8f;
// If we have a font bitmap, render pixel-perfect from the texture
if (font != null && font.FontTexture != null && font.SourceFont != null)
{
Texture2D fontTex = font.FontTexture;
int glyphsPerRow = font.GlyphsPerRow;
int texH = font.TextureHeight;
float cellScreenW = glyphW * psxPixelScale;
float cellScreenH = glyphH * psxPixelScale;
// Get advance widths for proportional positioning
float cursorX = guiX;
GUI.color = tintColor;
foreach (char ch in label)
@@ -119,24 +152,19 @@ namespace SplashEdit.EditorCode
int col = charIdx % glyphsPerRow;
int row = charIdx / glyphsPerRow;
float advance = glyphW; // fallback
float advance = glyphW;
if (font.AdvanceWidths != null && charIdx < font.AdvanceWidths.Length)
{
advance = font.AdvanceWidths[charIdx];
}
if (ch != ' ')
{
// UV rect for this glyph in the font bitmap
float uvX = (float)(col * glyphW) / fontTex.width;
float uvY = 1f - (float)((row + 1) * glyphH) / fontTex.height;
float uvW = (float)glyphW / fontTex.width;
float uvH = (float)glyphH / fontTex.height;
// Draw at advance width, not cell width - matches PS1 proportional rendering
float spriteScreenW = advance * psxPixelScale;
Rect screenRect = new Rect(cursorX, guiY, spriteScreenW, cellScreenH);
// UV: only show the portion of the cell that the advance covers
float uvWScaled = uvW * (advance / glyphW);
Rect uvRect = new Rect(uvX, uvY, uvWScaled, uvH);
@@ -150,7 +178,6 @@ namespace SplashEdit.EditorCode
}
else
{
// Fallback: use Unity's text rendering for system font
int fSize = Mathf.Clamp(Mathf.RoundToInt(glyphH * psxPixelScale * 0.75f), 6, 72);
GUIStyle style = new GUIStyle(EditorStyles.label);
style.normal.textColor = tintColor;
@@ -167,58 +194,30 @@ namespace SplashEdit.EditorCode
Handles.EndGUI();
}
[DrawGizmo(GizmoType.NonSelected | GizmoType.Selected)]
static void DrawProgressBarGizmo(PSXUIProgressBar bar, GizmoType gizmoType)
static void DrawProgressBar(PSXUIProgressBar bar, bool selected)
{
RectTransform rt = bar.GetComponent<RectTransform>();
if (rt == null) return;
Vector3[] corners = new Vector3[4];
rt.GetWorldCorners(corners);
bool selected = (gizmoType & GizmoType.Selected) != 0;
// Background
Color bgColor = bar.BackgroundColor;
bgColor.a = selected ? 0.8f : 0.5f;
Handles.DrawSolidRectangleWithOutline(corners, bgColor, Color.white * (selected ? 1f : 0.4f));
bgColor.a = selected ? 1f : 0.9f;
Handles.DrawSolidRectangleWithOutline(corners, bgColor, selected ? Color.white : new Color(1, 1, 1, 0.5f));
// Fill portion
float t = bar.InitialValue / 100f;
if (t > 0.001f)
{
Vector3[] fillCorners = new Vector3[4];
fillCorners[0] = corners[0]; // bottom-left
fillCorners[1] = corners[1]; // top-left
fillCorners[2] = Vector3.Lerp(corners[1], corners[2], t); // top-right (partial)
fillCorners[3] = Vector3.Lerp(corners[0], corners[3], t); // bottom-right (partial)
fillCorners[0] = corners[0];
fillCorners[1] = corners[1];
fillCorners[2] = Vector3.Lerp(corners[1], corners[2], t);
fillCorners[3] = Vector3.Lerp(corners[0], corners[3], t);
Color fillColor = bar.FillColor;
fillColor.a = selected ? 0.9f : 0.6f;
fillColor.a = selected ? 1f : 0.9f;
Handles.DrawSolidRectangleWithOutline(fillCorners, fillColor, Color.clear);
}
}
[DrawGizmo(GizmoType.NonSelected | GizmoType.Selected)]
static void DrawCanvasGizmo(PSXCanvas canvas, GizmoType gizmoType)
{
RectTransform rt = canvas.GetComponent<RectTransform>();
if (rt == null) return;
Vector3[] corners = new Vector3[4];
rt.GetWorldCorners(corners);
bool selected = (gizmoType & GizmoType.Selected) != 0;
Color border = selected ? Color.yellow : new Color(1, 1, 0, 0.3f);
Handles.DrawSolidRectangleWithOutline(corners, Color.clear, border);
// Label
if (selected)
{
Vector2 res = PSXCanvas.PSXResolution;
Vector3 topMid = (corners[1] + corners[2]) * 0.5f;
string label = $"PSX Canvas: {canvas.CanvasName} ({res.x}x{res.y})";
GUIStyle style = new GUIStyle(EditorStyles.boldLabel);
style.normal.textColor = Color.yellow;
Handles.Label(topMid, label, style);
}
}
}
/// <summary>
/// Custom inspector for PSXCanvas component.

View File

@@ -200,15 +200,16 @@ namespace SplashEdit.RuntimeCode
else Debug.LogWarning("No active Scene View.");
}
}
else if (!isUITrack && (track.TrackType == PSXTrackType.ObjectPosition || track.TrackType == PSXTrackType.ObjectRotationY))
else if (!isUITrack && (track.TrackType == PSXTrackType.ObjectPosition || track.TrackType == PSXTrackType.ObjectRotation))
{
if (GUILayout.Button("From Sel.", GUILayout.Width(70)))
// Capture from the named object in scene
if (!string.IsNullOrEmpty(track.ObjectName) && GUILayout.Button("From Object", GUILayout.Width(85)))
{
var sel = Selection.activeGameObject;
if (sel != null)
var go = GameObject.Find(track.ObjectName);
if (go != null)
kf.Value = track.TrackType == PSXTrackType.ObjectPosition
? sel.transform.position : new Vector3(0, sel.transform.eulerAngles.y, 0);
else Debug.LogWarning("No GameObject selected.");
? go.transform.position : go.transform.eulerAngles;
else Debug.LogWarning($"Object '{track.ObjectName}' not found in scene.");
}
}
@@ -229,10 +230,10 @@ namespace SplashEdit.RuntimeCode
kf.Value = new Vector3(active ? 1f : 0f, 0, 0);
break;
}
case PSXTrackType.ObjectRotationY:
case PSXTrackType.ObjectRotation:
case PSXTrackType.CameraRotation:
{
float yRot = EditorGUILayout.FloatField("Y\u00b0", kf.Value.y);
kf.Value = new Vector3(0, yRot, 0);
kf.Value = EditorGUILayout.Vector3Field("Rotation\u00b0", kf.Value);
break;
}
case PSXTrackType.UIProgress:
@@ -297,17 +298,20 @@ namespace SplashEdit.RuntimeCode
track.Keyframes.Add(new PSXKeyframe { Frame = frame, Value = val });
}
}
else if (!isUITrack && (track.TrackType == PSXTrackType.ObjectPosition || track.TrackType == PSXTrackType.ObjectRotationY))
else if (!isUITrack && (track.TrackType == PSXTrackType.ObjectPosition || track.TrackType == PSXTrackType.ObjectRotation))
{
if (GUILayout.Button("+ from Selected", GUILayout.Width(120)))
if (!string.IsNullOrEmpty(track.ObjectName))
{
var sel = Selection.activeGameObject;
Vector3 val = Vector3.zero;
if (sel != null)
val = track.TrackType == PSXTrackType.ObjectPosition
? sel.transform.position : new Vector3(0, sel.transform.eulerAngles.y, 0);
int frame = track.Keyframes.Count > 0 ? track.Keyframes[track.Keyframes.Count - 1].Frame + 15 : 0;
track.Keyframes.Add(new PSXKeyframe { Frame = frame, Value = val });
if (GUILayout.Button("+ from Object", GUILayout.Width(110)))
{
var go = GameObject.Find(track.ObjectName);
Vector3 val = Vector3.zero;
if (go != null)
val = track.TrackType == PSXTrackType.ObjectPosition
? go.transform.position : go.transform.eulerAngles;
int frame = track.Keyframes.Count > 0 ? track.Keyframes[track.Keyframes.Count - 1].Frame + 15 : 0;
track.Keyframes.Add(new PSXKeyframe { Frame = frame, Value = val });
}
}
}
EditorGUILayout.EndHorizontal();
@@ -584,9 +588,9 @@ namespace SplashEdit.RuntimeCode
if (_savedObjectPositions.ContainsKey(track.ObjectName ?? ""))
initialVal = _savedObjectPositions[track.ObjectName];
break;
case PSXTrackType.ObjectRotationY:
case PSXTrackType.ObjectRotation:
if (_savedObjectRotations.ContainsKey(track.ObjectName ?? ""))
initialVal = new Vector3(0, _savedObjectRotations[track.ObjectName].eulerAngles.y, 0);
initialVal = _savedObjectRotations[track.ObjectName].eulerAngles;
break;
case PSXTrackType.ObjectActive:
if (_savedObjectActive.ContainsKey(track.ObjectName ?? ""))
@@ -619,10 +623,10 @@ namespace SplashEdit.RuntimeCode
if (go != null) go.transform.position = val;
break;
}
case PSXTrackType.ObjectRotationY:
case PSXTrackType.ObjectRotation:
{
var go = GameObject.Find(track.ObjectName);
if (go != null) go.transform.rotation = Quaternion.Euler(0, val.y, 0);
if (go != null) go.transform.rotation = Quaternion.Euler(val);
break;
}
case PSXTrackType.ObjectActive:
@@ -706,16 +710,6 @@ namespace SplashEdit.RuntimeCode
{
float rawT = frame / after.Frame;
float t = ApplyInterpCurve(rawT, after.Interp);
bool isRotation = track.TrackType == PSXTrackType.CameraRotation
|| track.TrackType == PSXTrackType.ObjectRotationY;
if (isRotation)
{
return new Vector3(
Mathf.LerpAngle(initialValue.x, after.Value.x, t),
Mathf.LerpAngle(initialValue.y, after.Value.y, t),
Mathf.LerpAngle(initialValue.z, after.Value.z, t));
}
return Vector3.Lerp(initialValue, after.Value, t);
}
@@ -727,17 +721,8 @@ namespace SplashEdit.RuntimeCode
float rawT2 = (frame - before.Frame) / span;
float t2 = ApplyInterpCurve(rawT2, after.Interp);
// Use shortest-path angle interpolation for rotation tracks
bool isRot = track.TrackType == PSXTrackType.CameraRotation
|| track.TrackType == PSXTrackType.ObjectRotationY;
if (isRot)
{
return new Vector3(
Mathf.LerpAngle(before.Value.x, after.Value.x, t2),
Mathf.LerpAngle(before.Value.y, after.Value.y, t2),
Mathf.LerpAngle(before.Value.z, after.Value.z, t2));
}
// Linear interpolation for all tracks including rotation.
// No shortest-path wrapping: a keyframe from 0 to 360 rotates the full circle.
return Vector3.Lerp(before.Value, after.Value, t2);
}