, 39 tweets, 15 min read
Lately I've been messing with reverse engineering #panzerdragoonsaga file formats to get at the textures & models for a challenge. Texture (CGB) format wasn't too hard, after reading up some tech docs on saturn development it was fairly basic, except they had no meta data at all!
So while most image file formats contain data on width/height/bpp these were just pure texture data, not even a number of textures in the files nor any barriers. Just 4 bit per pixel indexed colour textures usually with 16 bit per colour (5bit per channel) palettes at the end.
CGB texture files for models usually are accompanied by an MCB file which I assumed was the mesh data... but I couldn't figure that out yet, no easy way of telling what relates to the textures in it without first knowing some textures to find. Catch 22!
So I started hacking together a tool for manually declaring the number of palettes, texturees and the texture sizes and have it automatically redistribute the pixel data as you define textures. Works rather well, especially when I figured out the byte alignment rules
So having figured out the texture format and a tool made to investigate them, next would be the mesh file format which is a bit more tricky. Until this point I had not managed to find any texture sizes in the MCB files nor where any MCB files were loaded in Yabause's memory.
I had used Yabause's debug tools extensively to poke around the texture data both to help figure things our and to confirm my thoughts, particularly about palette locations in the files. No MCB files in memory must mean the files are loaded & processed then deleted from memory.
Makes it difficult to see what they're used for, especially when your skills at following decompiled ASM are shockingly bad. However, following Yabause's source debugging a draw command lead me to this little gem: Width is stored as number of 8-pixel sequences!
No wonder I couldn't find the texture dimensions, I was looking for the wrong values! With this I could find a food hold. I found dimensions in the MCB, roughly the number I expect for the amount of quads in the two models in the file, because the Saturn used quads not triangles.
Eyeballing the data each dimension seems to have either 68 or 112 bytes of data accompanying it. The 44 bytes has 2 for the width/height, 16 sets of 4 bytes fixed point vertex coordinates and 6 other bytes, unsure about the 70 byte blocks, if they even are 70 byte blocks.
There's still a lot to figure out. As of yet I've not tested my guess about the vertex points or managed to find where the texture data position/offset is defined, what palette they use, not even the amount of quads or if there's animation data in there. Hope I figure it out!
In case anyone's wondering, I'm doing this purely for the challenge and out of love for the game and console. The Saturn is a mysterious machine and #panzerdragoon saga is a legendary game. It's fun to peek behind the curtains on both. Maybe I should write a blog about it all...
The #PanzerDragoon texture viewer has been progressing nicely. I have a large chunk of the MCB format figured out now, still lots to do but I've got the core sprite data figured out so I can now use that data to properly load up the matching CGB files. Not 100% solid but it works
I have the vertex positions loading along with the objects and sprites but I haven't figured out or found the hierachy and transform data yet so all the objects load at the origin so lots of work to do but coming along nicely.
Here's a higher quality version of that video in case anyone is interested:
Meshes from #PanzerDragoon Saga are now loading in Unity, complete with textures, some extra MCB bits figured out for flipping sprites on x/y axis. Still no hierarchy yet so here's a screenshot of the Basic Wing haphazardly pieced together by hand.
A big issue is texture distortion due to the quads now being made of triangles rather than actual quads. The original quad rendering with one vert moved closer to the next would have the texture squash equally all the way down, but triangles would have only one triangle distorted
The obvious solution would be to subdivide the quads, not sure if there's a better (possibly shader based) solution for it.
And here is the shockingly expensive solution to simulating how a 20+ yr old console renders quads on modern hardware: reverse bilinear interpolation as explained here reedbeta.com/blog/quadrilat… theres som artifacts on exteme deformations but overall it works well. #gamedev #unity3d
Turns out there was a slight deformation when the quad was aligned at certain angles due to the transform from 3D to 2D space skewing it. Added a second rotation to make the bottom edge always be horizontal and it's much better #panzerdragoon #screenshotsaturday L:before R:after
Having said that, I now say ARRRRGGGHHHH!! It seems certain angles between edges cause the UVs to offset. No idea why, which is wondeful. But in good news what I thought was the hierarchy data really is the hierarchy data so I now have that loading, still need transform data.
So it's a bit working now. Hierarchy figured out (ObjectOffset, FirstChildOffset, NextSiblingOffset), the transform block is what I thought, the position just needed multiplaying by 16, go figure. Still need to figure out the rotation. #PanzerDragoonSaga #segasaturn #unity3d
fun fact: the world map with the small dragon in #PanzerDragoon Saga is scaled to the proper dragon model, it's not small:
Not a fun fact, but fun none the less: All (possibly?) the characters from the on-foot sections. Duplicates are, I assume, from different scenes, probably with different animations. #PanzerDragoon #PanzerDragoonSaga #retrogaming #segasaturn
Fun fact #4: the mounted rider models are obscenely #lowpoly. The arms are just quads and the legs are an odd M shaped mesh rather than individual legs. Such a great job by the artist it's impossible to tell in game #PanzerDragoon #segasaturn #retrogaming
Taking a break from shiny pics for a moment, I've basically got the Hierarchy, Mesh and Transform blocks of the MCB format figured out. Rotations are still kicking my arse, I still have a load of sprite flags to figure out and some unknown sprite data possibly for render settings
Particularly there's a block of data after a sprite definition, the length of which seems dependant on a flag. Another couple of flags seem to relate to whether a texture & palette are used. I need to dig into the VDP1 docs again to see if I can match up render modes etc.
I still have the animation block to figure out, which is obviously quite large even for a single animation of a small mesh. Then there's about 3 other block types which I haven't even looked at yet, no idea what they might relate to.
This is all not even mentioning the "level" MCB files which don't have transform blocks, pretty much just tons of meshes. They are more than likely positioned by the PRG code which is going to be a total pain in the arse and need decompiling.
Probably going to look into figuring out the VDP2 background textures next, I've got a hunch they're either the PNB or SCB files, could be both. SCB for scrolling, PNB for positioned maybe? Just guessing at the moment.
A little update on the sprite flags, out of the 6 flag bytes, they actually seem to be 3 int16 with the 2nd being a CMDCTRL command the and the 3rd being a CMDPMOD command. Texture flipping, mesh flag, colour mode, draw type all match. Unsure of the first int16 still though.
In general the "sprite definitions" as I called them seem to be a rough command table, only referencing addresses relative to the files rather than the memory and no CMDXA-CMDYD, also doesn't seem to be a CMDLINK. Given me a good jump on figuring things out.
Tangent: I've used MENUEN.PRG to match MCB's to enemies as their names don't match, but I just noticed the attack names have a matching pair of int32's after the text, bits 0 to 3 the 2nd are the attack directions, which is neat.
0x01 = forward
0x02 = backward
0x04 = left
0x08 = right
0x16 = variable
Turns out the first int32 is the memory offset of the attack name string. PRG's are always loaded into exactly the same location so they can reference exactly memory locations.
An issue with figuring out how enviroments are constructed in their PRG's is the MCB's aren't kept in memory, they seem to be processed on load and then unloaded, so I've yet to be able to find where the command tables are then stored and how the PRG references them.
Aha, MCB's are kept in memory, the data in them is just manipulated to make sense in memory (e.g. file offsets transformed into memory addresses) which is why it's been difficult to find them. FLD_A3.MCB lives at 0x00029c6a0. I'm getting somewhere!
I had been wondering about both the extra sprite data and the fact some objects have different colours in-game than their textures. Turns our that's what the extra data is for! Cue using yabause's memory editor to make Hopper's textures white and fiddling with the data!
I haven't figured out the data exactly, there seems to be more going on than just vertex colours. Those screens show the colour changing based on the angle/distance which is also controlled by the data (12 bytes per vertex). Is this using Saturn's Gouraud shading system?
So it turns out the the dragons are split between Field (Dragon#.mcb), Camp (DragonC#.mcb) and Morph (DragonM#.mcb). The field versions have animation sets; the camp versions don't and only account for forms 0 through 4; the morph has the stat variants of 1 through 5 and 7 as so:
I might be a bit insane here. Got fed up with poking values into Yabause's memory through HXD to experiment with what the vertex colour data actually does, so I have experimented with a writing a memory hook in Unity so I can have some realtime feedback in Yabause.
Missing some Tweet in this thread? You can try to force a refresh.

Enjoying this thread?

Keep Current with Alex Darby

Profile picture

Stay in touch and get notified when new unrolls are available from this author!

Read all threads

This Thread may be Removed Anytime!

Twitter may remove this content at anytime, convert it as a PDF, save and print for later use!

Try unrolling a thread yourself!

how to unroll video

1) Follow Thread Reader App on Twitter so you can easily mention us!

2) Go to a Twitter thread (series of Tweets by the same owner) and mention us with a keyword "unroll" @threadreaderapp unroll

You can practice here first or read more on our help page!

Follow Us on Twitter!

Did Thread Reader help you today?

Support us! We are indie developers!

This site is made by just three indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3.00/month or $30.00/year) and get exclusive features!

Become Premium

Too expensive? Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal Become our Patreon

Thank you for your support!