Minor refactor and QoL features, updated splashpack

This commit is contained in:
2025-03-26 14:31:49 +01:00
parent b0800a3995
commit 9e0d1557ee
5 changed files with 251 additions and 129 deletions

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq;
using SplashEdit.RuntimeCode; using SplashEdit.RuntimeCode;
using Unity.Collections; using Unity.Collections;
using UnityEditor; using UnityEditor;
@@ -22,8 +23,6 @@ namespace SplashEdit.EditorCode
private Color bufferColor1 = new Color(1, 0, 0, 0.5f); private Color bufferColor1 = new Color(1, 0, 0, 0.5f);
private Color bufferColor2 = new Color(0, 1, 0, 0.5f); private Color bufferColor2 = new Color(0, 1, 0, 0.5f);
private Color prohibitedColor = new Color(1, 0, 0, 0.3f); private Color prohibitedColor = new Color(1, 0, 0, 0.3f);
private static string _psxDataPath = "Assets/PSXData.asset";
private PSXData _psxData; private PSXData _psxData;
private static readonly Vector2[] resolutions = private static readonly Vector2[] resolutions =
@@ -55,7 +54,11 @@ namespace SplashEdit.EditorCode
// Ensure minimum window size is applied. // Ensure minimum window size is applied.
this.minSize = new Vector2(800, 600); this.minSize = new Vector2(800, 600);
LoadData(); _psxData = DataStorage.LoadData();
selectedResolution = _psxData.OutputResolution;
dualBuffering = _psxData.DualBuffering;
verticalLayout = _psxData.VerticalBuffering;
prohibitedAreas = _psxData.ProhibitedAreas;
} }
/// <summary> /// <summary>
@@ -143,13 +146,17 @@ namespace SplashEdit.EditorCode
// Prompt the user to select a file location and save the VRAM data. // Prompt the user to select a file location and save the VRAM data.
string path = EditorUtility.SaveFilePanel("Select Output File", "", "output", "bin"); string path = EditorUtility.SaveFilePanel("Select Output File", "", "output", "bin");
using (BinaryWriter writer = new BinaryWriter(File.Open(path, FileMode.Create)))
if (path != string.Empty)
{ {
for (int y = 0; y < VramHeight; y++) using (BinaryWriter writer = new BinaryWriter(File.Open(path, FileMode.Create)))
{ {
for (int x = 0; x < VramWidth; x++) for (int y = 0; y < VramHeight; y++)
{ {
writer.Write(packed._vramPixels[x, y].Pack()); for (int x = 0; x < VramWidth; x++)
{
writer.Write(packed._vramPixels[x, y].Pack());
}
} }
} }
} }
@@ -192,30 +199,51 @@ namespace SplashEdit.EditorCode
} }
GUILayout.Space(10); GUILayout.Space(10);
GUILayout.Label("Prohibited areas", EditorStyles.boldLabel); GUILayout.Label("Prohibited Areas", EditorStyles.boldLabel);
scrollPosition = GUILayout.BeginScrollView(scrollPosition, GUILayout.MaxHeight(150f)); GUILayout.Space(10);
scrollPosition = GUILayout.BeginScrollView(scrollPosition, false, true, GUILayout.MinHeight(300f), GUILayout.ExpandWidth(true));
// List and edit each prohibited area. // List and edit each prohibited area.
List<int> toRemove = new List<int>();
for (int i = 0; i < prohibitedAreas.Count; i++) for (int i = 0; i < prohibitedAreas.Count; i++)
{ {
var area = prohibitedAreas[i]; var area = prohibitedAreas[i];
area.X = EditorGUILayout.IntField("X", area.X); GUI.backgroundColor = new Color(0.95f, 0.95f, 0.95f);
area.Y = EditorGUILayout.IntField("Y", area.Y); GUILayout.BeginVertical("box");
GUI.backgroundColor = Color.white;
// Display fields for editing the area
area.X = EditorGUILayout.IntField("X Coordinate", area.X);
area.Y = EditorGUILayout.IntField("Y Coordinate", area.Y);
area.Width = EditorGUILayout.IntField("Width", area.Width); area.Width = EditorGUILayout.IntField("Width", area.Width);
area.Height = EditorGUILayout.IntField("Height", area.Height); area.Height = EditorGUILayout.IntField("Height", area.Height);
if (GUILayout.Button("Remove"))
if (GUILayout.Button("Remove", GUILayout.Height(30)))
{ {
prohibitedAreas.RemoveAt(i); toRemove.Add(i); // Mark for removal
break;
} }
prohibitedAreas[i] = area; prohibitedAreas[i] = area;
GUILayout.EndVertical();
GUILayout.Space(10); GUILayout.Space(10);
} }
// Remove the areas marked for deletion outside the loop to avoid skipping elements
foreach (var index in toRemove.OrderByDescending(x => x))
{
prohibitedAreas.RemoveAt(index);
}
GUILayout.EndScrollView(); GUILayout.EndScrollView();
GUILayout.Space(10); GUILayout.Space(10);
if (GUILayout.Button("Add Prohibited Area")) if (GUILayout.Button("Add Prohibited Area"))
{ {
prohibitedAreas.Add(new ProhibitedArea()); prohibitedAreas.Add(new ProhibitedArea());
@@ -230,7 +258,13 @@ namespace SplashEdit.EditorCode
// Button to save settings; saving now occurs only on button press. // Button to save settings; saving now occurs only on button press.
if (GUILayout.Button("Save Settings")) if (GUILayout.Button("Save Settings"))
{ {
StoreData(); _psxData.OutputResolution = selectedResolution;
_psxData.DualBuffering = dualBuffering;
_psxData.VerticalBuffering = verticalLayout;
_psxData.ProhibitedAreas = prohibitedAreas;
DataStorage.StoreData(_psxData);
EditorUtility.DisplayDialog("splashedit", "Vram configuration saved", "OK");
} }
GUILayout.EndVertical(); GUILayout.EndVertical();
@@ -263,42 +297,10 @@ namespace SplashEdit.EditorCode
GUILayout.EndHorizontal(); GUILayout.EndHorizontal();
} }
/// <summary>
/// Loads stored PSX data from the asset.
/// </summary>
private void LoadData()
{
_psxData = AssetDatabase.LoadAssetAtPath<PSXData>(_psxDataPath);
if (!_psxData)
{
_psxData = CreateInstance<PSXData>();
AssetDatabase.CreateAsset(_psxData, _psxDataPath);
AssetDatabase.SaveAssets();
}
selectedResolution = _psxData.OutputResolution;
dualBuffering = _psxData.DualBuffering;
verticalLayout = _psxData.VerticalBuffering;
prohibitedAreas = _psxData.ProhibitedAreas;
}
/// <summary> /// <summary>
/// Stores current configuration to the PSX data asset. /// Stores current configuration to the PSX data asset.
/// This is now triggered manually via the "Save Settings" button. /// This is now triggered manually via the "Save Settings" button.
/// </summary> /// </summary>
private void StoreData()
{
if (_psxData != null)
{
_psxData.OutputResolution = selectedResolution;
_psxData.DualBuffering = dualBuffering;
_psxData.VerticalBuffering = verticalLayout;
_psxData.ProhibitedAreas = prohibitedAreas;
EditorUtility.SetDirty(_psxData);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
}
} }
} }

