WDF files deciphered!

WDF files + wdfedit & wdftool & basic wdf file info; support/discussion/questions

Moderator: thunderchero

User avatar
QuasarDonkey
Code Analyst
Code Analyst
Posts: 433
Joined: Tue Jul 26, 2011 8:29 pm
Location: Ireland

WDF files deciphered!

Post by QuasarDonkey »

Hey guys, I'm new here (so sorry if this is posted in the wrong place, and if it was posted before, I couldn't find it).

Anyways I've been recoding my own version of BOTF from scratch, and I've largely deciphered the WDF format for the User Interface. This is targeted for people with coding / hex editing experience. So here goes...

WDF Technical Information

The WDFs (presumably Window Definition Files) describe the layout of the various screens and user interface elements.

To begin, there are a few fundamental types used in the WDFs: byte, integer, rectangle, filename, and font entry. I use aliases for these throughout the rest of the code. Note all structures in the code are C/C++ structs, byte packed.
These basic types are described below:

Code: Select all

/* Byte (8-bit unsigned). */
typedef uint8_t wdfByte;

/* Integer (32-bit signed). */
typedef int32_t wdfInt;

/* Boolean (32-bit signed). Has value 0 or 1. */
typedef int32_t wdfBool;

/* Filename: 13-byte space-terminated string (DOS 8.3 filename + 1 character) */
typedef char wdfFilename[13];

/* Rectangle. */
struct wdfRect {
        wdfInt x, y, w, h;
};

/* Entry for font */
struct wdfFontEntry
{
        // this seems to be 3 bytes and 8 ints, followed by a filename for the font
        // these 3 bytes are the font color
        wdfByte unknown1;  // red 
        wdfByte unknown2;  // blue
        wdfByte unknown3;  // green
        wdfInt unknown4;
        wdfInt unknown5;
        wdfInt unknown6;
        wdfInt unknown7;
        wdfInt unknown8;
        wdfInt unknown9;
        wdfInt unknown10;
        wdfBool UseColor; // if 1, botf will use the above color, otherwise default color
        wdfFilename font;
};
Each WDF begins with an integer, with value 2. This is a magic number just to indicate the file type. You can ignore it. The rest of the file is simply a list of widgets. I'll get back to the overall file structure in a minute. The widgets all have the following properties in common:

Code: Select all

/* Basic properties for all objects. */
struct wdfWidget {
        wdfInt typeId;      /* widget type, covered below */
        wdfInt instanceId;  /* unique identifier for this widget, so BOTF knows what this is */
        wdfRect rect;       /* position/dimensions */
        wdfFilename backgroundImage; /* space-terminated filename of background image, may be "none" */
};
typeId tells you what type of widget you're looking at, and it's extended properties will follow. Here are the values for typeId:

Code: Select all

/* Type ID's for widget properties. */
enum wdfWidgetType_e 
{
        WDF_WINDOW = 1,         // 101 bytes
        WDF_PUSHBUTTON = 2,     // 76 bytes
        WDF_MENU = 5,           // 227 bytes
        WDF_SLIDER = 7,         // 119 bytes
        WDF_SCROLLBAR = 8,      // 75 bytes
        WDF_LISTBOX = 12,       // 181 bytes
        WDF_PICTBOX = 13,       // 41 bytes
        WDF_TEXTBOX = 14        // 101 bytes
};
Well let's cut to the chase. Here are the complete structures for all widgets:
Window:

Code: Select all

struct wdfWindow
{
        wdfInt typeId;
        wdfInt instanceId;
        wdfRect rect;
        wdfFilename backgroundImage;

        /* Number of objects of each type.
         * There are 15 possible widget types, but only 8 are actually used.
         * numObjects[0] is total number of objects.
         */
        wdfInt numObjects[16];
};
PushButton:

Code: Select all

struct wdfPushButton
{
        wdfInt typeId;
        wdfInt instanceId;
        wdfRect rect;
        wdfFilename backgroundImage;

        wdfInt unknown; // -1
        wdfByte ButtonType; // 0 for FADING GLOW, 1 for SOLID GLOW, 2 for TOGGLE
        wdfBool EnableRepeat;
        wdfInt RepeatRate;
        wdfFilename outImage;
        wdfFilename inImage;
};
Menu:

Code: Select all

struct wdfMenu
{
        wdfInt typeId;
        wdfInt instanceId;
        wdfRect rect;
        wdfFilename backgroundImage;

