NWN Binary Model Files Basics

The binary format of the model files contains 3 main sections, the header, the model data and the vertex or raw data.

The header is a only twelve bytes long.  It provides us with the offset and size of the raw data, and a 32 bit value of 0.  The value of 0 is important since it can be used to tell the difference between an ASCII model file and a binary one.  The chances of an ASCII model file starting with 4 bytes of 0 is somewhere between zero and none.

Offset Type Description
0x0000 UINT32 Value of 0 for binary models
0x0004 UINT32 Offset to the raw data/Size of the model data
0x0008 UINT32 Size of the raw data
0x000C Total length of the structure

The model data follows the header in the file.  Immediately following the model data is the raw data.  Thus, the second value in the header can be either the model size or the offset from the start of the model data to the raw data.  Either interpretation works since they are the exact same value.

Arrays and Pointers in a Model File

The structure of the model is reasonably complex.  Not only does it contain structures of data, but those structures reference other structures.  This is accomplished using arrays and pointers.  

There are two types of pointers inside of a model file, model data pointer and raw data pointer.  Each of these pointers are stored as a 32 bit value.  In the case of model data pointers, the pointer will contain an offset from the start of the model data to the data in question.  A value of zero represents a "NULL" pointer or a pointer that doesn't reference anything.  For raw data pointers, the pointer will contain an offset from the start of the raw data to the data in question.  A value of 0xFFFFFFFF (unsigned) or -1 (signed) represents a "NULL" pointer or a pointer that doesn't reference anything.  The reason the raw data uses a value of -1 is that an offset of zero is a valid pointer into the raw data.  Excluding one special case, this isn't true for model data pointers.  (Only one element in a binary model file points to the data at offset zero in the model data.  However, this value is transient and isn't actually stored in the model file.)

Some of you might be wondering why I am referring to these offsets as pointers.  After all, in the binary model format, they are always offsets and never actually a real pointer.  That is very true for the disk image of a model.  However, on 32 bit address processors (or processors such as the Alpha that can run in 32 bit address mode with sign extend), after the model is loaded from disk, all the offsets can be converted to pointers.  This improves greatly the run time performance.

Arrays in models are a slightly more complicated beast.  They consist of the following three elements.

Offset Type Description
0x0000 UINT32 Pointer/Offset to the first elements of the array
0x0004 UINT32 Number of used entries in the array
0x0008 UINT32 Number of allocated entries in the array
0x000C Total length of the structure

For binary model files, the number of used entries and number of allocated entries will always be the same.  During run time or complication time, these value will usually differ since these arrays by nature will grow as more elements are added.

Arrays can contain most anything as long as the elements are all the same type.  Examples of common arrays in model files would be arrays of vertices, faces, and even pointers.  In the case of pointers, these arrays are commonly used to represent a model hierarchy.

Controllers

Each node (to be defined later), in a model can contain zero or more controllers.  Controllers can be considered as attributes of a node.  They defined certain aspects of the node.  One of the most common controller is the position controller.  This controller dictates the position of the node relative to the parent node.

One of the first obvious questions about controllers is why isn't this information included as part of the standard node structures.  There are two reasons for this.  The first reason is that controllers are optional.  In the case of an emitter node, there are around 50 different controllers that can be specified.  Having to dedicate storage space to all of these controllers, used or not, would be a waste of space.  The second and more important reason is that controllers can be animated.

To animate a model, the model must change over time.  The way to do this is with time keyed controllers.  All animations take a given amount of time from start to finish.  For example, the swing of a sword might take 1 second of total animation time.  In order to draw the model properly, controllers have different that are time keyed.  For example, normally, the position controller would be specified as follows.

position 0.2 1.0 0.124

However, in the case of a time keyed position, it would be specified as follows.

positionkey 3
  0.0 0.2 1.0 0.124
  0.4 0.4 1.0 0.510
  0.8 0.6 1.0 0.516

