XWA OPT Files
by StealthJedi
http://code-alliance.com




Thanks to



History


Updated: 14/may/00

  1. Added Mesh Info 001 "C" header
  2. Addition LOD converstion formula
  3. Additional transparency info for Texture Header "E"


Conventions


Values are as follows unless other wise noted. For reference these are Delphi Pascal Units.

OPT Files General



OPT Files have an elaborate offset and header system. They contain the 3D information and textures palettes etc needed to render an XWvT ship. The following is the "general" structure

The XWA General Structure is:




There are several types of what appears to be offsets, we'll cover them as we get to them.

The first one is found in the Main Header. It may appear to be an arbitrary number, This number in BOP files is a combination of what appears to be a time stamp plus an offset . When you read the number you must subtract 8 from it's value before you can use it. The resultant number is used as a global offset number. When you encounter a jump offset value you subtract this global number from it to arrive at the offset in decimal from the beginning of file.

This global number can be set to " 8 " and at each place later in the file where an offset is needed you use file offset(decimal) + 8 to create a valid offset to where you want the offset to point in the file. Bop then created a much bigger number as the apparent time stamp of file creation was added to each offset. All bop files created for a mission will have the same global offset numbers. Later or earlier files will have different global offsets. Thus you could have the same op1 file with different offsets depending on when the file was created. Op1 files are the same as bop opt files.

Main Header


Main Header
 -----------
 FBFF FFFF                
 File size                 // size of file - 8 bytes
 Global Offset Number     // to get the number to use subtract 8
                          // use this number to subtract from jump offsets   
                             to arrive at offset from beginning of file.
                             to write a file set to "8" and add 8 to all
                             other offsets + file offset from beginning of file
							 


Main Jump Header


Next is the 02 Header. This contains the jump offsets to the Main Mesh Headers. One mesh header exists for each piece of the 3D object (mesh).


02 Header XWA
 -----------
 2                 // (byte)  unknown use // maybe a word ,Color index to a palette or color value
 0                 // (byte)  unknown use
 NumOfOffsets      // (Longint) the number of jump offsets to Main Mesh Headers ** See Note above
 Jump to Offsets   // Points to first offset
 [1..NumOfOffsets] // (beginning at offset 22)
 


Main Mesh Header


XWVT:: Main Mesh Headers can have any number of blocks to read so a file reader should not rely on the (003) byte format to locate this block. Each has different information. The one caveat is the number of block 22 to read. If the Main Mesh header block starts with a 3 there are no block 22's(hard point info) to read. An opt file reader to be reasonably accurate of what it is encountering should not rely on what will appear in each of these headers instead it should test to see what is at that offset and take the appropriate action. This is especially true in bop files where there may be an offset to a null entry.

BOP:: Main Mesh Headers have even more blocks to read. see the Main Mesh Header BOP structure.

The Mesh Master Reverse Offset (MMRV).
This number is similar to the file global offset, however it is used to go back "x" number of bytes, usually if you need to go back to the Mesh Master header. To use the number simply store the mesh master reverse offset, when you encounter a reverse offset in a Mesh Info header you subtract the MMRV from the Info headers RV number to get the number of bytes to go back.

The reverse offset can also be used to get to the next MMH block, Take the first MMH RV offset you encounter in the file, add any Main Jump offset (blk 02) to it. The result will be exactly 178 bytes more than the offset to that MMH blocks list of jumps.

With all that above, If the reverse offsets are set to "null" when writing a file , then they will not be changed when bop writes the op1 file. So either they are redundant code ,or some sort of material flags settings. Either way the opt seems no different under 3d conditions with these set to null.


Main Mesh Header XWA
-----------
 0
 0
 NumOfMeshSub headers       // num of block 22+ num of block 28  + 3 = num sub headers
 Offset to Jump Offsets
 1
 mesh master reverse offset // Mesh Global reverse offset
 offset to 03               // vertices
 offset to 11               // vertex normals
 offset to 13               // texture normals
 offset to 28 block         // Engine Glows 
 offset to 22               // Hard points
 offset to 23 block         // Insertion offset, and scale
 offset to 25 block         // Collision Box
 offset to 004 block        // Mesh Info Header


Mesh Descriptor 025 Block Header