        wdfRect unknown1; //TODO
        wdfFontEntry font1;
        wdfFontEntry font2;
        wdfFilename menuFile;
        wdfFilename leftImage;
        wdfFilename topImage;
        wdfFilename rightImage;
        wdfFilename bottomImage;
        wdfFilename unknown2; //TODO
};
Slider:

Code: Select all

struct wdfSlider
{
        wdfInt typeId;
        wdfInt instanceId;
        wdfRect rect;
        wdfFilename backgroundImage;

        //TODO: 2 bytes, followed by 4 ints
        wdfByte unknown1;
        wdfByte unknown2;
        wdfInt unknown3;
        wdfInt unknown4;
        wdfInt unknown5;  // this seems to be almost same as rect.w
        wdfInt unknown6;
        // 4 filnames: I think these are right
        wdfFilename cellOffImage;
        wdfFilename cellOnImage;
        wdfFilename markerOffImage;
        wdfFilename markerOnImage;
        //TODO 3 ints
        wdfInt unknown7;  // this seems to be same as rect.h
        wdfInt unknown8;
        wdfInt unknown9;
};
ScrollBar:

Code: Select all

struct wdfScrollBar
{
        wdfInt typeId;
        wdfInt instanceId;
        wdfRect rect;
        wdfFilename backgroundImage;

        wdfInt unknown;
        wdfFilename thumbOnImage;
        wdfFilename thumbOffImage;
        wdfInt minValue;
        wdfInt maxValue;
};
ListBox:

Code: Select all

struct wdfListBox
{
        wdfInt typeId;
        wdfInt instanceId;
        wdfRect rect;
        wdfFilename backgroundImage;

        wdfInt unknown1; // always -1?
        wdfFontEntry font1;
        wdfFontEntry font2;
        wdfInt ColumnWidths[10];
        wdfInt NumColumns;
};
PictureBox / Placeholder:

Code: Select all

struct wdfPictBox
{
        wdfInt typeId;
        wdfInt instanceId;
        wdfRect rect;
        wdfFilename backgroundImage;

        wdfInt unknown; // int32, always -1
};
TextBox:

Code: Select all

struct wdfTextBox
{
        wdfInt typeId;
        wdfInt instanceId;
        wdfRect rect;
        wdfFilename backgroundImage;

        wdfRect rect2;
        wdfFontEntry font;
};
Now let us look at the overall structure again:
Each file begins with the number 2, followed by a Window structure (typeId 1). Looking at the extended properties for wdfWindow, we see:

Code: Select all

        wdfInt NumObjects[16];
NumObjects[0] is the total number of objects/widgets that follow. Looking at the wdfWidgetType_e, we can see how many of each widgets of each type, e.g. WDF_PUSHBUTTON = 2, so numObjects[2] gives the number of PushButtons that follow. Note all the widgets are arranged by type, but you can just look at the typeId field to identify a widget type.

Well I guess that's it. Sorry if that was a bit terse. I can provide more info / code if anyone wants.

WDF Editing Software

You can download my WDF Editor here:
Last edited by QuasarDonkey on Sat Nov 12, 2011 7:51 pm, edited 3 times in total.
User avatar
Tethys
Past Administrator
Past Administrator
Posts: 2392
Joined: Fri Jul 18, 2008 2:00 am
Location: Your mom's bed ;)
Contact:

Re: WDF files deciphered!

Post by Tethys »

An interesting assessment of the wdf files. Is there any way you would be willing to provide a working in game wdf file that may be used as a comparison for certain mods/projects? If so I would be very much interested in what you have to say, I can say the same for my colleagues among the forums here. Also welcome to the forums on behalf of Star Trek Modding and AFC.
Not for the weak of heart...
Galaxies MOD v0.4.0 <--- GALM/Galaxies Mod latest version
User avatar
thunderchero
Site Administrator aka Fleet Admiral
Site  Administrator aka Fleet Admiral
Posts: 7824
Joined: Fri Apr 25, 2008 2:00 am
Location: On a three month training mission, in command of the USS Valiant.

Re: WDF files deciphered!

Post by thunderchero »

Interesting indeed,

But with the info you have found other than moving things have you gotten anything to work in game?

I had already given a detail list of the code for *senergy.wdf file here.

viewtopic.php?f=4&t=2078

but even with all the info found only moving of objects did not cause crash. The code within the trek.exe for each function is the hard part to disassemble.

