Files
ordoor/doc/formats/obj.md

223 lines
7.4 KiB
Markdown
Raw Normal View History

2018-03-18 04:23:34 +00:00
# Obj format information
The names of Obj files are highly suggestive of them being objects that can be
placed on [maps](map.md). Each map cell seems to have space for four objects to
be placed on it - a `SURFACE`, `LEFT`, `RIGHT`, and `CENTER`. Maps reference
objects in a space-efficient way via sets, which seem to be a kind of object
palette.
## Assign
The `Assign/` directory contains a matching `.asn` file for each `Obj/*.obj`.
It's a plain-text format which seems to assign properties to frames, and has
references to a `<name>.flc` file which does not exist in the tree.
Theory: .obj files were originally generated from `.flc` files. This is an
AutoDesk format for visual data, so this suggests the .obj files contain pixels
\o/
`blank.asn` references 6 frames (0-5):
```
# single pixel tile
# transpix.obj/.asn
#/--> transpix.flc
#
0-5:DEF 1;
0-5:TYPE 13;
END OF FILE
```
`jungtil.asn` references 18 frames (0-17):
2018-03-18 04:23:34 +00:00
```
# jungle floor
# jungtil.obj/.asn
# /--> d:\warflics\missions\jungtil.flc
#
0:DEF 2;
1-11:DEF 454;
#damaged frames!!!!
12:DEF 2;
13-16:DEF 454;
17:DEF 454;
0:TYPE 2;
1-11:TYPE 0;
12:TYPE 2;
13-16:TYPE 0;
17:TYPE 0;
0:DESTROY 12;
1-3:DESTROY 13;
4-6:DESTROY 14;
7-9:DESTROY 15;
10-11:DESTROY 16;
17:DESTROY 15;
1-11:Dmg1Lnk 17;
END OF FILE
```
So it seems this visual data can have quite complicated attributes. At a minimum
we see:
2018-03-18 04:23:34 +00:00
* `TYPE`
* `DEF`
* `DESTROY`
* `Dmg1Lnk`
2018-03-18 04:23:34 +00:00
The `type` field **may** tell us what format each sprite is in.
2018-03-18 04:23:34 +00:00
## OBJ container structure
2018-03-18 04:23:34 +00:00
`.obj` files represent visual data. They contain a number of sprites, which are
assigned attributes in `.asn` files and referenced from `.map` files.
2018-03-18 04:23:34 +00:00
The container format is worked out, but the per-sprite data is still unknown, so
I'm documenting the former here while still investigating the latter.
2018-03-18 04:23:34 +00:00
The file begins with a header, with all values 32-bit little-endians:
2018-03-18 04:23:34 +00:00
| Offset | Meaning |
| ------ | ------- |
| 0x0000 | Number of sprites |
| 0x0004 | Offset of sprite directory |
| 0x0008 | Size of sprite directory |
| 0x000c | Offset of the sprite data |
| 0x0010 | Size of the sprite data |
2018-03-18 04:23:34 +00:00
The sprite directory contains an 8-byte record per sprite. That record contains
two 32-bit little-endians:
2018-03-18 04:23:34 +00:00
| Offset | Meaning |
| ------ | ------- |
| 0x0000 | Relative offset of sprite in data block |
| 0x0004 | Size of sprite in data block |
2018-03-18 04:23:34 +00:00
For sanity checks, we can ensure that:
2018-03-18 04:23:34 +00:00
* The header, sprite directory and data blocks do not overlap or extend past the
end of the file
* None of the individual sprites overlap each other or extend past the end of
the data block
2018-03-18 04:23:34 +00:00
## Sprite structure
2018-03-18 04:23:34 +00:00
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.
2018-03-18 04:23:34 +00:00
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:
2018-03-18 04:23:34 +00:00
```
-------------------------------------------------------------------------------
0 1 2 3 4 5 6 7 01234567 0 1 2 3 4 5 6 7
-------------------------------------------------------------------------------
0x0000 10 01 61 01 01 00 01 00 | a | 16 1 97 1 1 0 1 0
0x0008 00 00 00 00 03 00 00 00 | | 0 0 0 0 3 0 0 0
0x0010 00 00 00 00 00 00 00 00 | | 0 0 0 0 0 0 0 0
0x0018 01 fd 00 | | 1 253 0
2018-03-18 04:23:34 +00:00
```
Total size is 27 bytes, so if there *is* only one pixel, it's tempting to
suggest that the first 24 bytes are header, and the final 3 bytes represent that
one pixel.
2018-03-18 04:23:34 +00:00
I think this is rendered as a 1px dot with the colour `#ff00ff` in WH40K_TD.exe:
2018-03-18 04:23:34 +00:00
![blank.obj as rendered by WH40K_TD.exe](img/blank.obj.png)
2018-03-18 04:23:34 +00:00
In the 64x64 tile, the dot is in the very centre.
2018-03-18 04:23:34 +00:00
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 16-bit-colour application and may use a
palette, but these factoids don't help me make immediate sense of the data. If
there's a palette in the first 24 bytes, it's not obvious.
2018-03-18 04:23:34 +00:00
There are 45 `TYPE 13` .obj files in the game. Comparing the above with the
start of the second sprite in `pillar.obj`:
2018-03-18 04:23:34 +00:00
```
----------------------------------------------
0 1 2 3 4 5 6 7 01234567
----------------------------------------------
0x0000 fa 00 25 01 2e 00 48 00 | H | 250 0 37 1 46 0 72 0
0x0008 00 00 00 00 f4 0c 00 00 | | 0 0 0 0 244 12 0 0
0x0010 00 00 00 00 00 00 00 00 | | 0 0 0 0 0 0 0 0
0x0018 80 0f 90 1a 4b 1a 1b 4b | K K | 128 15 144 26 75 26 27 75
0x0020 1a 4c 1a 4b 19 19 49 19 | L K I | 26 76 26 75 25 25 73 25
0x0028 4a 18 4a 80 0f 00 80 0b | J J | 74 24 74 128 15 0 128 11
0x0030 98 1a 4c 1a 4c 1a 9e 1a | L L | 152 26 76 26 76 26 158 26
0x0038 4c 1b 4b 1a 1a 49 19 48 | L K I H | 76 27 75 26 26 73 25 72
0x0040 18 18 48 19 4b 19 4b 19 | H K K | 24 24 72 25 75 25 75 25
0x0048 9d 80 0b 00 80 08 9e 1a | | 157 128 11 0 128 8 158 26
0x0050 4a 1a 1b 4d 9e 1a 4c 1b | J M L | 74 26 27 77 158 26 76 27
0x0058 1b 4c 1b 4c 1a 1a 49 18 | L L I | 27 76 27 76 26 26 73 24
0x0060 48 17 49 18 19 4a 19 4b | H I J K | 72 23 73 24 25 74 25 75
0x0068 19 9d 4a 1a 49 80 08 00 | J I | 25 157 74 26 73 128 8 0
0x0070 80 07 a0 19 4b 1a 1b 4c | K L | 128 7 160 25 75 26 27 76
0x0078 1b 1b 4d 9e 1b 4c 1b 4d | M L M | 27 27 77 158 27 76 27 77
2018-03-18 04:23:34 +00:00
```
Total size is 3340. The first 24 bytes look quite different to the remainder of
this file, lending weight to the 24-byte header theory.
Line-by-line comparison:
a 0x0000 10 01 61 01 01 00 01 00 | a | 16 1 97 1 1 0 1 0
b 0x0000 fa 00 25 01 2e 00 48 00 | H | 250 0 37 1 46 0 72 0
a 0x0008 00 00 00 00 03 00 00 00 | | 0 0 0 0 3 0 0 0
b 0x0008 00 00 00 00 f4 0c 00 00 | | 0 0 0 0 244 12 0 0
a 0x0010 00 00 00 00 00 00 00 00 | | 0 0 0 0 0 0 0 0
b 0x0010 00 00 00 00 00 00 00 00 | | 0 0 0 0 0 0 0 0
Assuming a 24-byte header, 0x0c matches "remaining pixeldata" size in both cases
- 3 and 3316.
It's odd that the last 8 bytes of this putative header are empty in both cases.
I need to see if I can find any examples that store it.
0x04 makes sense as height & width, 2 16-bit values, in `blank.obj` where we
*know* it's 1x1 pixel.
It makes less sense as such for `pillar.obj` where the individual sprites fit
into the 64x64x64 volume of a cell:
![pillar.obj as individual sprites](img/pillar_6_sprites.png)
WH40K_TD.exe crashes trying to load a set referencing `pillar` in it unless it's
in the CENTER position. Interesting.
Next: keep adding cases to the header comparison above until I make sense of it
all. Since `pillar.obj` is composable, it's not the best example I could have
picked. Need more non-composable ones, in case that makes a difference.
| Offset | Purpose |
| ------ | ------- |
| 0x0000 | ?
| 0x0004 | ?
| 0x0008 | ?
| 0x000c | Size of remaining pixeldata |
| 0x0010 | Padding?
| 0x0014 | Padding?
2018-03-19 11:42:57 +00:00