When specifying a time keyed controller, the first value is the start time for that value.  Following the start time is the actual value.  In this case, during animation time 0.0 through 0.4, the first position will be used.  Between 0.4 and 0.8, the second position will be used.  Between 0.8 and the animation time for the given animation, the 3rd value will be used.

To provide smoother animations, the values will be interpolated.  For example, given our previous data, if the current animation time was 0.2, then that would be half way between the first and second positions.  Thus each position will contribute equally to the actual position used.  If the animation time was earlier, then the first position would be given more weight.  The opposite is true if the animation time was later. 

To provide an even smoother animation, a second style of interpolation is available.  It is know as "bezier" interpolation.  Bezier interpolation is used when you specify "bezierkey" as the suffix to the controller name.  (Note: At this time, I have not verified that any Bioware model uses bezier interpolation.  I don't even know if the rendering engine supports this option.)

Inside a binary model file, controllers are stored as two arrays in the model data.  The first array is an array of a controller structure.  The second array is a simple array of floating point numbers.  The second array contains the actual controller data while the first tells us about all the controllers in the array.  The controller structure is as follows.

Offset Type Description
0x0000 INT32 Type of controller
0x0004 INT16 Number of rows of controller data
0x0006 INT16 Index into the float array of the first time key
0x0008 INT16 Index into the float array of the first controller data value
0x000A INT8 Number of columns excluding the time key column
0x000B INT8 Pad, not used
0x000C Total length of the structure

There are a few important notes about the controller structure.  The first thing of note is that for controllers that aren't time keyed, they are still stored as if they are time keyed but with a single row and a time key value of zero.  Thus, it is impossible to tell the difference between a controller that isn't time keyed, and a time keyed controller with a single row and a time key value of zero.  The second important note is that if the controller is actually bezier keyed, then the value of 0x10 is ORed in with the number of columns.  This is how you can tell the difference between a normal keyed controller and a bezier keyed controller.  Finally, all key values are stored continuously and all the data values are stored contiguously.  Thus, if a keyed controller had 3 rows with the time keys starting at floating point value 5, then the time keys for the other two rows would be value 6 and value 7.  Also, it appears that for some models, the controller "detonate" when used as a key controller doesn't even list a time key.  Thus, the number of columns listed is -1.

Following is a list of all controllers:

Name Value Used in nodes
Position 8 All
Orientation 20 All
Scale 36 All
Color 76 Light
Radius 88 Light
ShadowRadius 96 Light
VerticalDisplacement 100 Light
Multiplier 140 Light
AlphaEnd 80 Emitter
AlphaStart 84 Emitter
BirthRate 88 Emitter
Bounce_Co 92 Emitter
ColorEnd 96 Emitter
ColorStart 108 Emitter
CombineTime 120 Emitter
Drag 124 Emitter
FPS 128 Emitter
FrameEnd 132 Emitter
FrameStart 136 Emitter
Grav 140 Emitter
LifeExp 144 Emitter
Mass 148 Emitter
P2P_Bezier2 152 Emitter
P2P_Bezier3 156 Emitter
ParticleRot 160 Emitter
RandVel  164 Emitter
SizeStart 168 Emitter
SizeEnd 172 Emitter
SizeStart_Y 176 Emitter
SizeEnd_Y 180 Emitter
Spread 184 Emitter
Threshold 188 Emitter
Velocity 192 Emitter
XSize 196 Emitter
YSize 200 Emitter
BlurLength 204 Emitter
LightningDelay 208 Emitter
LightningRadius 212 Emitter
LightningScale 216 Emitter
Detonate 228 Emitter
AlphaMid 464 Emitter
ColorMid 468 Emitter
PercentStart 480 Emitter
PercentMid 481 Emitter
PercentEnd 482 Emitter
SizeMid 484 Emitter
SizeMid_Y 488 Emitter
SelfIllumColor 100 All Meshes
Alpha 128 All Meshes

Model Routines and the Node types

All nodes in a model begin with six values which have also been called "tokens".  During the early process of decoding the binary models, many people including myself made the mistake that these tokens were used to identify the different types of nodes.  As silly as it sounds, this was the best we could do at the time.  These six tokens did uniquely identify each of the nodes.  However, I and I would imagine most others knew there had to be a deeper meaning to these tokens.  Nobody uses 6 4-byte values to uniquely identify a handful of different nodes.  All of these tokens were values in the range of 0x00400000 and 0x00500000.  There was no apparent bit mask to the values.  However, the difference between the token values was interesting since it was usually either 0x10 or 0x20.  Now, if someone was really had everything on the ball and had a reasonable knowledge of the Win32 image loader, they would have realized something that eluded everyone, including myself for the longest time.  These tokens were not tokens, they were routine addresses.  You see, the Win32/NT image loader loads images at 0x0041000.  Thus, the funny start to all the numbers.  

So, as of now, these "tokens" should be consider unreliable as a method of identifying model node types.  What if Bioware releases new models using a new build of their model compiler and these routine addresses change.  All the existing software that utilizes these "tokens" would fail.

Luckily, the proper way to identify the node type has been located.  Every node contains a 32 bit bit mask that identifies which structures make up the node.  Following is a list of all the flags.

Name Value
HasHeader 0x00000001
HasLight 0x00000002
HasEmitter 0x00000004
HasReference 0x00000010
HasMesh 0x00000020
HasSkin 0x00000040
HasAnim 0x00000080
HasDangly 0x00000100
HasAABB 0x00000200

Every node contains a node header.  In the case of a dummy node, only a node header is required. All mesh nodes also contain a mesh structure.  In the case of a trimesh node, only the node header and the mesh header is required.  By looking at a combination of flags, not only do we know what structures make up the node, but we know what the node type is.

Name Value
Dummy 0x00000001
Light 0x00000003
Emitter 0x00000005
Reference 0x00000011
TriMesh 0x00000021
SkinMesh 0x00000061
AnimMesh 0x000000A1
DanglyMesh 0x00000121
AABBMesh 0x00000221

As you can see, each of the different node types contains one or more flags.

Part Numbers

Part numbers are values assigned to nodes as the model compiler creates them.  However, after the complete geometry has been compiled, these values are adjusted.

If a model has a super model, then the geometry for the model is compared against the geometry for the super model.  Any node that matches the name of a node in the super model will be given the part number assigned to the node in the super model.  If a node in the model isn't found in the super model, then it receives a part number of -1.  If a model doesn't have a super model, then the part numbers are left as is.

After the geometry for an animation has been compiled, the same process is used to match the nodes in the animation with the nodes in the main model geometry.  It is important to note that the animation geometry is compare against the model's geometry and not the model's super model geometry.

Layout of the Binary Model File

The basic layout of the binary model file is as follows:

File Header
Model
Data
Model Geometry Header
Node 1
Node 2
...
Node N
Animation Geometry Header 1
Node 1
Node 2
...
Node N
Animation Geometry Header 2
Node 1
Node 2
...
Node N
Animation Geometry Header N
Raw Data

Not all models contain animation headers.  Also, in many models, there might be no raw data.  It is also important to remember that this diagram is a simplification of the real model layout.  For example, to fully defined a node, it might take 100 bytes of data or 10,000 bytes of data.  This information might be scattered in sections throughout the model data.

The Geometry Header

All models contain at least one geometry header.  This header is part of the larger model geometry header.  If the model contains animations, then there will be a geometry header in each of the animation geometry headers. 

The format of the geometry header is as follows:

Offset Type Description
0x0000 Function Pointer Pointer to a function
0x0004 Function Pointer Pointer to the function to parse a ASCII model line
0x0008 CHAR [64] Geometry Name (model or animation name)
0x0048 Node Header Pointer Pointer/Offset to the root node of the geometry
0x004C UINT32 Number of nodes in the geometry.  In the case of the model geometry, if the model has a super mode defined, then this value also includes the number of nodes in the super model plus one.
0x0050 Pointer Array Array of unknown data (probably runtime only)
0x005C Pointer Array Array of unknown data (probably runtime only)
0x0068 UINT32 Reference count, initialized to 0.  When another model references this model, then this value is incremented.  When the referencing model dereferences this model the count is decremented.  When this count goes to zero, the model can be deleted since it is no longer needed.
0x006C UINT8 Geometry Type
0x01 = Basic geometry header (not in models)
0x02 = Model geometry header
0x05 = Animation geometry header
0x80 = If bit is set, then model is a compiled binary model loaded from disk and converted to absolute addresses.
0x006D UINT8 [3] Padding
0x0070 Total length of the structure

As noted, the two arrays at 0x50 and 0x5C, and the data at 0x68 is unknown at this time.  

The Model Header

There is only one model header per model file.  This header always starts at offset 0 in the model data section or offset 12 from the start of the file.

Offset Type Description
0x0000 Geometry Header Geometry Header
0x0070 UINT8 Unknown value initialized to 0
0x0071 UINT8 Unknown value initialized to 1
0x0072 UINT8 Model classification:
0x01 = Effect
0x02 = Tile
0x04 = Character
0x08 = Door
0x0073 UINT8 If non-zero, model should be fogged
0x0074 UINT32 Unknown value initialized to 0
0x0078 Animation Header Pointer Array Array of pointers to all the animation geometries
0x0084 Pointer to parent model Pointer to the parent model, always 0
0x0088 FLOAT [3] Bounding box min for the model, defaults to (-5, -5, -1)
0x0094 FLOAT [3] Bounding box max for the model., defaults to (5, 5, 10)
0x00A0 FLOAT Radius of the model, defaults to 7.0
0x00A4 FLOAT Animation scale, defaults to 1.0
0x00A8 CHAR [64] Super model name, defaults to ""
0x00E8 Total length of the structure

The Animation Header

There are zero or more animation headers per model, one header for each animation.  All animations contain their own geometry information.  However, this usually consists of dummy nodes containing controller information.

Offset Type Description
0x0000 Geometry Header Geometry Header
0x0070 FLOAT Animation length, defaults to 1.0
0x0074 FLOAT Trans time, defaults to 0.25
0x0078 CHAR [64] Animation root, defaults to ""
0x00B8 Animation Event Array Array of all the events associated with this animation
0x00C4 Total length of the structure

Each animation can have zero or more events.  Unlike other arrays that contain pointers to the structures, the animation event array is an array of the actual structure.  The structure is as follows:

Offset Type Description
0x0000 FLOAT After
0x0004 CHAR [32] Event name
0x0024 Total length of the structure

Nodes

Currently, there are nine different nodes types that make up a model's geometry.  These nodes specify such elements as lighting, animated graphics emitters, and different types of meshes.  Each node type share a common header that supplies us with enough information to tell what type of node it is and information about controllers and children.

Offset Type Description
0x0000 Function Pointer Unknown function
0x0004 Function Pointer Function to parse a line of an ASCII model file
0x0008 Function Pointer Function to perform post node processing
0x000C Function Pointer Unknown function
0x0010 Function Pointer Unknown function
0x0014 Function Pointer Unknown function
0x0018 UINT32 Inherit color flag
0x001C UINT32 Part number/Node number
0x0020 CHAR [32] Node name
0x0040 Geometry Pointer Pointer to the parent geometry, always zero
0x0044 Parent Node Pointer Pointer to the parent node, always zero
0x0048 Node Header Pointer Array Array of pointer to the children nodes
0x0054 Controller Key Array Array of controller key structures
0x0060 FLOAT Array Array of controller data values
0x006C UINT32 Node flags/type
0x0070 Total length of the structure

Mesh Nodes

All nodes that contain mesh information share a common header.  The header is as follows:

Offset Type Description
0x0000 Node Header Common node header
0x0070 Function Pointer Function to prepare the mesh information
0x0074 Function Pointer Function to cleanup after mesh has been built
0x0078 Face Array Array of face structures
0x0084 FLOAT [3] Bounding box min, defaults to (0, 0, 0), computed
0x0090 FLOAT [3] Bounding box max, defaults to (0, 0, 0), computed
0x009C FLOAT Mesh radius, defaults to 0, computed
0x00A0 FLOAT [3] Average of all points in the mesh, defaults to (0, 0, 0), computed
0x00AC FLOAT [3] Diffuse color, defaults to (0.8, 0.8, 0.8)
0x00B8 FLOAT [3] Ambient color, defaults to (0.2, 0.2, 0.2)
0x00C4 FLOAT [3] Specular color, defaults to (0, 0, 0)
0x00D0 FLOAT Shininess, defaults to 1
0x00D4 UINT32 Shadow flag, defaults to 1
0x00D8 UINT32 Beaming flag, defaults to 0
0x00DC UINT32 Render flag, defaults to 1 excluding AABB mesh where it defaults to 0
0x00E0 UINT32 Transparency hint, defaults to 0 excluding AABB mesh where it defaults to 1
0x00E4 UINT32 Unknown value, defaults to 0.  Known values probably 0, 1, 2, and 4.
0x00E8 CHAR [64] Texture0/Bitmap
0x0128 CHAR [64] Texture1
0x0168 CHAR [64] Texture2
0x01A8 CHAR [64] Texture3
0x01E8 UINT32 Tile fade, defaults to 0
0x01EC UINT32 Pointer Array Vertex Indices, compile only, not stored in binary
0x01F8 UINT32 Array Left over faces, compile only, not stored in binary??
0x0204 UINT32 Array Vertex Indices count array
0x0210 Raw UINT16 Pointer Array Vertex Indices offset array (The pointers exist in the model data, however, the list of UINT16 that they point to exist in the raw data.
0x021C Raw Data Pointer Unknown, probably used with triangle strips, initialized to -1
0x0220 UINT32 Unknown, probably used with triangle strips, initialized to 0
0x0224 UINT8 Triangle mode
0x03 = Triangle
0x04 = Triangle Strips
0x0225 UINT8 [3] Padding
0x0228 Pointer Pointer to a compile only structure, always zero
0x022C Raw FLOAT [3] Pointer Pointer to the vertex data, stored in the raw data region, -1 if not present
0x0230 UINT16 Vertex count
0x0232 UINT16 Texture count, usually 1
0x0234 Raw FLOAT [2] Pointer Pointer to the texture 0 vertex data, stored in the raw data region, -1 if not present
0x0238 Raw FLOAT [2] Pointer Pointer to the texture 1 vertex data, stored in the raw data region, -1 if not present
0x023C Raw FLOAT [2] Pointer Pointer to the texture 2 vertex data, stored in the raw data region, -1 if not present
0x0240 Raw FLOAT [2] Pointer Pointer to the texture 3 vertex data, stored in the raw data region, -1 if not present
0x0244 Raw FLOAT [3] Pointer Pointer to the vertex normals, stored in the raw data region, -1 if not present
0x0248 Raw UINT32 Pointer Pointer to the vertex RGBA colors, stored in the raw data region, -1 is not present
0x024C Raw FLOAT [3] Pointer Pointer to texture animation data, stored in the raw data region, -1 if not present
0x0250 Raw FLOAT [3] Pointer Pointer to texture animation data, stored in the raw data region, -1 if not present
0x0254 Raw FLOAT [3] Pointer Pointer to texture animation data, stored in the raw data region, -1 if not present
0x0258 Raw FLOAT [3] Pointer Pointer to texture animation data, stored in the raw data region, -1 if not present
0x025C Raw FLOAT [3] Pointer Pointer to texture animation data, stored in the raw data region, -1 if not present
0x0260 Raw FLOAT? Pointer Pointer to texture animation data, stored in the raw data region, -1 if not present
0x0264 UINT8 Light mapped flag, defaults to 0
0x0265 UINT8 Rotate texture flag, defaults to 0
0x0266 UINT16 Padding
0x0268 FLOAT Vertex normal sum divided by 2, initialized to 0
0x026C UINT32/FLOAT Unknown, initialized to 0
0x0270 Total length of structure

The two arrays at 0x0210 and 0x0204 are interrelated. The array at 0x0210 isn't an array of UINT16s, it is an array of pointers to lists of UINT16.  The number of UINT16s in each of the lists is specified by the elements of the array at 0x0204.  For the second entry in both 0x0210 and 0x0204, the array 0x0204 might tell us the there are 14 vertices in the list while the 0x0210 array gives us the pointer to the list.

All the pointers 0x022C through 0x0248 point to lists of data.  The number of elements in these list is specified by the UINT16 at 0x0230 which is the vertex count.

The face structure is as follows:

Offset Type Description
0x0000 FLOAT [3] Plane normal
0x000C FLOAT Plane distance
0x0010 INT32 Surface ID
0x0014 INT16 [3] Adjacent face number or -1
0x001A INT16 [3] Vertex indices
0x0020 Total length of structure

The Dummy Node 

The dummy node is a default node in a geometry that only contains children nodes and controller information.  It has no other data associated with it.

Offset Type Description
0x0000 Node Header Common node header
0x0070 Total length of structure

The Light Node

The light node specifies light sources in the geometry of the model.

Offset Type Description
0x0000 Node Header Common node header
0x0070 FLOAT Flare radius
0x0074 UINT32 Array Array of unknown information
0x0080 FLOAT Array Flare sizes
0x008C FLOAT Array Flare positions
0x0098 FLOAT [3] Array Flare color shifts
0x00A4 CHAR Pointer Array Array of pointers to the flare texture names
0x00B0 UINT32 Light priority, defaults to 5
0x00B4 UINT32 Ambient only flag, defaults to 0
0x00B8 UINT32 Dynamic type, defaults to 1
0x00BC UINT32 Affect dynamic flag, defaults to 1
0x00C0 UINT32 Shadow flag, defaults to 1
0x00C4 UINT32 Generate flare flag, defaults to 0
0x00C8 UINT32 Fading light flag, defaults to 1
0x00CC Total length of structure

The Emitter Node

The emitter node specifies dynamic graphical elements that are emitted from the model such as smoke or sparkles.

Offset Type Description
0x0000 Node Header Common node header
0x0070 FLOAT Dead space
0x0074 FLOAT Blast radius, defaults to 0
0x0078 FLOAT Blast length, defaults to 0
0x007C UINT32 X grid
0x0080 UINT32 Y grid
0x0084 UINT32 Space type, defaults to 0
0x0088 CHAR [32] Update
0x00A8 CHAR [32] Render
0x00C8 CHAR [32] Blend
0x00E8 CHAR [64] Texture
0x0128 CHAR [16] Chunk name
0x0138 UINT32 Two sided texture flag, defaults to 0
0x013C UINT32 Loop flag, defaults to 0
0x0140 UINT16 Render order, defaults to 0
0x0142 UINT16 Padding
0x0144 UINT32 Emitter flags
0x0001 = P2P
0x0002 = P2P Sel
0x0004 = Affected by Wind
0x0008 = Is Tinted
0x0010 = Bounce
0x0020 = Random
0x0040 = Inherit
0x0080 = Inherit Vel
0x0100 = Inherit Local
0x0200 = Splat
0x0400 = Inherit Part
0x0148 Total length of structure

The Reference Node

The reference node... TBD

Offset Type Description
0x0000 Node Header Common node header
0x0070 CHAR [64] Ref model
0x00B0 UINT32 Reattachable flag
0x00B4 Total Length of structure

The TriMesh Node

The trimesh node provides the basic drawing mesh used to render elements of the game.

Offset Type Description
0x0000 Mesh Header Common mesh header
0x0270 Total Length of structure

The Skin mesh Node

The skin mesh node provides a specialized mesh where the texture is stretched and contorted as the model moves to provide a more realistic look to skin.  It is mostly used just for things such as dragon wings.  

Offset Type Description
0x0000 Mesh Header Common mesh header
0x0270 Weight Array Used during compile time to store weight information
0x027C Raw FLOAT [4] Pointer Compiled weight information for each vertex
0x0280 Raw UINT16 [4] Pointer Reference index for bones
0x0284 Raw UINT16 Pointer Bone reference mapping array
0x0288 UINT32 Number of entries in the mapping array
0x028C Quaternion Array QBone ref inv
0x0298 FLOAT [3] Array TBome ref inv
0x02A4 UINT32 Array Bone constant indices
0x02B0 UINT16 [17] Bone part numbers
0x02D2 UINT16 Spare
0x02D4 Total length of structure

Most all skin data is computed from the weights array.

The Animmesh node

The animmesh nodes are used for the game's GUI

Offset Type Description
0x0000 Mesh Header Common mesh header
0x0270 FLOAT Sample Period
0x0274 FLOAT [3] Array Animation vertices, not stored in binary
0x0280 FLOAT [3] Array Animation texture vertices, not stored in binary
0x028C FLOAT [3] Array Animation vertex normals, not stored in binary
0x0298 FLOAT [3] Pointer Pointer to the stored animation vertex information
0x029C FLOAT [2] Pointer Pointer to the stored animation texture vertex information
0x02A0 UINT32 Number of vertex sets
0x02A4 UINT32 Number of texture vertex sets
0x02A8 Total length of structure

The stored arrays are much like the other stored vertex arrays.  There size is the number of sets times the number of mesh vertices.  There is also a difference between how this information is parsed from the ASCII version and stored in the binary.  In the ASCII version, each vertex is listed sequentially for each vertex or texture vertex  sets.  However, in the binary version, each vertex is store with the different sets store sequentially.

The Danglymesh node

The danglymesh node provides a model with the look of movement by allowing faces to move due to momentum even after the whole model has stopped.  Thus is much like how a car passenger jerks forward in a car when it stops suddenly.

Offset Type Description
0x0000 Mesh Header Common mesh header
0x0270 FLOAT Array Vertex constraints
0x027C FLOAT Displacement value
0x0280 FLOAT Tightness value
0x0284 FLOAT Period value
0x0288 Total length of structure

Much like the vertex information for the mesh, the constrains are expanded to match the vertex list stored in the model.

The AABB node

The aabb node provides the game with the ability to test for collisions.

Offset Type Description
0x0000 Mesh Header Common mesh header
0x0270 AABB Entry Pointer AABB table root pointer
0x0274 Total length of structure

The following is the layout of the AABB entry structure.

Offset Type Description
0x0000 FLOAT [3] Min bounding box
0x000C FLOAT [3] Max bounding box
0x0018 AABB Entry Pointer Left node
0x001C AABB Entry Pointer Right node
0x0020 INT32 Leaf face part number or -1 if not a leaf
0x0020 UINT32 Most significant plane???
0x01 = Positive X
0x02 = Positive Y
0x04 = Positive Z
0x08 = Negative X
0x10 = Negative Y
0x20 = Negative Z
0x0024 Total length of structure

Update - 09/29/2002

  1. Cleaned up the definition of the AABB entry slighly.
  2. Updated the skin node.

Update - 08/22/2002

  1. Corrected assorted typos and minor errors
  2. "Triangle fan" changed to "Triangle strip".
  3. Corrected the type on the offset in the mesh header at 0x0210.  The array exists in model data, but the actual data that the array points to exists in the raw data.
  4. Added a missing unknown value in the mesh header at 0x00E4.  Corrected the offset of texture0/bitmap.
  5. Updated information on the part numbers and the node counts.
  6. The value at 0x0068 in the geometry header is now known.
  7. Another flag in the geometry header discovered.

Credits

I wanted to thank Zaddix and Revinor.  Their information about the binary model formats provided an excellent starting point for my work.