thunderchero
User avatar
QuasarDonkey
Code Analyst
Code Analyst
Posts: 433
Joined: Tue Jul 26, 2011 8:29 pm
Location: Ireland

Re: WDF files deciphered!

Post by QuasarDonkey »

thunderchero: It seems you been working on this a lot longer that I have. I've really just started this from the point of view of recreating BOTF. I think you're right though; since the typeId's and instanceId's for each widget/object are hardcoded into trek.exe, while you can add new widgets, they don't really do much, since doing so would require modifying trek.exe (I wouldn't even know where to begin).

As regards BOTF crashing on modifying the WDFs, I have successfully changed some of the widget parameters, like turning PushButtons to ToggleButtons, and I've added widgets too. I'll give an example of adding a new widget soon. Whether any of this is actually useful for modding, I'm not sure.

I have used the information to build a WDF Viewer:
image no longer available
User avatar
QuasarDonkey
Code Analyst
Code Analyst
Posts: 433
Joined: Tue Jul 26, 2011 8:29 pm
Location: Ireland

Re: WDF files deciphered!

Post by QuasarDonkey »

Tethys wrote:An interesting assessment of the wdf files. Is there any way you would be willing to provide a working in game wdf file that may be used as a comparison for certain mods/projects? If so I would be very much interested in what you have to say, I can say the same for my colleagues among the forums here. Also welcome to the forums on behalf of Star Trek Modding and AFC.
Thanks for the welcome tethys!
I don't really do much in the line of modding myself, so I have no "real" examples. But here's a quick contrived example of manually modding a WDF: Let's take the main game options screen options.wdf, and use what we know to add a new button.
Here's a partial hexdump of options.wdf:

Code: Select all

00000000  02 00 00 00 01 00 00 00  2b 00 00 00 00 00 00 00  |........+.......|
00000010  00 00 00 00 20 03 00 00  58 02 00 00 4f 50 54 42  |.... ...X...OPTB|
00000020  4b 47 4e 44 2e 74 67 61  20 1f 00 00 00 00 00 00  |KGND.tga .......|
00000030  00 0a 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000040  00 00 00 00 00 04 00 00  00 00 00 00 00 00 00 00  |................|
00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 04 00 00  |................|
00000060  00 0d 00 00 00 00 00 00  00 02 00 00 00 a4 1f 00  |.............¤..|
00000070  00 e8 01 00 00 f8 01 00  00 7c 00 00 00 24 00 00  |.è...ø...|...$..|
00000080  00 6f 61 63 63 65 70 74  31 2e 74 67 61 20 ff ff  |.oaccept1.tga ÿÿ|
00000090  ff ff 00 00 00 00 00 00  00 00 00 6f 61 63 63 65  |ÿÿ.........oacce|
000000a0  70 74 31 2e 74 67 61 20  6f 61 63 63 65 70 74 32  |pt1.tga oaccept2|
000000b0  2e 74 67 61 20 02 00 00  00 a5 1f 00 00 10 00 00  |.tga ....¥......|
... (et cetera)
Let's skip the first 4 bytes (WDF header: integer with value 2). The next 101 bytes contain the Window object:

Code: Select all

00000000              01 00 00 00  2b 00 00 00 00 00 00 00  |    ....+.......|
00000010  00 00 00 00 20 03 00 00  58 02 00 00 4f 50 54 42  |.... ...X...OPTB|
00000020  4b 47 4e 44 2e 74 67 61  20 1f 00 00 00 00 00 00  |KGND.tga .......|
00000030  00 0a 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000040  00 00 00 00 00 04 00 00  00 00 00 00 00 00 00 00  |................|
00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 04 00 00  |................|
00000060  00 0d 00 00 00 00 00 00  00                       |.........       |
The total number of objects is right after the background image, at offset 0x29. It's currently 0x1f == 31. Now since we're adding a new button, we need to increase the total number of objects by 1: so change it to 0x20 == 32. We also need to increment the total number of button widgets (type 2 objects), at offset 0x31. It currently 0x0a == 10. Let's set it to 0x0b == 11.
So we now have:

Code: Select all

