Wrp File Format - OPRWv17 to 24: Difference between revisions

From Bohemia Interactive Community
Jump to navigation Jump to search
m (cleaned up discussion)
(new structure (not complete now))
Line 3: Line 3:
{{unsupported-doc}}
{{unsupported-doc}}


Current state of my researches on OPRW18 file format. Any additions, suggestions, etc. are appreciated.
==Introduction==
 
===Legend===
*'''byte''' 8 bits, unsigned.
*'''ushort''' 2 bytes, unsigned.
*'''ulong''' 4 bytes, unsigned.
*'''float''' 4 bytes, signed.


<code><nowiki>
/* Legend
**
** byte    8 bits,  unsigned. Normally used for flags.
** ushort  2 bytes, unsigned.
** ulong  4 bytes, unsigned. Normally used for offsets and ID's
** float  4 bytes. signed.  The preferred method of storing negative values (such as elevation)
*/


char[4] sig //"OPWR"
ulong version //0x12 = 18
ulong texX,texZ        //textures cell dimensions. 256x256 eg
ulong gridX,gridZ //elevations cell dimensions. 256x256 eg
float gridSize //in meters (normally 50.0)


==File Format==
<code><nowiki>
structHeader Header;


//still unknown stuff here
//still unknown stuff here
//followed by
//followed by


Peaks
structPeaks Peaks;
{
structTextureGridMaterials MaterialIndices; //see discussion below. Not fully defined (yet)
ulong nEntries
float XZY[nEntries][3] //Position of the Peak  (Z is height)
}


TextureGridMaterials[unknown size] //see discussion below. Not fully defined (yet)
ushort PackedRandom[texZ][texX] //probably random values needed for calculating clutter models position
 
ushort PackedRandom[texZ][texX] // probably random values needed for calculating clutter models position


byte  PackedUnknown[gridZ][gridX] // seems to be related to clutters or sat mask distance as it is responsible for the </nowiki>[http://tinyurl.com/6b27ed clutterbug]<nowiki>
byte  PackedUnknown[gridZ][gridX] // seems to be related to clutters or sat mask distance as it is responsible for the </nowiki>[http://tinyurl.com/6b27ed clutterbug]<nowiki>
Line 40: Line 31:
/* packed data corresponds to the standard pbo compression format */
/* packed data corresponds to the standard pbo compression format */


Rvmats
structMaterials Materials;
structModels Models;
structClassedModels ClassedModels;
 
//something grid related[size unknown]
// followed by:
 
byte[texZ][texX] bytes2 //seems to be connected to roads, runways and special grounds
byte[gridZ][gridX] bytes3 //unknown but 0x00 for forests and roads and sea, mostly 0x03 and rarely 0x02
 
ulong maxObjectID //not number of objects
ulong ObjectBlockOffset //amount of bytes used for RoadNets
 
structRoadNet RoadNets[texZ,texX]; //probably organized in texture grid cells to realize terrain streaming
structObject Objects[unknown];
 
structMapInfo MapInfos[unknown];
</nowiki></code>
 
==Structures==
 
===structHeader===
<code><nowiki>
structHeader
{
char signature[4]; //"OPWR"
ulong version; //0x12 = 18
ulong texX,texZ;        //textures cell dimensions. 256x256 eg
ulong gridX,gridZ; //elevations cell dimensions. 256x256 eg
float gridSize; //in meters (normally 50.0)
}
</nowiki></code>
----
 
 
----
===structPeaks===
<code><nowiki>
structPeaks
{
{
ulong nRvmatEntries //Number of Rvmat entries (at least one)
ulong nPeaks;
RvmatEntry
float XZY[nPeaks][3]; //Position of the Peak  (Z is height)
{
                Concatenated Asciiz path strings
        }[nRvmatEntries]
}
}
</nowiki></code>
----


/* Note
----
1) there is always a minimum of one rvmat entry. The first entry is *always* 0x00 0x00 (no file)
===structTextureGridMaterials===
  the *actual* number of files listed is therefore *always* one less than nRvmatEntries
<code><nowiki>
2) BI frequently use concatenated strings. One Asciiz string, followed by zero or more others.
structTextureGridMaterials
  in this case, there is always only one filename listed and thus the above could be viewed as
{
        ConcatenatedString
//still need to be worked out
        {
asciiz rvmat_path
byte 0x00
}
*/
}
}
</nowiki></code>
----
----
===structMaterials===


Models
<code><nowiki>
structMaterials
{
{
ulong nModels         //number of models
ulong nMaterials; //Number of Rvmat entries (at least one)
asciiz model_path[nModels] //e.g. ca\buildings\kostelik.p3d
structMaterial Materials[nMaterials];
}
}
/*
</nowiki></code>
** The ModelIndex in the ObjectsBlock below is a direct reference to one of the above p3d files for that object entry. If there are 99 nModels then
there is always a minimum of one rvmat entry. The first entry is *always* 0x00 0x00 (no file)
** the Object entries will contain ModelIndexes between 0 and 98
the *actual* number of files listed is therefore *always* one less than nRvmatEntries
*/
 
Classed Models
====structMaterial====
<code><nowiki>
structMaterial
{
{
ulong nClassedModels //number of classed models
asciiz rvmat_path;
byte 0x00;
}
</nowiki></code>
----


Model
 
{
----
asciiz class_name //e.g. Land_Hangar
===structModels===
asciiz model_path       //e.g. ca\buildings\kostelik.p3d
<code><nowiki>
float pos[3]            //XZY
structModels
ulong unknown
{
}[nClassedModels]
ulong nModels;         //number of models
asciiz model_path[nModels]; //e.g. ca\buildings\kostelik.p3d
}
}
</nowiki></code>
The ModelIndex in the ObjectsBlock below is a direct reference to one of the above p3d files for that object entry. If there are 99 nModels then the Object entries will contain ModelIndexes between 0 and 98
----


//something grid related[size unknown]
// followed by:


----
===structClassedModels===
<code><nowiki>
structClassedModels
{
ulong nClassedModels; //number of classed models
structClassedModel Models[nClassedModels];
}
</nowiki></code>


byte[texZ][texX] bytes2 //seems to be connected to roads, runways and special grounds
====structClassedModel====
byte[gridZ][gridX] bytes3 //unknown but 0x00 for forests and roads and sea, mostly 0x03 and rarely 0x02
<code><nowiki>
structClassedModel
{
asciiz class_name; //e.g. Land_Hangar
asciiz model_path;      //e.g. ca\buildings\kostelik.p3d
float pos[3];            //XZY
ulong unknown;
}
</nowiki></code>
----


ulong maxObjectID //not number of objects
ulong ObjectBlockOffset //amount of bytes used for RoadNets


TextureGridRoads
----
===structRoadNet===
<code><nowiki>
structRoadNet
{
{
RoadNet[texZ,texX] RoadNets; //probably organized in texture grid cells to realize terrain streaming
ulong nRoadParts; // Zero or More...
structRoadPart RoadParts[nRoadParts];
}
</nowiki></code>
Because of the variable length asciiz strings, the actual position of the following Objects block cannot be pre-calculated. Therefore,
the ObjectBlockOffset is also the size (in bytes) of the Roads Block
 
On a 256 x 256 cell island: Each cell *unconditionally* contains a roadnet entry. If there are no road(s) in that cell, there are no roadparts. There could, alternatively be
multiple roads in that cell, and, multiple parts to each road.


RoadNet
For a 256 x 256 cell island with NO roads, the size of this block, the ObjectBlockOffset , would be 256 x 256 x 4 bytes.
{
ulong NoOfRoadParts // Zero or More...
RoadPart[NoOfRoadParts] RoadParts
}


RoadPart
====structRoadPart====
{
<code><nowiki>
ushort NoOfRoadPositions
structRoadPart
float[NoOfRoadPositions][3] RoadPositions //XYZ
{
byte[4] Flags
ushort nRoadPositions;
asciiz Model
float RoadPositions[nRoadPositions][3]; //XYZ
float[4,3] matrix
byte Flags[4];
}
asciiz Model;
float matrix[12];
}
}
/* Because of the variable length asciiz strings, the actual position of the following Objects block cannot be pre-calculated. Therefore,
</nowiki></code>
** the ObjectBlockOffset is also the size (in bytes) of the Roads Block
----
**
** On a 256 x 256 cell island: Each cell *unconditionally* contains a roadnet entry. If there are no road(s) in that cell, there are no roadparts. There could, alternatively be
** multiple roads in that cell, and, multiple parts to each road.
**
** For a 256 x 256 cell island with NO roads, the size of this block, the ObjectBlockOffset , would be 256 x 256 x 4 bytes.
*/


Objects
 
----
===structObject===
<code><nowiki>
structObject
{
{
Object
ulong ObjectID;
{
ulong modelIndex;
ulong ObjectID
float matrix[12];
ulong modelIndex
ulong 0x02;
float[12] matrix
ulong 0x02 ??
}
}
}
/*
</nowiki></code>
** modelIndex is a direct reference to the Nth model entry in the Model Block above. If there are 99 p3d files listed in the Model Block, then any given Object entry will contain a
 
** modelIndex between 0 and 98.
modelIndex is a direct reference to the Nth model entry in the Model Block above. If there are 99 p3d files listed in the Model Block, then any given Object entry will contain a
**
modelIndex between 0 and 98.
** For any island, there are more than 100,000 (p3d) objects on the terrain. The ObjectID uniquely identifies *that* tree, at *that* position. The *same* tree, house, bush, will be
For any island, there are more than 100,000 (p3d) objects on the terrain. The ObjectID uniquely identifies *that* tree, at *that* position. The *same* tree, house, bush, will be
** used many times on the island at different locations. Thus many object entries contain the same modelIndex. Eg, the same, p3d tree.
used many times on the island at different locations. Thus many object entries contain the same modelIndex. Eg, the same, p3d tree.
*/
----
 


MapInfo
----
===structMapInfo===
<code><nowiki>
structMapInfo
{
{
ulong type
ulong infoType;
if(type in [0,1,2,10,11,13,14,15,16,17,22,23,26,27,30]) type1
if(infoType in [0,1,2,10,11,13,14,15,16,17,22,23,26,27,30]) structType1 type1;
if(type in [24,31,32]) type2
if(infoType in [24,31,32]) structType2 type2;
if(type in [25,33]) type3
if(infoType in [25,33]) structType3 type3;
if(type in [3,4,8,9,18,19,20,28,29]) type4
if(infoType in [3,4,8,9,18,19,20,28,29]) structType4 type4;
if(type in [34]) type5
if(infoType in [34]) structType5 type5;
}
</nowiki></code>


//type1
====structType1====
//{
<code><nowiki>
// ulong ObjectId
structType1
// float x, z
{
//}
ulong ObjectId
//type2
float x, z
//{
}
// ulong ObjectId
</nowiki></code>
// float[4][2] Bounds
 
//}
====structType2====
//type3
<code><nowiki>
//{
structType2
// long[2] unknown
{
// float[2][2] line?
ulong ObjectId
//}
float[4][2] Bounds
//type4
}
//{
</nowiki></code>
// ulong ObjectId
 
// float[4][2] Bounds
====structType3====
// byte[4] Color //rgba
<code><nowiki>
//}
structType3
//type5
{
//{
long[2] unknown
// ulong ObjectId
float[2][2] line?
// float[2][2] line?
}
//}
</nowiki></code>
 
====structType4====
<code><nowiki>
structType4
{
ulong ObjectId
float[4][2] Bounds
byte[4] Color //rgba
}
</nowiki></code>
 
====structType5====
<code><nowiki>
structType5
{
ulong ObjectId
float[2][2] line?
}
}
</nowiki></code>
</nowiki></code>
Line 181: Line 262:


----
----
'''Discussion'''
'''Discussion'''



Revision as of 22:04, 4 December 2008


Template:unsupported-doc

Introduction

Legend

  • byte 8 bits, unsigned.
  • ushort 2 bytes, unsigned.
  • ulong 4 bytes, unsigned.
  • float 4 bytes, signed.


File Format

structHeader Header; //still unknown stuff here //followed by structPeaks Peaks; structTextureGridMaterials MaterialIndices; //see discussion below. Not fully defined (yet) ushort PackedRandom[texZ][texX] //probably random values needed for calculating clutter models position byte PackedUnknown[gridZ][gridX] // seems to be related to clutters or sat mask distance as it is responsible for the clutterbug float PackedElevation[gridZ][gridX]// /* packed data corresponds to the standard pbo compression format */ structMaterials Materials; structModels Models; structClassedModels ClassedModels; //something grid related[size unknown] // followed by: byte[texZ][texX] bytes2 //seems to be connected to roads, runways and special grounds byte[gridZ][gridX] bytes3 //unknown but 0x00 for forests and roads and sea, mostly 0x03 and rarely 0x02 ulong maxObjectID //not number of objects ulong ObjectBlockOffset //amount of bytes used for RoadNets structRoadNet RoadNets[texZ,texX]; //probably organized in texture grid cells to realize terrain streaming structObject Objects[unknown]; structMapInfo MapInfos[unknown];

Structures

structHeader

