File Formats
Image Files
The majority of the image files within the Battlefield 2 directory structure have the PNG file extension, however most of these image files are in fact DDS files with an incorrect file extension. There are a few image files that really are PNG files (mainly within Battlefield 2\mods\bf2\Objects\), and can be easily loaded by an image viewer/editor.
The image files in Menu_client.zip are packed into a DDS Texture Atlas file. Basicly, an atlas file combines a lot of small images into one big image to improve reading performance. An index file with coordinates is used to locate the individual images in the Atlas. The Atlas images and index files are located in Menu_client.zip/Atlas.
Basic File Format Data Types
String
struct String { uint len; char cstr[len]; }
Vec2
struct Vec2 { float x; float y; }
Vec3
struct Vec3 { float x; float y; float z; }
Point
struct Point { float x; float y; float z; }
Mat4
struct Mat4 { float m[4][4]; }
Axis-Aligned Bounding Box
Used for collosion detection.
struct AABB { Point endpoint1; Point endpoint2; }
Mesh File Formats
A mesh describes how an object in the world needs to be rendered, all mesh file formats use little endian byte order.
Common Mesh Data Types
Header
struct Header { uint u1; uint version; uint u2; // not used uint u3; // not used uint u5; // not used char u6; // not used }
VertexElement
struct VertexElement { ushort flag; ushort offset; ushort varType; ushort usage; }
Geometry
struct Geometry { uint numGeom; // number of geometric objects in this file uint numLods[numGeom]; uint numVertexElements; VertexElement vertexElements[numVertexElements]; // based on D3DXVERTEXELEMENT9 uint vertexFormat; uint vertexStride; uint numVertices; float vertices[numVertices * (vertexStride / vertexFormat); uint numIndices; ushort indices[numIndices]; }
.staticmesh File Format
The .staticmesh format is used for meshes without animations, below is a description of the file layout in a C like syntax.
struct StaticMesh { Header header; Geometry geometry; uint u6; struct Lod { Vec3 u1; Vec3 u2; uint numNodes; Mat4 nodes[numNodes]; // nodes are the respective origins of the objects? } lods[sum(geometry.numLods, geometry.numGeom)]; // each geometric object can have multiple lods struct { uint numMaterials; struct Material { uint alphaMode; // opaque = 0, blend = 1, alphatest = 2 String shaderFile; String technique; uint numTextureMaps; String textureMapFiles[numTextureMaps]; uint verticesStartIndex; uint indicesStartIndex; uint numIndices; uint numVertices; uint u1; ushort u2; ushort u3; Vec3 u4; Vec3 u5; } materials[numMaterials]; } geomMaterials[sum(geometry.numLods, geometry.numGeom)]; }
.bundledmesh File Format
struct BundledMesh { Header header; Geometry geometry; uint u6; struct Lod { Vec3 u1; Vec3 u2; uint numNodes; // not used? } lods[sum(geometry.numLods, geometry.numGeom)]; // each geometric object can have multiple lods struct { uint numMaterials; struct Material { uint alphaMode; // opaque = 0, blend = 1, alphatest = 2 String shaderFile; String technique; uint numTextureMaps; String textureMapFiles[numTextureMaps]; uint verticesStartIndex; uint indicesStartIndex; uint numIndices; uint numVertices; uint u1; ushort u2; ushort u3; } materials[numMaterials]; } geomMaterials[sum(geometry.numLods, geometry.numGeom)]; }
.skinnedmesh File Format
struct SkinnedMesh { Header header; Geometry geometry; struct Lod { Vec3 u1; Vec3 u2; uint numRigs; struct Rig { uint numBones; struct Bone { uint id; Mat4 mat; // inverse bone matrix } bones[numBones]; } rigs[numRigs]; } lods[sum(geometry.numLods, geometry.numGeom)]; // each geometric object can have multiple lods struct { uint numMaterials; struct Material { String shaderFile; String technique; uint numTextureMaps; String textureMapFiles[numTextureMaps]; uint verticesStartIndex; uint indicesStartIndex; uint numIndices; uint numVertices; uint u1; ushort u2; ushort u3; } materials[numMaterials]; } geomMaterials[sum(geometry.numLods, geometry.numGeom)]; }
.mesh File Format
It seems that .mesh files are only used for road data. Note that this file has a different layout.
struct RoadCompiled { uint version; // version number consists of major and minor version, latest is 65540, 65540 >> 16 = 1, 65540 % 65536 = 4 (v1.4) Vec3 u1; uint u2; Vec3 u3; Vec3 u4; uint u5; uint numVertices; struct { Vec3 pos; Vec2 tex0; Vec2 tex1; uint alpha; } vertices[numVertices]; uint numIndices; ushort indices[numIndices]; uint numUnk; struct { uint u1; uint u2; uint u3; Vec3 u4; } unk[numUnk]; }
terraindata.raw
The terraindata.raw file describes the terrain of a level in BF2.
struct TerrainData { uint version; Vec3 primaryWorldScale; Vec3 secondaryWorldScale; float u1; float u2; float u3; uint patchSize; bool subdividePatches; uint numPatches; uint patchColormapSize; uint lowDetailmapSize; char* colorMapbaseName; // the following strings use a newline character ('\n') as terminator instead of the normal null terminated C string char* detailMapbaseName; char* lowDetailMapbaseName; char* lightmapBaseName; Vec2 farSideTiling; float farSideTilingHi; float farSideTilingLow; float farYOffset; Vec3 terrainSunColor; Vec3 terrainSkyColor; Vec3 terrainWaterColor; uint numLayers; // This is always 6 for BF2, these are the layers as found in the terrain editor struct { char* detailTexturePath; char planeMap; Vec2 sideTiling; float topTiling; float yOffset; bool envMap; } layers[numLayers]; uint u6[32 * 21]; uint u7[6 * 85]; uint numIndices; ushort indices[numIndices]; bool vertexFormat; struct QuadPatch { // This describes a rectangular region of the main terrain uint u1; uint u2; uint u3; uint u4; Vec3 u5; uint u6; struct { float u1; float u2; float u3; float u4; uint u5; uint u6; } compactVertexData[(patchSize + 1) * (patchSize + 1)]; struct { int magic; uint i; Vec3 zero1; // always 0/0/0, no longer in use? float zero2; // no longer in use? uint numChartIndices; uint numChartIndicesDiv3; // this is equal to numChartIndices / 3 uint four; // always the value 4 uint numSubIndexQuads; struct SubIndexQuad { uint u1; uint u2; uint u3; uint u4; uint u5; uint u6; } subIndexQuads[numSubIndexQuads]; ushort chartIndices[numChartIndices]; } detailCharts[]; // this array is terminated like a string, it ends when the magic field of the next detail chart is -1 uint terminator; // this will be -1, see above comment } patches[numPatches * numPatches]; // here should be the data for the surrounding terrain and maybe some other data, not yet clear. }
External Links
Microsoft Developer Network DDS File Reference
Nvidia DDS Plugin for reading and writing DDS files in Adobe Photoshop