Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 94 additions & 31 deletions Editor/Inspectors/PSXUIEditors.cs
Original file line number Diff line number Diff line change
Expand Up @@ -147,8 +147,6 @@ static void DrawText(PSXUIText text, bool selected)
Color fill = new Color(0, 0, 0, selected ? 0.6f : 0.4f);
Handles.DrawSolidRectangleWithOutline(corners, fill, borderColor);

string label = string.IsNullOrEmpty(text.DefaultText) ? "[empty]" : text.DefaultText;

PSXFontAsset font = text.GetEffectiveFont();
int glyphW = font != null ? font.GlyphWidth : 8;
int glyphH = font != null ? font.GlyphHeight : 16;
Expand All @@ -169,42 +167,74 @@ static void DrawText(PSXUIText text, bool selected)
Color tintColor = text.TextColor;
tintColor.a = selected ? 1f : 0.8f;

var layout = text.GetWrappedLayout(font, glyphW, glyphH, psxPixelScale, guiW);
float startY = guiY;
if (layout.BlockHeight < guiH)
{
switch (text.VerticalAlignment)
{
case PSXTextVerticalAlignment.CenterY:
startY = guiY + (guiH - layout.BlockHeight) * 0.5f;
break;
case PSXTextVerticalAlignment.BottomY:
startY = guiY + guiH - layout.BlockHeight;
break;
}
}

if (font != null && font.FontTexture != null && font.SourceFont != null)
{
Texture2D fontTex = font.FontTexture;
int glyphsPerRow = font.GlyphsPerRow;
float cellScreenH = glyphH * psxPixelScale;

float cursorX = guiX;
GUI.color = tintColor;
foreach (char ch in label)
for (int lineIndex = 0; lineIndex < layout.Lines.Length; lineIndex++)
{
if (ch < 32 || ch > 126) continue;
int charIdx = ch - 32;
int col = charIdx % glyphsPerRow;
int row = charIdx / glyphsPerRow;

float advance = glyphW;
if (font.AdvanceWidths != null && charIdx < font.AdvanceWidths.Length)
advance = font.AdvanceWidths[charIdx];

if (ch != ' ')
string line = layout.Lines[lineIndex];
float lineWidth = text.MeasureLineWidth(line, font, glyphW, psxPixelScale);
float currentX = guiX;
switch (text.HorizontalAlignment)
{
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;

float spriteScreenW = advance * psxPixelScale;
Rect screenRect = new Rect(cursorX, guiY, spriteScreenW, cellScreenH);
float uvWScaled = uvW * (advance / glyphW);
Rect uvRect = new Rect(uvX, uvY, uvWScaled, uvH);

if (screenRect.xMax > guiX && screenRect.x < guiX + guiW)
GUI.DrawTextureWithTexCoords(screenRect, fontTex, uvRect);
case PSXTextHorizontalAlignment.CenterX:
currentX = guiX + (guiW - lineWidth) * 0.5f;
break;
case PSXTextHorizontalAlignment.RightX:
currentX = guiX + guiW - lineWidth;
break;
}

cursorX += advance * psxPixelScale;
float currentY = startY + lineIndex * layout.LineHeight;
float cursorX = currentX;
foreach (char ch in line)
{
if (ch < 32 || ch > 126) continue;
int charIdx = ch - 32;
int col = charIdx % glyphsPerRow;
int row = charIdx / glyphsPerRow;

float advance = glyphW;
if (font.AdvanceWidths != null && charIdx < font.AdvanceWidths.Length)
advance = font.AdvanceWidths[charIdx];

if (ch != ' ')
{
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;

float spriteScreenW = advance * psxPixelScale;
Rect screenRect = new Rect(cursorX, currentY, spriteScreenW, cellScreenH);
float uvWScaled = uvW * (advance / glyphW);
Rect uvRect = new Rect(uvX, uvY, uvWScaled, uvH);

if (screenRect.xMax > guiX && screenRect.x < guiX + guiW)
GUI.DrawTextureWithTexCoords(screenRect, fontTex, uvRect);
}

cursorX += advance * psxPixelScale;
}
}
GUI.color = Color.white;
}
Expand All @@ -213,14 +243,41 @@ static void DrawText(PSXUIText text, bool selected)
int fSize = Mathf.Clamp(Mathf.RoundToInt(glyphH * psxPixelScale * 0.75f), 6, 72);
GUIStyle style = new GUIStyle(EditorStyles.label);
style.normal.textColor = tintColor;
style.alignment = TextAnchor.UpperLeft;
style.fontSize = fSize;
style.wordWrap = false;
style.clipping = TextClipping.Clip;