View File

@@ -45,7 +45,7 @@ namespace SplashEdit.RuntimeCode
/// <param name="textureHeight">Height of the texture (default is 256).</param> /// <param name="textureHeight">Height of the texture (default is 256).</param>
/// <param name="transform">Optional transform to convert vertices to world space.</param> /// <param name="transform">Optional transform to convert vertices to world space.</param>
/// <returns>A new PSXMesh containing the converted triangles.</returns> /// <returns>A new PSXMesh containing the converted triangles.</returns>
public static PSXMesh CreateFromUnityMesh(Mesh mesh, float GTEScaling, int textureWidth = 256, int textureHeight = 256, Transform transform = null) public static PSXMesh CreateFromUnityMesh(Mesh mesh, float GTEScaling, Transform transform, bool isStatic, int textureWidth = 256, int textureHeight = 256)
{ {
PSXMesh psxMesh = new PSXMesh { Triangles = new List<Tri>() }; PSXMesh psxMesh = new PSXMesh { Triangles = new List<Tri>() };
@@ -67,10 +67,27 @@ namespace SplashEdit.RuntimeCode
int vid1 = indices[i + 1]; int vid1 = indices[i + 1];
int vid2 = indices[i + 2]; int vid2 = indices[i + 2];
Vector3 v0, v1, v2;
// Transform vertices to world space if a transform is provided. // Transform vertices to world space if a transform is provided.
Vector3 v0 = transform ? transform.TransformPoint(vertices[vid0]) : vertices[vid0];
Vector3 v1 = transform ? transform.TransformPoint(vertices[vid1]) : vertices[vid1]; if (isStatic)
Vector3 v2 = transform ? transform.TransformPoint(vertices[vid2]) : vertices[vid2]; {
v0 = transform.TransformPoint(vertices[vid0]);
v1 = transform.TransformPoint(vertices[vid1]);
v2 = transform.TransformPoint(vertices[vid2]);
}
else
{
// Extract ONLY world scale
Vector3 worldScale = transform.lossyScale;
// Apply scale *before* transformation, ensuring rotation isnt affected
v0 = Vector3.Scale(vertices[vid0], worldScale);
v1 = Vector3.Scale(vertices[vid1], worldScale);
v2 = Vector3.Scale(vertices[vid2], worldScale);
}
// Convert vertices to PSX format including fixed-point conversion and shading. // Convert vertices to PSX format including fixed-point conversion and shading.
PSXVertex psxV0 = ConvertToPSXVertex(v0, GTEScaling, normals[vid0], uv[vid0], lightDir, lightColor, textureWidth, textureHeight); PSXVertex psxV0 = ConvertToPSXVertex(v0, GTEScaling, normals[vid0], uv[vid0], lightDir, lightColor, textureWidth, textureHeight);
@@ -116,13 +133,13 @@ namespace SplashEdit.RuntimeCode
nz = (short)PSXTrig.ConvertCoordinateToPSX(normal.z), nz = (short)PSXTrig.ConvertCoordinateToPSX(normal.z),
// Map UV coordinates to a byte range after scaling based on texture dimensions. // Map UV coordinates to a byte range after scaling based on texture dimensions.
u = (byte)(Mathf.Clamp((uv.x * (textureWidth - 1)), 0, 255)), u = (byte)Mathf.Clamp(uv.x * (textureWidth - 1), 0, 255),
v = (byte)(Mathf.Clamp(((1.0f - uv.y) * (textureHeight - 1)), 0, 255)), v = (byte)Mathf.Clamp((1.0f - uv.y) * (textureHeight - 1), 0, 255),
// Convert the computed color to a byte range. // Convert the computed color to a byte range.
r = (byte)(Mathf.Clamp(shadedColor.r * 255, 0, 255)), r = (byte)Mathf.Clamp(shadedColor.r * 255, 0, 255),
g = (byte)(Mathf.Clamp(shadedColor.g * 255, 0, 255)), g = (byte)Mathf.Clamp(shadedColor.g * 255, 0, 255),
b = (byte)(Mathf.Clamp(shadedColor.b * 255, 0, 255)) b = (byte)Mathf.Clamp(shadedColor.b * 255, 0, 255)
}; };
return psxVertex; return psxVertex;