00000000              01 00 00 00  2b 00 00 00 00 00 00 00  |    ....+.......|
00000010  00 00 00 00 20 03 00 00  58 02 00 00 4f 50 54 42  |.... ...X...OPTB|
00000020  4b 47 4e 44 2e 74 67 61  20 20 00 00 00 00 00 00  |KGND.tga .......|
00000030  00 0b 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000040  00 00 00 00 00 04 00 00  00 00 00 00 00 00 00 00  |................|
00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 04 00 00  |................|
00000060  00 0d 00 00 00 00 00 00  00                       |.........       |
Now let's add a new entry for the pushbutton. We'll just copy the quit button from the opening screen, opening.wdf. Copy the 76 bytes, offset 0x69 - 0xB4:

Code: Select all

00000060                              02 00 00 00 8f 00 00  |................|
00000070  00 6d 02 00 00 dc 01 00  00 a4 00 00 00 28 00 00  |.m...Ü...¤...(..|
00000080  00 4d 63 71 75 69 74 31  2e 74 67 61 20 20 ff ff  |.Mcquit1.tga  ÿÿ|
00000090  ff ff 00 00 00 00 00 00  00 00 00 6d 63 71 75 69  |ÿÿ.........mcqui|
000000a0  74 31 2e 74 67 61 20 20  6d 63 71 75 69 74 32 2e  |t1.tga  mcquit2.|
000000b0  74 67 61 20 20                                    |tga  ........m..|
and paste it just after the window entry in options.wdf, where all the buttons are listed, again offset 0x69:

Code: Select all

00000000  02 00 00 00 01 00 00 00  2b 00 00 00 00 00 00 00  |........+.......|
00000010  00 00 00 00 20 03 00 00  58 02 00 00 4f 50 54 42  |.... ...X...OPTB|
00000020  4b 47 4e 44 2e 74 67 61  20 20 00 00 00 00 00 00  |KGND.tga  ......|
00000030  00 0b 00 00 00 00 00 00  00 00 00 00 00 00 00 00  |................|
00000040  00 00 00 00 00 04 00 00  00 00 00 00 00 00 00 00  |................|
00000050  00 00 00 00 00 00 00 00  00 00 00 00 00 04 00 00  |................|
00000060  00 0d 00 00 00 00 00 00  00 02 00 00 00 8f 00 00  |................|
00000070  00 6d 02 00 00 dc 01 00  00 a4 00 00 00 28 00 00  |.m...Ü...¤...(..|
00000080  00 4d 63 71 75 69 74 31  2e 74 67 61 20 20 ff ff  |.Mcquit1.tga  ÿÿ|
00000090  ff ff 00 00 00 00 00 00  00 00 00 6d 63 71 75 69  |ÿÿ.........mcqui|
000000a0  74 31 2e 74 67 61 20 20  6d 63 71 75 69 74 32 2e  |t1.tga  mcquit2.|
000000b0  74 67 61 20 20 02 00 00  00 a4 1f 00 00 e8 01 00  |tga  ....¤...è..|
000000c0  00 f8 01 00 00 7c 00 00  00 24 00 00 00 6f 61 63  |.ø...|...$...oac|
000000d0  63 65 70 74 31 2e 74 67  61 20 ff ff ff ff 00 00  |cept1.tga ÿÿÿÿ..|
000000e0  00 00 00 00 00 00 00 6f  61 63 63 65 70 74 31 2e  |.......oaccept1.|
000000f0  74 67 61 20 6f 61 63 63  65 70 74 32 2e 74 67 61  |tga oaccept2.tga|
Here you can see the new button in the options screen.
image no longer available

Unfortunately, the button doesn't do anything. As thunderchero stated, the hard part is hacking the functions in trek.exe to make the button actually do something. So modding the WDF's might not have utility (other than cosmetic changes).

Here's a link to the original and modified options.wdf:
http://www.megaupload.com/?d=D6LACQZY

I'm considering building a mod tool for WDFs if that would help, but I'm a bit busy over the next few days.
User avatar
thunderchero
Site Administrator aka Fleet Admiral
Site  Administrator aka Fleet Admiral
Posts: 7824
Joined: Fri Apr 25, 2008 2:00 am
Location: On a three month training mission, in command of the USS Valiant.

Re: WDF files deciphered!

Post by thunderchero »

QuasarDonkey wrote:I have used the information to build a WDF Viewer
this sounds interesting it would be a quicker way to view what has been edited than loading game.

Does it load the stbof.res or do you have to have each file extracted to use this?

thunderchero
User avatar
Tethys
Past Administrator
Past Administrator
Posts: 2392
Joined: Fri Jul 18, 2008 2:00 am
Location: Your mom's bed ;)
Contact:

Re: WDF files deciphered!

Post by Tethys »

Will your utility be built using Java or C++, i noticed a mention to C++ in your first post. If you use Java, or if C++ is able to be converted to Java, we could add it to UE if DCER agrees, which I think would be the best way to go.
Not for the weak of heart...
Galaxies MOD v0.4.0 <--- GALM/Galaxies Mod latest version
User avatar
Flocke
BORG Trouble Maker
BORG Trouble Maker
Posts: 3178
Joined: Sun Apr 27, 2008 2:00 am
Location: Hamburg, Germany
Contact:

Re: WDF files deciphered!

Post by Flocke »

you don't have to add everything to ue, viewing wdf user interfaces is best on native 800x600 resolution and a simple seperate tool is no worse than integrating it with ue. ue also could offer to launch the viewer via button and automaticly extract the wdf files you want to view passing them to the viewer so they can be shown promptly, if it would be too much work otherwise. ;)

Nice work QuasarDonkey btw!
User avatar
Tethys
Past Administrator
Past Administrator
Posts: 2392
Joined: Fri Jul 18, 2008 2:00 am
Location: Your mom's bed ;)
Contact:

Re: WDF files deciphered!

Post by Tethys »

Good idea Flocke i forgot that was possible
Not for the weak of heart...
Galaxies MOD v0.4.0 <--- GALM/Galaxies Mod latest version
Dr_Breen
Commodore
Commodore
Posts: 889
Joined: Wed Apr 30, 2008 2:00 am
Location: Zurich, Switzerland
Contact:

Re: WDF files deciphered!

Post by Dr_Breen »

on the other hand it makes everything a lot easier when you have everything in a Java tool that runs on nearly any machine. by the way isn't it a developers dream not being forced to use hundreds of tools (creator, hob filters, hex editors, wdf viewers, ultimate editors, photoshop, 3ds max,.....*goes crazy*)?
Public BotF / EF2 Teamspeak 3 Server: 83.169.13.55
User avatar
Tethys
Past Administrator
Past Administrator
Posts: 2392
Joined: Fri Jul 18, 2008 2:00 am
Location: Your mom's bed ;)
Contact:

Re: WDF files deciphered!

Post by Tethys »

This was my thoughts too Breen, however even if it IS a separate program, i would much rather use UE to at least launch the program...
Not for the weak of heart...
Galaxies MOD v0.4.0 <--- GALM/Galaxies Mod latest version
User avatar
DCER
Code Master
Code Master
Posts: 683
Joined: Sat Apr 26, 2008 2:00 am

Re: WDF files deciphered!

Post by DCER »

QuasarDonkey thanks for posting this and welcome to the forums.

Converting a graphical C++ program won't work, but based on the info we have I shouldn't have problems adding this sort of functionality to UE.
User avatar
QuasarDonkey
Code Analyst
Code Analyst
Posts: 433
Joined: Tue Jul 26, 2011 8:29 pm
Location: Ireland

Re: WDF files deciphered!

Post by QuasarDonkey »

Sorry for the delay gentlemen, I was away for a few days.

To answer your questions, the tool is written in C++ using SDL for graphics/input. Also it's a command line tool with minimal interface. It's just a prototype, so it does not read from stbof.res: you need to extract the WDF and needed TGAs in order to view.

Maybe it's not a great idea for me to spend a lot of time developing it if the plan is to just incorporate it into UE. I believe UE already has many needed features like ZIP reading, TGA loading, etc.

I'll try get a Windows version cleaned up and uploaded soon so you guys can take a look (I'm not running Windows). After I upload it, maybe DCER, you could take a look and see if you want to integrate it into UE; if not, I'll do some work it instead.
User avatar
DCER
Code Master
Code Master
Posts: 683
Joined: Sat Apr 26, 2008 2:00 am

Re: WDF files deciphered!

Post by DCER »

Thanks QuasarDonkey, that would be great.
User avatar
DCER
Code Master
Code Master
Posts: 683
Joined: Sat Apr 26, 2008 2:00 am

Re: WDF files deciphered!

Post by DCER »

I've started looking into this and implementing the wdf format.

The first three bytes in the font entry are indeed the font color, but not RGB or BGR, for some reason the order is RBG instead.

The last unknown value is a boolean switch. When set to 1 botf uses the color information found here, otherwise it will use the default color instead.
Post Reply

Return to “WDF files + wdfedit & wdftool & basic wdf file info”