Sprites in .obj files are composed of Y null-separated records with a probable type field
This commit is contained in:
@@ -115,11 +115,6 @@ For sanity checks, we can ensure that:
|
||||
|
||||
## Sprite structure
|
||||
|
||||
If the `type` field of an `.asn` field *does* tell us how to interpret sprite
|
||||
data, I'll need to split this up per type. For now, I'm investigating a small
|
||||
number of files in depth, and comparing across files in a shallow manner, so all
|
||||
I need to do is manually select sets with the same type in the latter case.
|
||||
|
||||
First, the `blank.obj` file. `blank.asn` helpfully tells us that it's a single-
|
||||
pixel tile and assigns it a type of 13. There are six sprites, all of which are
|
||||
identical. Data dump:
|
||||
@@ -148,14 +143,6 @@ The colour itself doesn't show up in the data directly, so it's not a simple RGB
|
||||
array of pixels. WH40K_TD.exe is a 256-colour application, so the pixel data may
|
||||
account for 1 of the 3 bytes.
|
||||
|
||||
All sprites seem to end with 0x00 - like a GIF image descriptor, this may say
|
||||
"end of data".
|
||||
|
||||
So what's the 1? Simple RLE, like FLIC type 15 BYTE_RUN? - "Repeat 253 one time"?
|
||||
|
||||
There are 45 `TYPE 13` .obj files in the game. Comparing the above with the
|
||||
start of the second sprite in `pillar.obj`:
|
||||
|
||||
```
|
||||
----------------------------------------------
|
||||
0 1 2 3 4 5 6 7 01234567
|
||||
@@ -213,32 +200,6 @@ close correspondence in all cases.
|
||||
WH40K_TD.exe crashes trying to load a set referencing `pillar` in it unless it's
|
||||
in the CENTER position. Interesting.
|
||||
|
||||
Not all pixeldatas are evenly divisible by 3. blank.obj seems to be the special
|
||||
case.
|
||||
|
||||
The volume represented by a cell is a little odd. We see three faces of a fake
|
||||
3D volume of size 64x64x32(ish). This is presented in an isomorphic fashion, so
|
||||
the height is 32px at the leftmost and rightmost extents and 96 in the centre.
|
||||
Overall width is 128px, and the minimum rectangle covering the whole space would
|
||||
be 128x96, or 12288 bytes at 8bpp.
|
||||
|
||||
Or it could be represented as the three planes separately. So for an altar, we'd
|
||||
have 64x64 pixels, plus 32x64 pixels, plus 32x64 pixels (minus a few around the
|
||||
edges, perhaps) - 4096 + 2048 + 2048 = 8192. The sprite is only slightly smaller
|
||||
than that.
|
||||
|
||||
Or perhaps we draw a normal X/Y rectangle which is then skewed appropriately.
|
||||
That seems like it would be odd for pixeldata though?
|
||||
|
||||
Bytes per pixel (intuited from hypothetical x,y) for the four frames so far:
|
||||
|
||||
```
|
||||
a: 1 * 1 = 1. 27 - 24 = 3. 24 bits / pixel
|
||||
b: 46 * 72 = 3312. 3340 - 24 = 3316. 8 bits / pixel with 4 bytes left over.
|
||||
c: 116 * 103 = 11948. 7465 - 24 = 7439. 4.9 bits / pixel
|
||||
d: 116 * 100 = 11600. 7368 - 24 = 7344. 5.1 bits / pixel
|
||||
```
|
||||
|
||||
| Offset | Purpose |
|
||||
| ------ | ------- |
|
||||
| 0x0000 | ?
|
||||
@@ -248,8 +209,16 @@ d: 116 * 100 = 11600. 7368 - 24 = 7344. 5.1 bits / pixel
|
||||
| 0x0010 | Padding? |
|
||||
| 0x0014 | Padding? |
|
||||
|
||||
We still don't know what the first 32 bits are all about. Perhaps they can help
|
||||
to explain the differences in putative bpp.
|
||||
We still don't know what the first 32 bits are all about.
|
||||
|
||||
The volume represented by a cell is a little odd. We see three faces of a fake
|
||||
3D volume of size 64x64x32(ish). This is presented in an isomorphic fashion, so
|
||||
the height is 32px at the leftmost and rightmost extents and 96 in the centre.
|
||||
Overall width is 128px, and the minimum rectangle covering the whole space would
|
||||
be 128x96, or 12288 bytes at 8bpp.
|
||||
|
||||
It seems pixels can be larger than a cell - TZEENTCH.OBJ is almost 2 cells high,
|
||||
for instance.
|
||||
|
||||
0x002-0x003 changes in step with total number of pixels, but that doesn't seem
|
||||
to account for the difference.
|
||||
@@ -269,6 +238,25 @@ first byte of data for these 1x1 tiles.
|
||||
Sprites with `X= 128 Y=63` *almost always* seem to have a u0..u3 of
|
||||
`d1 00 42 01` with a few exceptions, e.g. `treemac{1,2}.obj`
|
||||
|
||||
Investigating the sprite data a little more, it seems that we tend to have Y
|
||||
null-separated records: 1 record for sprites with a height of 1, 100 for those
|
||||
with a height of 100, etc.
|
||||
|
||||
The first byte of each record seems likely to specify format - it's mostly
|
||||
invariant (always 1 for the 1x1 examples, almost always 0x80 for the altar
|
||||
sprites and the majority of other .obj files). Some other values appear too, but
|
||||
not a wide distribution.
|
||||
|
||||
Number of bytes per row varies. `altar.obj` is diamond-shaped, and the widths
|
||||
are also diamond-shaped, so perhaps 0x80 means "center the data around the X
|
||||
origin and assume anything unspecified is transparent"?
|
||||
|
||||
Result, with my rendering according to those rules on the left and WH40K_TD.exe
|
||||
on the right:
|
||||
|
||||

|
||||
|
||||
Hurrah!
|
||||
|
||||
WH40K_TD.exe loops around "ReadInMissionFLCs", incl. address 0x0041dd10, where
|
||||
it loads in all the .asc and .obj files in a set.
|
||||
|
Reference in New Issue
Block a user