View File

@@ -34,16 +34,7 @@ namespace SplashEdit.RuntimeCode
MeshFilter meshFilter = gameObject.GetComponent<MeshFilter>(); MeshFilter meshFilter = gameObject.GetComponent<MeshFilter>();
if (meshFilter != null) if (meshFilter != null)
{ {
if (MeshIsStatic) Mesh = PSXMesh.CreateFromUnityMesh(meshFilter.sharedMesh, GTEScaling, transform, MeshIsStatic, Texture.Width, Texture.Height);
{
// Static meshes take object transformation into account
Mesh = PSXMesh.CreateFromUnityMesh(meshFilter.sharedMesh, GTEScaling, Texture.Width, Texture.Height, transform);
}
else
{
// Dynamic meshes do not consider object transformation
Mesh = PSXMesh.CreateFromUnityMesh(meshFilter.sharedMesh, GTEScaling, Texture.Width, Texture.Height);
}
} }
} }
} }

View File

@@ -16,19 +16,20 @@ namespace SplashEdit.RuntimeCode
private TextureAtlas[] _atlases; private TextureAtlas[] _atlases;
private PSXData _psxData; private PSXData _psxData;
private readonly string _psxDataPath = "Assets/PSXData.asset";
private Vector2 selectedResolution; private Vector2 selectedResolution;
private bool dualBuffering; private bool dualBuffering;
private bool verticalLayout; private bool verticalLayout;
private List<ProhibitedArea> prohibitedAreas; private List<ProhibitedArea> prohibitedAreas;
private VRAMPixel[,] vramPixels;
public void Export() public void Export()
{ {
LoadData(); _psxData = DataStorage.LoadData();
selectedResolution = _psxData.OutputResolution;
dualBuffering = _psxData.DualBuffering;
verticalLayout = _psxData.VerticalBuffering;
prohibitedAreas = _psxData.ProhibitedAreas;
_exporters = FindObjectsByType<PSXObjectExporter>(FindObjectsSortMode.None); _exporters = FindObjectsByType<PSXObjectExporter>(FindObjectsSortMode.None);
foreach (PSXObjectExporter exp in _exporters) foreach (PSXObjectExporter exp in _exporters)
{ {
@@ -59,8 +60,37 @@ namespace SplashEdit.RuntimeCode
} }
public static string PSXMatrixToStringMultiline(int[,] matrix)
{
return $@"
RT11={matrix[0, 0],6} RT12={matrix[0, 1],6} RT13={matrix[0, 2],6}
RT21={matrix[1, 0],6} RT22={matrix[1, 1],6} RT23={matrix[1, 2],6}
RT31={matrix[2, 0],6} RT32={matrix[2, 1],6} RT33={matrix[2, 2],6}";
}
public static Vector3 ConvertPSXMatrixToEulerAngles(int[,] psxMatrix)
{
// Convert PSX fixed-point (s3.12) to float
float r00 = psxMatrix[0, 0] / 4096.0f;
float r01 = psxMatrix[0, 1] / 4096.0f;
float r02 = psxMatrix[0, 2] / 4096.0f;
float r10 = psxMatrix[1, 0] / 4096.0f;
float r11 = psxMatrix[1, 1] / 4096.0f;
float r12 = psxMatrix[1, 2] / 4096.0f;
float r20 = psxMatrix[2, 0] / 4096.0f;
float r21 = psxMatrix[2, 1] / 4096.0f;
float r22 = psxMatrix[2, 2] / 4096.0f;
// Compute Euler angles (YXZ order for Unity)
float thetaX = Mathf.Asin(-r21) * Mathf.Rad2Deg; // X Rotation
float thetaY = Mathf.Atan2(r20, r22) * Mathf.Rad2Deg; // Y Rotation
float thetaZ = Mathf.Atan2(r01, r11) * Mathf.Rad2Deg; // Z Rotation
return new Vector3(thetaX, thetaY, thetaZ);
}
void ExportFile() void ExportFile()
{ {
string path = EditorUtility.SaveFilePanel("Select Output File", "", "output", "bin"); string path = EditorUtility.SaveFilePanel("Select Output File", "", "output", "bin");
int totalFaces = 0; int totalFaces = 0;
@@ -86,12 +116,12 @@ namespace SplashEdit.RuntimeCode
// GameObject section (exporters) // GameObject section (exporters)
foreach (PSXObjectExporter exporter in _exporters) foreach (PSXObjectExporter exporter in _exporters)
{ {
// Write object's position // Write object's transform
writer.Write((int)PSXTrig.ConvertCoordinateToPSX(transform.position.x)); writer.Write((int)PSXTrig.ConvertCoordinateToPSX(exporter.transform.localToWorldMatrix.GetPosition().x, GTEScaling));
writer.Write((int)PSXTrig.ConvertCoordinateToPSX(transform.position.y)); writer.Write((int)PSXTrig.ConvertCoordinateToPSX(-exporter.transform.localToWorldMatrix.GetPosition().y, GTEScaling));
writer.Write((int)PSXTrig.ConvertCoordinateToPSX(transform.position.z)); writer.Write((int)PSXTrig.ConvertCoordinateToPSX(exporter.transform.localToWorldMatrix.GetPosition().z, GTEScaling));
int[,] rotationMatrix = PSXTrig.ConvertRotationToPSXMatrix(exporter.transform.rotation); int[,] rotationMatrix = PSXTrig.ConvertRotationToPSXMatrix(exporter.transform.rotation);
writer.Write((int)rotationMatrix[0, 0]); writer.Write((int)rotationMatrix[0, 0]);
writer.Write((int)rotationMatrix[0, 1]); writer.Write((int)rotationMatrix[0, 1]);
writer.Write((int)rotationMatrix[0, 2]); writer.Write((int)rotationMatrix[0, 2]);
@@ -277,35 +307,7 @@ namespace SplashEdit.RuntimeCode
{ {
long position = writer.BaseStream.Position; long position = writer.BaseStream.Position;
int padding = (int)(4 - (position % 4)) % 4; // Compute needed padding int padding = (int)(4 - (position % 4)) % 4; // Compute needed padding
Debug.Log($"aligned {padding} bytes");
writer.Write(new byte[padding]); // Write zero padding writer.Write(new byte[padding]); // Write zero padding
} }
public void LoadData()
{
_psxData = AssetDatabase.LoadAssetAtPath<PSXData>(_psxDataPath);
if (!_psxData)
{
_psxData = ScriptableObject.CreateInstance<PSXData>();
AssetDatabase.CreateAsset(_psxData, _psxDataPath);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
selectedResolution = _psxData.OutputResolution;
dualBuffering = _psxData.DualBuffering;
verticalLayout = _psxData.VerticalBuffering;
prohibitedAreas = _psxData.ProhibitedAreas;
}
void OnDrawGizmos()
{
Gizmos.DrawIcon(transform.position, "Packages/net.psxsplash.splashedit/Icons/PSXSceneExporter.png", true);
Vector3 sceneOrigin = new Vector3(0, 0, 0);
Vector3 cubeSize = new Vector3(8.0f * GTEScaling, 8.0f * GTEScaling, 8.0f * GTEScaling);
Gizmos.color = Color.red;
Gizmos.DrawWireCube(sceneOrigin, cubeSize);
}
} }
} }

View File

@@ -1,8 +1,39 @@
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using UnityEditor;
using UnityEngine; using UnityEngine;
namespace SplashEdit.RuntimeCode namespace SplashEdit.RuntimeCode
{ {
public static class DataStorage
{
private static readonly string psxDataPath = "Assets/PSXData.asset";
public static PSXData LoadData()
{
PSXData psxData = AssetDatabase.LoadAssetAtPath<PSXData>(psxDataPath);
if (!psxData)
{
psxData = ScriptableObject.CreateInstance<PSXData>();
AssetDatabase.CreateAsset(psxData, psxDataPath);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
return psxData;
}
public static void StoreData(PSXData psxData)
{
if (psxData != null)
{
EditorUtility.SetDirty(psxData);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();
}
}
}
/// <summary> /// <summary>
/// Represents a prohibited area in PlayStation 2D VRAM where textures should not be packed. /// Represents a prohibited area in PlayStation 2D VRAM where textures should not be packed.
/// This class provides conversion methods to and from Unity's Rect structure. /// This class provides conversion methods to and from Unity's Rect structure.
@@ -42,48 +73,83 @@ namespace SplashEdit.RuntimeCode
return new Rect(X, Y, Width, Height); return new Rect(X, Y, Width, Height);
} }
} }
/// <summary>
/// A utility class containing methods for converting Unity-specific data formats to PSX-compatible formats.
/// This includes converting coordinates and rotations to PSX's 3.12 fixed-point format.
/// </summary>
public static class PSXTrig public static class PSXTrig
{ {
/// <summary>
/// Converts a floating-point coordinate to a PSX-compatible 3.12 fixed-point format.
/// The value is clamped to the range [-4, 3.999] and scaled by the provided GTEScaling factor.
/// </summary>
/// <param name="value">The coordinate value to convert.</param>
/// <param name="GTEScaling">A scaling factor for the value (default is 1.0f).</param>
/// <returns>The converted coordinate in 3.12 fixed-point format.</returns>
public static short ConvertCoordinateToPSX(float value, float GTEScaling = 1.0f) public static short ConvertCoordinateToPSX(float value, float GTEScaling = 1.0f)
{ {
return (short)(Mathf.Clamp(value/GTEScaling, -4f, 3.999f) * 4096); return (short)(Mathf.Clamp(value / GTEScaling, -4f, 3.999f) * 4096);
} }
/// <summary>
/// Converts a quaternion rotation to a PSX-compatible 3x3 rotation matrix.
/// The matrix is adjusted for the difference in the Y-axis orientation between Unity (Y-up) and PSX (Y-down).
/// Each matrix element is converted to a 3.12 fixed-point format.
/// </summary>
/// <param name="rotation">The quaternion representing the rotation to convert.</param>
/// <returns>A 3x3 matrix representing the PSX-compatible rotation.</returns>
public static int[,] ConvertRotationToPSXMatrix(Quaternion rotation) public static int[,] ConvertRotationToPSXMatrix(Quaternion rotation)
{ {
float xx = rotation.x * rotation.x; // Convert the quaternion to a Unity rotation matrix.
float yy = rotation.y * rotation.y; Matrix4x4 unityMatrix = Matrix4x4.Rotate(rotation);
float zz = rotation.z * rotation.z;
float xy = rotation.x * rotation.y;
float xz = rotation.x * rotation.z;
float yz = rotation.y * rotation.z;
float wx = rotation.w * rotation.x;
float wy = rotation.w * rotation.y;
float wz = rotation.w * rotation.z;
// Create the 3x3 rotation matrix // Flip the Y-axis to match PSX's Y-down convention.
int[,] psxMatrix = new int[3, 3] float[,] fixedMatrix = new float[3, 3]
{ {
{ ConvertToFixed12(1.0f - 2.0f * (yy + zz)), ConvertToFixed12(2.0f * (xy - wz)), ConvertToFixed12(2.0f * (xz + wy)) }, { unityMatrix.m00, -unityMatrix.m01, unityMatrix.m02 }, // Flip Y
{ ConvertToFixed12(2.0f * (xy + wz)), ConvertToFixed12(1.0f - 2.0f * (xx + zz)), ConvertToFixed12(2.0f * (yz - wx)) }, { -unityMatrix.m10, unityMatrix.m11, -unityMatrix.m12 }, // Flip Y
{ ConvertToFixed12(2.0f * (xz - wy)), ConvertToFixed12(2.0f * (yz + wx)), ConvertToFixed12(1.0f - 2.0f * (xx + yy)) } { unityMatrix.m20, -unityMatrix.m21, unityMatrix.m22 } // Flip Y
}; };
// Convert the Unity matrix to PSX fixed-point format.
int[,] psxMatrix = new int[3, 3];
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 3; j++)
{
psxMatrix[i, j] = ConvertToFixed12(fixedMatrix[i, j]);
}
}
return psxMatrix; return psxMatrix;
} }
private static int ConvertToFixed12(float value) /// <summary>
/// Converts a floating-point value to a 3.12 fixed-point format (PSX format).
/// The value is scaled by a factor of 4096 and clamped to the range of a signed 16-bit integer.
/// </summary>
/// <param name="value">The floating-point value to convert.</param>
/// <returns>The converted value in 3.12 fixed-point format as a 16-bit signed integer.</returns>
public static short ConvertToFixed12(float value)
{ {
return (int)(value * 4096.0f); // 2^12 = 4096 int fixedValue = Mathf.RoundToInt(value * 4096.0f); // Scale to 3.12 format
return (short)Mathf.Clamp(fixedValue, -32768, 32767); // Clamp to signed 16-bit
} }
} }
[StructLayout(LayoutKind.Sequential, Pack = 1)] /// <summary>
/// Represents the attributes of a texture page in the PSX graphics system.
/// Provides methods for setting various properties such as the page coordinates, transparency type, color mode, dithering, and display area.
/// </summary>
public struct TPageAttr public struct TPageAttr
{ {
public ushort info; public ushort info; // Stores the packed attribute information as a 16-bit unsigned integer.
/// <summary>
/// Sets the X-coordinate of the texture page.
/// The lower 4 bits of the 'info' field are used to store the X value.
/// </summary>
/// <param name="x">The X-coordinate value (0 to 15).</param>
/// <returns>The updated TPageAttr instance.</returns>
public TPageAttr SetPageX(byte x) public TPageAttr SetPageX(byte x)
{ {
info &= 0xFFF0; // Clear lower 4 bits info &= 0xFFF0; // Clear lower 4 bits
@@ -92,6 +158,12 @@ namespace SplashEdit.RuntimeCode
return this; return this;
} }
/// <summary>
/// Sets the Y-coordinate of the texture page.
/// The 4th bit of the 'info' field is used to store the Y value (0 or 1).
/// </summary>
/// <param name="y">The Y-coordinate value (0 or 1).</param>
/// <returns>The updated TPageAttr instance.</returns>
public TPageAttr SetPageY(byte y) public TPageAttr SetPageY(byte y)
{ {
info &= 0xFFEF; // Clear bit 4 info &= 0xFFEF; // Clear bit 4
@@ -100,6 +172,12 @@ namespace SplashEdit.RuntimeCode
return this; return this;
} }
/// <summary>
/// Sets the transparency type of the texture page.
/// The transparency type is stored in bits 5 and 6 of the 'info' field.
/// </summary>
/// <param name="trans">The transparency type to set.</param>
/// <returns>The updated TPageAttr instance.</returns>
public TPageAttr Set(SemiTrans trans) public TPageAttr Set(SemiTrans trans)
{ {
info &= 0xFF9F; // Clear bits 5 and 6 info &= 0xFF9F; // Clear bits 5 and 6
@@ -108,6 +186,12 @@ namespace SplashEdit.RuntimeCode
return this; return this;
} }
/// <summary>
/// Sets the color mode of the texture page.
/// The color mode is stored in bits 7 and 8 of the 'info' field.
/// </summary>
/// <param name="mode">The color mode to set (4-bit, 8-bit, or 16-bit).</param>
/// <returns>The updated TPageAttr instance.</returns>
public TPageAttr Set(ColorMode mode) public TPageAttr Set(ColorMode mode)
{ {
info &= 0xFE7F; // Clear bits 7 and 8 info &= 0xFE7F; // Clear bits 7 and 8
@@ -116,31 +200,54 @@ namespace SplashEdit.RuntimeCode
return this; return this;
} }
/// <summary>
/// Enables or disables dithering for the texture page.
/// Dithering is stored in bit 9 of the 'info' field.
/// </summary>
/// <param name="dithering">True to enable dithering, false to disable it.</param>
/// <returns>The updated TPageAttr instance.</returns>
public TPageAttr SetDithering(bool dithering) public TPageAttr SetDithering(bool dithering)
{ {
if (dithering) if (dithering)
info |= 0x0200; info |= 0x0200; // Set bit 9 to enable dithering
else else
info &= 0xFDFF; info &= 0xFDFF; // Clear bit 9 to disable dithering
return this; return this;
} }
/// <summary>
/// Disables the display area for the texture page.
/// This will clear bit 10 of the 'info' field.
/// </summary>
/// <returns>The updated TPageAttr instance.</returns>
public TPageAttr DisableDisplayArea() public TPageAttr DisableDisplayArea()
{ {
info &= 0xFBFF; // Clear bit 10 info &= 0xFBFF; // Clear bit 10
return this; return this;
} }
/// <summary>
/// Enables the display area for the texture page.
/// This will set bit 10 of the 'info' field.
/// </summary>
/// <returns>The updated TPageAttr instance.</returns>
public TPageAttr EnableDisplayArea() public TPageAttr EnableDisplayArea()
{ {
info |= 0x0400; // Set bit 10 info |= 0x0400; // Set bit 10 to enable display area
return this; return this;
} }
/// <summary>
/// Returns a string representation of the TPageAttr instance, showing the 'info' value in hexadecimal.
/// </summary>
/// <returns>A string representing the 'info' value in hexadecimal format.</returns>
public override string ToString() => $"Info: 0x{info:X4}"; public override string ToString() => $"Info: 0x{info:X4}";
// Define the enums for SemiTrans and ColorMode (assuming their values) // Define the enums for SemiTrans and ColorMode (assuming their values)
/// <summary>
/// Defines the transparency types for a texture page.
/// </summary>
public enum SemiTrans : uint public enum SemiTrans : uint
{ {
None = 0, None = 0,
@@ -149,6 +256,9 @@ namespace SplashEdit.RuntimeCode
Type3 = 3 Type3 = 3
} }
/// <summary>
/// Defines the color modes for a texture page.
/// </summary>
public enum ColorMode : uint public enum ColorMode : uint
{ {
Mode4Bit = 0, Mode4Bit = 0,