User Tools

Site Tools


ofp:file_formats:mlod

OFP MLOD

OFP Forum, OFP Home, OFP File Formats, OFP Tools, OFP Missions, OFP 3D Modeling, OFP Terrain

Operation Flashpoint (OFP) aka ArmA: Cold War Assault (CWA)

OFP MLOD file format. This information comes largely from the long defunct 'ofpinternals'.

Acknowledgement from OFPInternals. Thanks to FlipeR (filipus@hotmail.com) for helping in research.

Type Explanation

byte - 8-bit unsigned integer
integer - 32-bit signed integer
float32 - 32-bit float number (single precision)
zstring32 - zero-terminated string, data length is fixed = 32 bytes (so max. string length is 31)
zstring64 - zero-terminated string, data length is fixed = 64 bytes (so max. string length is 63)

Basics: Polygon Vertex Order

For a visible 3-vertex polygon:

AB // clockwise order
C

AC // CounterClock
B

The same for 4-vertex polygon:

AB // clockwise
DC

AD // CounterClock
BC

Your 3D device will cull invisible polygons. An invisible polygon is a polygon that has the other direction order. For example, DirectX default setting is 'cull counterclockwise polygons', so only clockwise is visible.

Structure

Overall

struct P3D
 {
 char Signature[4]; //"MLOD"
 float Version;     //1.1
 ulong LodCount;    //at least one
 struct Lod1
 {
  char Signature[4]; //"SP3X"
  ulong VersionMajor; //0x1C
  ulong VersionMinor; //0x99
  ulong VerticesCount;
  ulong NormalsCount; //(perpendicular)
  ulong PolygonCount;
  ulong Flags;        // unknown values
  struct VertexTables[VerticesCount];
  struct NormalsTables[NormalsCount];
  struct PolyTables[PolyCount];
  char TagSig[4]; //"TAGG"
  struct TagSets[........];
  float LodResolution; // see Appendix A
 };
 .....
 Struct LodN
 {
   ....
 };
 Asciiz DefaultPath[32]; //Optional. Default Path to Textures - (see O2L 'Options')
};

VertexTable

struct VertexTable
{
 float XZY[3];
 long VertexFlags;
};

Vertex Flags

See also O2L 'Point Properties'.

Surface: (0x0000000f mask)

0x00000000 - normal
0x00000001 - on surface
0x00000002 - above surface
0x00000004 - undersurface
0x00000008 - keep height (fence)

Decal (0x00000300 mask)

0x00000000 - normal
0x00000100 - decal
0x00000200 - radio12

Fog (0x00003000 mask)

0x00000000 - normal
0x00001000 - none
0x00002000 - sky

Lightning (0x000000f0 mask)

0x00000000 - normal
0x00000010 - shining
0x00000020 - always in shadow
0x00000040 - fully lighted
0x00000080 - half lighted

User (0x00ff0000 mask)

0x00ff0000 - user additional mark value (0..255)

Hidden (0x01000000 mask)

0x00000000 - Visible
0x01000000 - Hidden

NormalsTable

struct NormalsTable
{
  float XZY[3];
};

Important Note: normals must be inverted (-X, -Y, -Z) for clockwise vertex order (default for DirextX), and not changed for counterclockwise order.

PolygonTable

struct PolygonTable
{
  asciiz TextureName[32];
  ulong VerticesCount;    // (valid values: 3 or 4)
  PolyVertex PVertex[4]; // vertex descriptors, 3, or 4
   // 4th always present in file, even if polygon has only 3 vertex (0 filled)
  ulong PolygonFlags;
};

Important Notes: Order of vertices

Vertices must be reordered for clockwise vertex order (default for DirextX), and not changed for counterclockwise order:

for 3-vertices polygon: 1. 1st vertice descriptor 2. 3rd vertice descriptor 3. 2nd vertice descriptor 4. (not used, zero filled)

for 4-vertices polygon: 1. 1st vertice descriptor 2. 4th vertice descriptor 3. 3rd vertice descriptor 4. 2nd (not used, zero filled)

PolygonFlags

See also O2L 'face properties'.

Enable shadow

0x00000010 - off (disable shadow)

Enable texture merging

0x01000000 - off (disable texture merging)

ZBias (0x00000300 mask)

0x00000000 - none
0x00000100 - low
0x00000200 - middle
0x00000300 - high

Lightning (0x003000a0 mask)

0x00000020 - both sides
0x00000080 - position
0x00200000 - flat
0x00100000 - reversed (transpared)

User (0xfe000000 mask)

0xfe000000 - user additional mark value (0..127)

PolyVertex

struct PolyVertex
{
   ulong Vertex_Index; // (zero based) into respective tables
   ulong Normals_Index;
   float UV_values[2]; // for texture mapping
};

TagSet

struct TagSet
{
   asciiz  Name[64];
   ulong   Size;
   byte    Data[Size];
};

TagNames

Every LodSet contains one or more Tagname entries. The #EndOfFile# tag is a mandatory entry in every LodSet if only to indicate no more tags!

The #Mass# tag is mandatory for Geometry LODs.

Tagnames are Asciiz and can be up to 63 bytes long. 'Official' bis tags are surround by #…..# marks.

