From fa747ad786ecc0b46980ba38f946cd437c5b1ae5 Mon Sep 17 00:00:00 2001 From: jracek Date: Thu, 3 Apr 2025 17:52:14 +0200 Subject: [PATCH] Updated Splashpack structure, added imhex project --- Runtime/PSXSceneExporter.cs | 94 ++++++++++++++++++++++++------------ doc/splashbundle.md | 66 ++++++++++++++----------- tools.meta | 8 +++ tools/imhex.hexproj | Bin 0 -> 18944 bytes tools/imhex.hexproj.meta | 7 +++ 5 files changed, 115 insertions(+), 60 deletions(-) create mode 100644 tools.meta create mode 100644 tools/imhex.hexproj create mode 100644 tools/imhex.hexproj.meta diff --git a/Runtime/PSXSceneExporter.cs b/Runtime/PSXSceneExporter.cs index dd88b01..b9ebfa9 100644 --- a/Runtime/PSXSceneExporter.cs +++ b/Runtime/PSXSceneExporter.cs @@ -62,13 +62,17 @@ namespace SplashEdit.RuntimeCode int totalFaces = 0; // Lists for mesh data offsets. - List offsetPlaceholderPositions = new List(); + List meshOffsetPlaceholderPositions = new List(); List meshDataOffsets = new List(); // Lists for atlas data offsets. List atlasOffsetPlaceholderPositions = new List(); List atlasDataOffsets = new List(); + // Lists for clut data offsets. + List clutOffsetPlaceholderPositions = new List(); + List clutDataOffsets = new List(); + int clutCount = 0; // Cluts @@ -86,18 +90,21 @@ namespace SplashEdit.RuntimeCode 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); - // Start of Metadata section + writer.Write('S'); // 1 byte + writer.Write('P'); // 1 byte + writer.Write((ushort)1); // 2 bytes - version + writer.Write((ushort)_exporters.Length); // 2 bytes + writer.Write((ushort)_atlases.Length); // 2 bytes + writer.Write((ushort)clutCount); // 2 bytes + for (int i = 0; i < 3; i++) writer.Write((ushort)0); // GameObject section (exporters) foreach (PSXObjectExporter exporter in _exporters) { + // Write placeholder for mesh data offset and record its position. + meshOffsetPlaceholderPositions.Add(writer.BaseStream.Position); + writer.Write((int)0); // 4-byte placeholder for mesh data offset. + // 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)); @@ -114,12 +121,8 @@ namespace SplashEdit.RuntimeCode 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); + writer.Write((ushort)exporter.Mesh.Triangles.Count); + writer.Write((ushort) 0); } // Atlas metadata section @@ -142,18 +145,12 @@ namespace SplashEdit.RuntimeCode { 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); + clutOffsetPlaceholderPositions.Add(writer.BaseStream.Position); + writer.Write((int)0); // 4-byte placeholder for clut data offset. + writer.Write((ushort)texture.ClutPackingX); // 2 bytes + writer.Write((ushort)texture.ClutPackingY); // 2 bytes + writer.Write((ushort)texture.ColorPalette.Count); // 2 bytes + writer.Write((ushort) 0); // 2 bytes } } } @@ -189,7 +186,7 @@ namespace SplashEdit.RuntimeCode writer.Write((byte)v.b); writer.Write((byte)0); // padding } - void writeVertexUV(PSXVertex v, PSXTexture2D t ,int expander) + void writeVertexUV(PSXVertex v, PSXTexture2D t, int expander) { writer.Write((byte)(v.u + t.PackingX * expander)); writer.Write((byte)(v.v + t.PackingY)); @@ -249,12 +246,31 @@ namespace SplashEdit.RuntimeCode } } - // Backfill the mesh data offsets into the metadata section. - if (offsetPlaceholderPositions.Count == meshDataOffsets.Count) + // Clut data section + foreach (TextureAtlas atlas in _atlases) { - for (int i = 0; i < offsetPlaceholderPositions.Count; i++) + foreach (var texture in atlas.ContainedTextures) { - writer.Seek((int)offsetPlaceholderPositions[i], SeekOrigin.Begin); + if (texture.ColorPalette != null) + { + AlignToFourBytes(writer); + long clutDataOffset = writer.BaseStream.Position; + clutDataOffsets.Add(clutDataOffset); + + foreach(VRAMPixel color in texture.ColorPalette) { + writer.Write((ushort) color.Pack()); + } + } + } + + } + + // Backfill the mesh data offsets into the metadata section. + if (meshOffsetPlaceholderPositions.Count == meshDataOffsets.Count) + { + for (int i = 0; i < meshOffsetPlaceholderPositions.Count; i++) + { + writer.Seek((int)meshOffsetPlaceholderPositions[i], SeekOrigin.Begin); writer.Write((int)meshDataOffsets[i]); } } @@ -276,6 +292,20 @@ namespace SplashEdit.RuntimeCode { Debug.LogError("Mismatch between atlas offset placeholders and atlas data blocks!"); } + + // Backfill the clut data offsets into the metadata section. + if (clutOffsetPlaceholderPositions.Count == clutDataOffsets.Count) + { + for (int i = 0; i < clutOffsetPlaceholderPositions.Count; i++) + { + writer.Seek((int)clutOffsetPlaceholderPositions[i], SeekOrigin.Begin); + writer.Write((int)clutDataOffsets[i]); + } + } + else + { + Debug.LogError("Mismatch between clut offset placeholders and clut data blocks!"); + } } Debug.Log(totalFaces); } diff --git a/doc/splashbundle.md b/doc/splashbundle.md index e91cc8a..4b03159 100644 --- a/doc/splashbundle.md +++ b/doc/splashbundle.md @@ -4,7 +4,7 @@ All numeric values are stored in little‐endian format. All offsets are counted --- -## 1. File Header (12 bytes) +## 1. File Header (16 bytes) | Offset | Size | Type | Description | | ------ | ---- | ------ | ----------------------------------- | @@ -13,7 +13,7 @@ All numeric values are stored in little‐endian format. All offsets are counted | 0x04 | 2 | uint16 | Number of Exporter descriptors | | 0x06 | 2 | uint16 | Number of Texture Atlas descriptors | | 0x08 | 2 | uint16 | Number of CLUT descriptors | -| 0x0A | 2 | uint16 | Reserved (always 0) | +| 0x0A | 3*2 | uint16 | Reserved (always 0) | --- @@ -21,18 +21,19 @@ All numeric values are stored in little‐endian format. All offsets are counted The metadata section comprises three groups of descriptors. -### 2.1 Exporter Descriptors (56 bytes each) +### 2.1 GameObject Descriptors (56 bytes each) -Each exporter descriptor stores the transform and mesh metadata for one GameObject. +Each gameobject descriptor stores the transform and mesh metadata for one GameObject. | Offset (per entry) | Size | Type | Description | | ------------------ | ---- | ------ | --------------------------------- | -| 0x00 | 4 | int | X coordinate (Fixed-point) | -| 0x04 | 4 | int | Y coordinate (Fixed-point) | -| 0x08 | 4 | int | Z coordinate (Fixed-point) | -| 0x0C | 36 | int[9] | 3×3 Rotation matrix (Fixed-point) | -| 0x30 | 4 | int | **Mesh Data Offset Placeholder** | -| 0x34 | 4 | int | Triangle count in the mesh | +| 0x00 | 4 | int | **Mesh Data Offset** | +| 0x04 | 4 | int | X coordinate (Fixed-point) | +| 0x08 | 4 | int | Y coordinate (Fixed-point) | +| 0x0C | 4 | int | Z coordinate (Fixed-point) | +| 0x10 | 36 | int[9] | 3×3 Rotation matrix (Fixed-point) | +| 0x28 | 4 | uint16 | Triangle count in the mesh | +| 0x2A | 2 | uint16 | Reserved | ### 2.2 Texture Atlas Descriptors (12 bytes each) @@ -46,18 +47,18 @@ Each texture atlas descriptor holds atlas layout data and a placeholder for the | 0x08 | 2 | uint16 | Atlas position X – relative to VRAM origin | | 0x0A | 2 | uint16 | Atlas position Y – relative to VRAM origin | -### 2.3 CLUT Descriptors (520 bytes each) +### 2.3 CLUT Descriptors (12 bytes each) CLUTs are the only data which is stored in the Metadata section. For each CLUT (Color Lookup Table) associated with an atlas texture that has a palette: -| Offset (per entry) | Size | Type | Description | -| ------------------ | ---- | ----------- | --------------------------------------------------------------------------------- | -| 0x00 | 512 | uint16[256] | Color palette entries (each entry is 2 bytes 16bpp). If unused, entries are zero. | -| 0x200 | 2 | uint16 | CLUT packing X coordinate - already in 16 pixel steps | -| 0x202 | 2 | uint16 | CLUT packing Y coordinate | -| 0x204 | 2 | uint16 | Palette count (number of valid palette entries) | -| 0x206 | 2 | uint16 | Reserved (always 0) | +| Offset (per entry) | Size | Type | Description | +| ------------------ | ---- | ------ | ----------------------------------------------------- | +| 0x00 | 4 | int | **Clut Data Offset Placeholder** | +| 0x04 | 2 | uint16 | CLUT packing X coordinate - already in 16 pixel steps | +| 0x06 | 2 | uint16 | CLUT packing Y coordinate | +| 0x08 | 2 | uint16 | Palette count (number of valid palette entries) | +| 0x0A | 2 | uint16 | Reserved (always 0) | --- @@ -71,23 +72,32 @@ For each exporter, a mesh data block is written at the offset specified in its d #### **Triangle Data Layout (per triangle – 52 bytes total):** -| Field | Size | Description | -| ----------------------------- | -------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| **Vertex Coordinates** | 3 vertices × 3 × 2 bytes = 18 bytes | For each vertex (v0, v1, v2): X, Y, Z coordinates (int16) | -| **Vertex Normal** | 3 × 2 bytes = 6 bytes | Normal vector for vertex v0 (int16: nx, ny, nz) | -| **Vertex Colors** | 3 vertices × (3 bytes color + 1 byte padding) = 12 bytes | For each vertex (v0, v1, v2): Red, Green, Blue (uint8) plus 1 byte padding | -| **Texture Coordinates (UVs)** | 3 vertices × 2 bytes = 6 bytes | For each vertex (v0, v1, v2): U and V coordinates (uint8), adjusted by texture packing factors | -| **UV Padding** | 2 bytes | Padding (uint16, set to zero) | -| **Texture Attributes** | 2 + 2 + 2 + 2 = 8 bytes | Contains:
• Texture page attributes (uint16 – encoded from page X/Y, bit depth, dithering)
• Texture CLUT packing X (uint16)
• Texture CLUT packing Y (uint16)
• Reserved (uint16, set to zero) | +| Field | Size | Description | +| ----------------------------- | -------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | +| **Vertex Coordinates** | 3 vertices × 3 × 2 bytes = 18 bytes | For each vertex (v0, v1, v2): X, Y, Z coordinates (int16) | +| **Vertex Normal** | 3 × 2 bytes = 6 bytes | Normal vector for vertex v0 (int16: nx, ny, nz) | +| **Vertex Colors** | 3 vertices × (3 bytes color + 1 byte padding) = 12 bytes | For each vertex (v0, v1, v2): Red, Green, Blue (uint8) plus 1 byte padding | +| **Texture Coordinates (UVs)** | 3 vertices × 2 bytes = 6 bytes | For each vertex (v0, v1, v2): U and V coordinates (uint8), adjusted by texture packing factors | +| **UV Padding** | 2 bytes | Padding (uint16, set to zero) | +| **Texture Attributes** | 2 bytes | The TPage attribute for the given polygon | +| **Clut X** | 2 bytes | Clut position within VRAM (already predivided by 16) | +| **Clut Y** | 2 bytes | Clut position within VRAM | +| **Padding** | 2 bytes | | + + -*Triangles are written sequentially. Prior to writing each mesh data block, the file pointer is aligned to a 4-byte boundary.* ### 3.2 Atlas Data Blocks -For each atlas, a raw texture data block is written at the offset specified in its descriptor. Before writing, the file pointer is aligned to a 4-byte boundary. +For each atlas, a raw texture data block is written at the offset specified in its descriptor - **Raw Texture Data:** The atlas data is written pixel by pixel as returned by the pixel packing function. The total size equals *(Atlas Width × Atlas Height)* The data is prepared for a DMA transfer to the VRAM. + +### 3.3 Clut Data Blocks + +For each clut, a raw pixel data block is written at the offset specified in its descriptor as an array of `uint16` colors already formatted for the VRAM. + --- diff --git a/tools.meta b/tools.meta new file mode 100644 index 0000000..b76e2a1 --- /dev/null +++ b/tools.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: cf7149f85c29d3f4d9a7f968d8825ffa +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/tools/imhex.hexproj b/tools/imhex.hexproj new file mode 100644 index 0000000000000000000000000000000000000000..b57631c16288f7dabee6dadb63e17351efa91c6c GIT binary patch literal 18944 zcmeHOUvJws5cjh`h2W=kHDt-MTT_cJwT$fFmIZ? zcsEo)*{acdB+T(p5a4iwJJjhv#Q%nAsrbJ`mk80q|C2NfBIg0St;7GI3IDCBP@@+A z&+XYv;eTnJ?n*iSBggac4sUUouuy-gAiq14_e!#9cCXIA$A8l@rwaeO_sn2mniDvW zCzymQ8l}X+D<^WX4rgp2x1>N5{!izYNC3&PzF{oj1fcN0CG&q(OnRm{Q5wPo&|YcA z`EWR-2}zwq`-7)qV&pu$!w3?@d0q(O1)^=y#&?#}yK{a#NKISYK?d26!jiCo6wrtD zC+sAbOnljp;C+%3e33w=r`F^IX`LHVPnhhmyR=}iCr~ff?jt53DA$RC0{d(PRy>r& z$4aNmD2R&pfcGZj&3K(FcBaM1tuX)jF_#XU>3COZyCHtwnCr0v%dxyzQ8la8X{8!Q zWQ&4~l&RzxW6d$)H)n*g(;d{)-IV>YGG1oqba&14WMi>v5A!%70;&DRNG?ey+H~3aDNXO!At}N`u;kiW$jR@JyvQYO0G~s{QdG5X?g$wg_{6N z4riX?nz46b1_d6vtT5hbueHSUsa{u0ng}=2bUJz+CQ^PCX0pG1H}S?E_BWn1EBE7k z)-aaX-{XLpVab_)&X|QZvQ$ZvOR)Np2Fw+84H)ej))nMiZ%Z#pRLOVjXqI>-m#~H1)F8{aQ2j2F&6T42sfAjrxx`y8o%({RId;noDfmM||DW zWhq{-!2we;mtPL~@>MaCB!ms}1s}^Of-57*EquB?GnUMcDI4yxbR@H3MLHvVi&Wn6 z#rapEw-=2n{_BMs{x>Bc{&NB8R(^QTwxt9%@zxUnP4S;;EJOyl8vohGRNeobWKMkM z8_7t%Q6y9^=p@eC=8>7PaM_&!6TOL`qnI`v|<|wv`y!>)PzH{ z4zQc|;c66Dch70V<4@?ADbE6k(RWBIa^LbAXiYf5L1r7zj~fiQCM*^S^GjBJ-e@DK z0k&2M*+ENFB2u)C16)|!vd`?U(5jjeUr->SiTCQRXf&m3}MbpZc8NIwKD1+gM&fIBz^G~vJW@t^wVe`eNP z;r}V7!t(AEqo^_ZY5|4+ef7*~^kVoAU%BZ5_QeY{;(ufOZ`thgzbgJ0ChV+G-2d=7 zpprkG*}1QR75?|tGpErD@Sk4^cJ$R>{t}J&Z})Ck literal 0 HcmV?d00001 diff --git a/tools/imhex.hexproj.meta b/tools/imhex.hexproj.meta new file mode 100644 index 0000000..d51da29 --- /dev/null +++ b/tools/imhex.hexproj.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 871e1f08910e9f329ad3fce5d77c8785 +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: