{"name":"Wrp File Format - OPRWv17 to 24","title":"Wrp File Format - OPRWv17 to 24","type":"topic","url":"https://community.bistudio.com/wiki/Wrp_File_Format_-_OPRWv17_to_24","revid":373416,"updated":"2025-05-08T11:27:11Z","aliases":["OPRW v18 File Format","Wrp File Format - OPRWv17,18,20","Wrp File Format - OPRWv18"],"markdown":"> **Disclaimer: This page describes internal undocumented structures of Bohemia Interactive software.**\n>\n> This page contains unofficial information.\n>\n> 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.\n> 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.\n\n### Introduction\n\nFor a general description of wrp files see 8WVR\n\n#### Legend\n\nsee Generic FileFormat Data Types\n\n### File Format\n\n- Layer and Map Sizes are derived from the header.\n\nThis document is based on analysis of arma1 wrps (OPRW18). The following are known differences between them, and later versions\n\n- OPRW17 (Elite) does not have the clutter\n- OPRW20 (sara and desert pbo's) :So far, this is the SAME format as 18 except PackedBytes1\n- OPRW23 (vbs2lite us) :So far, this is the SAME format as 20\n- OPRW24 (arma2)uses lzo compresion, not, lzss\n\n```\nOPRWv17://elite\nOPRWv18://arma1\nOPRWv20://arma1 sara\nOPRWv23://vbs2_lite\nOPRWv24://arma2\n{\n WrpHeader     Header;\n\n ushort        GridBlock_CellEnv[MapSize];      // a gridblock containing cellenv bits (16 bits per terrain cell).\n                                                // Bits 0-2 are ground (0x0), coast (0x1), beach (0x2) and sea (0x3). Bit 4 indicates road/airstrip.\n byte          GridBlock_CfgEnvSounds[MapSize]; // a gridblock. mostly the value 0x03 and probably related to Config.cpp CfgEnvSounds class\n\n ulong         nPeaks;\n XYZTriplet    PeakPositions[nPeaks];           //see http://en.wikipedia.org/wiki/Maxima_and_minima\n\n ushort        GridBlock_RvmatLayerIndex[LayerSize];\n\n if !Elite\n  if ArmaOne\n   ushort       RandomClutter[LayerSize];        //compressed. probably random values needed for calculating clutter models position\n                                                 //seems to be related to clutters or sat mask distance as it is\n                                                 //responsible for the clutterbug\n  else\n    bytes       RandomClutter[MapSize];    //compressed\n  endif\n```\n\n```\n     bytes         CompressedBytes1[MapSize];    //compressed\n```\n\n```\n endif\n\n float         Elevation[MapSize];              //compressed\n\n ulong         nRvmats;\n Texture       Textures[nRvmats];               //\"PrefixRoot\\data\\layers\\some.rvmat\\0\\0\"\n\n ulong         nModels;\n asciiz        modelPaths[nModels];             //\"ca\\buildings\\kostelik.p3d\\0\"\n\n ulong         nClassedModels;\n ClassedModel  Models[nClassedModels];          //\"Land_Hangar\\0\" : \"ca\\buildings\\Hangar.p3d\\0\"\n\n ushort        GridBlock_UnknownGrid3[MapSize];\n\n ulong         SizeOfObjects;                   //in bytes\n\n ushort        GridBlock_UnknownGrid4[MapSize];\n\n ulong         SizeOfMapInfo;                   //in bytes\n\n byte          CompressedBytes2[LayerSize];     // seems to be connected to roads, runways and special grounds\n byte          CompressedBytes3[MapSize];       // unknown but 0x00 for forests and roads and sea, mostly 0x03 and rarely 0x02\n ulong         maxObjectID;\n\n ulong         SizeOfRoadNets;                  //in bytes\n RoadNet       RoadNets[SizeOfRoadNets];\n\n Object        Objects[SizeOfObjects/SizeOfObject]; // SizeOfObject ==60\n\n MapInfo       MapInfos[...];\n}\n```\n\n- 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.\n- Similarly, SizeOfObjects can be used to skip to the MapInfo\n\n#### ClutterMask\n\nEach byte represents the intensity or, number of clutter objects for that area of **terrain**\n\n- Sea and road terrain have zilch.\n- desert terrain have very low values\n\n#### WrpHeader\n\n```\nWrpHeader\n{\n char    Filetype;        // \"OPWR\"\n ulong   version;         // 0x12 = 18\n XYPair  LayerSize;       // 256 x 256 (SaraLite), 128 x 128 (Intro)\n XYPair  MapSize;         // 1024 x 1024 (SaraLite), 512 x 512 (Intro)\n float   LayerCellSize;   // Layer cell size in meters (40m)\n}\n```\n\nThis is a traditional wrp header endemic to most wrp formats. The LayerCellSize was introduced during Elite. The MapCellSize can be derived as follows:\n\n```\nMapCellSize= LayerCellSize * LayerSizeX / MapSizeX, and is 10m for SaraLite and Intro.\n```\n\n---\n\n#### GridBlock\n\nThe 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.\n\nThere are five gridblocks in the file, two ushort arrays, and 3 byte arrays(if present)\n\n- when the grid is present, the leading flag = 0x01\n- when a default fill GridBlock exists\n\n```\n{\n  byte  flag;     // =0\n  ulong FillBits; // = almost always zero\n}\n```\n\nGridBlock is currently in the 'discussion tab'.\n\n#### Texture\n\n```\nTexture\n{\n Concatenated Asciiz TextureFilenames; //\"PrefixRoot\\data\\layers\\some.rvmat\\0\\0\" (Arma)\n                                       //\"PrefixRoot\\desert\\data\\pt.bimpas\\0\\0\"  (ELite)\n                                       //\"PboRoot\\more_anim.01.pac\\0\"            (OFP)(by way of example)\n}\n```\n\n- The Operation Flashpoint entry is solely here by way of example. No such entry exists in arma/Elite format.\n\nIn all cases (bimpas,ofp,rvmat) they devolve, ultimately, to (a series of) pac/paa texture files.\n\n- see PrefixRoot\\ description. Essentially, it is a reference to a pbo.\n\nEach cell in the grid references a (series of) rvmat texture(s) for it is surface. The RvmatLayerIndex is an index to these filenames.\n\nThus, **each** entry of this materials list consists of concatenated asciiz strings in the form\n\n\"AnRvmatFile\\0AnotherOne\\0EvenMore\\0\\0\"\n\nIe, the end of **this** entry = \\0\\0\n\nIt so happens that only one, single rvmat file, is used per cell, but, the construct is there to have any amount.\n\ntherefore, this list is of the form\n\n\"AnRvmatFile\\0\\0\"\n\nThere is always, at least one materials entry. The 1st entry.\nThe first entry (effectively index 0) is a dummy, with an empty path, because it will never be accessed. Indexes start at 1.\n\nThe 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)\n\nSimilar 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.\n\n#### ClassedModel\n\n```\n ClassedModel\n {\n    asciiz     class_name;    //\"Land_Hangar\\0\"\n    asciiz     model_path;  //\"ca\\buildings\\Hangar.p3d\"\n    XYZTriplet Position;\n    ulong      unknown;\n }\n```\n\nThis is a fairly repetitious list of often identically named class and model, used as an index from an as yet unknown grid table.\n\n#### RoadNet\n\n```\n RoadNet\n {\n  ulong    nRoadParts; // Zero or More...\n  RoadPart RoadParts[nRoadParts];\n } [LayerSize];\n```\n\nEvery Layer cell on the map has a **RoadNet** entry. If there are no road(s) for that cell, there are no **RoadParts** (nRoadParts=0)\n\nRoadParts, 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.\n\n##### RoadPart\n\n```\n RoadPart\n {\n    ushort     nRoadPositions;// at least 1? sometimes 0\n    XYZTriplet RoadPositions[nRoadPositions];\n    byte       Flags[4];\n         if WrpType==24\n          byte      MoreFlags[nRoadPositions];\n    Asciiz     P3DModel;\n    XYZTransform Transform[12]; // the averaged position of all the roads in this cell of this type\n }\n```\n\n#### Object Optional\n\n```\n Object\n {\n    ulong ObjectID;\n    ulong modelIndex; // into the [[#Models|models path name list]] (1 based)\n    float TransformMatrix[3][4]; // standard directX RowFormat transform matrix\n    ulong 0x02;\n }\n```\n\n- 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.\n\n- If *SizeOfObjects* above == 0 then there are no objects.\n\nNote 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.\nNamely, a common list of models is indexed into, by each Object entry.\n\n#### MapInfo Optional\n\n```\nMapInfo\n{\n ulong infoType;\n MapData[...];\n}\n```\n\nMapinfo, when it exists, extends to end of file. The sizeof each entry, is determined by it is info type thus:\n\n##### MapData\n\n```\nMapData\n{\n if(infoType in [0,1,2,10,11,13,14,15,16,17,22,23,26,27,30]) MapType1;\n if(infoType in [24,31,32])                                  MapType2;\n if(infoType in [25,33])                                     MapType3;\n if(infoType in [3,4,8,9,18,19,20,21,28,29])                 MapType4;\n if(infoType in [34])                                        MapType5;\n if(infoType in [35])                                        MapType35;\n```\n\n}\n\n##### MapType1\n\n```\n MapType1\n {\n    ulong ObjectId\n    float x, z\n }\n```\n\n##### MapType2\n\n```\n MapType2\n {\n  ulong ObjectId\n  float Bounds[4][2];\n }\n```\n\n##### MapType3\n\n```\nMapType3\n{\n ulong color; // maybe. or default ind of 0xFFFFFFF generally\n ulong indicator; // typically 0x01010000\n float [4]       // typically 0.5,1.0.1,5.3.0 always 'integers'\n}\n```\n\n##### MapType4\n\n```\nMapType4\n{\n    ulong ObjectId\n    float Bounds[4][2];\n    byte  Color[4] //rgba\n}\n```\n\n##### MapType5\n\n```\nMapType5\n{\n   ulong ObjectId\n   float line[2][2];?\n}\n```\n\n##### MapType35\n\n```\nMapType35  // found in chernarus\n{\n   ulong ObjectId\n   float line[3][2];?\n   byte  unknown;\n}\n```\n\nType 35 is also found in oprw23 formats but is currently indecipherable and may, in fact, be an error\n\n### Packed Data\n\nAll variables starting with \"Packed\" are compressed with the common BIS algorithm that is also used in paa and OFP pbo files.","sections":[{"heading":null,"level":1,"markdown":"> **Disclaimer: This page describes internal undocumented structures of Bohemia Interactive software.**\n>\n> This page contains unofficial information.\n>\n> 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.\n> 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."},{"heading":"Introduction","level":3,"markdown":"For a general description of wrp files see 8WVR"},{"heading":"Legend","level":4,"markdown":"see Generic FileFormat Data Types"},{"heading":"File Format","level":3,"markdown":"- Layer and Map Sizes are derived from the header.\n\nThis document is based on analysis of arma1 wrps (OPRW18). The following are known differences between them, and later versions\n\n- OPRW17 (Elite) does not have the clutter\n- OPRW20 (sara and desert pbo's) :So far, this is the SAME format as 18 except PackedBytes1\n- OPRW23 (vbs2lite us) :So far, this is the SAME format as 20\n- OPRW24 (arma2)uses lzo compresion, not, lzss\n\n```\nOPRWv17://elite\nOPRWv18://arma1\nOPRWv20://arma1 sara\nOPRWv23://vbs2_lite\nOPRWv24://arma2\n{\n WrpHeader     Header;\n\n ushort        GridBlock_CellEnv[MapSize];      // a gridblock containing cellenv bits (16 bits per terrain cell).\n                                                // Bits 0-2 are ground (0x0), coast (0x1), beach (0x2) and sea (0x3). Bit 4 indicates road/airstrip.\n byte          GridBlock_CfgEnvSounds[MapSize]; // a gridblock. mostly the value 0x03 and probably related to Config.cpp CfgEnvSounds class\n\n ulong         nPeaks;\n XYZTriplet    PeakPositions[nPeaks];           //see http://en.wikipedia.org/wiki/Maxima_and_minima\n\n ushort        GridBlock_RvmatLayerIndex[LayerSize];\n\n if !Elite\n  if ArmaOne\n   ushort       RandomClutter[LayerSize];        //compressed. probably random values needed for calculating clutter models position\n                                                 //seems to be related to clutters or sat mask distance as it is\n                                                 //responsible for the clutterbug\n  else\n    bytes       RandomClutter[MapSize];    //compressed\n  endif\n```\n\n```\n     bytes         CompressedBytes1[MapSize];    //compressed\n```\n\n```\n endif\n\n float         Elevation[MapSize];              //compressed\n\n ulong         nRvmats;\n Texture       Textures[nRvmats];               //\"PrefixRoot\\data\\layers\\some.rvmat\\0\\0\"\n\n ulong         nModels;\n asciiz        modelPaths[nModels];             //\"ca\\buildings\\kostelik.p3d\\0\"\n\n ulong         nClassedModels;\n ClassedModel  Models[nClassedModels];          //\"Land_Hangar\\0\" : \"ca\\buildings\\Hangar.p3d\\0\"\n\n ushort        GridBlock_UnknownGrid3[MapSize];\n\n ulong         SizeOfObjects;                   //in bytes\n\n ushort        GridBlock_UnknownGrid4[MapSize];\n\n ulong         SizeOfMapInfo;                   //in bytes\n\n byte          CompressedBytes2[LayerSize];     // seems to be connected to roads, runways and special grounds\n byte          CompressedBytes3[MapSize];       // unknown but 0x00 for forests and roads and sea, mostly 0x03 and rarely 0x02\n ulong         maxObjectID;\n\n ulong         SizeOfRoadNets;                  //in bytes\n RoadNet       RoadNets[SizeOfRoadNets];\n\n Object        Objects[SizeOfObjects/SizeOfObject]; // SizeOfObject ==60\n\n MapInfo       MapInfos[...];\n}\n```\n\n- 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.\n- Similarly, SizeOfObjects can be used to skip to the MapInfo"},{"heading":"ClutterMask","level":4,"markdown":"Each byte represents the intensity or, number of clutter objects for that area of **terrain**\n\n- Sea and road terrain have zilch.\n- desert terrain have very low values"},{"heading":"WrpHeader","level":4,"markdown":"```\nWrpHeader\n{\n char    Filetype;        // \"OPWR\"\n ulong   version;         // 0x12 = 18\n XYPair  LayerSize;       // 256 x 256 (SaraLite), 128 x 128 (Intro)\n XYPair  MapSize;         // 1024 x 1024 (SaraLite), 512 x 512 (Intro)\n float   LayerCellSize;   // Layer cell size in meters (40m)\n}\n```\n\nThis is a traditional wrp header endemic to most wrp formats. The LayerCellSize was introduced during Elite. The MapCellSize can be derived as follows:\n\n```\nMapCellSize= LayerCellSize * LayerSizeX / MapSizeX, and is 10m for SaraLite and Intro.\n```\n\n---"},{"heading":"GridBlock","level":4,"markdown":"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.\n\nThere are five gridblocks in the file, two ushort arrays, and 3 byte arrays(if present)\n\n- when the grid is present, the leading flag = 0x01\n- when a default fill GridBlock exists\n\n```\n{\n  byte  flag;     // =0\n  ulong FillBits; // = almost always zero\n}\n```\n\nGridBlock is currently in the 'discussion tab'."},{"heading":"Texture","level":4,"markdown":"```\nTexture\n{\n Concatenated Asciiz TextureFilenames; //\"PrefixRoot\\data\\layers\\some.rvmat\\0\\0\" (Arma)\n                                       //\"PrefixRoot\\desert\\data\\pt.bimpas\\0\\0\"  (ELite)\n                                       //\"PboRoot\\more_anim.01.pac\\0\"            (OFP)(by way of example)\n}\n```\n\n- The Operation Flashpoint entry is solely here by way of example. No such entry exists in arma/Elite format.\n\nIn all cases (bimpas,ofp,rvmat) they devolve, ultimately, to (a series of) pac/paa texture files.\n\n- see PrefixRoot\\ description. Essentially, it is a reference to a pbo.\n\nEach cell in the grid references a (series of) rvmat texture(s) for it is surface. The RvmatLayerIndex is an index to these filenames.\n\nThus, **each** entry of this materials list consists of concatenated asciiz strings in the form\n\n\"AnRvmatFile\\0AnotherOne\\0EvenMore\\0\\0\"\n\nIe, the end of **this** entry = \\0\\0\n\nIt so happens that only one, single rvmat file, is used per cell, but, the construct is there to have any amount.\n\ntherefore, this list is of the form\n\n\"AnRvmatFile\\0\\0\"\n\nThere is always, at least one materials entry. The 1st entry.\nThe first entry (effectively index 0) is a dummy, with an empty path, because it will never be accessed. Indexes start at 1.\n\nThe 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)\n\nSimilar 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."},{"heading":"ClassedModel","level":4,"markdown":"```\n ClassedModel\n {\n    asciiz     class_name;    //\"Land_Hangar\\0\"\n    asciiz     model_path;  //\"ca\\buildings\\Hangar.p3d\"\n    XYZTriplet Position;\n    ulong      unknown;\n }\n```\n\nThis is a fairly repetitious list of often identically named class and model, used as an index from an as yet unknown grid table."},{"heading":"RoadNet","level":4,"markdown":"```\n RoadNet\n {\n  ulong    nRoadParts; // Zero or More...\n  RoadPart RoadParts[nRoadParts];\n } [LayerSize];\n```\n\nEvery Layer cell on the map has a **RoadNet** entry. If there are no road(s) for that cell, there are no **RoadParts** (nRoadParts=0)\n\nRoadParts, 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."},{"heading":"RoadPart","level":5,"markdown":"```\n RoadPart\n {\n    ushort     nRoadPositions;// at least 1? sometimes 0\n    XYZTriplet RoadPositions[nRoadPositions];\n    byte       Flags[4];\n         if WrpType==24\n          byte      MoreFlags[nRoadPositions];\n    Asciiz     P3DModel;\n    XYZTransform Transform[12]; // the averaged position of all the roads in this cell of this type\n }\n```"},{"heading":"Object Optional","level":4,"markdown":"```\n Object\n {\n    ulong ObjectID;\n    ulong modelIndex; // into the [[#Models|models path name list]] (1 based)\n    float TransformMatrix[3][4]; // standard directX RowFormat transform matrix\n    ulong 0x02;\n }\n```\n\n- 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.\n\n- If *SizeOfObjects* above == 0 then there are no objects.\n\nNote 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.\nNamely, a common list of models is indexed into, by each Object entry."},{"heading":"MapInfo Optional","level":4,"markdown":"```\nMapInfo\n{\n ulong infoType;\n MapData[...];\n}\n```\n\nMapinfo, when it exists, extends to end of file. The sizeof each entry, is determined by it is info type thus:"},{"heading":"MapData","level":5,"markdown":"```\nMapData\n{\n if(infoType in [0,1,2,10,11,13,14,15,16,17,22,23,26,27,30]) MapType1;\n if(infoType in [24,31,32])                                  MapType2;\n if(infoType in [25,33])                                     MapType3;\n if(infoType in [3,4,8,9,18,19,20,21,28,29])                 MapType4;\n if(infoType in [34])                                        MapType5;\n if(infoType in [35])                                        MapType35;\n```\n\n}"},{"heading":"MapType1","level":5,"markdown":"```\n MapType1\n {\n    ulong ObjectId\n    float x, z\n }\n```"},{"heading":"MapType2","level":5,"markdown":"```\n MapType2\n {\n  ulong ObjectId\n  float Bounds[4][2];\n }\n```"},{"heading":"MapType3","level":5,"markdown":"```\nMapType3\n{\n ulong color; // maybe. or default ind of 0xFFFFFFF generally\n ulong indicator; // typically 0x01010000\n float [4]       // typically 0.5,1.0.1,5.3.0 always 'integers'\n}\n```"},{"heading":"MapType4","level":5,"markdown":"```\nMapType4\n{\n    ulong ObjectId\n    float Bounds[4][2];\n    byte  Color[4] //rgba\n}\n```"},{"heading":"MapType5","level":5,"markdown":"```\nMapType5\n{\n   ulong ObjectId\n   float line[2][2];?\n}\n```"},{"heading":"MapType35","level":5,"markdown":"```\nMapType35  // found in chernarus\n{\n   ulong ObjectId\n   float line[3][2];?\n   byte  unknown;\n}\n```\n\nType 35 is also found in oprw23 formats but is currently indecipherable and may, in fact, be an error"},{"heading":"Packed Data","level":3,"markdown":"All variables starting with \"Packed\" are compressed with the common BIS algorithm that is also used in paa and OFP pbo files."}],"categories":["Operation Flashpoint: Modelling","Real Virtuality File Formats"],"groups":["Tools and File Formats"]}