Tagnames not listed here (one's with no ## marks) are component names (named selections).

Component names can contain space characters. Proxy names contain 'proxy:' + ProxyName + '.' + ProxyNumber ('01' .. )

'Official' tagnames listed below are a mish mash of obsolete, and still used, commands. This because, the p3d was a still in development at time of CWC release.

#SharpEdges#

The Data field for his tag is

ulong Vertex[VertexCount][2] // 1st and 2nd vertex index of each edge for 'VertexCount' edges

Sharp edge means that these vertices normals are not calculated as average (normalized) between polygons.

#Property#

struct PropertyPair
{
 Asciiz PropertyName1[64];
 Asciiz PropertyValue[64];
};

struct PropertyPair1{...};
   .....
struct PropertyPairN{...}; // N == size of this tag

#MaterialIndex# (only in O2L)

Unknown tag. Used only in O2L. This tag contains a 16-byte structure:

Seems, this tag contains material properties:

4 (RGBA or BGRA) diffuse
4 (RGBA or BGRA) ambient
4 (RGBA or BGRA) specular
4 (RGBA or BGRA) emissive

By default, O2L writes down these values:

51, 75, 55, 0
0, 0, 0, 0
255, 255, 255, 255
255, 255, 255, 255

#Animation# (obsolete)

Obsolete tag. MLOD animation is per-vertex animation and not used now.

float KeyFrameTime; // Valid Values: 0.0 (start) - 1.0 (stop).
                    // Used to change duration of animation playing.
ulong VerticesCount; // Must be the same as Vertices Count in the LOD header.
byte  VertexArray[VerticesCount];// This data replaces main LOD Vertex Table.

#Mass# (only for Geometry LOD)

Must be present only for Geometry LOD.

ulong VerticesCount; // Must be the same as Vertices Count in the LOD header.
float VertexMassArray[VerticesCount];

#Selected# (only in O2L)

#Hide# (only in O2L)

#Lock# (only in O2L)

These tags all have the same structure and are used only while editing in O2L.

They are used so that O2L can save your last selections in the edited file.

byte VertexSaved; // Non-zero value if vertex selected/hidden/locked.
byte PolygonsSaved;// Non-zero value if polygon selected/hidden/locked.

Data Size for any of these tags is

VertexCount + PolygonsCount from current LOD header.

Example: if VertexCount=5, PolygonsCount=3 then a #selected# tag would contain:

2, 2, 0, 2, 0, 0, 1, 1

then Vertex 0, 1, 3 is selected (indices of Vertex Table entries) and

Polygon 1, 2 selected (indices of Polygon Table entries).

Common values for vertices and polygons are the 2 and 1 respectively. But I recommend to compare it only with zero value (for example I saw early this value was 6 instead of 2 or 1).

#EndOfFile#

Mandatory for every LodSet. This is the last tag of current LOD Data structure. It contains no data, so 'Tag Size' field is 0.

LOD Resolution

Valid Values for LOD Resolution are:

1.0e3 = 1'000.0 = View - Gunner
1.1e3 = 1'100.0 = View - Pilot
1.2e3 = 1'200.0 = View - Cargo
1.0e13 = 10'000'000'000'000.0 = Geometry
1.0e15 = 1'000'000'000'000'000.0 = Memory
2.0e15 = 2'000'000'000'000'000.0 = LandContact
3.0e15 = 3'000'000'000'000'000.0 = Roadway
4.0e15 = 4'000'000'000'000'000.0 = Paths
5.0e15 = 5'000'000'000'000'000.0 = Hitpoints
6.0e15 = 6'000'000'000'000'000.0 = View Geometry
7.0e15 = 7'000'000'000'000'000.0 = Fire Geometry
8.0e15 = 8'000'000'000'000'000.0 = View - Cargo - Geometry
9.0e15 = 9'000'000'000'000'000.0 = View - Cargo - Fire Geometry
1.0e16 = 10'000'000'000'000'000.0 = View - Commander
1.1e16 = 11'000'000'000'000'000.0 = View - Commander - Geometry
1.2e16 = 12'000'000'000'000'000.0 = View - Commander - Fire Geometry
1.3e16 = 13'000'000'000'000'000.0 = View - Pilot - Geometry
1.4e16 = 14'000'000'000'000'000.0 = View - Pilot - Fire Geometry
1.5e16 = 15'000'000'000'000'000.0 = View - Gunner - Geometry
1.6e16 = 16'000'000'000'000'000.0 = View - Gunner - Fire Geometry

Other values (< 1000.0) are extact LOD's resolution.

LOD selected for displaying if

DistanceToObject * LODCoef * M ⇐ LODResolution

Where: - LODCoef is value from OFP preferences (I have LODCoef = 0.019). - M is some value that changed by OFP developers (I use M=1 in WRPEdit and M=2 in P3DEdit).

ofp/file_formats/mlod.txt · Last modified: 2024/07/31 12:42 by snakeman

Except where otherwise noted, content on this wiki is licensed under the following license: CC Attribution-Share Alike 4.0 International
CC Attribution-Share Alike 4.0 International Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki

All PMC web site download services are temporarily suspended until web site yearly fees have been recovered, want to download addons/mods? Then Support PMC.

If you are grateful for all the work PMC has done in the past 25 years, use Support PMC page.