Mesh Descriptor O25 Block Header
 -----------
 0
 25
 0
 0
 1
 Jump to mesh type
 Mesh type               // see list below
 Explosion type          // see below
 array[0..11]of single; (float) //Hit zone info see below for note on calculating
 targeting group id         //  longint
 array[0..2] of single; (float) // Targeting box coords ***** see notes below
  


Here is a list of the Mesh Types

  • 0: Default
  • 1: MainHull
  • 2: Wing
  • 3: Fuselage
  • 4: GunTurret
  • 5: Smallgun
  • 6: Engine
  • 7: Bridge
  • 8: ShieldGen
  • 9: EnergyGen
  • 10: Launcher
  • 11: CommSys
  • 12: BeamSys
  • 13: CommandBeam
  • 14: DockingPlat
  • 15: LandingPlat
  • 16: Hangar
  • 17: CargoPod
  • 18: MiscHull
  • 19: Antenna
  • 20: RotWing
  • 21: RotGunTurret
  • 22: RotLauncher
  • 23: RotCommSys
  • 24: RotBeamSys
  • 25: RotCommandBeam
  • 26: Custom1
  • 27: Custom2
  • 28: Custom3
  • 29: Custom4
  • 30: Custom5
  • 31: Custom6


    Explosion Type

    0,1,4,5,8,9 = Mesh continues in straight line when destroyed 2,3,6,10 = Mesh breaks off and explodes 7 = destructible parts


    Hit Zone floats array[0..11] of single how to calculate values

    The floats are in 4 sets representing X,Y,Z as follows.

  • Floats [0..2] = The SPAN X,Y,Z
  • Floats [3..5] = Center point of Hit Zone (very close to block 23 center point)
  • Floats [6..8] = MIN X,Y,Z of the USED in face data vertices
  • Floats [9..11]= MAX X,Y,Z of the USED in face data vertices

    How to calculate The SPAN X,Y,Z.

    SpanX = MaxX subtract MinX 
    ,repeat for Y,Z.

    How to calculate the Hit Zone center point.

    CenterX = SpanX divided by negative 2 then add MaxX
    repeat for Y,Z.

    Targeting Group ID

    The targeting group id is used to describe which and where the small yellow targeting boxes show up in the Hud with the "," key. You can associate several meshes together by assigning them the same coordinates in the float array + the same group id number. Turrets/generators etc are set to coordinates "0,0,0" because they can be blown up.In that case the mesh center is used( Could be the Turret block coordinate too but the mesh hit zone center makes more sense).

    IE: Two separate main hull meshes could be set to Id number 2 and both sets of floats are set to the same X,Y,Z coordinate of where you want the targeting box to show up at in the HUD.

    conversely you could have each Mesh show up as as separate target by giving ea a different id and set of coordinates.

    The Ids start from 0 to ~.


    Rotation Scale Block Header


    This block describes various aspects about which way the mesh is oriented. These are not fully tested yet. the last three sets of floats are vectors. Most notably used in turrets to describe which is the plane of rotation and aiming.

    Rotation/Scale Block Header
     -----------
     0
     23
     0
     0
     1
     jump to floats
     array[0..2] of float   //  Pivot point
     array[3..5] of float   //  axis of rotation  (z)
     array[6..8] of float   //  aim direction     (x)
     array[9..11]of float   //  90 deg to aim direction
     



    XWA Engine Glow Block Header


    Engine glow blocks ,jumps to these are in mesh header that has the engines in it. The two colors use the RGB from the longint and the extra high byte seems to be a density or transparency value. There is two colors the core is like a cross right in the middle surrounded by the second color. You can set multi engine models to different colors if you wish , though in original models they are set to the same within model. The Last three sets of floats are likely fog density`s value 0 - 1.0 these are floats.Not sure why so many values though. Most likely for shaping reasons.The main vector should be the end of d3d fog setting , need to play with that one a bit more.

     XWA Engine Glow Block Header
     -----------
     0
     28
     0
     0
     1
     jump to "0"
     0
     Core Color   Longint                // with alpha component
     Outer Color  longint                // with alpha component
     array[0..2] of float                //  vector 1   Point in middle of Engine face
     array[3..5] of float                //  vector 2   x= width , y= height , z= length
     (next is 3 axis)                    // unknown function
     (0,1,0) array[0..2] of float
     (0,0,1) array[3..5] of float
     (1,0,0) array[6..8] of float
     


    Hard Point Block Header


    Block 22 describes the location of the hard points on ships ,ie the end of the gun barrels... Ships such as a platform have two sets sometimes of Hard points in the same location, one set is empire weapons the other set is rebel weapons.

    XWA Hard points some additional Hard points have been added beyond this list , (not researched up to 39 hp)

    hard point Block Header
     -----------
     0
     22
     0
     0
     1
     jump to hard point type
     hard point type        //  hard point type ie: Rebel laser
     3 Floats             // hard point coordinate
     

    Here is a list of the Hard points.

  • 0: NONE
  • 1: REBELLASER
  • 2: TURBOREBELLASER
  • 3: EMPIRELASER
  • 4: TURBOEMPIRELASER
  • 5: IONCANNON
  • 6: TURBOIONCANNON
  • 7: TORPEDO
  • 8: MISSILE
  • 9: SUPERREBELLASER
  • 10: SUPEREMPIRELASER
  • 11: SUPERIONCANNON
  • 12: SUPERTORPEDO
  • 13: SUPERMISSILE
  • 14: DUMBBOMB
  • 15: FIREDBOMB
  • 16: MAGPULSE
  • 17: TURBOMAGPULSE
  • 18: SUPERMAGPULSE
  • 19: NEWWEAPON1
  • 20: NEWWEAPON2
  • 21: NEWWEAPON3
  • 22: NEWWEAPON4
  • 23: NEWWEAPON5
  • 24: NEWWEAPON6
  • 25: INSIDEHANGAR
  • 26: OUTSIDEHANGAR
  • 27: DOCKFROMBIG
  • 28: DOCKFROMSMALL
  • 29: DOCKTOBIG
  • 30: DOCKTOSMALL
  • 31: COCKPIT


    Mesh Info Header


    Mesh Info Headers contain

    Main Info Header 004 block  "A"
    ---------
     0
     0
     4
     jump to jumps
     1
     Reverse Offset       // Subtract the mesh reverse num from block 3 to
                          // arrive at how many bytes to get back there
     0                    // Null vertex jump
     0                    // Null Texture vertex jump
     0                    // Null Vertex normal jump
     Jump to 21 block     // Jump to Face Jump
     

    may also have this section with no "Nulls" as below.
    Mesh Info Header "B"

    Main Info Header 001 block  "B"
    ---------
     0
     0
     1
     jump to jumps
     1
     Reverse Offset       // Subtract the mesh reverse num from block 3 to
                          // arrive at how many bytes to get back there
     Jump to 21 block     // Jump to Face Jump
     

    Mesh Info Header "C"

    Main Info Header 001 block  "C"
    ---------
     0
     0
     1
     jump to jumps
     1
     Unknown Longint   // longint of unknown function
     0                 // Null vertex jump
     0                 // Null Texture vertex jump
     Jump to 21 block  // Jump to Face Jump
     

    Can be found in planetaryfighter.opt


    Mesh Vertex Header


    Mesh Vertex Headers contain the float type data for the vertices.

    03 Vertex Header
    ------------------
     0
     3
     0
     0
     NumVertices       // (Longint)
     Jump to Floats
     Vertices         // NumVertices*3 Floats (x,y,z)


    Texture Vertex Header


    Texture Vertex Headers contain the float type data for aligning textures on faces. these are normalized u,v or s,t

    13 Texture Vertex Header
     ------------------
     0
     13
     0
     0
     NumTexVertices      // (Longint)
     Jump to Floats
     TexVertices        // NumTexVertices*2 Floats (u,v)
     


    Vertex Normal Header


    Vertex Normal Headers contain the float type data describing the normalized direction of the vertices. This is found by averaging the normals of all the faces that use this vertex.

    11 Vertex Normal Header
     ------------------
     0
     11
     0
     0
     NumVertNorms          // (Longint)
     Jump to Floats
     VertNorms             // NumVertNorms*3 Floats (i,j,k)
     


    Mesh Data Header


    This is a directory for master face groups. Follow the MFH Jumps to get to Face Headers (Face Headers then have their own groupings of faces). A small float is included.

    Mesh Data Header
    ------------------
     0
     21
     1                               // Number of Face Data Header Jumps
     Jump to the MFH Block Jump
     1                               // Number of jumps to face data headers
     Jump to Float
     Jump to Mesh Face Header        // High Res Face Data Header
     Jump to Mesh Face Header        // Low Res Face Data Header if present see Notes**
     LOD Float[array]                // One float for ea Face Data Header jump (Lo res distance numbers) 
     

    NOTES on Model Resolutions

    If the Number of Face Data Headers is >1 then ,each successive Face data header represents a lower detail model.

    Ie: an Xwing has 3 detail models, the highest would be FDH 0, next highest detail would be FDH 1 , and finally the lowest detail model is FDH 2.

    XWA , all except one model only have two levels of detail.

    To roughly convert the raw distance value found int the OPT to kilometers, you must use the equation:

    km = .000028537 x (RawValue ^ -1.0848093)

    To convert kilometers to a raw value, use the equation:

    raw = (km  / .000028537) ^ (1/-1.0848093)

    A raw value of 0 means that the detail level is always visible, and a value of 1 means that the detail level is never visible.

    Mesh Face Header


    This Block jumps to various areas related to the geometry and appearance of faces. Various "face groups" can be specified so different textures will be used.

    Mesh Face Header
     ------------------
    0
    0
    NumFaceGroups        // Num of 20/00/01/07/24 blocks to read 
    Offset to Jumps
    1
    Reverse Offset     // 
    Jump to 20 Block    // Texturing Block  ** many variations **
    Jump to 00 block    // Unknown texturing block suspect bug in code
    Jump to 01 Block    // Face Data
    Jump to 07 Block    // texture name re declared for reuse on another face.
    Jump to 24 block    // Texture Jump list, for Flight Group Textures in XWA , 
                           XWA also seems to be used for animations
    

    *** Does not always have block 20/07/24 to read only 01 block if num is 1.

    *** 20 block new texture.
    *** 24 Block New Group of textures ,generally the flight group color textures( not always 4 in xwa)? Has other uses in XWA
    *** 07 Block Re use texture on this face
    *** 01 Face Data


    20 Texture Header


    Includes Texture and MipMaps. MipMaps are a series of images that decrease in dimensions by a factor of 2. Three MipMaps are included along with the main image.
    ie. A Texture would include an image that is 64x64, 32x32, 16x16, and 8x8.

    Texture data is stored like a bmp (upside down to convention) , Ie bottom right pixel of image is first byte and top right pixel last byte ,unlike a bmp there is no padding of the bytes.

    Texture headers have been found in several variations.


    Texture Header "AA" (XWA)
    ------------------
    JumpToTex            // Points the 'T' in "Tex00000"
    20
    1
    Jump to 26 block jump
    UID                  // unique Id per texture
    Jump To "Palette offset " jump
    Byte[0..8]           // "Tex00000" + '\0' (null term string (9-bytes))
    Jump to 26 Texture block
    Jump to "Palettes"   //  beginning of Palettes 8192k for XWA
    0
    TexSize              // Size without MipMaps (Width*Height)
    DataSize             // Size including MipMap Sizes
    Widthbs              // Width of Image
    Height               // Height of Image
    Byte[0..DataSize-1]  // Image Data + MipMap Data

    Following this block is the palettes then a 0,26 block (E ) texture block.


    Texture Header "AAA" (XWA)
    ------------------
    JumpToTex            // Points the 'T' in "Tex00000"
    20
    0
    0
    UID                  // unique Id per texture 
    Jump To "Palette offset " jump
    Byte[0..8]           // "Tex00000" + '\0' (null term string (9-bytes))
    Jump to "Palettes"   //  beginning of Palettes 8192k for XWA
    0
    TexSize              // Size without MipMaps (Width*Height)
    DataSize             // Size including MipMap Sizes
    Width                // Width of Image
    Height               // Height of Image
    Byte[0..DataSize-1]  // Image Data + MipMap Data

    Standard XWA texture block


    Texture Header "B" 
    ------------------
    0
    7
    0
    0
    1
    JumpToTex            // Points the 'T' in "Tex00000"
    Byte[0..8]           // "Tex00000" + '\0' (null term string (9-bytes))
    


    Texture Header "C" 
    ------------------
    0
    24
    NumOfJumps           // Number of (20,07) offsets to read
    JumpListOffset       // Offset to Jump List
    1
    Reverse Offset
    Array Of Offsets     // these offsets point to the first entry in a Texture Header"A" Block      
    

    XWA , Does not seem to only have 4 "NUmOFJumps" in checking several models found up to 37 jump entries in though the first four were different the remaining were the same as 4th entry, strange it `s like this in more than one model though , was hoping it was a bug. Still think it is.


    Texture Header "CC" XWA
    ------------------
    0
    24
    1           
    JumpListOffset       // Offset to Jump List
    0
    0
    Offset               // to 20  Texture Header"AAA" Block      
    

    XWA , points to one texture 20 only , seems to be multiple of these in front of a regular 20 texture, probably overlays


    Texture Header "CCC" XWA
    ------------------
    0
    24
    num of jumps          //            
    JumpListOffset       // Offset to Jump List
    0
    0
    Offsets               // can be a combination of AAA texture blocks  and normal 07 blocks     
    

    XWA , The 07 textures seem to be repeated or mixed for some reason , whether it is some sort of animation.


    Texture Header "E" (XWA)
    ------------------
    0
    26
    0
    0
    NumOfBYTES (image+mipmaps)
    JumptoBytes
    Bytes
    

    Appears to be an alpha mask , image values are either "00" or "FF" the image is the same as the 0,20,1 image plus mipmaps.

    Any value ranging from 0 to 255 can be used in the alpha mask, where a hex value of 0xFF means that that specific pixel of the texture is completely nontransparent and a value of 0x00 is completely transparent.  The standard is 0x6F.


    Palettes


    Palettes are found by using the Jump to palettes offset in the 20 texture header block. Then comes 15 color maps (shade tables)and 1 palette. Each is 256 * word for a total of 8192 bytes. The color maps go from dark to lighter shades with the [0..15] # 8 one being the palette.

    Textures can share a set of palette/color maps , if the "Jump to "Palettes" entry is the same in the Texture header "A" then these textures share that set of 16 palettes.

    Use a bit pattern of 5-6-5 b,g,r .

    Unknown if there is a limit on the number of pals you can add, though file size would have to be a consideration if no pals were shared among textures.

    Pals are written after the texture .


    Palette XWA General
    ------------------
    (256 * word)*16      // ea palette X 16 = 8192 bytes
                         // pals use 5-6-5  blue,green,red bit pattern 
    


    Face Data Header


    This block contains information for the faces in the mesh that called it.

    Face Data Header
    ------------------
     0
     1
     0
     0
     NumFaces                   // Number of Faces being declared
     Offset to Longint          // Face data immediately follows the longint
     Edges                      // unique edge count for faces in this header
     FaceVerts[0..NumFaces-1]   // vertex index
     FaceEdges[0..NumFaces-1]   // edge index (no list)
     FaceTXVX[0..NumFaces-1]    // texture vertex index 
     FaceVxN[0..NumFaces-1]     // vertex normal index 
     FaceNorms[0..NumFaces-1]   // Face Normals
     FaceText[0..NumFaces-1]    // Face Texturing Info (software vectors)
     

    Vertices: Each face declares four groups of four vertex references (longints). The first group is the references to the geometry vertices (3 Block).

    Edges The second group is edges numbers.Ea edge has a unique number in this group of faces,Ea pair of vertices that share an edge will have the same number. New numbers per Face Header

    TX CoordinatesThe third group is references to the texture vertex list.

    Vertex Normals The fourth group is referenced to the vertex normal list .

    All references are Longints. If a reference is FFFFFFFF (-1), then it should be ignored, and that face should be assumed to have only 3 vertices. Each face will take 64 bytes. Faces are either a triangle or a quad.

    Normals: Each face has three floats (i,j,k) representing its normalized vector. Each face then has 12 Bytes.

    Texturing: Used by the software rendering engine. Six floats for each face (24 bytes). These are 2 vectors.Direction and magnitude are significant.
    1. the cross product of the two must be the face normal (not unit length, but same direction as the face normal) or the texture exhibits weird "out-of-plane" effects.
    2. The vectors are set to the "across-top" dx,dy,dz and the "down side" dx,dy,dz. In the case of a rectangular face the vector magnitudes (lengths) will equal the side lengths. Which side the face is viewed from in calculating this doesn't seem to matter.
    3. The two vectors position the texture in 3-D space and also set the scale of the texture - the texture is basically stretched in space to fit the vectors.

    XWA If the face is a Triangle, Edge,Vxn,and Txvx may not necessarily also be limited to 3 numbers, in fact they can be mixed between quad numbers and tri.