structHeader { char signature[4]; //"OPWR" ulong version; //0x12 = 18 ulong texX,texZ; //textures cell dimensions. 256x256 eg ulong gridX,gridZ; //elevations cell dimensions. 256x256 eg float gridSize; //in meters (normally 50.0) }




structPeaks

structPeaks { ulong nPeaks; float XZY[nPeaks][3]; //Position of the Peak (Z is height) }




structTextureGridMaterials

structTextureGridMaterials { //still need to be worked out }




structMaterials

structMaterials { ulong nMaterials; //Number of Rvmat entries (at least one) structMaterial Materials[nMaterials]; } there is always a minimum of one rvmat entry. The first entry is *always* 0x00 0x00 (no file) the *actual* number of files listed is therefore *always* one less than nRvmatEntries

structMaterial

structMaterial { asciiz rvmat_path; byte 0x00; }




structModels

structModels { ulong nModels; //number of models asciiz model_path[nModels]; //e.g. ca\buildings\kostelik.p3d } The ModelIndex in the ObjectsBlock below is a direct reference to one of the above p3d files for that object entry. If there are 99 nModels then the Object entries will contain ModelIndexes between 0 and 98




structClassedModels

structClassedModels { ulong nClassedModels; //number of classed models structClassedModel Models[nClassedModels]; }

structClassedModel

structClassedModel { asciiz class_name; //e.g. Land_Hangar asciiz model_path; //e.g. ca\buildings\kostelik.p3d float pos[3]; //XZY ulong unknown; }




structRoadNet

structRoadNet { ulong nRoadParts; // Zero or More... structRoadPart RoadParts[nRoadParts]; } Because of the variable length asciiz strings, the actual position of the following Objects block cannot be pre-calculated. Therefore, the ObjectBlockOffset is also the size (in bytes) of the Roads Block

On a 256 x 256 cell island: Each cell *unconditionally* contains a roadnet entry. If there are no road(s) in that cell, there are no roadparts. There could, alternatively be multiple roads in that cell, and, multiple parts to each road.

For a 256 x 256 cell island with NO roads, the size of this block, the ObjectBlockOffset , would be 256 x 256 x 4 bytes.

structRoadPart

structRoadPart { ushort nRoadPositions; float RoadPositions[nRoadPositions][3]; //XYZ byte Flags[4]; asciiz Model; float matrix[12]; }




structObject

structObject { ulong ObjectID; ulong modelIndex; float matrix[12]; ulong 0x02; }

modelIndex is a direct reference to the Nth model entry in the Model Block above. If there are 99 p3d files listed in the Model Block, then any given Object entry will contain a modelIndex between 0 and 98. For any island, there are more than 100,000 (p3d) objects on the terrain. The ObjectID uniquely identifies *that* tree, at *that* position. The *same* tree, house, bush, will be used many times on the island at different locations. Thus many object entries contain the same modelIndex. Eg, the same, p3d tree.




structMapInfo

structMapInfo { ulong infoType; if(infoType in [0,1,2,10,11,13,14,15,16,17,22,23,26,27,30]) structType1 type1; if(infoType in [24,31,32]) structType2 type2; if(infoType in [25,33]) structType3 type3; if(infoType in [3,4,8,9,18,19,20,28,29]) structType4 type4; if(infoType in [34]) structType5 type5; }

structType1

structType1 { ulong ObjectId float x, z }

structType2

structType2 { ulong ObjectId float[4][2] Bounds }

structType3

structType3 { long[2] unknown float[2][2] line? }

structType4

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

structType5

structType5 { ulong ObjectId float[2][2] line? }



Discussion

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. --T_D 12:11, 13 October 2008 (CEST)


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 --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.
No it is not NoOfObjects. Already checked that by reading objects from 8WVR and comparing readed objects with this value --T_D 04:33, 18 October 2008 (CEST)
Experience has taught me that one can never be to certain about these things until one is certain, if you know what I mean... :)
It maybe MaxObjectId it maybe not... time will tell.
Building the standard SampleMap.pew into a 8wvr.wrp yeilds 5134 obejcts, then into a oprw18.wrp yeilds 5132 in the MaxOjectId/NoOfObjects field. If you add 1 to this value this is the number of obejcts that happens to be in the array of objects in this particular file.
However, this senario doesn't hold true for a certain 'ca' mod oprw18.wrp. That value (as I mentioned earlier) is 637,876 and the number of actual objects in the list array is 602,481.
This may be because there is a prior structure in the file that denotes out of the 637,876 objects ones that are not specified in the Objects array... dunno, well see if that pans out.
The most logical senario is that this is the NoOfObjects less some other structure count = ObejctList count.
If this isn't the senario then there maybe another ObjectCount item lying around the file somewhere that does indicate how many objects are in the objects list array.


this block ushort[gridZ][gridX] unknown //packed seems to consist of random numbers. So my guess is, that these random values are used to calculate the positions of the clutter models, so that the island is always looking the same without saving the pos of every grass model. Could this be the case? --T_D 13:50, 19 October 2008 (CEST)