Rect guiRect = new Rect(guiX, guiY, guiW, guiH);
GUI.color = tintColor;
GUI.Label(guiRect, label, style);
TextAnchor anchor = TextAnchor.UpperLeft;
switch (text.HorizontalAlignment)
{
case PSXTextHorizontalAlignment.CenterX:
anchor = TextAnchor.UpperCenter;
break;
case PSXTextHorizontalAlignment.RightX:
anchor = TextAnchor.UpperRight;
break;
}
style.alignment = anchor;

for (int lineIndex = 0; lineIndex < layout.Lines.Length; lineIndex++)
{
string line = layout.Lines[lineIndex];
float lineWidth = text.MeasureLineWidth(line, font, glyphW, psxPixelScale);
float currentX = guiX;
switch (text.HorizontalAlignment)
{
case PSXTextHorizontalAlignment.CenterX:
currentX = guiX + (guiW - lineWidth) * 0.5f;
break;
case PSXTextHorizontalAlignment.RightX:
currentX = guiX + guiW - lineWidth;
break;
}

Rect guiRect = new Rect(currentX, startY + lineIndex * layout.LineHeight, lineWidth, layout.LineHeight);
GUI.color = tintColor;
GUI.Label(guiRect, line, style);
}
GUI.color = Color.white;
}
Handles.EndGUI();
Expand Down Expand Up @@ -418,6 +475,12 @@ public override void OnInspectorGUI()
"Text render color."));
EditorGUILayout.PropertyField(serializedObject.FindProperty("fontOverride"), new GUIContent("Font Override",
"Custom font for this text element. If empty, uses the canvas default font or built-in system font (8x16)."));
EditorGUILayout.PropertyField(serializedObject.FindProperty("wrapText"), new GUIContent("TextWrapped",
"Automatically wrap text onto additional lines when it exceeds the element width."));
EditorGUILayout.PropertyField(serializedObject.FindProperty("horizontalAlignment"), new GUIContent("TextXAlignment",
"How each wrapped line is aligned within the element bounds."));
EditorGUILayout.PropertyField(serializedObject.FindProperty("verticalAlignment"), new GUIContent("TextYAlignment",
"How the full wrapped text block is aligned within the element bounds."));
EditorGUILayout.PropertyField(serializedObject.FindProperty("startVisible"));
PSXEditorStyles.EndCard();

