Updated Splashpack structure, added imhex project

This commit is contained in:
2025-04-03 17:52:14 +02:00
parent 6c1a0854c7
commit fa747ad786
5 changed files with 115 additions and 60 deletions

View File

@@ -62,13 +62,17 @@ namespace SplashEdit.RuntimeCode
int totalFaces = 0; int totalFaces = 0;
// Lists for mesh data offsets. // Lists for mesh data offsets.
List<long> offsetPlaceholderPositions = new List<long>(); List<long> meshOffsetPlaceholderPositions = new List<long>();
List<long> meshDataOffsets = new List<long>(); List<long> meshDataOffsets = new List<long>();
// Lists for atlas data offsets. // Lists for atlas data offsets.
List<long> atlasOffsetPlaceholderPositions = new List<long>(); List<long> atlasOffsetPlaceholderPositions = new List<long>();
List<long> atlasDataOffsets = new List<long>(); List<long> atlasDataOffsets = new List<long>();
// Lists for clut data offsets.
List<long> clutOffsetPlaceholderPositions = new List<long>();
List<long> clutDataOffsets = new List<long>();
int clutCount = 0; int clutCount = 0;
// Cluts // Cluts
@@ -86,18 +90,21 @@ namespace SplashEdit.RuntimeCode
using (BinaryWriter writer = new BinaryWriter(File.Open(path, FileMode.Create))) using (BinaryWriter writer = new BinaryWriter(File.Open(path, FileMode.Create)))
{ {
// Header // Header
writer.Write('S'); writer.Write('S'); // 1 byte
writer.Write('P'); writer.Write('P'); // 1 byte
writer.Write((ushort)1); writer.Write((ushort)1); // 2 bytes - version
writer.Write((ushort)_exporters.Length); writer.Write((ushort)_exporters.Length); // 2 bytes
writer.Write((ushort)_atlases.Length); writer.Write((ushort)_atlases.Length); // 2 bytes
writer.Write((ushort)clutCount); writer.Write((ushort)clutCount); // 2 bytes
writer.Write((ushort)0); for (int i = 0; i < 3; i++) writer.Write((ushort)0);
// Start of Metadata section
// GameObject section (exporters) // GameObject section (exporters)
foreach (PSXObjectExporter exporter in _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 // Write object's transform
writer.Write((int)PSXTrig.ConvertCoordinateToPSX(exporter.transform.localToWorldMatrix.GetPosition().x, GTEScaling)); 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().y, GTEScaling));
@@ -114,12 +121,8 @@ namespace SplashEdit.RuntimeCode
writer.Write((int)rotationMatrix[2, 1]); writer.Write((int)rotationMatrix[2, 1]);
writer.Write((int)rotationMatrix[2, 2]); writer.Write((int)rotationMatrix[2, 2]);
writer.Write((ushort)exporter.Mesh.Triangles.Count);
// Write placeholder for mesh data offset and record its position. writer.Write((ushort) 0);
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 // Atlas metadata section
@@ -142,18 +145,12 @@ namespace SplashEdit.RuntimeCode
{ {
if (texture.ColorPalette != null) if (texture.ColorPalette != null)
{ {
foreach (VRAMPixel clutPixel in texture.ColorPalette) clutOffsetPlaceholderPositions.Add(writer.BaseStream.Position);
{ writer.Write((int)0); // 4-byte placeholder for clut data offset.
writer.Write((ushort)clutPixel.Pack()); writer.Write((ushort)texture.ClutPackingX); // 2 bytes
} writer.Write((ushort)texture.ClutPackingY); // 2 bytes
for (int i = texture.ColorPalette.Count; i < 256; i++) writer.Write((ushort)texture.ColorPalette.Count); // 2 bytes
{ writer.Write((ushort) 0); // 2 bytes
writer.Write((ushort)0);
}
writer.Write((ushort)texture.ClutPackingX);
writer.Write((ushort)texture.ClutPackingY);
writer.Write((ushort)texture.ColorPalette.Count);
writer.Write((ushort)0);
} }
} }
} }
@@ -249,12 +246,31 @@ namespace SplashEdit.RuntimeCode
} }
} }
// Clut data section
foreach (TextureAtlas atlas in _atlases)
{
foreach (var texture in atlas.ContainedTextures)
{
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. // Backfill the mesh data offsets into the metadata section.
if (offsetPlaceholderPositions.Count == meshDataOffsets.Count) if (meshOffsetPlaceholderPositions.Count == meshDataOffsets.Count)
{ {
for (int i = 0; i < offsetPlaceholderPositions.Count; i++) for (int i = 0; i < meshOffsetPlaceholderPositions.Count; i++)
{ {
writer.Seek((int)offsetPlaceholderPositions[i], SeekOrigin.Begin); writer.Seek((int)meshOffsetPlaceholderPositions[i], SeekOrigin.Begin);
writer.Write((int)meshDataOffsets[i]); writer.Write((int)meshDataOffsets[i]);
} }
} }
@@ -276,6 +292,20 @@ namespace SplashEdit.RuntimeCode
{ {
Debug.LogError("Mismatch between atlas offset placeholders and atlas data blocks!"); 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); Debug.Log(totalFaces);
} }

View File

@@ -4,7 +4,7 @@ All numeric values are stored in littleendian format. All offsets are counted
--- ---
## 1. File Header (12 bytes) ## 1. File Header (16 bytes)
| Offset | Size | Type | Description | | Offset | Size | Type | Description |
| ------ | ---- | ------ | ----------------------------------- | | ------ | ---- | ------ | ----------------------------------- |
@@ -13,7 +13,7 @@ All numeric values are stored in littleendian format. All offsets are counted
| 0x04 | 2 | uint16 | Number of Exporter descriptors | | 0x04 | 2 | uint16 | Number of Exporter descriptors |
| 0x06 | 2 | uint16 | Number of Texture Atlas descriptors | | 0x06 | 2 | uint16 | Number of Texture Atlas descriptors |
| 0x08 | 2 | uint16 | Number of CLUT 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 littleendian format. All offsets are counted
The metadata section comprises three groups of descriptors. 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 | | Offset (per entry) | Size | Type | Description |
| ------------------ | ---- | ------ | --------------------------------- | | ------------------ | ---- | ------ | --------------------------------- |
| 0x00 | 4 | int | X coordinate (Fixed-point) | | 0x00 | 4 | int | **Mesh Data Offset** |
| 0x04 | 4 | int | Y coordinate (Fixed-point) | | 0x04 | 4 | int | X coordinate (Fixed-point) |
| 0x08 | 4 | int | Z coordinate (Fixed-point) | | 0x08 | 4 | int | Y coordinate (Fixed-point) |
| 0x0C | 36 | int[9] | 3×3 Rotation matrix (Fixed-point) | | 0x0C | 4 | int | Z coordinate (Fixed-point) |
| 0x30 | 4 | int | **Mesh Data Offset Placeholder** | | 0x10 | 36 | int[9] | 3×3 Rotation matrix (Fixed-point) |
| 0x34 | 4 | int | Triangle count in the mesh | | 0x28 | 4 | uint16 | Triangle count in the mesh |
| 0x2A | 2 | uint16 | Reserved |
### 2.2 Texture Atlas Descriptors (12 bytes each) ### 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 | | 0x08 | 2 | uint16 | Atlas position X relative to VRAM origin |
| 0x0A | 2 | uint16 | Atlas position Y 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. 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: For each CLUT (Color Lookup Table) associated with an atlas texture that has a palette:
| Offset (per entry) | Size | Type | Description | | Offset (per entry) | Size | Type | Description |
| ------------------ | ---- | ----------- | --------------------------------------------------------------------------------- | | ------------------ | ---- | ------ | ----------------------------------------------------- |
| 0x00 | 512 | uint16[256] | Color palette entries (each entry is 2 bytes 16bpp). If unused, entries are zero. | | 0x00 | 4 | int | **Clut Data Offset Placeholder** |
| 0x200 | 2 | uint16 | CLUT packing X coordinate - already in 16 pixel steps | | 0x04 | 2 | uint16 | CLUT packing X coordinate - already in 16 pixel steps |
| 0x202 | 2 | uint16 | CLUT packing Y coordinate | | 0x06 | 2 | uint16 | CLUT packing Y coordinate |
| 0x204 | 2 | uint16 | Palette count (number of valid palette entries) | | 0x08 | 2 | uint16 | Palette count (number of valid palette entries) |
| 0x206 | 2 | uint16 | Reserved (always 0) | | 0x0A | 2 | uint16 | Reserved (always 0) |
--- ---
@@ -72,22 +73,31 @@ For each exporter, a mesh data block is written at the offset specified in its d
#### **Triangle Data Layout (per triangle 52 bytes total):** #### **Triangle Data Layout (per triangle 52 bytes total):**
| Field | Size | Description | | Field | Size | Description |
| ----------------------------- | -------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | ----------------------------- | -------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| **Vertex Coordinates** | 3 vertices × 3 × 2 bytes = 18 bytes | For each vertex (v0, v1, v2): X, Y, Z coordinates (int16) | | **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 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 | | **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 | | **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) | | **UV Padding** | 2 bytes | Padding (uint16, set to zero) |
| **Texture Attributes** | 2 + 2 + 2 + 2 = 8 bytes | Contains: <br> • Texture page attributes (uint16 encoded from page X/Y, bit depth, dithering)<br> • Texture CLUT packing X (uint16)<br> • Texture CLUT packing Y (uint16)<br> • Reserved (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 ### 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:** - **Raw Texture Data:**
The atlas data is written pixel by pixel as returned by the pixel packing function. The total size equals 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. *(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.
--- ---

8
tools.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: cf7149f85c29d3f4d9a7f968d8825ffa
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

BIN
tools/imhex.hexproj Normal file

Binary file not shown.

7
tools/imhex.hexproj.meta Normal file
View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 871e1f08910e9f329ad3fce5d77c8785
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: