Wrp File Format - OPRWv17 to 24: Difference between revisions

From Bohemia Interactive Community
Jump to navigation Jump to search
No edit summary
m (Text replacement - "\[ *(https?:\/\/[^ = ]+) +([^= ]+) *\]" to "{{Link|$1|$2}}")
 
(89 intermediate revisions by 7 users not shown)
Line 1: Line 1:
[[Category:Sandbox]]
{{Feature|UnsupportedDoc}}


Current state of my researches on OPRW18 file format. Any additions, suggestions, etc. are appreciated.
== Introduction ==


<code><nowiki>char[4] sig //"OPWR"
For a general description of wrp files see [[Wrp_File_Format_-_8WVR|8WVR]]
ulong version //0x12 = 18
=== Legend ===
ulong texX,texZ //texture cell dimension.
see [[Generic FileFormat Data Types]]
ulong gridX,gridZ //elevations cell dimensions.
float gridSize //in meters




//still unknown stuff here




Peaks
{
ulong size
float[size][3] XYZ //Position of the Peak(Y is heigth)
}


TextureGridMaterials //will be described later
== File Format ==


ushort[gridZ][gridX] unknown //packed
*Layer and Map Sizes are derived from the header.


byte[gridZ][gridX] envSoundsIndices //packed
This document is based on analysis of arma1 wrps (OPRW18). The following are known differences between them, and later versions


float[gridZ][gridX] elevation //packed
::*OPRW17 (Elite) does not have the clutter
::*OPRW20 (sara and desert pbo's) :So far, this is the SAME format as 18 except PackedBytes1
::*OPRW23 (vbs2lite us) :So far, this is the SAME format as 20
::*OPRW24 (arma2)uses lzo compresion, not, lzss


Rvmats
OPRWv17://elite
{
OPRWv18://arma1
ulong size //Number of Rvmats + 1
OPRWv20://arma1 sara
ushort 0x0
OPRWv23://vbs2_lite
OPRWv24://arma2
{
  WrpHeader    Header;
 
  ushort        GridBlock_CellEnv[MapSize];      // a gridblock containing cellenv bits (16 bits per terrain cell).
                                                // Bits 0-2 are ground (0x0), coast (0x1), beach (0x2) and sea (0x3). Bit 4 indicates road/airstrip.
  byte          GridBlock_CfgEnvSounds[MapSize]; // a gridblock. mostly the value 0x03 and probably related to Config.cpp CfgEnvSounds class
  ulong         nPeaks;
  XYZTriplet    PeakPositions[nPeaks];          //see http://en.wikipedia.org/wiki/Maxima_and_minima
  ushort       GridBlock_RvmatLayerIndex[LayerSize];
 
  if !Elite
  if ArmaOne
    ushort      RandomClutter[LayerSize];        //compressed. probably random values needed for calculating clutter models position
                                                  //seems to be related to clutters or sat mask distance as it is
                                                  //responsible for the {{Link|http://tinyurl.com/6b27ed|clutterbug}}
  else
    bytes      RandomClutter[MapSize];    //compressed
  endif


Rvmat
 
{
      bytes        CompressedBytes1[MapSize];    //compressed
asciiz rvmat_path
byte 0x00
}
}


Models
  endif
{
ulong size //number of models
  float        Elevation[MapSize];              //compressed
asciiz[size] model_path //e.g. ca\buildings\kostelik.p3d
}
  ulong         nRvmats;
  Texture      Textures[nRvmats];              //"PrefixRoot\data\layers\some.rvmat\0\0"
  ulong        nModels;
  asciiz       modelPaths[nModels];         //"ca\buildings\kostelik.p3d\0"
  ulong        nClassedModels;
  ClassedModel  Models[nClassedModels];          //"Land_Hangar\0" : "ca\buildings\Hangar.p3d\0"
  ushort        GridBlock_UnknownGrid3[MapSize];
  ulong        SizeOfObjects;                  //in bytes
  ushort        GridBlock_UnknownGrid4[MapSize];
  ulong        SizeOfMapInfo;                  //in bytes
  byte          CompressedBytes2[LayerSize];    // seems to be connected to roads, runways and special grounds
  byte          CompressedBytes3[MapSize];      // unknown but 0x00 for forests and roads and sea, mostly 0x03 and rarely 0x02
  ulong        maxObjectID;
  ulong        SizeOfRoadNets;                  //in bytes
  RoadNet      RoadNets[SizeOfRoadNets];
  Object        Objects[SizeOfObjects/SizeOfObject]; // SizeOfObject ==60
  MapInfo      MapInfos[...];
}


Classed Models
*Because of the variable length of the asciiz strings in '''RoadParts''', the actual position of the following [[#Objects]] block cannot be pre-calculated. Therefore the ''SizeOfRoadNets'' can be used, as it is the size (in bytes) of this '''RoadNet''' block.
{
*Similarly, SizeOfObjects can be used to skip to the MapInfo
ulong size //number of models


Model
=== ClutterMask ===
{
asciiz class_name //e.g. Land_Hangar
asciiz model_path
float[3] pos
ulong unknown
}
}


//something grid related
Each byte represents the intensity or, number of clutter objects for that area of '''terrain'''
*Sea and road terrain have zilch.
*desert terrain have very low values


=== WrpHeader ===


byte[texZ][texX] //maybe connected to landing system
WrpHeader   
byte[texZ][texX] //maybe connected to landing system
{
  char    Filetype;        // "OPWR"
  ulong  version;        // 0x12 = 18
  XYPair  LayerSize;      // 256 x 256 (SaraLite), 128 x 128 (Intro)
  XYPair  MapSize;        // 1024 x 1024 (SaraLite), 512 x 512 (Intro)
  float  LayerCellSize;  // Layer cell size in meters (40m)
}


TextureGridRoads
This is a traditional wrp header endemic to most wrp formats. The LayerCellSize was introduced during Elite. The MapCellSize can be derived as follows:
{
ulong maxObjectID //not number of objects
ulong size //amount of bytes used for RoadNets
RoadNet[texZ,texX] RoadNets; //probably organized in texture grid cells to realize terrain streaming


RoadNet
MapCellSize= LayerCellSize * LayerSizeX / MapSizeX, and is 10m for SaraLite and Intro.
{
----
ulong NoOfRoadParts // Zero or More...
RoadPart[NoOfRoadParts] RoadParts
}


RoadPart
=== GridBlock ===
{
ushort NoOfRoadPositions
float[NoOfRoadPositions][3] RoadPositions //XYZ
byte[4] Flags
asciiz Model
float[4,3] matrix
}
}


Objects
The result of decompressing any GridBlock is to produce an array the size of either the Header's LayerSize or MapSize, at the TypeSize specified. Eg be it byte, or ushort.
{
Object
{
ulong ObjectID
ulong modelIndex
float[12] matrix
ulong 0x02 ??
}
}


MapInfo
There are five gridblocks in the file, two ushort arrays, and 3 byte arrays(if present)
{
ulong type
if(type in [0,1,2,10,11,13,14,15,16,17,22,23,26,27,30]) type1
if(type in [24,31,32]) type2
if(type in [25,33]) type3
if(type in [3,4,8,9,18,19,20,28,29]) type4
if(type in [34]) type5


//type1
*when the grid is present, the leading flag = 0x01
//{
*when a default fill GridBlock exists
// ulong ObjectId
{
// float x, z
  byte flag;    // =0
//}
  ulong FillBits; // = almost always zero
//type2
}
//{
// ulong ObjectId
GridBlock is currently in the 'discussion tab'.
// float[4][2] Bounds
//}
//type3
//{
// long[2] unknown
// float[2][2] line?
//}
//type4
//{
// ulong ObjectId
// float[4][2] Bounds
// byte[4] Color //rgba
//}
//type5
//{
// ulong ObjectId
// float[2][2] line?
//}
}
</nowiki></code>


=== Texture ===
Texture
{
  Concatenated Asciiz TextureFilenames; //"PrefixRoot\data\layers\some.rvmat\0\0" (Arma)
                                        //"PrefixRoot\desert\data\pt.bimpas\0\0"  (ELite)
                                        //"PboRoot\more_anim.01.pac\0"            (OFP)(by way of example)
}


----
*The {{ofp}} entry is solely here by way of example. No such entry exists in arma/Elite format.
----


Are you still interested in some input/observations or are you fine now? -- [[User:Sy|Sy]] 09:16, 9 October 2008 (CEST)
In all cases (bimpas,ofp,rvmat) they devolve, ultimately, to (a series of) pac/paa texture files.
: Of course I am still interested. Gimme all you have and know ;) --[[User:T D|T_D]] 15:18, 9 October 2008 (CEST)


*see [[P3D_File_Format_-_ODOLV40_Revised|PrefixRoot\]] description. Essentially, it is a reference to a pbo.


----
Each cell in the grid references a (series of) rvmat texture(s) for it is surface. The RvmatLayerIndex is an index to these filenames.


'''TextureGridModels'''
Thus, '''each''' entry of this materials list consists of concatenated asciiz strings in the form


"AnRvmatFile\0AnotherOne\0EvenMore\0\0"


Ok, first let's talk about the area of the file you call the 'Road Block'.
Ie, the end of '''this''' entry = \0\0
As you've noted it appears at first glance to be road models with intermittent x00 blocks.
First of all find the first lot of road models in your file and you'll see there is a 'block' of x00's before these... Navigate backwards through these x00's till they stop being x00's.
This is the ''real'' start of this area of the file.
You should see 3 int's before it starts into the x00's.


:The first int is undecided about at the moment.
It so happens that only one, single rvmat file, is used per cell, but, the construct is there to have any amount.
:The second int is the number of 'classless' objects there are in the file. Further talk about this later as there is a small ''issue'' with this.
:The third int would be better described as a long because it's the total size of the structure of this area of the file. This, structure size int is then the starting point for this area of the file.


At the moment a preference exists to describe this part of the file as the 'TextureGridModels' area.
therefore, this list is of the form
This is because it is a area that is of the form int[TxGrid_Z, TxGrid_X].
Although the models defined within this area always seem to be of the 'road' type I have for the moment decided to call the area (as mentioned) 'TextureGridModels' to identify this area as a list of models within each cell of the 'TextureGrid'.
It is imagined at some later date this area would most likely be renamed to something like 'TextureGridRoads' or 'RoadNetworks' or just 'Roads' or some such.


To illustrate... If there were NO roads and the texture grid was 128 x 128 then this entire block would be 128 x 128 0x0000 entries, or 65,536 bytes in length. This size would also be equal to the 'Third' integer I mentioned above.
"AnRvmatFile\0\0"


Everytime you come across a number in one of these 'slots' (if you will) it represents how many 'sub-objects' are present in this one cell.
There is always, at least one materials entry. The 1st entry.
Then of course the 'sub-objects' are defined. At the end of these 'sub-objects' you are into the next 'cell' of the grid array.
The first entry (effectively index 0) is a dummy, with an empty path, because it will never be accessed. Indexes start at 1.


Do you understand this?
The ushort GridBlock RvmatIndices (once decomposed) contain index entries to specific rvmat files. No index value of zero exists. (The first texture of the list is always a dummy entry)


Similar to it is 8WVR cousin (from which it is derived)the rvmat filenames *should* be unique (redundant, duplicate entries, defeat the purpose of the index). However, there is quite often some duplication.


----


'''Objects'''


As you've already indicated the structure that directly follows the above 'TextureGridModels' area is of course the 'Objects' list. Probably, more accurately it's the list of 'Classless' models that are present on the island.
=== ClassedModel ===
The problem is that the '2nd int' that was mentioned at the beginning of the 'TextureGridModels' area it apprears now is the 'maximum' object Id that is present on the island. This, is because in the are often quite a number of items less than this, but never more, of course.
<code style="display: block"><nowiki>
Eg. In a large island that comes with the 'ca' mod the NoOfObjects or MaxObjectId is 637,876 and the number of actual objects in the list array is 602,481. And, the highest Object Id in this list array is 637,876.
ClassedModel
It's unfortunate at this time that the array does not contain 637,876 entries, with some of them say having an Object Id of -1 or something as this would then mean that the '2nd int' truly would indicate the NoOfObjects in the array list of 'Classless Objects'.
{
Currently, this makes iterating this area a little difficult.
asciiz    class_name; //"Land_Hangar\0"
asciiz    model_path; //"ca\buildings\Hangar.p3d"
XYZTriplet Position;
ulong      unknown;
}
</nowiki></code>


This is a fairly repetitious list of often identically named class and model, used as an index from an as yet unknown grid table.


----
=== RoadNet ===
<code style="display: block"><nowiki>
RoadNet
{
  ulong    nRoadParts; // Zero or More...
  RoadPart RoadParts[nRoadParts];
} [LayerSize];
</nowiki></code>


'''Map Object Features'''
Every Layer cell on the map has a '''RoadNet''' entry. If there are no road(s) for that cell, there are no '''RoadParts''' (nRoadParts=0)


Dunno, if this is an appropriate name for this area but you have an accurate description for it anyway.
RoadParts, while, ultimately being no more (or less) than just another P3D model, are contained separately to models generally, to better realize terrain streaming and for AI driving ability.
The only thing to add is that it extends to the the EndOfFile. And, there are a number of other values + another type.
Some quick psdeuo-code...


<code><nowiki>
==== RoadPart ====
while (filepointer < filesize)
<code style="display: block"><nowiki>
{
RoadPart
  //type1 = Id, x, z
{
  //type2 = Id, Bounds (float[8])
ushort    nRoadPositions;// at least 1? sometimes 0
  //type3 = int[2], float[4]
XYZTriplet RoadPositions[nRoadPositions];
  //type4 = Id, Bounds (float[8]), Colour (byte[4])
byte       Flags[4];
  //type5 = Id, float[4]
        if WrpType==24
  type=readint();
          byte      MoreFlags[nRoadPositions];
  switch(type)
Asciiz     P3DModel;
  {
XYZTransform Transform[12]; // the averaged position of all the roads in this cell of this type
    case 0:
}
        {
            typeid = TypeIdEnum.Type1;
            break;
        }
    case 1:
        {
            typeid = TypeIdEnum.Type1;
            break;
        }
    case 2:
        {
            typeid = TypeIdEnum.Type1;
            break;
        }
    case 3:
        {
            typeid = TypeIdEnum.Type4;
            break;
        }
    case 4:
        {
            typeid = TypeIdEnum.Type4;
            break;
        }
    case 8:
        {
            typeid = TypeIdEnum.Type4;
            break;
        }
    case 9:
        {
            typeid = TypeIdEnum.Type4;
            break;
        }
    case 10:
        {
            typeid = TypeIdEnum.Type1;
            break;
        }
    case 11:
        {
            typeid = TypeIdEnum.Type1;
            break;
        }
    case 14:
        {
            typeid = TypeIdEnum.Type1;
            break;
        }
    case 15:
        {
            typeid = TypeIdEnum.Type1;
            break;
        }
    case 16:
        {
            typeid = TypeIdEnum.Type1;
            break;
        }
    case 17:
        {
            typeid = TypeIdEnum.Type1;
            break;
        }
    case 18:
        {
            typeid = TypeIdEnum.Type4;
            break;
        }
    case 20:
        {
            typeid = TypeIdEnum.Type4;
            break;
        }
    case 22:
        {
            typeid = TypeIdEnum.Type1;
            break;
        }
    case 23:
        {
            typeid = TypeIdEnum.Type1;
            break;
        }
    case 24:
        {
            typeid = TypeIdEnum.Type2;
            break;
        }
     case 25:
        {
            typeid = TypeIdEnum.Type3;
            break;
        }
    case 26:
        {
            typeid = TypeIdEnum.Type1;
            break;
        }
    case 27:
        {
            typeid = TypeIdEnum.Type1;
            break;
        }
    case 28:
        {
            typeid = TypeIdEnum.Type4;
            break;
        }
    case 29:
        {
            typeid = TypeIdEnum.Type4;
            break;
        }
    case 30:
        {
            typeid = TypeIdEnum.Type1;
            break;
        }
    case 31:
        {
            typeid = TypeIdEnum.Type2;
            break;
        }
    case 32:
        {
            typeid = TypeIdEnum.Type2;
            break;
        }
    case 33:
        {
            typeid = TypeIdEnum.Type3;
            break;
        }
    case 34:
        {
            typeid = TypeIdEnum.Type5;
            break;
        }
    default:
        {
            typeid = TypeIdEnum.Nothing;
            break;
        }
  }
}
</nowiki></code>
</nowiki></code>


=== Object Optional ===
<code style="display: block"><nowiki>
Object
{
ulong ObjectID;
ulong modelIndex; // into the [[#Models|models path name list]] (1 based)
float TransformMatrix[3][4]; // standard directX RowFormat transform matrix
ulong 0x02;
}
</nowiki></code>
*maxObjectID is somewhat irrelevant. It is indeed the id of the highest value ObjectID, but, these 'ID's, while unique are highly arbitrary in nature and alter on any change to the 'world' when editing in oxygen/visitor. This ID can occur anywhere in the object list, and the id values before it are non-sequential. maxObjectID '''cannot''' be used as a nObject ID's eg.


----
*If ''SizeOfObjects'' above == 0 then there are no objects.


'''TextureIndices / TextureGridMaterials'''
Note that unlike it is 4/8WVR cousin, where each Object entry contains (an often) repetitious list of p3d files. The same construct is (now) used similar to Rvamts and Indexes.
Namely, a common list of models is indexed into, by each Object entry.


This area as you are probably aware maps the 'TextureGrid' to the material files and (near the beginning of the file) is almost analysed.


=== MapInfo Optional ===


----
MapInfo
{
  ulong infoType;
  MapData[...];
}


Mapinfo, when it exists, extends to end of file. The sizeof each entry, is determined by it is info type thus:


That's all to add at this stage. Besides, what you had originally was enough to get a working .pew out of...
==== MapData ====
MapData
{
  if(infoType in [0,1,2,10,11,13,14,15,16,17,22,23,26,27,30]) MapType1;
  if(infoType in [24,31,32])                                  MapType2;
  if(infoType in [25,33])                                    MapType3;
  if(infoType in [3,4,8,9,18,19,20,21,28,29])                MapType4;
  if(infoType in [34])                                        MapType5;
  if(infoType in [35])                                        MapType35;
}


If the style in which the above info. is conveyed maybe difficult to envisage or follow, apologies.
==== MapType1 ====
<code style="display: block"><nowiki>
MapType1
{
ulong ObjectId
float x, z
}
</nowiki></code>


Was this at all helpful? If you have any questions or further insights...
==== MapType2 ====
<code style="display: block"><nowiki>
MapType2
{
  ulong ObjectId
  float Bounds[4][2];
}
</nowiki></code>


: thank you very very much for this info. I guess I understood most of your descriptions and very appreciate your effort. I will integrate your infos in the next time (my holidays ended yesterday, so I dont have as much time as I had the last months).
==== MapType3 ====
:For the TextureIndices block I found out that it is organized in 8x4 blocks. If the block starts with 0x00 you just read in 32 short values describing the block. Otherwise you mostly see 2 identical short values describing one 8x4 block filled just with this value. Sometimes instead of the 0x00 value or the 2 identical short values, other values occur probably describing what sort of data follows and what position the next 8x4 block in the whole ''texX'' x ''texZ'' block has. But I am still not sure what order these 8x4 blocks follow. The TextureIndices block also seems to start with some "header" data which I couldnt identify so far. --[[User:T D|T_D]] 12:11, 13 October 2008 (CEST)
<code style="display: block"><nowiki>
::Ah you seem to already know about the TextureIndices very well. Good to know ^^
MapType3
 
{
:Err, question: if the objectblock only contains the classless objects, where are the objects with classes then? In model list? --[[User:T D|T_D]] 23:52, 13 October 2008 (CEST)
ulong color; // maybe. or default ind of 0xFFFFFFF generally
 
ulong indicator; // typically 0x01010000
::On closer inspection of the 'Classed Models' - while they are indeed classed, that is they have a 'Land_' config definition each model entry in this array is also present in the 'Classless Models' array.
float [4]       // typically 0.5,1.0.1,5.3.0 always 'integers'
 
}
::This then means that the 'Classless Models' array would be better referred to as just the 'Models' array... in a .pew these would be the model templates.
</nowiki></code>
::As a test create a blank island and setup just 1 config'd/classed/Land_ house model as a template & 1 Tree template.
::Place the house model 20 times in different locations. Place 50 Trees in different locations.
::You'll see these 20 different located houses are in the 'Classed Models' array. Same model, 20 different locations.
::Then in the 'Models' array there will be 2 'Models' / 'Model Templates'. 1 for the House & 1 for the Tree.
::Then in the Objects or Model Instances array you'll have 20 House instances & 50 Tree instances. The 20 house instances transforms x,y,z's will exactly match the x,y,z's from the 'Named Models' array.


:::It seems that BIS has quite some redundant data then:
==== MapType4 ====
:::#like you said the positions of "classed" models in objectslist and "classed" models block
<code style="display: block"><nowiki>
:::#road model pathes in model list and in TextureGridModels block (an index to the roadpath would have been enough in my opinion)
MapType4
:::#transform matrix in Objectlist and in roadblocks
:::#"classed" modelnames also present in modellist
 
:::Dunno what they want to achieve with that --[[User:T D|T_D]] 15:27, 14 October 2008 (CEST)
 
:::One can infer quite alot about the capabilities of certain things based upon the data structures used. Sometimes redundancy seems the case but it sort of is and sort of isn't. Alot of data structures are this way to allow direct injection into shader code or directx structures with little or no effort. So, sometimes some of the structures on the surface look inefficient but when used in DirectX can save alot of pre-precessing. Keep-it-Simple-Stupid could be a good term to use. Although, saying this there are some quite redundant data structures lying about.
:::The .paa file format is fifo for instance which is ideal for streaming...
 
:::Maybe something like...
 
:::<code><nowiki>
 
structRoadNetwork[TxGridZ,TxGridX] TextureGridRoads;
 
 
structRoadNetwork
{
{
  int NoOfRoadParts; // Zero or More...
ulong ObjectId
  if (NoOfRoadParts != 0)
float Bounds[4][2];
  {
byte  Color[4] //rgba
      structRoadPart[NoOfRoadParts] RoadParts;
}
  }
</nowiki></code>
};


structRoadPart
==== MapType5 ====
<code style="display: block"><nowiki>
MapType5
{
{
   short NoOfRoadPositions;
   ulong ObjectId
   structRoadPosition[NoOfRoadPositions] RoadPositions;
   float line[2][2];?
  int Flags;
}
  asciiz Model;
</nowiki></code>
  float[4,3] Transform;
==== MapType35 ====
};
<code style="display: block"><nowiki>
 
MapType35  // found in chernarus
structPoadPosition
{
{
   float X;
   ulong ObjectId
   float Y;
   float line[3][2];?
   float Z;
   byte  unknown;
};
}
</nowiki></code>
</nowiki></code>


:::A T-Juntion will have 4 road positions StartPos1, EndPos1, StartPos2, EndPos2... :)
Type 35 is also found in oprw23 formats but is currently indecipherable and may, in fact, be an error
 
::::The unknown int in the the TextureGridRoads block is the checksum of the packed data before so it does not belong to the TextureGridRoads block --[[User:T D|T_D]] 14:54, 17 October 2008 (CEST)


::::Agreed, yeah... saw that, also, maxObjectID isn't part of the TextureGridRoads structure and it will probably end up really being NoOfObjects.
== Packed Data ==
All variables starting with "Packed" are compressed with the common BIS algorithm that is also used in [[PAA File Format|paa]] and OFP [[PBO File Format|pbo]] files.
{{GameCategory|ofp|Modelling}}
[[Category:BIS_File_Formats]]

Latest revision as of 15:11, 28 April 2023

bi symbol white.png
Disclaimer: This page describes internal undocumented structures of Bohemia Interactive software.

This page contains unofficial information.

Some usage of this information may constitute a violation of the rights of Bohemia Interactive and is in no way endorsed or recommended by Bohemia Interactive.
Bohemia Interactive is not willing to tolerate use of such tools if it contravenes any general licenses granted to end users of this community wiki or BI products.

Introduction

For a general description of wrp files see 8WVR

Legend

see Generic FileFormat Data Types



File Format

  • Layer and Map Sizes are derived from the header.

This document is based on analysis of arma1 wrps (OPRW18). The following are known differences between them, and later versions

  • OPRW17 (Elite) does not have the clutter
  • OPRW20 (sara and desert pbo's) :So far, this is the SAME format as 18 except PackedBytes1
  • OPRW23 (vbs2lite us) :So far, this is the SAME format as 20
  • OPRW24 (arma2)uses lzo compresion, not, lzss
OPRWv17://elite
OPRWv18://arma1
OPRWv20://arma1 sara
OPRWv23://vbs2_lite
OPRWv24://arma2
{
 WrpHeader     Header;
 
 ushort        GridBlock_CellEnv[MapSize];      // a gridblock containing cellenv bits (16 bits per terrain cell). 
                                                // Bits 0-2 are ground (0x0), coast (0x1), beach (0x2) and sea (0x3). Bit 4 indicates road/airstrip.
 byte          GridBlock_CfgEnvSounds[MapSize]; // a gridblock. mostly the value 0x03 and probably related to Config.cpp CfgEnvSounds class

 ulong         nPeaks;
 XYZTriplet    PeakPositions[nPeaks];           //see http://en.wikipedia.org/wiki/Maxima_and_minima

 ushort        GridBlock_RvmatLayerIndex[LayerSize];
 
 if !Elite
  if ArmaOne
   ushort       RandomClutter[LayerSize];        //compressed. probably random values needed for calculating clutter models position
                                                 //seems to be related to clutters or sat mask distance as it is
                                                 //responsible for the clutterbug
  else
    bytes       RandomClutter[MapSize];    //compressed
  endif


     bytes         CompressedBytes1[MapSize];    //compressed
 endif

 float         Elevation[MapSize];              //compressed

 ulong         nRvmats;
 Texture       Textures[nRvmats];               //"PrefixRoot\data\layers\some.rvmat\0\0"

 ulong         nModels;
 asciiz        modelPaths[nModels];	         //"ca\buildings\kostelik.p3d\0"

 ulong         nClassedModels;
 ClassedModel  Models[nClassedModels];          //"Land_Hangar\0" : "ca\buildings\Hangar.p3d\0"

 ushort        GridBlock_UnknownGrid3[MapSize];

 ulong         SizeOfObjects;                   //in bytes

 ushort        GridBlock_UnknownGrid4[MapSize];

 ulong         SizeOfMapInfo;                   //in bytes

 byte          CompressedBytes2[LayerSize];     // seems to be connected to roads, runways and special grounds
 byte          CompressedBytes3[MapSize];       // unknown but 0x00 for forests and roads and sea, mostly 0x03 and rarely 0x02
 ulong         maxObjectID;

 ulong         SizeOfRoadNets;                  //in bytes
 RoadNet       RoadNets[SizeOfRoadNets];

 Object        Objects[SizeOfObjects/SizeOfObject]; // SizeOfObject ==60

 MapInfo       MapInfos[...];
}
  • Because of the variable length of the asciiz strings in RoadParts, the actual position of the following #Objects block cannot be pre-calculated. Therefore the SizeOfRoadNets can be used, as it is the size (in bytes) of this RoadNet block.
  • Similarly, SizeOfObjects can be used to skip to the MapInfo

ClutterMask

Each byte represents the intensity or, number of clutter objects for that area of terrain

  • Sea and road terrain have zilch.
  • desert terrain have very low values

WrpHeader

WrpHeader     
{
 char    Filetype;        // "OPWR"
 ulong   version;         // 0x12 = 18
 XYPair  LayerSize;       // 256 x 256 (SaraLite), 128 x 128 (Intro)
 XYPair  MapSize;         // 1024 x 1024 (SaraLite), 512 x 512 (Intro)
 float   LayerCellSize;   // Layer cell size in meters (40m)
}

This is a traditional wrp header endemic to most wrp formats. The LayerCellSize was introduced during Elite. The MapCellSize can be derived as follows:

MapCellSize= LayerCellSize * LayerSizeX / MapSizeX, and is 10m for SaraLite and Intro.

GridBlock

The result of decompressing any GridBlock is to produce an array the size of either the Header's LayerSize or MapSize, at the TypeSize specified. Eg be it byte, or ushort.

There are five gridblocks in the file, two ushort arrays, and 3 byte arrays(if present)

  • when the grid is present, the leading flag = 0x01
  • when a default fill GridBlock exists
{
  byte  flag;     // =0
  ulong FillBits; // = almost always zero
}

GridBlock is currently in the 'discussion tab'.

Texture

Texture
{
 Concatenated Asciiz TextureFilenames; //"PrefixRoot\data\layers\some.rvmat\0\0" (Arma)
                                       //"PrefixRoot\desert\data\pt.bimpas\0\0"  (ELite)
                                       //"PboRoot\more_anim.01.pac\0"            (OFP)(by way of example)
}
  • The Operation Flashpoint entry is solely here by way of example. No such entry exists in arma/Elite format.

In all cases (bimpas,ofp,rvmat) they devolve, ultimately, to (a series of) pac/paa texture files.

  • see PrefixRoot\ description. Essentially, it is a reference to a pbo.

Each cell in the grid references a (series of) rvmat texture(s) for it is surface. The RvmatLayerIndex is an index to these filenames.

Thus, each entry of this materials list consists of concatenated asciiz strings in the form

"AnRvmatFile\0AnotherOne\0EvenMore\0\0"

Ie, the end of this entry = \0\0

It so happens that only one, single rvmat file, is used per cell, but, the construct is there to have any amount.

therefore, this list is of the form

"AnRvmatFile\0\0"

There is always, at least one materials entry. The 1st entry. The first entry (effectively index 0) is a dummy, with an empty path, because it will never be accessed. Indexes start at 1.

The ushort GridBlock RvmatIndices (once decomposed) contain index entries to specific rvmat files. No index value of zero exists. (The first texture of the list is always a dummy entry)

Similar to it is 8WVR cousin (from which it is derived)the rvmat filenames *should* be unique (redundant, duplicate entries, defeat the purpose of the index). However, there is quite often some duplication.


ClassedModel

ClassedModel { asciiz class_name; //"Land_Hangar\0" asciiz model_path; //"ca\buildings\Hangar.p3d" XYZTriplet Position; ulong unknown; }

This is a fairly repetitious list of often identically named class and model, used as an index from an as yet unknown grid table.

RoadNet

RoadNet { ulong nRoadParts; // Zero or More... RoadPart RoadParts[nRoadParts]; } [LayerSize];

Every Layer cell on the map has a RoadNet entry. If there are no road(s) for that cell, there are no RoadParts (nRoadParts=0)

RoadParts, while, ultimately being no more (or less) than just another P3D model, are contained separately to models generally, to better realize terrain streaming and for AI driving ability.

RoadPart

RoadPart { ushort nRoadPositions;// at least 1? sometimes 0 XYZTriplet RoadPositions[nRoadPositions]; byte Flags[4]; if WrpType==24 byte MoreFlags[nRoadPositions]; Asciiz P3DModel; XYZTransform Transform[12]; // the averaged position of all the roads in this cell of this type }

Object Optional

Object { ulong ObjectID; ulong modelIndex; // into the [[#Models|models path name list]] (1 based) float TransformMatrix[3][4]; // standard directX RowFormat transform matrix ulong 0x02; }

  • maxObjectID is somewhat irrelevant. It is indeed the id of the highest value ObjectID, but, these 'ID's, while unique are highly arbitrary in nature and alter on any change to the 'world' when editing in oxygen/visitor. This ID can occur anywhere in the object list, and the id values before it are non-sequential. maxObjectID cannot be used as a nObject ID's eg.
  • If SizeOfObjects above == 0 then there are no objects.

Note that unlike it is 4/8WVR cousin, where each Object entry contains (an often) repetitious list of p3d files. The same construct is (now) used similar to Rvamts and Indexes. Namely, a common list of models is indexed into, by each Object entry.


MapInfo Optional

MapInfo
{
 ulong infoType;
 MapData[...];
}

Mapinfo, when it exists, extends to end of file. The sizeof each entry, is determined by it is info type thus:

MapData

MapData
{
 if(infoType in [0,1,2,10,11,13,14,15,16,17,22,23,26,27,30]) MapType1;
 if(infoType in [24,31,32])                                  MapType2;
 if(infoType in [25,33])                                     MapType3;
 if(infoType in [3,4,8,9,18,19,20,21,28,29])                 MapType4;
 if(infoType in [34])                                        MapType5;
 if(infoType in [35])                                        MapType35;

}

MapType1

MapType1 { ulong ObjectId float x, z }

MapType2

MapType2 { ulong ObjectId float Bounds[4][2]; }

MapType3

MapType3 { ulong color; // maybe. or default ind of 0xFFFFFFF generally ulong indicator; // typically 0x01010000 float [4] // typically 0.5,1.0.1,5.3.0 always 'integers' }

MapType4

MapType4 { ulong ObjectId float Bounds[4][2]; byte Color[4] //rgba }

MapType5

MapType5 { ulong ObjectId float line[2][2];? }

MapType35

MapType35 // found in chernarus { ulong ObjectId float line[3][2];? byte unknown; }

Type 35 is also found in oprw23 formats but is currently indecipherable and may, in fact, be an error

Packed Data

All variables starting with "Packed" are compressed with the common BIS algorithm that is also used in paa and OFP pbo files.