fix after merge
This commit is contained in:
@@ -56,7 +56,7 @@ namespace SplashEdit.EditorCode
|
|||||||
// Ensure minimum window size is applied.
|
// Ensure minimum window size is applied.
|
||||||
this.minSize = MinSize;
|
this.minSize = MinSize;
|
||||||
|
|
||||||
_psxData = Utils.LoadData(out selectedResolution, out dualBuffering, out verticalLayout, out prohibitedAreas);
|
_psxData = DataStorage.LoadData(out selectedResolution, out dualBuffering, out verticalLayout, out prohibitedAreas);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -266,7 +266,10 @@ namespace SplashEdit.EditorCode
|
|||||||
|
|
||||||
// Display VRAM image preview.
|
// Display VRAM image preview.
|
||||||
Rect vramRect = GUILayoutUtility.GetRect(VramWidth, VramHeight, GUILayout.ExpandWidth(false));
|
Rect vramRect = GUILayoutUtility.GetRect(VramWidth, VramHeight, GUILayout.ExpandWidth(false));
|
||||||
EditorGUI.DrawPreviewTexture(vramRect, vramImage, null, ScaleMode.ScaleToFit, 0, 0, ColorWriteMask.All);
|
if (vramImage)
|
||||||
|
{
|
||||||
|
EditorGUI.DrawPreviewTexture(vramRect, vramImage, null, ScaleMode.ScaleToFit, 0, 0, ColorWriteMask.All);
|
||||||
|
}
|
||||||
|
|
||||||
// Draw framebuffer overlays.
|
// Draw framebuffer overlays.
|
||||||
(Rect buffer1, Rect buffer2) = Utils.BufferForResolution(selectedResolution, verticalLayout, vramRect.min);
|
(Rect buffer1, Rect buffer2) = Utils.BufferForResolution(selectedResolution, verticalLayout, vramRect.min);
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ namespace SplashEdit.RuntimeCode
|
|||||||
public PSXVertex v2;
|
public PSXVertex v2;
|
||||||
|
|
||||||
public PSXTexture2D Texture;
|
public PSXTexture2D Texture;
|
||||||
|
public readonly PSXVertex[] Vertexes => new PSXVertex[] { v0, v1, v2 };
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ using UnityEngine;
|
|||||||
|
|
||||||
namespace SplashEdit.RuntimeCode
|
namespace SplashEdit.RuntimeCode
|
||||||
{
|
{
|
||||||
[RequireComponent(typeof(MeshFilter))]
|
|
||||||
[RequireComponent(typeof(Renderer))]
|
[RequireComponent(typeof(Renderer))]
|
||||||
public class PSXObjectExporter : MonoBehaviour
|
public class PSXObjectExporter : MonoBehaviour
|
||||||
{
|
{
|
||||||
@@ -55,7 +54,6 @@ namespace SplashEdit.RuntimeCode
|
|||||||
if (renderer != null)
|
if (renderer != null)
|
||||||
{
|
{
|
||||||
Material[] materials = renderer.sharedMaterials;
|
Material[] materials = renderer.sharedMaterials;
|
||||||
Textures = new List<PSXTexture2D>(); // Ensure the list is initialized
|
|
||||||
|
|
||||||
foreach (Material mat in materials)
|
foreach (Material mat in materials)
|
||||||
{
|
{
|
||||||
@@ -84,17 +82,6 @@ namespace SplashEdit.RuntimeCode
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
//TODO: Better handle object with default texture
|
|
||||||
Texture = new PSXTexture2D()
|
|
||||||
{
|
|
||||||
BitDepth = BitDepth,
|
|
||||||
Width = 0,
|
|
||||||
Height = 0,
|
|
||||||
};
|
|
||||||
Texture.OriginalTexture = null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Texture2D ConvertToTexture2D(Texture texture)
|
private Texture2D ConvertToTexture2D(Texture texture)
|
||||||
@@ -123,11 +110,6 @@ namespace SplashEdit.RuntimeCode
|
|||||||
{
|
{
|
||||||
Mesh = PSXMesh.CreateFromUnityRenderer(renderer, GTEScaling, transform, Textures);
|
Mesh = PSXMesh.CreateFromUnityRenderer(renderer, GTEScaling, transform, Textures);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
// Dynamic meshes do not consider object transformation
|
|
||||||
Mesh = PSXMesh.CreateFromUnityMesh(meshFilter.sharedMesh, Texture.Width, Texture.Height);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -7,313 +8,296 @@ using UnityEngine;
|
|||||||
namespace SplashEdit.RuntimeCode
|
namespace SplashEdit.RuntimeCode
|
||||||
{
|
{
|
||||||
|
|
||||||
[ExecuteInEditMode]
|
[ExecuteInEditMode]
|
||||||
public class PSXSceneExporter : MonoBehaviour
|
public class PSXSceneExporter : MonoBehaviour
|
||||||
{
|
|
||||||
|
|
||||||
public float GTEScaling = 100.0f;
|
|
||||||
|
|
||||||
private PSXObjectExporter[] _exporters;
|
|
||||||
private TextureAtlas[] _atlases;
|
|
||||||
|
|
||||||
private PSXData _psxData;
|
|
||||||
|
|
||||||
private Vector2 selectedResolution;
|
|
||||||
private bool dualBuffering;
|
|
||||||
private bool verticalLayout;
|
|
||||||
private List<ProhibitedArea> prohibitedAreas;
|
|
||||||
|
|
||||||
public void Export()
|
|
||||||
{
|
{
|
||||||
_psxData = DataStorage.LoadData();
|
|
||||||
selectedResolution = _psxData.OutputResolution;
|
|
||||||
dualBuffering = _psxData.DualBuffering;
|
|
||||||
verticalLayout = _psxData.VerticalBuffering;
|
|
||||||
prohibitedAreas = _psxData.ProhibitedAreas;
|
|
||||||
|
|
||||||
_exporters = FindObjectsByType<PSXObjectExporter>(FindObjectsSortMode.None);
|
public float GTEScaling = 100.0f;
|
||||||
foreach (PSXObjectExporter exp in _exporters)
|
|
||||||
{
|
private PSXObjectExporter[] _exporters;
|
||||||
exp.CreatePSXTextures2D();
|
private TextureAtlas[] _atlases;
|
||||||
exp.CreatePSXMesh(GTEScaling);
|
|
||||||
}
|
|
||||||
PackTextures();
|
|
||||||
ExportFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
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()
|
||||||
VRAMPacker tp = new VRAMPacker(framebuffers, prohibitedAreas);
|
|
||||||
var packed = tp.PackTexturesIntoVRAM(_exporters);
|
|
||||||
_exporters = packed.processedObjects;
|
|
||||||
_atlases = packed.atlases;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExportFile()
|
|
||||||
{
|
|
||||||
|
|
||||||
string path = EditorUtility.SaveFilePanel("Select Output File", "", "output", "bin");
|
|
||||||
int totalFaces = 0;
|
|
||||||
|
|
||||||
// Lists for mesh data offsets.
|
|
||||||
List<long> offsetPlaceholderPositions = new List<long>();
|
|
||||||
List<long> meshDataOffsets = new List<long>();
|
|
||||||
|
|
||||||
// Lists for atlas data offsets.
|
|
||||||
List<long> atlasOffsetPlaceholderPositions = new List<long>();
|
|
||||||
List<long> atlasDataOffsets = new List<long>();
|
|
||||||
|
|
||||||
int clutCount = 0;
|
|
||||||
|
|
||||||
// Cluts
|
|
||||||
foreach (TextureAtlas atlas in _atlases)
|
|
||||||
{
|
|
||||||
foreach (var texture in atlas.ContainedTextures)
|
|
||||||
{
|
{
|
||||||
if (texture.ColorPalette != null)
|
_psxData = DataStorage.LoadData(out selectedResolution, out dualBuffering, out verticalLayout, out prohibitedAreas);
|
||||||
{
|
|
||||||
clutCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
using (BinaryWriter writer = new BinaryWriter(File.Open(path, FileMode.Create)))
|
_exporters = FindObjectsByType<PSXObjectExporter>(FindObjectsSortMode.None);
|
||||||
{
|
foreach (PSXObjectExporter exp in _exporters)
|
||||||
// Header
|
|
||||||
writer.Write('S');
|
|
||||||
writer.Write('P');
|
|
||||||
writer.Write((ushort)1);
|
|
||||||
writer.Write((ushort)_exporters.Length);
|
|
||||||
writer.Write((ushort)_atlases.Length);
|
|
||||||
writer.Write((ushort)clutCount);
|
|
||||||
writer.Write((ushort)0);
|
|
||||||
// Start of Metadata section
|
|
||||||
|
|
||||||
// GameObject section (exporters)
|
|
||||||
foreach (PSXObjectExporter exporter in _exporters)
|
|
||||||
{
|
|
||||||
// Write object's transform
|
|
||||||
writer.Write((int)PSXTrig.ConvertCoordinateToPSX(exporter.transform.localToWorldMatrix.GetPosition().x, GTEScaling));
|
|
||||||
writer.Write((int)PSXTrig.ConvertCoordinateToPSX(-exporter.transform.localToWorldMatrix.GetPosition().y, GTEScaling));
|
|
||||||
writer.Write((int)PSXTrig.ConvertCoordinateToPSX(exporter.transform.localToWorldMatrix.GetPosition().z, GTEScaling));
|
|
||||||
int[,] rotationMatrix = PSXTrig.ConvertRotationToPSXMatrix(exporter.transform.rotation);
|
|
||||||
|
|
||||||
writer.Write((int)rotationMatrix[0, 0]);
|
|
||||||
writer.Write((int)rotationMatrix[0, 1]);
|
|
||||||
writer.Write((int)rotationMatrix[0, 2]);
|
|
||||||
writer.Write((int)rotationMatrix[1, 0]);
|
|
||||||
writer.Write((int)rotationMatrix[1, 1]);
|
|
||||||
writer.Write((int)rotationMatrix[1, 2]);
|
|
||||||
writer.Write((int)rotationMatrix[2, 0]);
|
|
||||||
writer.Write((int)rotationMatrix[2, 1]);
|
|
||||||
writer.Write((int)rotationMatrix[2, 2]);
|
|
||||||
|
|
||||||
|
|
||||||
// Write placeholder for mesh data offset and record its position.
|
|
||||||
offsetPlaceholderPositions.Add(writer.BaseStream.Position);
|
|
||||||
writer.Write((int)0); // 4-byte placeholder for mesh data offset.
|
|
||||||
|
|
||||||
writer.Write((int)exporter.Mesh.Triangles.Count);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Atlas metadata section
|
|
||||||
foreach (TextureAtlas atlas in _atlases)
|
|
||||||
{
|
|
||||||
// Write placeholder for texture atlas raw data offset.
|
|
||||||
atlasOffsetPlaceholderPositions.Add(writer.BaseStream.Position);
|
|
||||||
writer.Write((int)0); // 4-byte placeholder for atlas data offset.
|
|
||||||
|
|
||||||
writer.Write((ushort)atlas.Width);
|
|
||||||
writer.Write((ushort)TextureAtlas.Height);
|
|
||||||
writer.Write((ushort)atlas.PositionX);
|
|
||||||
writer.Write((ushort)atlas.PositionY);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cluts
|
|
||||||
foreach (TextureAtlas atlas in _atlases)
|
|
||||||
{
|
|
||||||
foreach (var texture in atlas.ContainedTextures)
|
|
||||||
{
|
|
||||||
if (texture.ColorPalette != null)
|
|
||||||
{
|
{
|
||||||
foreach (VRAMPixel clutPixel in texture.ColorPalette)
|
exp.CreatePSXTextures2D();
|
||||||
{
|
exp.CreatePSXMesh(GTEScaling);
|
||||||
writer.Write((ushort)clutPixel.Pack());
|
}
|
||||||
}
|
PackTextures();
|
||||||
for (int i = texture.ColorPalette.Count; i < 256; i++)
|
ExportFile();
|
||||||
{
|
}
|
||||||
|
|
||||||
|
void PackTextures()
|
||||||
|
{
|
||||||
|
(Rect buffer1, Rect buffer2) = Utils.BufferForResolution(selectedResolution, verticalLayout);
|
||||||
|
|
||||||
|
List<Rect> framebuffers = new List<Rect> { buffer1 };
|
||||||
|
if (dualBuffering)
|
||||||
|
{
|
||||||
|
framebuffers.Add(buffer2);
|
||||||
|
}
|
||||||
|
|
||||||
|
VRAMPacker tp = new VRAMPacker(framebuffers, prohibitedAreas);
|
||||||
|
var packed = tp.PackTexturesIntoVRAM(_exporters);
|
||||||
|
_exporters = packed.processedObjects;
|
||||||
|
_atlases = packed.atlases;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void ExportFile()
|
||||||
|
{
|
||||||
|
|
||||||
|
string path = EditorUtility.SaveFilePanel("Select Output File", "", "output", "bin");
|
||||||
|
int totalFaces = 0;
|
||||||
|
|
||||||
|
// Lists for mesh data offsets.
|
||||||
|
List<long> offsetPlaceholderPositions = new List<long>();
|
||||||
|
List<long> meshDataOffsets = new List<long>();
|
||||||
|
|
||||||
|
// Lists for atlas data offsets.
|
||||||
|
List<long> atlasOffsetPlaceholderPositions = new List<long>();
|
||||||
|
List<long> atlasDataOffsets = new List<long>();
|
||||||
|
|
||||||
|
int clutCount = 0;
|
||||||
|
|
||||||
|
// Cluts
|
||||||
|
foreach (TextureAtlas atlas in _atlases)
|
||||||
|
{
|
||||||
|
foreach (var texture in atlas.ContainedTextures)
|
||||||
|
{
|
||||||
|
if (texture.ColorPalette != null)
|
||||||
|
{
|
||||||
|
clutCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
using (BinaryWriter writer = new BinaryWriter(File.Open(path, FileMode.Create)))
|
||||||
|
{
|
||||||
|
// Header
|
||||||
|
writer.Write('S');
|
||||||
|
writer.Write('P');
|
||||||
|
writer.Write((ushort)1);
|
||||||
|
writer.Write((ushort)_exporters.Length);
|
||||||
|
writer.Write((ushort)_atlases.Length);
|
||||||
|
writer.Write((ushort)clutCount);
|
||||||
writer.Write((ushort)0);
|
writer.Write((ushort)0);
|
||||||
}
|
// Start of Metadata section
|
||||||
writer.Write((ushort)texture.ClutPackingX);
|
|
||||||
writer.Write((ushort)texture.ClutPackingY);
|
// GameObject section (exporters)
|
||||||
writer.Write((ushort)texture.ColorPalette.Count);
|
foreach (PSXObjectExporter exporter in _exporters)
|
||||||
writer.Write((ushort)0);
|
{
|
||||||
|
// Write object's transform
|
||||||
|
writer.Write((int)PSXTrig.ConvertCoordinateToPSX(exporter.transform.localToWorldMatrix.GetPosition().x, GTEScaling));
|
||||||
|
writer.Write((int)PSXTrig.ConvertCoordinateToPSX(-exporter.transform.localToWorldMatrix.GetPosition().y, GTEScaling));
|
||||||
|
writer.Write((int)PSXTrig.ConvertCoordinateToPSX(exporter.transform.localToWorldMatrix.GetPosition().z, GTEScaling));
|
||||||
|
int[,] rotationMatrix = PSXTrig.ConvertRotationToPSXMatrix(exporter.transform.rotation);
|
||||||
|
|
||||||
|
writer.Write((int)rotationMatrix[0, 0]);
|
||||||
|
writer.Write((int)rotationMatrix[0, 1]);
|
||||||
|
writer.Write((int)rotationMatrix[0, 2]);
|
||||||
|
writer.Write((int)rotationMatrix[1, 0]);
|
||||||
|
writer.Write((int)rotationMatrix[1, 1]);
|
||||||
|
writer.Write((int)rotationMatrix[1, 2]);
|
||||||
|
writer.Write((int)rotationMatrix[2, 0]);
|
||||||
|
writer.Write((int)rotationMatrix[2, 1]);
|
||||||
|
writer.Write((int)rotationMatrix[2, 2]);
|
||||||
|
|
||||||
|
|
||||||
|
// Write placeholder for mesh data offset and record its position.
|
||||||
|
offsetPlaceholderPositions.Add(writer.BaseStream.Position);
|
||||||
|
writer.Write((int)0); // 4-byte placeholder for mesh data offset.
|
||||||
|
|
||||||
|
writer.Write((int)exporter.Mesh.Triangles.Count);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Atlas metadata section
|
||||||
|
foreach (TextureAtlas atlas in _atlases)
|
||||||
|
{
|
||||||
|
// Write placeholder for texture atlas raw data offset.
|
||||||
|
atlasOffsetPlaceholderPositions.Add(writer.BaseStream.Position);
|
||||||
|
writer.Write((int)0); // 4-byte placeholder for atlas data offset.
|
||||||
|
|
||||||
|
writer.Write((ushort)atlas.Width);
|
||||||
|
writer.Write((ushort)TextureAtlas.Height);
|
||||||
|
writer.Write((ushort)atlas.PositionX);
|
||||||
|
writer.Write((ushort)atlas.PositionY);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cluts
|
||||||
|
foreach (TextureAtlas atlas in _atlases)
|
||||||
|
{
|
||||||
|
foreach (var texture in atlas.ContainedTextures)
|
||||||
|
{
|
||||||
|
if (texture.ColorPalette != null)
|
||||||
|
{
|
||||||
|
foreach (VRAMPixel clutPixel in texture.ColorPalette)
|
||||||
|
{
|
||||||
|
writer.Write((ushort)clutPixel.Pack());
|
||||||
|
}
|
||||||
|
for (int i = texture.ColorPalette.Count; i < 256; i++)
|
||||||
|
{
|
||||||
|
writer.Write((ushort)0);
|
||||||
|
}
|
||||||
|
writer.Write((ushort)texture.ClutPackingX);
|
||||||
|
writer.Write((ushort)texture.ClutPackingY);
|
||||||
|
writer.Write((ushort)texture.ColorPalette.Count);
|
||||||
|
writer.Write((ushort)0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start of data section
|
||||||
|
|
||||||
|
// Mesh data section: Write mesh data for each exporter.
|
||||||
|
foreach (PSXObjectExporter exporter in _exporters)
|
||||||
|
{
|
||||||
|
AlignToFourBytes(writer);
|
||||||
|
// Record the current offset for this exporter's mesh data.
|
||||||
|
long meshDataOffset = writer.BaseStream.Position;
|
||||||
|
meshDataOffsets.Add(meshDataOffset);
|
||||||
|
|
||||||
|
totalFaces += exporter.Mesh.Triangles.Count;
|
||||||
|
|
||||||
|
void writeVertexPosition(PSXVertex v)
|
||||||
|
{
|
||||||
|
writer.Write((short)v.vx);
|
||||||
|
writer.Write((short)v.vy);
|
||||||
|
writer.Write((short)v.vz);
|
||||||
|
}
|
||||||
|
void writeVertexNormals(PSXVertex v)
|
||||||
|
{
|
||||||
|
writer.Write((short)v.nx);
|
||||||
|
writer.Write((short)v.ny);
|
||||||
|
writer.Write((short)v.nz);
|
||||||
|
}
|
||||||
|
void writeVertexColor(PSXVertex v)
|
||||||
|
{
|
||||||
|
writer.Write((byte)v.r);
|
||||||
|
writer.Write((byte)v.g);
|
||||||
|
writer.Write((byte)v.b);
|
||||||
|
writer.Write((byte)0); // padding
|
||||||
|
}
|
||||||
|
void writeVertexUV(PSXVertex v, PSXTexture2D t ,int expander)
|
||||||
|
{
|
||||||
|
writer.Write((byte)(v.u + t.PackingX * expander));
|
||||||
|
writer.Write((byte)(v.v + t.PackingY));
|
||||||
|
}
|
||||||
|
void foreachVertexDo(Tri tri, Action<PSXVertex> action)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < tri.Vertexes.Length; i++)
|
||||||
|
{
|
||||||
|
action(tri.Vertexes[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (Tri tri in exporter.Mesh.Triangles)
|
||||||
|
{
|
||||||
|
int expander = 16 / ((int)tri.Texture.BitDepth);
|
||||||
|
// Write vertices coordinates
|
||||||
|
foreachVertexDo(tri, (v) => writeVertexPosition(v));
|
||||||
|
|
||||||
|
// Write vertex normals for v0 only
|
||||||
|
writeVertexNormals(tri.v0);
|
||||||
|
|
||||||
|
// Write vertex colors with padding
|
||||||
|
foreachVertexDo(tri, (v) => writeVertexColor(v));
|
||||||
|
|
||||||
|
// Write UVs for each vertex, adjusting for texture packing
|
||||||
|
foreachVertexDo(tri, (v) => writeVertexUV(v, tri.Texture, expander));
|
||||||
|
|
||||||
|
writer.Write((ushort)0); // padding
|
||||||
|
|
||||||
|
|
||||||
|
TPageAttr tpage = new TPageAttr();
|
||||||
|
tpage.SetPageX(tri.Texture.TexpageX);
|
||||||
|
tpage.SetPageY(tri.Texture.TexpageY);
|
||||||
|
tpage.Set(tri.Texture.BitDepth.ToColorMode());
|
||||||
|
tpage.SetDithering(true);
|
||||||
|
writer.Write((ushort)tpage.info);
|
||||||
|
writer.Write((ushort)tri.Texture.ClutPackingX);
|
||||||
|
writer.Write((ushort)tri.Texture.ClutPackingY);
|
||||||
|
writer.Write((ushort)0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Atlas data section: Write raw texture data for each atlas.
|
||||||
|
foreach (TextureAtlas atlas in _atlases)
|
||||||
|
{
|
||||||
|
AlignToFourBytes(writer);
|
||||||
|
// Record the current offset for this atlas's data.
|
||||||
|
long atlasDataOffset = writer.BaseStream.Position;
|
||||||
|
atlasDataOffsets.Add(atlasDataOffset);
|
||||||
|
|
||||||
|
// Write the atlas's raw texture data.
|
||||||
|
for (int y = 0; y < atlas.vramPixels.GetLength(1); y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < atlas.vramPixels.GetLength(0); x++)
|
||||||
|
{
|
||||||
|
writer.Write(atlas.vramPixels[x, y].Pack());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backfill the mesh data offsets into the metadata section.
|
||||||
|
if (offsetPlaceholderPositions.Count == meshDataOffsets.Count)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < offsetPlaceholderPositions.Count; i++)
|
||||||
|
{
|
||||||
|
writer.Seek((int)offsetPlaceholderPositions[i], SeekOrigin.Begin);
|
||||||
|
writer.Write((int)meshDataOffsets[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogError("Mismatch between metadata mesh offset placeholders and mesh data blocks!");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Backfill the atlas data offsets into the metadata section.
|
||||||
|
if (atlasOffsetPlaceholderPositions.Count == atlasDataOffsets.Count)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < atlasOffsetPlaceholderPositions.Count; i++)
|
||||||
|
{
|
||||||
|
writer.Seek((int)atlasOffsetPlaceholderPositions[i], SeekOrigin.Begin);
|
||||||
|
writer.Write((int)atlasDataOffsets[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Debug.LogError("Mismatch between atlas offset placeholders and atlas data blocks!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
Debug.Log(totalFaces);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start of data section
|
void AlignToFourBytes(BinaryWriter writer)
|
||||||
|
|
||||||
// Mesh data section: Write mesh data for each exporter.
|
|
||||||
foreach (PSXObjectExporter exporter in _exporters)
|
|
||||||
{
|
{
|
||||||
AlignToFourBytes(writer);
|
long position = writer.BaseStream.Position;
|
||||||
// Record the current offset for this exporter's mesh data.
|
int padding = (int)(4 - (position % 4)) % 4; // Compute needed padding
|
||||||
long meshDataOffset = writer.BaseStream.Position;
|
writer.Write(new byte[padding]); // Write zero padding
|
||||||
meshDataOffsets.Add(meshDataOffset);
|
|
||||||
|
|
||||||
totalFaces += exporter.Mesh.Triangles.Count;
|
|
||||||
|
|
||||||
|
|
||||||
foreach (Tri tri in exporter.Mesh.Triangles)
|
|
||||||
{
|
|
||||||
int expander = 16 / ((int)tri.Texture.BitDepth);
|
|
||||||
// Write vertices coordinates
|
|
||||||
writer.Write((short)tri.v0.vx);
|
|
||||||
writer.Write((short)tri.v0.vy);
|
|
||||||
writer.Write((short)tri.v0.vz);
|
|
||||||
|
|
||||||
writer.Write((short)tri.v1.vx);
|
|
||||||
writer.Write((short)tri.v1.vy);
|
|
||||||
writer.Write((short)tri.v1.vz);
|
|
||||||
|
|
||||||
writer.Write((short)tri.v2.vx);
|
|
||||||
writer.Write((short)tri.v2.vy);
|
|
||||||
writer.Write((short)tri.v2.vz);
|
|
||||||
|
|
||||||
// Write vertex normals for v0 only
|
|
||||||
writer.Write((short)tri.v0.nx);
|
|
||||||
writer.Write((short)tri.v0.ny);
|
|
||||||
writer.Write((short)tri.v0.nz);
|
|
||||||
|
|
||||||
// Write vertex colors with padding
|
|
||||||
writer.Write((byte)tri.v0.r);
|
|
||||||
writer.Write((byte)tri.v0.g);
|
|
||||||
writer.Write((byte)tri.v0.b);
|
|
||||||
writer.Write((byte)0); // padding
|
|
||||||
|
|
||||||
writer.Write((byte)tri.v1.r);
|
|
||||||
writer.Write((byte)tri.v1.g);
|
|
||||||
writer.Write((byte)tri.v1.b);
|
|
||||||
writer.Write((byte)0); // padding
|
|
||||||
|
|
||||||
writer.Write((byte)tri.v2.r);
|
|
||||||
writer.Write((byte)tri.v2.g);
|
|
||||||
writer.Write((byte)tri.v2.b);
|
|
||||||
writer.Write((byte)0); // padding
|
|
||||||
|
|
||||||
// Write UVs for each vertex, adjusting for texture packing
|
|
||||||
writer.Write((byte)(tri.v0.u + tri.Texture.PackingX * expander));
|
|
||||||
writer.Write((byte)(tri.v0.v + tri.Texture.PackingY));
|
|
||||||
|
|
||||||
writer.Write((byte)(tri.v1.u + tri.Texture.PackingX * expander));
|
|
||||||
writer.Write((byte)(tri.v1.v + tri.Texture.PackingY));
|
|
||||||
|
|
||||||
writer.Write((byte)(tri.v2.u + tri.Texture.PackingX * expander));
|
|
||||||
writer.Write((byte)(tri.v2.v + tri.Texture.PackingY));
|
|
||||||
|
|
||||||
writer.Write((ushort)0); // padding
|
|
||||||
|
|
||||||
|
|
||||||
TPageAttr tpage = new TPageAttr();
|
|
||||||
tpage.SetPageX(tri.Texture.TexpageX);
|
|
||||||
tpage.SetPageY(tri.Texture.TexpageY);
|
|
||||||
switch (tri.Texture.BitDepth)
|
|
||||||
{
|
|
||||||
case PSXBPP.TEX_4BIT:
|
|
||||||
tpage.Set(TPageAttr.ColorMode.Mode4Bit);
|
|
||||||
break;
|
|
||||||
case PSXBPP.TEX_8BIT:
|
|
||||||
tpage.Set(TPageAttr.ColorMode.Mode8Bit);
|
|
||||||
break;
|
|
||||||
case PSXBPP.TEX_16BIT:
|
|
||||||
tpage.Set(TPageAttr.ColorMode.Mode16Bit);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
tpage.SetDithering(true);
|
|
||||||
writer.Write((ushort)tpage.info);
|
|
||||||
writer.Write((ushort)tri.Texture.ClutPackingX);
|
|
||||||
writer.Write((ushort)tri.Texture.ClutPackingY);
|
|
||||||
writer.Write((ushort)0);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Atlas data section: Write raw texture data for each atlas.
|
void OnDrawGizmos()
|
||||||
foreach (TextureAtlas atlas in _atlases)
|
|
||||||
{
|
{
|
||||||
AlignToFourBytes(writer);
|
|
||||||
// Record the current offset for this atlas's data.
|
|
||||||
long atlasDataOffset = writer.BaseStream.Position;
|
|
||||||
atlasDataOffsets.Add(atlasDataOffset);
|
|
||||||
|
|
||||||
// Write the atlas's raw texture data.
|
Gizmos.DrawIcon(transform.position, "Packages/net.psxsplash.splashedit/Icons/PSXSceneExporter.png", true);
|
||||||
for (int y = 0; y < atlas.vramPixels.GetLength(1); y++)
|
Vector3 sceneOrigin = new Vector3(0, 0, 0);
|
||||||
{
|
Vector3 cubeSize = new Vector3(8.0f * GTEScaling, 8.0f * GTEScaling, 8.0f * GTEScaling);
|
||||||
for (int x = 0; x < atlas.vramPixels.GetLength(0); x++)
|
Gizmos.color = Color.red;
|
||||||
{
|
Gizmos.DrawWireCube(sceneOrigin, cubeSize);
|
||||||
writer.Write(atlas.vramPixels[x, y].Pack());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Backfill the mesh data offsets into the metadata section.
|
|
||||||
if (offsetPlaceholderPositions.Count == meshDataOffsets.Count)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < offsetPlaceholderPositions.Count; i++)
|
|
||||||
{
|
|
||||||
writer.Seek((int)offsetPlaceholderPositions[i], SeekOrigin.Begin);
|
|
||||||
writer.Write((int)meshDataOffsets[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.LogError("Mismatch between metadata mesh offset placeholders and mesh data blocks!");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Backfill the atlas data offsets into the metadata section.
|
|
||||||
if (atlasOffsetPlaceholderPositions.Count == atlasDataOffsets.Count)
|
|
||||||
{
|
|
||||||
for (int i = 0; i < atlasOffsetPlaceholderPositions.Count; i++)
|
|
||||||
{
|
|
||||||
writer.Seek((int)atlasOffsetPlaceholderPositions[i], SeekOrigin.Begin);
|
|
||||||
writer.Write((int)atlasDataOffsets[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Debug.LogError("Mismatch between atlas offset placeholders and atlas data blocks!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Debug.Log(totalFaces);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AlignToFourBytes(BinaryWriter writer)
|
|
||||||
{
|
|
||||||
long position = writer.BaseStream.Position;
|
|
||||||
int padding = (int)(4 - (position % 4)) % 4; // Compute needed padding
|
|
||||||
writer.Write(new byte[padding]); // Write zero padding
|
|
||||||
}
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,7 +102,7 @@ namespace SplashEdit.RuntimeCode
|
|||||||
foreach (var texture in group.OrderByDescending(tex => tex.QuantizedWidth * tex.Height))
|
foreach (var texture in group.OrderByDescending(tex => tex.QuantizedWidth * tex.Height))
|
||||||
{
|
{
|
||||||
// Remove duplicate textures
|
// Remove duplicate textures
|
||||||
if (uniqueTextures.Where(tex => tex.OriginalTexture != null).Any(tex => tex.OriginalTexture.GetInstanceID() == obj.Texture.OriginalTexture.GetInstanceID() && tex.BitDepth == obj.Texture.BitDepth))
|
if (uniqueTextures.Any(tex => tex.OriginalTexture.GetInstanceID() == texture.OriginalTexture.GetInstanceID() && tex.BitDepth == texture.BitDepth))
|
||||||
{
|
{
|
||||||
// Skip packing this texture – it will be replaced later.
|
// Skip packing this texture – it will be replaced later.
|
||||||
continue;
|
continue;
|
||||||
|
|||||||
@@ -10,6 +10,26 @@ namespace SplashEdit.RuntimeCode
|
|||||||
public static class DataStorage
|
public static class DataStorage
|
||||||
{
|
{
|
||||||
private static readonly string psxDataPath = "Assets/PSXData.asset";
|
private static readonly string psxDataPath = "Assets/PSXData.asset";
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Loads stored PSX data from the asset.
|
||||||
|
/// </summary>
|
||||||
|
public static PSXData LoadData(out Vector2 selectedResolution, out bool dualBuffering, out bool verticalLayout, out List<ProhibitedArea> prohibitedAreas)
|
||||||
|
{
|
||||||
|
var _psxData = AssetDatabase.LoadAssetAtPath<PSXData>(psxDataPath);
|
||||||
|
if (!_psxData)
|
||||||
|
{
|
||||||
|
_psxData = ScriptableObject.CreateInstance<PSXData>();
|
||||||
|
AssetDatabase.CreateAsset(_psxData, psxDataPath);
|
||||||
|
AssetDatabase.SaveAssets();
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedResolution = _psxData.OutputResolution;
|
||||||
|
dualBuffering = _psxData.DualBuffering;
|
||||||
|
verticalLayout = _psxData.VerticalBuffering;
|
||||||
|
prohibitedAreas = _psxData.ProhibitedAreas;
|
||||||
|
return _psxData;
|
||||||
|
}
|
||||||
public static PSXData LoadData()
|
public static PSXData LoadData()
|
||||||
{
|
{
|
||||||
PSXData psxData = AssetDatabase.LoadAssetAtPath<PSXData>(psxDataPath);
|
PSXData psxData = AssetDatabase.LoadAssetAtPath<PSXData>(psxDataPath);
|
||||||
@@ -288,8 +308,6 @@ namespace SplashEdit.RuntimeCode
|
|||||||
|
|
||||||
public static class Utils
|
public static class Utils
|
||||||
{
|
{
|
||||||
private static string _psxDataPath = "Assets/PSXData.asset";
|
|
||||||
|
|
||||||
public static (Rect, Rect) BufferForResolution(Vector2 selectedResolution, bool verticalLayout, Vector2 offset = default)
|
public static (Rect, Rect) BufferForResolution(Vector2 selectedResolution, bool verticalLayout, Vector2 offset = default)
|
||||||
{
|
{
|
||||||
if (offset == default)
|
if (offset == default)
|
||||||
@@ -302,24 +320,15 @@ namespace SplashEdit.RuntimeCode
|
|||||||
return (buffer1, buffer2);
|
return (buffer1, buffer2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
public static TPageAttr.ColorMode ToColorMode(this PSXBPP depth)
|
||||||
/// Loads stored PSX data from the asset.
|
|
||||||
/// </summary>
|
|
||||||
public static PSXData LoadData(out Vector2 selectedResolution, out bool dualBuffering, out bool verticalLayout, out List<ProhibitedArea> prohibitedAreas)
|
|
||||||
{
|
{
|
||||||
var _psxData = AssetDatabase.LoadAssetAtPath<PSXData>(_psxDataPath);
|
return depth switch
|
||||||
if (!_psxData)
|
|
||||||
{
|
{
|
||||||
_psxData = ScriptableObject.CreateInstance<PSXData>();
|
PSXBPP.TEX_4BIT => TPageAttr.ColorMode.Mode4Bit,
|
||||||
AssetDatabase.CreateAsset(_psxData, _psxDataPath);
|
PSXBPP.TEX_8BIT => TPageAttr.ColorMode.Mode8Bit,
|
||||||
AssetDatabase.SaveAssets();
|
PSXBPP.TEX_16BIT => TPageAttr.ColorMode.Mode16Bit,
|
||||||
}
|
_ => throw new System.NotImplementedException(),
|
||||||
|
};
|
||||||
selectedResolution = _psxData.OutputResolution;
|
|
||||||
dualBuffering = _psxData.DualBuffering;
|
|
||||||
verticalLayout = _psxData.VerticalBuffering;
|
|
||||||
prohibitedAreas = _psxData.ProhibitedAreas;
|
|
||||||
return _psxData;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user