MDL File Format
The MDL file format is used for Quest for Glory 5's 3d models. These files contain the textures and models used for characters and objects from the game.
qfg5model is a command-line app with the ability to export and import textures and meshes from MDL files.
Contents
MDL File Format
Model format
Let M+0 be the start of the model (offset in hex):
- M+0C is the name of the mesh. Mesh names can only be up to 0h10 bytes in size.
- M+1C is a 4byte integer showing the number of submeshes.
- M+2D through to 0h427 is the bitmap palette for the 256 (0h100) color bitmap texture (B+0).
- M+0h428 is a 4byte address pointing to the start of the bitmap texture.
- M+0h42C through to M+0h42C+numberOfSubmeshes: each 4byte address points to the start of a submesh (there is an address for each submesh)
- Continues with first submesh...
- Continues with Bitmap...
SubMesh format
Let SM+0 be the start of each submesh;
- SM+0 is a 0h10 byte segment containing the name of the submesh.
- SM+0h60 is a 4Byte integer showing the number of Vertices.
- SM+0h64 is a 4Byte integer showing the number of UV cords
- SM+0h68 is a 4Byte integer showing the number of Faces.
- (Note the QFG5 engine maps Vertexes and UV on to Faces not the other way around)
- SM+0h6C is a 4Byte integer representing the relative (submesh) address of the start of the vertex list (i.e. this register is always set to 7C).
- SM+0h70 (aka "R1") is a 4Byte integer representing a first function of the number of vertices
- = (SUBMESH_HEADER_VERTICES_LIST_ADDRESS=7C) + numberOfVertices*(sizeOfVertexInBytes=12)*(BYTES_PER_INT=4)
- SM+0h74 (aka "R2") is a 4Byte integer representing a second function of the number of vertices
- = (SUBMESH_HEADER_VERTICES_LIST_ADDRESS=7C) + numberOfVertices*(sizeOfVertexInBytes=12)*(BYTES_PER_INT=4) + numberOfUVCoords*(sizeOfUVcoordInBytes=8)*(BYTES_PER_INT=4) (imprecise?)
- SM+0h78 (aka "R3") is a 4Byte integer representing a third function of the number of vertices
- = (SUBMESH_HEADER_VERTICES_LIST_ADDRESS=7C) + numberOfVertices*(sizeOfVertexInBytes=12)*(BYTES_PER_INT=4) + numberOfUVCoords*(sizeOfUVcoordInBytes=8)*(BYTES_PER_INT=4) + numberOfFaces*(sizeOfFaceInBytes=40)*(BYTES_PER_INT=4) (imprecise?)
- SM+0h7C are all the 4ByteFloatVertexes, each of which is 12 bytes and of the following format:
- FloatX
- FloatY
- FloatZ
- Note the vertices also appear to contain light map coordinates - which are not referenced by the faces (and are disregarded - i.e. left alone - by qfg5model)
- SM+0h7C+[#Vertices]*12 are all the 4ByteFloat UV coordinate mappings, each of which is 8 bytes and of the following format:
- FloatU
- FloatV
- SM+0h7C+[#Vertices]*12+[#UV]*8 are the Face Data arrays, each of which is 40 bytes and of the following format:
- 4ByteIntVertex#1 (vertex index)
- 4ByteIntVertex#2 (vertex index)
- 4ByteIntVertex#3 (vertex index)
- 4ByteIntUVMap#1 (UVcoord index)
- 4ByteIntUVMap#2 (UVcoord index)
- 4ByteIntUVMap#3 (UVcoord index)
- 4ByteIntSubbitmap# (subbitmap index) - previously "Unknown" - it references the subbitmap to which this face's UV coords apply
- 4BytefloatFACENormalMappingX
- 4BytefloatFACENormalMappingY
- 4BytefloatFACENormalMappingZ
- SM+0h7C+[#Vertexes]*12+[#UV]*8+[#faces]*40 are the Lighting Entries (number of lighting entries = number of vertices), each of which is 16 bytes and of the following format:
- 4ByteIntLightingEntryPartA-UNDETERMINED
- 4ByteIntLightingEntryPartB-UNDETERMINED
- 4ByteIntLightingEntryPartC-UNDETERMINED
- 4ByteIntLightingEntryPartD-UNDETERMINED
Note lighting entry data is currently disregarded - i.e. left alone - by qfg5model - yet when a mesh resolution is increased, nearest (best guess) lighting entry data is applied for all new vertices. If the exact nature of this lighting entry data is determined, it will be possible to interpolate across it (potentially enhancing the quality of the lighting as viewed on a high resolution mesh).
- Continues with next submesh...
Bitmap format
Let B+0 be the start of each bitmap;
- B+0 is an 4Byte integer representing (the numberOfSubbitmaps * 4)
- If numberOfSubbitmaps > 1, then add "MultiBitmapHeaderAdditionSpace" consisting of (numberOfSubbitmaps-1) 4Byte integers
- i.e. B+4 -> B+(numberOfSubbitmaps*4): content format UNDETERMINED - see qfg5model source code for current diagnosis
- Continues with first subbitmap...
Subbitmap format
Let SB+0 be the start of each subbitmap;
- SB+0 is a 4Byte integer representing the Subbitmap width formatted as 32 bit float
- SB+4 is a 4Byte integer representing the Subbitmap height formatted as 32 bit float
- SB+8 is a 4Byte integer representing the power of 2 value corresponding to the Subbitmap width
- SB+12 is a 4Byte integer representing the power of 2 value corresponding to the Subbitmap height
- SB+16 is a 4Byte integer representing the Subbitmap width minus 1
- SB+20 is a 4Byte integer representing the Subbitmap height minus 1
- SB+24 is the Subbitmap contents (width*height bytes)
- Continues with next subbitmap (if existent)...