Expand Down
42 changes: 25 additions & 17 deletions Editor/PSXObjectExporterEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ private void DrawMeshSummary()
{
if (meshFilter == null || meshFilter.sharedMesh == null)
{
EditorGUILayout.LabelField("No mesh on this object.", PSXEditorStyles.InfoBox);
EditorGUILayout.LabelField("No Mesh Filter or mesh was found on this object. Lua-only export is still valid, but geometry will be skipped.", PSXEditorStyles.InfoBox);
return;
}

Expand Down Expand Up @@ -128,28 +128,36 @@ private void DrawExportSection()

EditorGUI.indentLevel++;

EditorGUILayout.PropertyField(bitDepthProp, new GUIContent("Bit Depth"));
if (meshFilter != null && meshFilter.sharedMesh != null)
{
EditorGUILayout.PropertyField(bitDepthProp, new GUIContent("Bit Depth"));

EditorGUILayout.PropertyField(smoothNormalsProp, new GUIContent("Smooth Normals",
"Smooth normals for lighting. Disable for flat/faceted shading."));
EditorGUILayout.PropertyField(smoothNormalsProp, new GUIContent("Smooth Normals",
"Smooth normals for lighting. Disable for flat/faceted shading."));

EditorGUILayout.PropertyField(vertexColorModeProp, new GUIContent("Vertex Colors"));
var vcMode = (VertexColorMode)vertexColorModeProp.enumValueIndex;
if (vcMode == VertexColorMode.FlatColor)
{
EditorGUILayout.PropertyField(flatVertexColorProp, new GUIContent("Flat Color"));
}
else if (vcMode == VertexColorMode.MeshVertexColors)
{
var exporter = target as PSXObjectExporter;
var mf = exporter.GetComponent<MeshFilter>();
if (mf != null && mf.sharedMesh != null && (mf.sharedMesh.colors == null || mf.sharedMesh.colors.Length == 0))
EditorGUILayout.PropertyField(vertexColorModeProp, new GUIContent("Vertex Colors"));
var vcMode = (VertexColorMode)vertexColorModeProp.enumValueIndex;
if (vcMode == VertexColorMode.FlatColor)
{
EditorGUILayout.HelpBox("This mesh has no vertex colors. Will fall back to gray (128,128,128).", MessageType.Warning);
EditorGUILayout.PropertyField(flatVertexColorProp, new GUIContent("Flat Color"));
}
else if (vcMode == VertexColorMode.MeshVertexColors)
{
var exporter = target as PSXObjectExporter;
var mf = exporter.GetComponent<MeshFilter>();
if (mf != null && mf.sharedMesh != null && (mf.sharedMesh.colors == null || mf.sharedMesh.colors.Length == 0))
{
EditorGUILayout.HelpBox("This mesh has no vertex colors. Will fall back to gray (128,128,128).", MessageType.Warning);
}
}

EditorGUILayout.PropertyField(uvOffsetMaterialProp, new GUIContent("UV Offset Material"));
}
else
{
EditorGUILayout.HelpBox("This object has no mesh. Add a Mesh Filter to use a Lua script for script-only behavior.", MessageType.Warning);
}

EditorGUILayout.PropertyField(uvOffsetMaterialProp, new GUIContent("UV Offset Material"));
EditorGUILayout.PropertyField(luaFileProp, new GUIContent("Lua Script"));

if (luaFileProp.objectReferenceValue != null)
Expand Down
6 changes: 3 additions & 3 deletions Runtime/PSXObjectExporter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,13 @@ public enum VertexColorMode
MeshVertexColors = 2
}

[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
[Icon("Packages/net.psxsplash.splashedit/Icons/PSXObjectExporter.png")]
public class PSXObjectExporter : MonoBehaviour, IPSXExportable
{
public LuaFile LuaFile => luaFile;

[FormerlySerializedAs("IsActive")]
[SerializeField] private bool isActive = true;
[SerializeField] private bool isActive = true;
public bool IsActive => isActive;

public List<PSXTexture2D> Textures { get; set; } = new List<PSXTexture2D>();
Expand Down Expand Up @@ -119,6 +117,8 @@ public PSXTexture2D GetTexture(int index)
public void CreatePSXMesh(float GTEScaling)
{
Renderer renderer = GetComponent<Renderer>();
Mesh = new PSXMesh { Triangles = new List<Tri>() };

if (renderer != null)
{
Mesh = PSXMesh.CreateFromUnityRenderer(renderer, GTEScaling, transform, Textures, vertexColorMode, flatVertexColor, smoothNormals);
Expand Down
10 changes: 6 additions & 4 deletions Runtime/PSXSceneWriter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -351,7 +351,8 @@ public static void Write(string path, in SceneData scene, Action<string, LogType
for (int c = 0; c < 3; c++)
writer.Write((int)rot[r, c]);

writer.Write((ushort)exporter.Mesh.Triangles.Count);
int triangleCount = exporter.Mesh?.Triangles?.Count ?? 0;
writer.Write((ushort)triangleCount);

if (exporter.LuaFile != null)
writer.Write((short)luaFiles.IndexOf(exporter.LuaFile));
Expand Down Expand Up @@ -542,9 +543,10 @@ public static void Write(string path, in SceneData scene, Action<string, LogType
{
AlignToFourBytes(writer);
meshOffset.DataOffsets.Add(writer.BaseStream.Position);
totalFaces += exporter.Mesh.Triangles.Count;
int exporterTriangleCount = exporter.Mesh?.Triangles?.Count ?? 0;
totalFaces += exporterTriangleCount;

foreach (Tri tri in exporter.Mesh.Triangles)
foreach (Tri tri in exporter.Mesh?.Triangles ?? new List<Tri>())
{
// Vertex positions (3 × 6 bytes)
WriteVertexPosition(writer, tri.v0);
Expand Down Expand Up @@ -656,7 +658,7 @@ public static void Write(string path, in SceneData scene, Action<string, LogType
writer.Write((byte)name.Length);
audioNameOffsetPositions.Add(writer.BaseStream.Position);
writer.Write((uint)0); // nameOffset placeholder
audioClipNames.Add(name);
audioClipNames.Add(name);
}

// Phase 2: Write name strings (after all metadata entries)
Expand Down
Loading
Loading