Triton's HDV model format
There was a slight delay in publishing this article as I’d hoped to be able to find the time to delve a little deeper into the format, however this hasn’t been the case so I’ve decided to publish my findings thus far.
I really hope these serve as a good foundation for anyone else looking to take a dive into the demonstration. If you’re perhaps interested in continuing this work, you’ll be able to download the models that I’ve extracted from the demonstration here. Additionally I’ve recently published most of my notes regarding the demonstration, which can be found here.
One of my major goals when digging through the Into the Shadows character demonstration was to figure out a way to pull the models out from the game and then identifying them - this proved to be considerably easier than I anticipated, particularly because of the helpful prompts that Triton’s engine provides when loading the format.
Below I’ve provided my current interpretation of how the header for the HDV format is laid out. There are quite a few holes, especially the data following the variable containing the number of faces within the model.
char identity; /* includes start indicator before text string */ uint32_t face_offset; uint32_t vert_offset; uint32_t file_size; /* provided twice, for some reason */ int32_t unknown; uint16_t num_vertices; uint16_t version; uint16_t num_faces; /* -2, due to some left-over data */ /* the rest of this is unknown - skip to the face offsets once done here! */
For a start, fudging the header ever so slightly gave me the opportunity to identify what each model actually was within the demonstration - if the model fails to pass validation then the engine will provide the name of the file it was attempting to load. This is partly how I determined the name of each model that was extracted, though I also used the paths and scripts visible within the executable as reference as well.
The header of a model begins with a single byte which is then followed by a string of 31 characters in length which is null terminated. This single byte before the rest of the string is the same for all of the models, so you can pretty much skip this when loading the format (or use it for validation as I have).
All the models are of the same version number, which is simply 514 (or as the engine displays in hexadecimal format, 0x0202).
Besides the header, there are two blocks of data; one for the vertices and the other for faces. The offsets are provided immediately post the identification tag and the offsets provided are relative to the beginning of the file.
Models in Into the Shadows are composed of both triangles and quads - unsurprising for the time.
You ready for this?
int32_t x; int32_t y; int32_t z;
Yes, that’s it. Nothing more to it.
The faces on the other hand are a little bit more involved and I’m afraid I didn’t have time to figure out the rest of the structure after finding the vertex offsets, but for the most part you’ll be able to load the model geometry with what I’ve uncovered thus far and should of course also serve as a good starting point for any further digging.
uint8_t u0; /* u0 has relation to the number of vertices for the face */ uint8_t c_flag; /* somehow alters the colour of the face? */ uint8_t u1; uint8_t u2; uint16_t vertex_offsets; int8_t unknown1;
The first unknown byte for the face appears to somehow determine the number of vertices, but for the most part if it’s anything but 4 you can assume it’s a triangle and if it does come back as 4 then it’s a quad. I’m perhaps forgetting something here but this was generally the rule to follow.
The second variable that I uncovered, which I’ve dubbed as c_flag, appears to alter the colour of the given face. I’m not sure why it exists but you can actually ignore it, because as far as I’ve seen it’s not actually used for any of the models within the demonstration.
So that’s it for the model format at this time. I’ve implemented an example loader which you’ll be able to find here on GitHub which might also serve as a good starting point with the format.
If anyone else makes any further progress with the model format then don’t hesitate to perhaps throw me an email and I can update this article with any additional information that’s found - it would be great to eventually have a complete understanding of the format, but I also understand there’s very little motivation for this especially when this was, after all, only a basic demonstration of the unfinished technology being built for the game.