PEW File Format: Difference between revisions

From Bohemia Interactive Community
Jump to navigation Jump to search
mNo edit summary
m (Text replacement - "{{ExternalLink|" to "{{Link|")
 
(24 intermediate revisions by 5 users not shown)
Line 1: Line 1:
{{unsupported-doc}}
{{Feature|UnsupportedDoc}}
{{TOC|side|0.8}}
PEW files are [[Visitor 3|Visitor]]'s project files. Visitor is [[{{Name|bi}}]]'s tool for creating Islands.


== Introduction ==
Visitor is a GUI tool interface that interacts with [[Bulldozer]], an in-built 'world' viewer inside any [[:Category:ArmA: Armed Assault|{{arma1}}]] engine.


PEW files are [[Visitor 3|Visitor]]'s project files.  Visitor is [[BI]]'s tool for creating Islands.
The contents of the PEW project file are not directly related to the ultimate output, a WRP file.
However, that data contains all similar elements, such as road networks, elevations, cell matrices, models (P3D files) and textures (RVMAT files).


Visitor is a GUI tool interface that interacts with [[Bulldozer]], an in-built 'world' viewer inside any [[Armed Assault]] engine.
Exporting a PEW file into WRP format involves the use of Bulldozer, since it is Bulldozer that decides how it wants that data presented rather than anything Visitor might like to decide.
It is Bulldozer that determines the format and version of the resulting WRP file (in 8WVR format), so the WRP version is based on the version of the [[Real Virtuality]] engine used to create it.
This is not the same thing as saying the VERSION of the engine. It is the engine, that decides, the VERSION of wrp it needs to generate.


The contents of the PEW project file are not directly related to the ultimate output, a WRP file. However, that data contains all similar elements, such as road networks, elevations, cell matrices, models (P3D files) and textures (RVMAT files).
Furthermore, the resulting Wrp file is (for want of a better expression) 'unbinarised' 8WVR format. It is nothing more or less, than a (modified) copy of texture, elevations and models. Period.
Roadnetworks and other ancilliary data is only processed into a 'binarised' OPRW format wrp, using Bi's binarizer tool.


Exporting a PEW file into WRP format involves the use of Bulldozer, since it is Bulldozer that decides how it wants that data presented rather than anything Visitor might like to decide. It is Bulldozer that determines the format and version of the resulting WRP file (in 8WVR format), so the WRP version is based on the version of the [[Real Virtuality]] engine used to create it. This is not the same thing as saying the VERSION of the engine. It is the engine, that decides, the VERSION of wrp it needs to generate.
Note that it is possible to generate 8WVR format without involving bulldozer (or arma) using [{{Link|link= http://dev-heaven.net/projects/list_files/mikero-pbodll|3rd|text= party tools}}].


Furthermore, the resulting Wrp file is (for want of a better expression) 'unbinarised' 8WVR format. It is nothing more or less, than a (modified) copy of texture, elevations and models. Period. Roadnetworks and other ancilliary data is only processed into a 'binarised' OPRW format wrp, using Bi's binarizer tool.


Note that it is possible to generate 8WVR format without involving bulldozer (or arma) using [[http://dev-heaven.net/projects/list_files/mikero-pbodll|3rd party tools]].
While there have been several PEW versions, the ones listed here are:
* POSEW59
* POSEW60


There are only a few subtle differences to their makeup.


While there have been several PEW versions, the ones listed here are:
*POSEW59 and
*POSEW60


There are only a few subtle differences to their makeup.
== Legend ==


=== Legend ===
See [[Generic FileFormat Data Types]].


See [[Generic FileFormat Data Types]]


== File Format ==
== File Format ==


::*This file format is principally used with Armed Assault v1.09 and later, with the ArmA Tools Suite final release (v1.14).
{{Feature|informative|This file format is principally used with {{arma1}} v1.09 and later, with the ArmA Tools Suite final release (v1.14).}}


  POSEW59
<syntaxhighlight lang="C#">
  POSEW60
POSEW59
  {
POSEW60
    PoseHeader               Header;
{
    ulong                   nOFPTextures           // none in Arma;
PoseHeader Header;
    OFPTexture               OFPTextures[nOFPTextures];
ulong nOFPTextures; // none in Arma
    ulong                   nObjectTemplates;
OFPTexture OFPTextures[nOFPTextures];
    ObjectTemplate           ObjectTemplates[nObjectTemplates];
ulong nObjectTemplates;
    shortBool               NoOfpTerrains;
ObjectTemplate ObjectTemplates[nObjectTemplates];
    if (!NoOfpTerrains)
shortBool NoOfpTerrains;
    {
if (!NoOfpTerrains)
    ulong                   nOFPTerrains;         // none in Arma;
{
    OFPTerrain               OFPTerrains[nOFPTerrains];
ulong nOFPTerrains; // none in Arma
    }
OFPTerrain OFPTerrains[nOFPTerrains];
    shortBool               NoOFPForests;         // none in Arma;
}
    if (!NoOFPForests)
shortBool NoOFPForests; // none in Arma
    {
if (!NoOFPForests)
    ulong                   nOFPForests;        
{
    OFPForest               OFPForests[nOFPForests];
ulong nOFPForests;
    }
OFPForest OFPForests[nOFPForests];
    RoadNets                RoadNets[...];
}
    Elevation               Elevation[...];
RoadNetworkTemplate RoadNetworkTemplates[...];
    ulong                   NoOfObjects;
Elevation Elevation[...];
    Object                   Objects[NoOfObjects];
ulong NoOfObjects;
Object Objects[NoOfObjects];
    ulong                    NoOfLayers;
    String                  LayerName;          //"Base"
    Layer                    Layers[[NoOfLayers] ;
    ulong                    nNamedZones;// almost never present on pose60
    NamedZone                NamedZones[nNamedZones];
 
    ulong                    nRoadBlocks;
    RoadBlock                RoadBlocks[nRoadBlocks];
    ulong                    nAltNamedZones;
    AltNamedZone            AltNamedZones[nAltNamedZones];//never seen (so far) on pose59


ulong NoOfLayers;
String CurrentLayerName; // "Base"
Layer Layers[NoOfLayers] ;


    ulong                   nKeyPoints;
ulong nNamedZones;// almost never present on pose60
    KeyPoint                KeyPoints[nKeyPoints];   
NamedZone NamedZones[nNamedZones];
    ulong                    NoOfBackgrounds;
    Background              Backgrounds[NoOfBackgrounds] ;// not checked for 59
    ulong                    TotalSizeOfSelections; // from here, to end of file
    ulong                    nSelections;
    Selection                Selections[nSelections];
  }


ulong nRoadNetworks;
if (nRoadNetworks > 0)
RoadNetwork RoadNetworks[nRoadNetworks];


===PoseHeader===
ulong nKeyPoints;
Header
KeyPoint KeyPoints[nKeyPoints];
{
ulong NoOfBackgrounds;
  char    Signature[7];       // "POSEW59" or "POSEW60" note: NOT null terminated
Background Backgrounds[NoOfBackgrounds]; // not checked for 59
  ulong   Length;             // of PEW file;
ulong TotalSizeOfSelections; // from here, to end of file
  ulong   UnknownLong;         // typically 0
ulong nSelections;
  String  IslandRvMatPath;     //"SomePboPrefix\SomeIsland\data\0" see below
Selection Selections[nSelections];
  String  IslandP3dPath;      //"" (objects)
}
  float   TerrainGridSize;    //10.0 metres
</syntaxhighlight>
  float   SegmentSize;        //400.0 (==SegmentSize - SegmentOverlap)
  String  IslandClassname;    //""
};


====Texture And Terrain Sizes====
=== PoseHeader ===


*Pew files deal with '''terrain'''. There is no 'texture' size as such. Therefore the gridsize specified in the header pertains to '''terrain''' cells.
<syntaxhighlight lang="C#">
Header
{
char Signature[7]; // "POSEW59" or "POSEW60" note: NOT null terminated
ulong Length; // of PEW file;
ulong UnknownLong; // typically 0
String IslandRvMatPath; // "SomePboPrefix\SomeIsland\data\0" see below
String IslandP3dPath; // "" (objects)
float TerrainGridSize; // 10.0 metres
float SegmentSize; // 400.0 (==SegmentSize - SegmentOverlap)
String IslandClassname; // ""
};
</syntaxhighlight>


*In contrast, the gridsize specified in a WRP pertains to TEXTURE(rvmat) cells.
==== Texture And Terrain Sizes ====
* Pew files deal with '''terrain'''. There is no 'texture' size as such. Therefore the gridsize specified in the header pertains to '''terrain''' cells.
* In contrast, the gridsize specified in a WRP pertains to TEXTURE(rvmat) cells.


 
"Texture", 'Material', 'Surface', 'Layer' are synonomous to rvmat files.
"Texture", 'Material','Surface', 'Layer' are synonomous to rvmat files. They are the island's unique surface as generated by importing from a sat mask image. There can be, multipler layers of rvmat files.  
They are the island's unique surface as generated by importing from a sat mask image. There can be multipler layers of rvmat files.


''Terrain'', are the cell grids of the map and as often as not specified at a different (larger) dimension.
''Terrain'', are the cell grids of the map and as often as not specified at a different (larger) dimension.
Line 107: Line 110:
The Terrain (Map) Size is declared in the elevations structure.
The Terrain (Map) Size is declared in the elevations structure.


TextureSizeS (plural) are derived, not declared, in each surface 'Layer' of pew. Since, ultimately, each layer must 'fit' onto the map. Each layer contains a shift value of how much SMALLER the surface is, relative to the map. For OFP, and OFP converted-to-arma, islands, this is 0 (there is no difference betweem a 256x256 cell Terrain and a 256x256 cell Texture.
TextureSizeS (plural) are derived, not declared, in each surface 'Layer' of pew. Since, ultimately, each layer must 'fit' onto the map.
Each layer contains a shift value of how much SMALLER the surface is, relative to the map.
For OFP, and OFP converted-to-arma, islands, this is 0 (there is no difference betweem a 256x256 cell Terrain and a 256x256 cell Texture.


For Arma,it is *generally* x 4 (shift value=2).
For Arma, it is *generally* x 4 (shift value=2).
 
*TerrainGridSize


===== TerrainGridSize =====
A wrp file's GridSize is the OPPOSITE of a PewFile's GridSize.
A wrp file's GridSize is the OPPOSITE of a PewFile's GridSize.


Line 122: Line 126:




*IslandRvMatPath
===== IslandRvMatPath =====
RVMAT file references in the Layers structure are listed as ''relative'' addresses to the IslandRvMatPath.
This is in contradistinction to the general Bis way-of-doing-things where all references are hard references.


RVMAT file references in the Layers structure are listed as ''relative'' addresses to the IslandRvMatPath. This is in contradistinction to the general Bis way-of-doing-things where all references are hard references.
Traditionally, an RVMAT(Island) data path is declared as "Layers\some.rvmat".
It is expected, therefore, that you do indeed have a "P:\SomePboPrefix\SomeIsland\...\Layers" folder.
Put another way, the ''prefix'' of the PBO must be "SomePboPrefix\SomeIsland\...".


Traditionally, an RVMAT(Island) data path is declared as "Layers\some.rvmat". It is expected, therefore, that you do indeed have a "P:\SomePboPrefix\SomeIsland\...\Layers" folder. Put another way, the ''prefix'' of the PBO must be "SomePboPrefix\SomeIsland\...".
The SubFolder 'Layers' is hard wired by Visitor. It is generated automatically when importing a satmask image.
Thus, all relative reverences to the rvmats that Visitor produces, are prefaced by 'Layers\'.


The SubFolder 'Layers' is hard wired by Visitor. It is generated automatically when importing a satmask image. Thus, all relative reverences to the rvmats that Visitor produces, are prefaced by 'Layers\'.
Using 3rd party tools, you can, should you wish to, alter this prefixing and location of the rvmats to anywhere at all, including no path at all (Visitor, the engine, and the binarizer don't actually care).
The purpose in doing so is somewhat moot, since, unlike p3d's, rvmat's for an island are unique to an island.
The chances or need of referencing them by something else is zilch. Hence, unlike p3d's, they may just as well stay in the wrp's pbo. Point being, they don't have to.


Using 3rd party tools, you can, should you wish to, alter this prefixing and location of the rvmats to anywhere at all, including no path at all (Visitor, the engine, and the binarizer don't actually care). The purpose in doing so is somewhat moot, since, unlike p3d's, rvmat's for an island are unique to an island. The chances or need of referencing them by something else is zilch. Hence, unlike p3d's, they may just as well stay in the wrp's pbo. Point being, they don't have to.
===== IslandObjectPath =====
IslandObjectPath uses the same mechanics as above.
However, since P3D files are almost inevitable declared from multiple locations (any PBO, including the base 'CA' PBO included in the game) its use is moot.
Be that as it may, the mechanism exists and works, identically to {{Link|#IslandRvMatPath}}.


*IslandObjectPath uses the same mechanics as above.  However, since P3D files are almost inevitable declared from multiple locations (any PBO, including the base 'CA' PBO included in the game) its use is moot. Be that as it may, the mechanism exists and works, identically to IslandRvMatPath.


PEW files are not known to contain anything in IslandObjectPath or IslandClassname. <!-- This statement is subject to revision. -->


PEW files are not known to contain anything in IslandObjectPath or IslandClassname. <!-- This statement is subject to revision. -->
=== OFPTexture ===
 
<syntaxhighlight lang="C#">
OFPTexture
{
ulong TextureID;
String TextureFileName; // "snih3.paa"
String TextureName; // "snih3"
String RvmatName; // "snih3.rvmat"
byte UnknownBytes[14]; // (typically 0)
RGBAColor Colour;
}
</syntaxhighlight>


===OFPTexture===
=== ObjectTemplate ===
OFPTexture
{
  ulong     TextureID;
  String    TextureFileName; // "snih3.paa"
  String    TextureName; // "snih3"
  String    RvmatName; // "snih3.rvmat"
  byte      UnknownBytes[14]; // (typically 0)
  RGBAColor Colour;
}


===ObjectTemplate===
<syntaxhighlight lang="C#">
  ObjectTemplate
ObjectTemplate
  {
{
      String       ModelFilename; //"SomePrefixRoot\data\jablon.p3d\0"
String ModelFilename; // "SomePrefixRoot\data\jablon.p3d\0"
      String       ModelName;     //"jablon"
String ModelName; // "jablon"
      ulong       ObjectType;   // 0..5
ulong ObjectType; // 0..5 (so far...)
                                  // 0 Natural
// 0 Undefined - This type should never be encountered.
                                  // 1 Artificial
// 1 Natural
                                  // 2 ???
// 2 Artificial
                                  // 3 Road (RoadFlag will be true)
// 3 Road (RoadFlag will be true)
                                  // 4 ???
// 4 Forest
                                  // 5 ArtificialAndDefinedInRoad
// 5 Road2 (RoadFlag will be false)
      RGBAColor   OutlineColour;  
RGBAColor OutlineColour;
      RGBAColor   ObjectColour;
RGBAColor ObjectColour;
      double   GeometryBounds[2];           // 50.0
double GeometryBounds[2]; // 50.0
      ulong   ModelID;                     // uniqueID, used by objects to lookup this model(p3d)
ulong ModelID; // uniqueID, used by objects to lookup this model(p3d)
      XYZTriplet   GeometryAutocenterPos;
XYZTriplet GeometryAutocenterPos;
      double   ResolutionBounds[2];         // 50.0
double ResolutionBounds[2]; // 50.0
      XYZTriplet   ResolutionAutoCenterPos;
XYZTriplet ResolutionAutoCenterPos;
      shortBool   Generally0x01;  
shortBool Generally0x01;
      shortBool   RandomScaleFlag;
shortBool RandomScaleFlag;
      double   RandomScaleMinMax[2];         // 50.0
double RandomScaleMinMax[2]; // 50.0
      shortBool   RandomRotateFlag;
shortBool RandomRotateFlag;
      double   RandomRotateMinMax[2];       // 20.0
double RandomRotateMinMax[2]; // 20.0
      shortBool   RandomOrientationFlag;    
shortBool RandomOrientationFlag;
      double   RanmdomOrientationMinMax[2]; // 180.0
double RanmdomOrientationMinMax[2]; // 180.0
      shortBool   RoadFlag;
shortBool RoadFlag;
      if (RoadFlag)  
if (RoadFlag)
      {
{
            TransformMatrix RoadNamedSelections; // (LB, PB, LE, PE)
TransformMatrix RoadNamedSelections; // (LB, PB, LE, PE)
            TransformMatrix XRoadNamedSelections;// (LD, LH, PD, PH)
TransformMatrix XRoadNamedSelections; // (LD, LH, PD, PH)
      };
};
      ulong           nArtificialObjects;
ulong nNamedVectors; // Usually 0 (zero)
      ArtificialObject ArtificialObjects[nArtificialObjects];
NamedVector NamedVectors[nNamedVectors];
      ulong           MarkerType;                 // Rectangular = 0, Elliptical = 1  
ulong MarkerType; // Rectangular = 0, Elliptical = 1
  }
}
</syntaxhighlight>


As opposed to layers (material RVMAT surfaces), 'objects' are instances of models placed onto the map. Irrespective of the number of objects there is only one reference to the model used, which is then referenced as often as needed.
As opposed to layers (material RVMAT surfaces), 'objects' are instances of models placed onto the map.
Irrespective of the number of objects there is only one reference to the model used, which is then referenced as often as needed.


ModelFilename, ModelName, and ModelID are unique unduplicated entries.
ModelFilename, ModelName, and ModelID are unique unduplicated entries.
Line 191: Line 210:
The ModelID is not zero based; its value is incremental according to the number of times ''any'' model has been added while editing, even if previous models have been deleted; model IDs do not rearrange themselves and deleted IDs are not recycled for re-use.
The ModelID is not zero based; its value is incremental according to the number of times ''any'' model has been added while editing, even if previous models have been deleted; model IDs do not rearrange themselves and deleted IDs are not recycled for re-use.
The ObjectID illustrated on maps is, in contrast, the unique InstanceID of each object in the objects structure below.
The ObjectID illustrated on maps is, in contrast, the unique InstanceID of each object in the objects structure below.
'Road2' type cannot be defined with Visitor3 Personal Edition. It's a type specific to VBS2 V3 edition.
==== NamedVector ====
<syntaxhighlight lang="C#">
NamedVector
{
String Name; // "pohrada"
LongBool Unknown;
ulong nTriplets; // generally 2 sometimes 1
XYZTriplet StartEndPos[nTriplets];
}
</syntaxhighlight>
As of v60 a rarely used sub structure with ObjTemplates.
=== OFPTerrain ===
<syntaxhighlight lang="C#">
OFPTerrain
{
String TerrainName;
byte UnknownBytes[11];
ulong nSurfaces;
OFPSurface OFPSurfaces[nSurfaces];
}
</syntaxhighlight>
==== OFPSurface ====
<syntaxhighlight lang="C#">
OFPSurface
{
String SurfaceName;
float Surfacefloat[4];
byte UnknownBytes[16];
}
</syntaxhighlight>
=== OFPForest ===
<syntaxhighlight lang="C#">
OFPForest
{
String ForestName;
RGBAColor OutlineColour;
RGBAColor ObjectColour;
ulong SquareFillModelID;
ulong SquareModelID;
ulong TriangleModelID;
ulong Unknown1; // (typically 0)
ulong Unknown2; // (typically 0)
}
</syntaxhighlight>
=== NamedZone ===
<syntaxhighlight lang="C#">
NamedZone
{
ushort IsPresent;
ushort Moveable;
String Name; // Les_new
RGBAColor AreaColor;
RGBAColor OutlineColor;
ulong DisplayStyle;
ulong nFloats;
float Floats[nFloats];
ulong ID;
String Name2;
}
</syntaxhighlight>
=== AltNamedZone ===


====ArtificialObject====
<syntaxhighlight lang="C#">
  ArtificialObject
AltNamedZone
  {
{
    String     Name;       //"pohrada"
ushort IsPresent;
    LongBool  Unknown;
ushort Moveable;
    ulong     nTriplets; // generally 2 sometimes 1
String Name; // Les_new
    XYZTriplet StartEndPos[nTriplets];
RGBAColor AreaColor;
  }
RGBAColor OutlineColor;
ulong DisplayStyle;
ulong nFloats;
float Floats[nFloats];
ulong ID;
ulong Visible;
}
</syntaxhighlight>


===OFPTerrain===
=== RoadNetworkTemplates ===
OFPTerrain
{
  String  TerrainName;
  byte    UnknownBytes[11];
  ulong   nSurfaces;
  OFPSurface OFPSurfaces[nSurfaces];
}
====OFPSurface====
OFPSurface
{
  String SurfaceName;
  float Surfacefloat[4];
  byte  UnknownBytes[16];
}
===OFPForest===
OFPForest
{
  String    ForestName;
  RGBAColor OutlineColour;
  RGBAColor ObjectColour;
  ulong     SquareFillModelID;
  ulong     SquareModelID;
  ulong     TriangleModelID;
  ulong     Unknown1; // (typically 0)
  ulong     Unknown2; // (typically 0)
}


===RoadNet===
<syntaxhighlight lang="C#">
    shortBool NoRoads;
RoadNetworkTemplates
    if (!NoRoads)
{
    {
shortBool RoadNetworkTemplatesDefined;
      ulong    nTypes;
if (!RoadNetworkTemplatesDefined)
      RoadType RoadTypes[nTypes];
{
      ulong    nXRoads;
//RoadNetworkTemplates
      XRoad    XRoads[nXRoads];
ulong NoOfRoadNetworkTemplates;
    }
if (NoOfRoadNetworkTemplates > 0)
{
====RoadType====
RoadNetTemplate RoadNetTemplates[NoOfRoadNetworkTemplates];
  RoadType
}
  {
    String      FamilyName;        // "cesta","silnice",etc
    RGBA        KeyPartsColour;  
    RGBA        NormalPartsColour;
    shortBool    FilledLine;        // 0 or 1
    double      MaxAngle;          // 25.0 degrees
    double      MaxBankAngle;      // 5.0 degrees
    ulong        nStraights;
    RoadList    Straights[nStraights];
    ulong        nCurves;
    RoadList    Curves[nCurves];
    ulong        nSpecials;
    RoadList    Specials[nSpecials];
    ulong        nTerminators;
    RoadList    Terminators[nTerminators];
    }
  }


=====RoadList=====
//CrossroadTemplates
  RoadList   
ulong NoOfCrossroadTemplates;
  {
if (NoOfCrossroadTemplates > 0)
      String     ModelName;     // "cesta25"
{
      ulong       ObjectID;       // in the model list
CrossroadTemplate CrossroadTemplates[NoOfCrossroadTemplates];
      ushort      MeterType;     // 0,1,2,3 not present for Terminators
}
      shortBool   CanChangeAngle; // not present for Terminators or Curves
}
  }
}
</syntaxhighlight>
 
==== RoadNetTemplate ====
<syntaxhighlight lang="C#">
RoadNetTemplate
{
String TemplateName;
RGBAColor KeyPartsColour;
RGBAColor NormalPartsColour;
shortBool FilledLine;
double MaxAngle;
double MaxBankAngle;
 
ulong NoOfStraightParts;
if (NoOfStraightParts > 0)
StraightPart StraightParts[NoOfStraightParts];
 
ulong NoOfCurveParts;
if (NoOfCurveParts > 0)
CurvePart CurveParts[NoOfCurveParts];
 
ulong NoOfSpecialParts;
if (NoOfSpecialParts > 0)
SpecialPart SpecialParts[NoOfSpecialParts];
 
ulong NoOfTerminatorParts;
if (NoOfTerminatorParts > 0)
TerminatorPart TerminatorParts[NoOfTerminatorParts];
}
</syntaxhighlight>
 
===== StraightPart =====
<syntaxhighlight lang="C#">
StraightPart
{
String StraightPartName;
ulong ObjectTemplateID;
StraightPartEnum StraightPartType;
shortBool CanChangeBankAngle;
}
</syntaxhighlight>
 
===== CurvePart =====
<syntaxhighlight lang="C#">
CurvePart
{
String CurvePartName;
ulong ObjectTemplateID;
CurvePartEnum CurvePartType;
}
</syntaxhighlight>
 
===== SpecialPart =====
<syntaxhighlight lang="C#">
SpecialPart
{
String SpecialPartName;
ulong ObjectTemplateID;
SpecialPartEnum SpecialPartType;
}
</syntaxhighlight>
 
===== TerminatorPart =====
<syntaxhighlight lang="C#">
TerminatorPart
{
String TerminatorPartName;
ulong ObjectTemplateID;
}
</syntaxhighlight>
 
==== CrossroadTemplate ====
<syntaxhighlight lang="C#">
CrossroadTemplate
{
String TemplateName;
CrossroadTypeEnum Shape;
RGBAColor Color;
shortBool FilledLine;
ulong ObjectTemplateID;
String Net_A;
String Net_B;
String Net_C;
String Net_D;
}
</syntaxhighlight>


{| class="wikitable"
{| class="wikitable"
|-
|+ MeterType Values
! colspan="3"| MeterType Values
|-
|-
! Type
! Type
Line 276: Line 416:
! Curves
! Curves
|-
|-
| 0 ||  6 m || 25 m
| 0 ||  6 m || 25 m
|-
|-
| 1 || 12 m || 50 m
| 1 || 12 m || 50 m
|-
|-
| 2 || 25 m || 75 m
| 2 || 25 m || 75 m
|-
|-
| 3 ||      ||100 m
| 3 ||      || 100 m
|-
|-
|}
|}
Line 298: Line 438:
* 1 'termination' type.
* 1 'termination' type.
The termination type is a road like any other but tends to be a fixed 6 meter fade out of the general road texture.
The termination type is a road like any other but tends to be a fixed 6 meter fade out of the general road texture.
====XRoad====
XRoad
{
  String    Name;       //kr_asfaltka_asfaltka_t.
  ushort    Shape;            //1 or 3
  RGBA      color;       //FF FF FF FF
  shortBool CanChangeBankAngle;
  ulong    ObjectID;
  String    Intersections[4]; //"asfaltka","silnice","cesta",Type=3 "silnice" else ""
}


Although "CrossRoads" could conceivably have any number of intersections, only two types are handled.
Although "CrossRoads" could conceivably have any number of intersections, only two types are handled.


*Type 1: A T_Junction (3 intersections)
* Type 1: A T_Junction (3 intersections)
*Type 3: A genuine crossroad (4 way intersection)
* Type 3: A genuine crossroad (4 way intersection)


For T_Junctions, there is obviously no 4th intersection and this is null filled.
For T_Junctions, there is obviously no 4th intersection and this is null filled.
Line 319: Line 448:
Without taking too literal an interpretation, there are some major types of road.
Without taking too literal an interpretation, there are some major types of road.


*asfaltka:bitumen (sealed)
* asfaltka: Bitumen (sealed)
*silnice: Paved
* silnice: Paved
*cesta:   Dirt
* cesta: Dirt


Thus the names of each intersection reflect the road type of that intersection, sometimes resulting in (up to) four identical names.
Thus the names of each intersection reflect the road type of that intersection, sometimes resulting in (up to) four identical names.


The overall name of the crossroad itself, tries to reflect the nature of it's makeup thus
The overall name of the crossroad itself, tries to reflect the nature of it is makeup thus
kr_asfaltka_asfaltka_t: an bitumen T_Junction
* {{hl|kr_asfaltka_asfaltka_t}}: an bitumen T_Junction
kr_silince_x_cesta: a crossroad of paved and dirt roads.
* {{hl|kr_silince_x_cesta}}: a crossroad of paved and dirt roads.
 
=== Elevation ===


===Elevation===
<syntaxhighlight lang="C#">
Elevation
Elevation
{
{
    XYPair   TerrainSize; // 256 x 256 eg
XYPair TerrainSize; // 256 x 256 eg
    float   Heights[TerrainSize];
float Heights[TerrainSize];
    float   BlueEdgeTerrainHeights[NoOfBlueFloats] ; //Always zero values  
float BlueEdgeTerrainHeights[NoOfBlueFloats]; // Always zero values
    // NoOfBlueFloats = (TerrainSize_Y * TerrainSize_X)/16;
// NoOfBlueFloats = (TerrainSize_Y * TerrainSize_X) / 16;
    ulong   Always0;
ulong Always0;
}
}
</syntaxhighlight>


===Object===
=== Object ===
<code><nowiki>
  Object
  {
      ShortBool IsPresent;
      if (IsPresent)
      {
        ShortBool Moveable;              // always 0
        ulong    ObjectID;              // See Below
        float    TransformColumn[3][4]; // See Generic FileFormat Data Types]] in COLUMN format
        double    ObjectRelativeSize;    // decimal percentage
        String    InstanceName;          // "" mostly. "minimalStrelPos" eg for artifical objects
        float    RelativeSurfaceElevation;
        RGBA      OutlineColour;
        RGBA      ObjectColour; 
        ulong    ModelID;              // See below
      };
  };
</nowiki></code>


*TransformColumn
<syntaxhighlight lang="C#">
Object
{
ShortBool IsPresent;
if (IsPresent)
{
ShortBool Moveable; // always 0
ulong ObjectID; // See Below
TransformMatrix ColumnFormat;
 
double ObjectRelativeSize; // decimal percentage
String InstanceName; // "" mostly. "minimalStrelPos" eg for artifical objects
float RelativeSurfaceElevation;
RGBA OutlineColour;
RGBA ObjectColour;
ulong ModelID; // See below
};
};
</syntaxhighlight>
 
==== TransformMatrix ====
Note that a '''pew''' TransformMatrix is the only instance in the entire repertoire of bis file formats where the transform is specified in columns.
All other TransformMatrices of BI (notably models) are in Row format.
It makes diddly squat difference to the '''values''' in the matrix, only the positions of those values are different.


The XYZ positional component is the absolute position. If a relative elevation has been specified in the pew, that value has been added to the component at this storage time.
The XYZ positional component is the absolute position. If a relative elevation has been specified in the pew, that value has been added to the component at this storage time.


* ObjectID
{{Feature|informative|See {{Link|Generic FileFormat Data Types#TransformMatrices|TransformMatrix}}.}}


Every object entry has a zero-based, linear sequential ObjectID. ObjectID is unique for every object and is the value displayed on a map for all models placed on it (including roads, grass, etc.). Thus, every tree and every road section has its own unique ObjectID.
==== ObjectID ====
Every object entry has a zero-based, linear sequential ObjectID.
ObjectID is unique for every object and is the value displayed on a map for all models placed on it (including roads, grass, etc.).
Thus, every tree and every road section has its own unique ObjectID.


The first Object in the PEW file is ObjectID==0, the next 1,2,3,4 etc.
The first Object in the PEW file is ObjectID==0, the next 1,2,3,4 etc.


If an object has been deleted, that entry retains its unique object ID, even though the ObjectID is no longer stored. If an object is not present (IsPresent is false), the ObjectID is calculated based on the last used object ID. The next real object (IsPresent is true) will always be the ''N''th ObjectID because the number always increases by the number of object entries, present or not. The reason for this is to maintain consistent IDs for objects so that missions can rely on a bush having the same NearestObject ID as it always had, irrespective of map upgrades.
If an object has been deleted, that entry retains its unique object ID, even though the ObjectID is no longer stored.
If an object is not present (IsPresent is false), the ObjectID is calculated based on the last used object ID.
The next real object (IsPresent is true) will always be the ''N''th ObjectID because the number always increases by the number of object entries, present or not.
The reason for this is to maintain consistent IDs for objects so that missions can rely on a bush having the same NearestObject ID as it always had, irrespective of map upgrades.


When you add a new object, it is thus always is added to end of table with a new object ID. When you remove an object, the object ID remains reserved even though the object no longer exists.
When you add a new object, it is thus always is added to end of table with a new object ID.
When you remove an object, the object ID remains reserved even though the object no longer exists.


This mechanism works well within the ArmA engine, but fails to help at all for conversion of OFP islands unless you methodically and manually enter all of the entries in the correct order. With upwards of 100,000 entries per island, this is practically impossible.
This mechanism works well within the ArmA engine, but fails to help at all for conversion of OFP islands unless you methodically and manually enter all of the entries in the correct order.
With upwards of 100,000 entries per island, this is practically impossible.


* ModelID
==== ModelID ====
Note that this is the unique ID of the ModelID in the object Template. It is not an index into the template structures.
Unusual, and slow as a result.<!-- This should be explained in more detail. Why is it unusual? Why is it slow? -->


Note that this is the unique ID of the ModelID in the object Template.  It is not an index into the template structures.  Unusual, and slow as a result.  <!-- This should be explained in more detail.  Why is it unusual?  Why is it slow? -->
=== Layer ===


===Layer===
<syntaxhighlight lang="C#">
Layer
{
ulong SizeType; // 0..2 - see below
String Name; // "Base"
shortBool DefaultIndicator; // 0 ... 1


    Layer
if (DefaultIndicator == 0)
    {
{
        ulong          SizeType;        //0..2 //see below
ulong SurfaceTable[TableSize.x*y];
        String          Name;            //"Base"
ulong TextureTable[TableSize.x*y];
        shortBool      DefaultIndicator; // 0 ... 1
byte UnknownTable[(TableSize.x*y/4)];
        if (DefaultIndicator == 0)
ushort UnknownShort;
        {
};
            ulong SurfaceTable[TableSize.x*y];
            ulong TextureTable[TableSize.x*y];
            byte   UnknownTable[(TableSize.x*y/4)];
            ushort UnknownShort;
        };
        if (DefaultIndicator == 1)
        {
            ulong          NoOfTerrainMaterials;
            TerrainMaterial[NoOfTerrainMaterials]
            {
                ulong  BitFlags;    // 1 = label, 0x40 = rvmatfile,,,,
                String MaterialName; // "---sea---","Layers\P_000-000_L00.rvmat"
                ulong  TypeID;      // 0..3
            };
            ulong RvmatIndexTable[TableSize.x*y];
        };
    };


TableSize = Elevations.TerrainSize>> SizeType;
if (DefaultIndicator == 1)
{
ulong NoOfTerrainMaterials;
TerrainMaterial[NoOfTerrainMaterials]
{
ulong BitFlags; // 1 = label, 0x40 = rvmatfile,,,,
String MaterialName; // "---sea---", "Layers\P_000-000_L00.rvmat"
ulong TypeID; // 0..3
};
ulong RvmatIndexTable[TableSize.x*y];
};
};


====RvmatIndexTable====
TableSize = Elevations.TerrainSize >> SizeType;
</syntaxhighlight>


The texture table contains 1-based indexes into the rvmats. This is a traditional bis way-of-doing-things in that the 0th 'rvmat' is, by default 'sea' texture and does not have an associated file, nor, is it referenced in this table.
==== RvmatIndexTable ====
The texture table contains 1-based indexes into the rvmats.
This is a traditional bis way-of-doing-things in that the 0th 'rvmat' is, by default 'sea' texture and does not have an associated file, nor is it referenced in this table.


The organisation of 'cells' differs from it's equivalent wrp. They are the reversed, mirror image of each other. Thus for a pew file with a 'poetic' 4x4 island:
The organisation of 'cells' differs from its equivalent wrp. They are the reversed, mirror image of each other. Thus for a pew file with a 'poetic' 4x4 island:


  PEW  
{|
  D 9 5 1
|+ PEW vs WRP format
  E A 6 2
|-
  F B 7 3
|
10 C 8 4


vs WRP
{| class="wikitable"
! colspan="4" | PEW
|-
| C || 8 || 4 || '''0'''
|-
| D || 9 || 5 || 1
|-
| E || A || 6 || 2
|-
| F || B || 7 || 3
|}
 
|
 
{| class="wikitable"
! colspan="4" | WRP
|-
| C || D || E || F
|-
| 8 || 9 || A || B
|-
| 4 || 5 || 6 || 7
|-
| '''0''' || 1 || 2 || 3
|}
 
|}


D E F 10
9 A B C
5 6 7 8
1 2 3 4


Unlike a wrp there is no Texture Size (256x256) eg. It is a derived value from the Elevations size (ergo the TerrainSize) (1024x1024 eg)
Unlike a wrp there is no Texture Size (256x256) eg. It is a derived value from the Elevations size (ergo the TerrainSize) (1024x1024 eg)
The size of this table, the 'Texture Size' is defined as a ratio via LayerSizeType.
The size of this table, the 'Texture Size' is defined as a ratio via LayerSizeType.


*0 same
* 0 same
*1 half
* 1 half
*2 quarter
* 2 quarter


====Rvmat Conventions====
==== Rvmat Conventions ====


Naming of rvmat files (generally) follows a simple convention largely because the files are auto_generated when importing the satmask.
Naming of rvmat files (generally) follows a simple convention largely because the files are auto_generated when importing the satmask.
Line 452: Line 622:




PxxPyy
=== RoadNetworks ===
A 'RoadNetwork' essentially is comprised of a 'KeyPart' and 1-4 Directions. A Direction comprsises 0 to 'N' number of 'Parts'.
When the Visitor3 user starts placing a 'RoadNetwork' on a map they are 'forced' to place a 'KeyPart'. Each 'RoadNetwork' has at least 1 'Direction' defined. A 'Direction' may have zero 'RoadParts' placed on the map.
<syntaxhighlight lang="C#">
RoadNetworks
{
shortBool NetworkDefined;
if (NetworkDefined)
{
shortBool Always0x01;
shortBool Movable;
ulong NetworkID;
float Network_XZY[3];
float Direction;
shortBool KeyPartDefined; // Should always be 1=Yes 'cause you cant start a road without placing a KeyPart
float KeyPart_XZY[3];
float KeyPart_Direction;
ulong KeyPart_TemplateObjectID;
KeyPartTypeEnum KeyPart_Type;
ushort KeyPart_FamilyType;
String KeyPart_RoadNetworkTemplateName;
String KeyPart_ModelName;
RGBAColor KeyPart_Color;
shortBool DirectionsDefined; // Should always be 0x0100=yes because every RoadNetwork has at least 1 direction.
ulong NoOfDirections;
ulong Direction_A_Something; //Always 0x0000 0000
ulong Direction_B_Something; //Always 0x0000 0000
ulong Direction_C_Something; //Always 0x0000 0000
ulong Direction_D_Something; //Always 0x0000 0000
DirectionHeader DirectionHeaders[NoOfDirections];
byte Unknown[92];
ulong NoOfDirections;
Direction Directions[NoOfDirections];
}
}
</syntaxhighlight>


==== DirectionHeader ====
<syntaxhighlight lang="C#">
DirectionHeader
{
String RoadNetworkTemplateName;
float DirectionOffsetXZY[3];
float DirectionOffsetDirection; // 180.0 degrees.
}
</syntaxhighlight>


PxxPyy
==== Direction ====
<syntaxhighlight lang="C#">
Direction
{
ulong NoOfParts;
RoadPart RoadParts[NoOfParts];
String RoadNetworkTemplateName;
float DirectionOffsetXZY[3];
float DirectionOffsetDirection; // 180.0 degrees.
RGBAColor KeyPartColor;
RGBAColor NormalPartColor;
shortBool FilledLine;
double MaxAngle;
double MaxBankAngle;
}
</syntaxhighlight>
 
===== RoadPart =====
<syntaxhighlight lang="C#">
RoadPart
{
shortBool Defined;
shortBool Enabled; // Possibly incorrect.
float RoadPartXZY[3];
float RoadPartDirection;
ulong RoadPart_ObjectTemplateID;
ushort PartTypeUIListboxIndex;
String ModelName;
byte Unknown[102];
}
</syntaxhighlight>


=== KeyPoint ===


===RoadBlock===
<syntaxhighlight lang="C#">
RoadBlock
KeyPoint
{
{
  ShortBool IsPresent;  
ShortBool IsPresent;
  if IsPresent
if (IsPresent)
  {
{
  ShortBool Always1;  
ShortBool Always0;
  ulong    Unknown[12];  
String ClassName; // "Noe_Lany"
            /* typical data
RGBA AreaColor,OutlineColor;
            ** 00 00 00 00  00 00 00 F0
ulong DisplayStyle; // 0 solid
            ** 2C 46 00 98  23 46 C6 6F
// 1..6 hatch-horz,vert,cross,skew right,skew left,skewcross
            ** C6 42 0E 01  00 00 01 00
// 7 standard
            ** 00 F0 2C 46  00 98 23 46
ShortBool Visible;
            ** C6 6F C6 42  0E 01 00 00
float Offset[2]; // map relative
            ** 4B 00 00 00  00 00 00 00
float Size[2]; // 250 x 250.0 eg (width and height)
            */
ulong ID; // 0,1,2,3,4,5,6....
  ushort    Type;             // 0,1,2,3
BisString TownName; // "Lipany", "Hill"
  String    RoadFamilyName;   //"hlavni silnice"
BisString LocaleType; // "NameCity" NameCityCapital, NameVillage, NameLocal, VegetationBroadLeaf, Hill, Marine, ViewPoint
  String    RoadModelName;   //"kr_silnice_cesta_t"
BisString ClassText; // "canOcclude=1; BumbleButt='FlowControl2"; ++=)#4555Semi"
  RGBA      color;           
}
  ShortBool Always1;
}
  ulong    Count;
</syntaxhighlight>
  FamilyList FamilyLists[Count];
  ulong    Unknown[27];
            /* typical data
            ** FA D4 30 BF  94 58 08 3D  00 00 C8 C0  00 00 60 C0
            ** 00 00 00 00  00 00 48 C1  00 00 60 40  00 00 00 00
            ** 00 00 48 C1  00 00 60 C0  00 00 00 00  00 00 00 00
            ** 00 00 60 40  00 00 00 00  00 00 00 00  00 00 C8 C0
            ** 00 00 00 00  00 00 30 C0  00 00 C8 C0  00 00 00 00
            ** 00 00 1C C1  04 01 00 00  00 00 00 00  00 00 00 00
            ** 09 00 00 00  0B 80 00 00  04 00 00 00
            */
  ulong    Count;  
  ModelList ModelLists[Count];
  }
}


{| class="wikitable"
There is '''always''' a classname associated with this Keypoint,
|-
* Forest_Owls
! colspan="2"| Type
* Abel_LaTrinite
! Description
* MyPinkElephant
|-
| 0 || Road Ending with FamilyName and its ModelName_konec
|-
| 1 || TJunction ModelName Only
|-
| 2 || Road similar to type 0
|-
| 3 || Xroad with ModelName Only
|-
|} <!-- Documentation is like air; when it's bad, it's better than nothing... -->


====FamilyList====
and in most cases a text name that is 'seen' on the map
FamilyList
{
  ulong  Unknown[4];// Typically 00 00 C8 C0 00 00 C8 C0 00 00 00 00 0E 01 00 00
  String Name;    // "silnice hlavni silnic\0"
}


This struct is principally used for XRoads and T_Junctions. It typically lists the order of all RoadFamilyName values required.
  "Le Refuge Des Chasseurs"


====ModelList====
Viewpoint and Marine types normally don't have names associated with them. There is no "place" in the sea.
ModelList
{
  ulong      Count;          //for example, 15
  BlockModel BlockModel[Count];
  String    FamilyName;      //"silnice hlavni silnic\0"
  ulong      Unknown[4];      //Typically 00 00 C8 C0 00 00 C8 C0 00 00 00 00 0E 01 00 00
  RGBA      color[2];       
  ShortBool  Always01;        //01
  ulong      buf2[4];        // Typically 00 00 00 00 00 00 39 40 00 00 00 00 00 00 24 40
}


=====BlockModel=====
Each of these Keypoints have a Locale '''Type'''. Some of which are:
    BlockModel
* NameCity
    {
* NameCityCapital
        ulong   ModelFlag;  // 0x000001 ... 0x00010001
* NameVillage
        XYZTriplet Position;      // Model coordinates
* VegetationBroadLeaf (Forest)
        float   ModelDirection;
        ulong   ObjectID;
        ushort    Type;              //0,1,2,3
        String    ModelName;          //"silnice10 100\0"
        ulong      unknown[25];
          /*typical data
          **00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
          **C4 76 C2 3F 0E EB 8A C1 00 00 00 00 BE 00 00 00
          **CC ED 26 BE CA 0F 12 40 56 30 28 3F 00 00 00 00
          **18 CA 04 C1 48 8B 3D C0 00 00 00 00 2D 3D 91 C1
          **06 01 C0 40 00 00 00 00 EE 98 84 C1 99 99 91 C0
          **00 00 00 00 64 4A 5F 35 99 99 91 40 00 00 00 00
          **64 4A 5F B5 01 00
          */
        ShortBool  ok; // 0 or 1
}


===(Alt)NamedZone===
{{Feature|informative|See [[Location]].}}


NamedZone
=== Background ===
{
  ShortBool IsPresent;
  if IsPresent
  {
  ShortBool Movable;        // almost Always0;
  BisString Name1;          //"Les_new"
  ulong    AreaColor,OutlineColor;
  ulong    DisplayStyle;
  ulong    nPoints;
  PointsRectangle
  {
      float TopLeft.xy;
      float BottomRight.xy;
  }[nPoints/4];
            /* Typical Data
            **00 00 61 45  00 78 1B 46  00 20 64 45  00 20 19 46
            **00 20 64 45  00 78 1B 46  00 40 67 45  00 58 18 46
            **00 40 67 45  00 78 1B 46  00 60 6A 45  00 58 18 46
            **00 60 6A 45  00 78 1B 46  00 80 6D 45  00 90 17 46
            **00 80 6D 45  00 B0 1A 46  00 A0 70 45  00 C8 16 46
            **00 A0 70 45  00 E8 19 46  00 C0 73 45  00 00 16 46
            */
  ulong    ID;            // 0,1,2,3,4....
  if POSEW60
  {
    LongBool  Visible; // almost always true
  }
  else
  {
    BisString Name2;          //Les_new Name2==Name1
  }
  }
};


altnamed zone and named zone seem to be mutually exclusive
<syntaxhighlight lang="C#">
Background // this structure has not been seen
{
String BackgroundFilename; // "sat_lco.bmp"
String BackgroundName; // "overlay1"
float OffsetXY[2];
float SizeXY[2];
ulong Transparency;
shortBool Visible; // or ulong?
}
</syntaxhighlight>


===KeyPoint===
=== Selection ===
KeyPoint
{
  LongBool  Always1;
  String    ClassName;  //"Noe_Lany"
  RGBA      AreaColor,OutlineColor;
  ulong    DisplayStyle;
  ShortBool Visible;
  float    Offset[2];  // map relative
  float    Size[2];    // 250 x 250.0 eg (width and height)
  ulong    ID;        // 0,1,2,3,4,5,6....
  BisString TownName;  //"Lipany", "Hill"
  BisString LocaleType; //"NameCity" NameCityCapital, NameVillage, NameLocal, VegetationBroadLeaf,Hill,Marine,ViewPoint
  BisString ClassText;  // "canOcclude=1; BumbleButt='FlowControl2"; ++=)#4555Semi"
}


Each of these locales have a LocaleType. Some of which are:
<syntaxhighlight lang="C#">
*NameCity
Selection
*NameCityCapital
{
*NameVillage
ushort strlen;
*VegetationBroadLeaf (Forest)
char[] SelectionName[strlen]; // NOT null terminated
ulong nObjects;
SelectionObject SelectionObjects[nObjects]
}
</syntaxhighlight>


==== SelectionObject ====
<syntaxhighlight lang="C#">
SelectionObject
{
ulong ObjectInstanceID;
byte Unknown[8];
}
</syntaxhighlight>


There is always a classname associated with this locale,
== Enums ==
*Forest_Owls
*Abel_LaTrinite


and in most cases a text name


"La Refuge Des Chassuers"
=== ObjectTemplateTypeEnum ===


Viewpoint and Marine types do not have names associated with them.  There is no "place" in the sea.
<syntaxhighlight lang="C#">
enum ObjectTemplateTypeEnum
{
Undefined = 0,
Natural = 1,
Artificial = 2,
Road = 3,
Forest = 4,
Road2 = 5
}
</syntaxhighlight>


===Background===
=== MarkerTypeEnum ===


  Background // this structure has not been seen
<syntaxhighlight lang="C#">
  {
enum MarkerTypeEnum
      String BackgroundFilename;//"sat_lco.bmp"
{
      String BackgroundName; //"overlay1"
Rectangular = 0,
      float  OffsetXY[2];
Elliptical = 1
      float  SizeXY[2];
}
      ulong  Transparency;
</syntaxhighlight>
      shortBool Visible; // or ulong?
  }


=== StraightPartEnum ===


===Selection===
<syntaxhighlight lang="C#">
Selection
enum StraightPartEnum : ushort
{
{
  ushort      strlen;
SixBy25, // 6,25m
  char[]      SelectionName[strlen];  // NOT null terminated
TwelveBy5, // 12,5m
  ulong        nSubSelections;
TwentyFive // 25m
  SubSelection SubSelections[nSubSelections]
}
====SubSelection====
SubSelection
{
  ulong ObjectId;
  byte  Type;
  byte  Unknown[7];
}
}
</syntaxhighlight>
=== CurvePartEnum ===


== Enums ==
<syntaxhighlight lang="C#">
enum CurvePartEnum : ushort
{
Radius25m,
Radius50m,
Radius75m,
Radius100m
}
</syntaxhighlight>


=== SpecialPartEnum ===


=== ObjectClassEnum ===
<syntaxhighlight lang="C#">
enum SpecialPartEnum : ushort
{
SixBy25, // 6,25m
TwelveBy5, // 12,5m
TwentyFive // 25m
}
</syntaxhighlight>


<code><nowiki>
=== KeyPartTypeEnum ===
  enum ObjectClassEnum
  {
    Natural = 1,
    Artificial = 2,
    Road = 3,
    Forest = 4,
    ArtificialAndDefinedInRoad =
  }
</nowiki></code>


=== MarkerTypeEnum ===
<syntaxhighlight lang="C#">
enum KeyPartTypeEnum
{
Crossroad,
Straight,
Special,
Terminator
}
</syntaxhighlight>


<code><nowiki>
  enum MarkerTypeEnum
  {
    Rectangular = 0,
    Elliptical = 1
  }
</nowiki></code>


[[Category:BIS_File_Formats]]
[[Category:BIS File Formats]]

Latest revision as of 17:24, 4 January 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.

PEW files are Visitor's project files. Visitor is Bohemia Interactive's tool for creating Islands.

Visitor is a GUI tool interface that interacts with Bulldozer, an in-built 'world' viewer inside any Armed Assault engine.

The contents of the PEW project file are not directly related to the ultimate output, a WRP file. However, that data contains all similar elements, such as road networks, elevations, cell matrices, models (P3D files) and textures (RVMAT files).

Exporting a PEW file into WRP format involves the use of Bulldozer, since it is Bulldozer that decides how it wants that data presented rather than anything Visitor might like to decide. It is Bulldozer that determines the format and version of the resulting WRP file (in 8WVR format), so the WRP version is based on the version of the Real Virtuality engine used to create it. This is not the same thing as saying the VERSION of the engine. It is the engine, that decides, the VERSION of wrp it needs to generate.

Furthermore, the resulting Wrp file is (for want of a better expression) 'unbinarised' 8WVR format. It is nothing more or less, than a (modified) copy of texture, elevations and models. Period. Roadnetworks and other ancilliary data is only processed into a 'binarised' OPRW format wrp, using Bi's binarizer tool.

Note that it is possible to generate 8WVR format without involving bulldozer (or arma) using [party tools (dead link)].


While there have been several PEW versions, the ones listed here are:

  • POSEW59
  • POSEW60

There are only a few subtle differences to their makeup.


Legend

See Generic FileFormat Data Types.


File Format

This file format is principally used with Armed Assault v1.09 and later, with the ArmA Tools Suite final release (v1.14).
POSEW59
POSEW60
{
	PoseHeader				Header;
	ulong					nOFPTextures;			// none in Arma
	OFPTexture				OFPTextures[nOFPTextures];
	ulong					nObjectTemplates;
	ObjectTemplate			ObjectTemplates[nObjectTemplates];
	shortBool				NoOfpTerrains;
	if (!NoOfpTerrains)
	{
		ulong				nOFPTerrains;			// none in Arma
		OFPTerrain			OFPTerrains[nOFPTerrains];
	}
	shortBool				NoOFPForests;			// none in Arma
	if (!NoOFPForests)
	{
		ulong				nOFPForests;
		OFPForest			OFPForests[nOFPForests];
	}
	RoadNetworkTemplate		RoadNetworkTemplates[...];
	Elevation				Elevation[...];
	ulong					NoOfObjects;
	Object					Objects[NoOfObjects];

	ulong					NoOfLayers;
	String					CurrentLayerName;		// "Base"
	Layer					Layers[NoOfLayers] ;

	ulong					nNamedZones;// almost never present on pose60
	NamedZone				NamedZones[nNamedZones];

	ulong					nRoadNetworks;
	if (nRoadNetworks > 0)
		RoadNetwork			RoadNetworks[nRoadNetworks];

	ulong					nKeyPoints;
	KeyPoint				KeyPoints[nKeyPoints];
	ulong					NoOfBackgrounds;
	Background				Backgrounds[NoOfBackgrounds]; // not checked for 59
	ulong					TotalSizeOfSelections; // from here, to end of file
	ulong					nSelections;
	Selection				Selections[nSelections];
}

PoseHeader

Header
{
	char	Signature[7];		// "POSEW59" or "POSEW60" note: NOT null terminated
	ulong	Length;				// of PEW file;
	ulong	UnknownLong;		// typically 0
	String	IslandRvMatPath;	// "SomePboPrefix\SomeIsland\data\0" see below
	String	IslandP3dPath;		// "" (objects)
	float	TerrainGridSize;	// 10.0 metres
	float	SegmentSize;		// 400.0 (==SegmentSize - SegmentOverlap)
	String	IslandClassname;	// ""
};

Texture And Terrain Sizes

  • Pew files deal with terrain. There is no 'texture' size as such. Therefore the gridsize specified in the header pertains to terrain cells.
  • In contrast, the gridsize specified in a WRP pertains to TEXTURE(rvmat) cells.

"Texture", 'Material', 'Surface', 'Layer' are synonomous to rvmat files. They are the island's unique surface as generated by importing from a sat mask image. There can be multipler layers of rvmat files.

Terrain, are the cell grids of the map and as often as not specified at a different (larger) dimension.

Unlike Wrp files, Textures and Terrain sizes are not declared in a pew directly. At least, not, in the header.

The Terrain (Map) Size is declared in the elevations structure.

TextureSizeS (plural) are derived, not declared, in each surface 'Layer' of pew. Since, ultimately, each layer must 'fit' onto the map. Each layer contains a shift value of how much SMALLER the surface is, relative to the map. For OFP, and OFP converted-to-arma, islands, this is 0 (there is no difference betweem a 256x256 cell Terrain and a 256x256 cell Texture.

For Arma, it is *generally* x 4 (shift value=2).

TerrainGridSize

A wrp file's GridSize is the OPPOSITE of a PewFile's GridSize.

In a wrp, it defines the size (in meters) of each cell of the TEXTURE (rvmats).

In a pew, there is no direct TEXTURE dimension since there can be multiple layers, each with different (derived) dimensions.

So this value, in a pew, is the TERRAIN dimension.


IslandRvMatPath

RVMAT file references in the Layers structure are listed as relative addresses to the IslandRvMatPath. This is in contradistinction to the general Bis way-of-doing-things where all references are hard references.

Traditionally, an RVMAT(Island) data path is declared as "Layers\some.rvmat". It is expected, therefore, that you do indeed have a "P:\SomePboPrefix\SomeIsland\...\Layers" folder. Put another way, the prefix of the PBO must be "SomePboPrefix\SomeIsland\...".

The SubFolder 'Layers' is hard wired by Visitor. It is generated automatically when importing a satmask image. Thus, all relative reverences to the rvmats that Visitor produces, are prefaced by 'Layers\'.

Using 3rd party tools, you can, should you wish to, alter this prefixing and location of the rvmats to anywhere at all, including no path at all (Visitor, the engine, and the binarizer don't actually care). The purpose in doing so is somewhat moot, since, unlike p3d's, rvmat's for an island are unique to an island. The chances or need of referencing them by something else is zilch. Hence, unlike p3d's, they may just as well stay in the wrp's pbo. Point being, they don't have to.

IslandObjectPath

IslandObjectPath uses the same mechanics as above. However, since P3D files are almost inevitable declared from multiple locations (any PBO, including the base 'CA' PBO included in the game) its use is moot. Be that as it may, the mechanism exists and works, identically to IslandRvMatPath.


PEW files are not known to contain anything in IslandObjectPath or IslandClassname.

OFPTexture

OFPTexture
{
	ulong		TextureID;
	String		TextureFileName;	// "snih3.paa"
	String		TextureName;		// "snih3"
	String		RvmatName;			// "snih3.rvmat"
	byte		UnknownBytes[14];	// (typically 0)
	RGBAColor	Colour;
}

ObjectTemplate

ObjectTemplate
{
	String		ModelFilename;	// "SomePrefixRoot\data\jablon.p3d\0"
	String		ModelName;		// "jablon"
	ulong		ObjectType;		// 0..5 (so far...)
								// 0 Undefined - This type should never be encountered.
								// 1 Natural
								// 2 Artificial
								// 3 Road (RoadFlag will be true)
								// 4 Forest
								// 5 Road2 (RoadFlag will be false)
	RGBAColor	OutlineColour;
	RGBAColor	ObjectColour;
	double		GeometryBounds[2];				// 50.0
	ulong		ModelID;						// uniqueID, used by objects to lookup this model(p3d)
	XYZTriplet	GeometryAutocenterPos;
	double		ResolutionBounds[2];			// 50.0
	XYZTriplet	ResolutionAutoCenterPos;
	shortBool	Generally0x01;
	shortBool	RandomScaleFlag;
	double		RandomScaleMinMax[2];			// 50.0
	shortBool	RandomRotateFlag;
	double		RandomRotateMinMax[2];			// 20.0
	shortBool	RandomOrientationFlag;
	double		RanmdomOrientationMinMax[2];	// 180.0
	shortBool	RoadFlag;
	if (RoadFlag)
	{
		TransformMatrix RoadNamedSelections;	// (LB, PB, LE, PE)
		TransformMatrix XRoadNamedSelections;	// (LD, LH, PD, PH)
	};
	ulong		nNamedVectors;					// Usually 0 (zero)
	NamedVector	NamedVectors[nNamedVectors];
	ulong		MarkerType;						// Rectangular = 0, Elliptical = 1
}

As opposed to layers (material RVMAT surfaces), 'objects' are instances of models placed onto the map. Irrespective of the number of objects there is only one reference to the model used, which is then referenced as often as needed.

ModelFilename, ModelName, and ModelID are unique unduplicated entries.

The ModelID is not zero based; its value is incremental according to the number of times any model has been added while editing, even if previous models have been deleted; model IDs do not rearrange themselves and deleted IDs are not recycled for re-use. The ObjectID illustrated on maps is, in contrast, the unique InstanceID of each object in the objects structure below. 'Road2' type cannot be defined with Visitor3 Personal Edition. It's a type specific to VBS2 V3 edition.

NamedVector

NamedVector
{
	String		Name;		// "pohrada"
	LongBool	Unknown;
	ulong		nTriplets; // generally 2 sometimes 1
	XYZTriplet	StartEndPos[nTriplets];
}

As of v60 a rarely used sub structure with ObjTemplates.

OFPTerrain

OFPTerrain
{
	String		TerrainName;
	byte		UnknownBytes[11];
	ulong		nSurfaces;
	OFPSurface	OFPSurfaces[nSurfaces];
}

OFPSurface

OFPSurface
{
	String	SurfaceName;
	float	Surfacefloat[4];
	byte	UnknownBytes[16];
}

OFPForest

OFPForest
{
	String		ForestName;
	RGBAColor	OutlineColour;
	RGBAColor	ObjectColour;
	ulong		SquareFillModelID;
	ulong		SquareModelID;
	ulong		TriangleModelID;
	ulong		Unknown1; // (typically 0)
	ulong		Unknown2; // (typically 0)
}

NamedZone

NamedZone
{
	ushort		IsPresent;
	ushort		Moveable;
	String		Name; // Les_new
	RGBAColor	AreaColor;
	RGBAColor	OutlineColor;
	ulong		DisplayStyle;
	ulong		nFloats;
	float		Floats[nFloats];
	ulong		ID;
	String		Name2;
}

AltNamedZone

AltNamedZone
{
	ushort		IsPresent;
	ushort		Moveable;
	String		Name; // Les_new
	RGBAColor	AreaColor;
	RGBAColor	OutlineColor;
	ulong		DisplayStyle;
	ulong		nFloats;
	float		Floats[nFloats];
	ulong		ID;
	ulong		Visible;
}

RoadNetworkTemplates

RoadNetworkTemplates
{
	shortBool	RoadNetworkTemplatesDefined;
	if (!RoadNetworkTemplatesDefined)
	{
		//RoadNetworkTemplates
		ulong	NoOfRoadNetworkTemplates;
		if (NoOfRoadNetworkTemplates > 0)
		{
			RoadNetTemplate RoadNetTemplates[NoOfRoadNetworkTemplates];
		}

		//CrossroadTemplates
		ulong	NoOfCrossroadTemplates;
		if (NoOfCrossroadTemplates > 0)
		{
			CrossroadTemplate CrossroadTemplates[NoOfCrossroadTemplates];
		}
	}
}

RoadNetTemplate

RoadNetTemplate
{
	String		TemplateName;
	RGBAColor	KeyPartsColour;
	RGBAColor	NormalPartsColour;
	shortBool	FilledLine;
	double		MaxAngle;
	double		MaxBankAngle;

	ulong		NoOfStraightParts;
	if (NoOfStraightParts > 0)
		StraightPart StraightParts[NoOfStraightParts];

	ulong		NoOfCurveParts;
	if (NoOfCurveParts > 0)
		CurvePart CurveParts[NoOfCurveParts];

	ulong		NoOfSpecialParts;
	if (NoOfSpecialParts > 0)
		SpecialPart SpecialParts[NoOfSpecialParts];

	ulong		NoOfTerminatorParts;
	if (NoOfTerminatorParts > 0)
		TerminatorPart TerminatorParts[NoOfTerminatorParts];
}
StraightPart
StraightPart
{
	String				StraightPartName;
	ulong				ObjectTemplateID;
	StraightPartEnum	StraightPartType;
	shortBool			CanChangeBankAngle;
}
CurvePart
CurvePart
{
String			CurvePartName;
ulong			ObjectTemplateID;
CurvePartEnum	CurvePartType;
}
SpecialPart
SpecialPart
{
	String				SpecialPartName;
	ulong				ObjectTemplateID;
	SpecialPartEnum		SpecialPartType;
}
TerminatorPart
TerminatorPart
{
	String	TerminatorPartName;
	ulong	ObjectTemplateID;
}

CrossroadTemplate

CrossroadTemplate
{
	String				TemplateName;
	CrossroadTypeEnum	Shape;
	RGBAColor			Color;
	shortBool			FilledLine;
	ulong				ObjectTemplateID;
	String				Net_A;
	String				Net_B;
	String				Net_C;
	String				Net_D;
}
MeterType Values
Type Straights Curves
0 6 m 25 m
1 12 m 50 m
2 25 m 75 m
3 100 m

Broadly speaking, there are a few basic road types:

  • asfalt: Bitumen
  • silnice: Paved
  • cesta: Dirt

Each RoadType describes the general characteristics of the corresponding road, and can have multiple curved, straight, special, and termination P3D models associated with it.

Generally speaking, there are:

  • 3 'straight' models, approximately 6, 12, and 25 meters long respectively.
  • 4 'curved' models, approximately 25, 50, 75, and 100 meters long.
  • 1 'termination' type.

The termination type is a road like any other but tends to be a fixed 6 meter fade out of the general road texture.

Although "CrossRoads" could conceivably have any number of intersections, only two types are handled.

  • Type 1: A T_Junction (3 intersections)
  • Type 3: A genuine crossroad (4 way intersection)

For T_Junctions, there is obviously no 4th intersection and this is null filled.

Without taking too literal an interpretation, there are some major types of road.

  • asfaltka: Bitumen (sealed)
  • silnice: Paved
  • cesta: Dirt

Thus the names of each intersection reflect the road type of that intersection, sometimes resulting in (up to) four identical names.

The overall name of the crossroad itself, tries to reflect the nature of it is makeup thus

  • kr_asfaltka_asfaltka_t: an bitumen T_Junction
  • kr_silince_x_cesta: a crossroad of paved and dirt roads.

Elevation

Elevation
{
	XYPair	TerrainSize; // 256 x 256 eg
	float	Heights[TerrainSize];
	float	BlueEdgeTerrainHeights[NoOfBlueFloats]; // Always zero values
	// NoOfBlueFloats = (TerrainSize_Y * TerrainSize_X) / 16;
	ulong	Always0;
}

Object

Object
{
	ShortBool IsPresent;
	if (IsPresent)
	{
		ShortBool			Moveable;				// always 0
		ulong				ObjectID;				// See Below
		TransformMatrix		ColumnFormat;

		double				ObjectRelativeSize;		// decimal percentage
		String				InstanceName;			// "" mostly. "minimalStrelPos" eg for artifical objects
		float				RelativeSurfaceElevation;
		RGBA				OutlineColour;
		RGBA				ObjectColour;
		ulong				ModelID;				// See below
	};
};

TransformMatrix

Note that a pew TransformMatrix is the only instance in the entire repertoire of bis file formats where the transform is specified in columns. All other TransformMatrices of BI (notably models) are in Row format. It makes diddly squat difference to the values in the matrix, only the positions of those values are different.

The XYZ positional component is the absolute position. If a relative elevation has been specified in the pew, that value has been added to the component at this storage time.

ObjectID

Every object entry has a zero-based, linear sequential ObjectID. ObjectID is unique for every object and is the value displayed on a map for all models placed on it (including roads, grass, etc.). Thus, every tree and every road section has its own unique ObjectID.

The first Object in the PEW file is ObjectID==0, the next 1,2,3,4 etc.

If an object has been deleted, that entry retains its unique object ID, even though the ObjectID is no longer stored. If an object is not present (IsPresent is false), the ObjectID is calculated based on the last used object ID. The next real object (IsPresent is true) will always be the Nth ObjectID because the number always increases by the number of object entries, present or not. The reason for this is to maintain consistent IDs for objects so that missions can rely on a bush having the same NearestObject ID as it always had, irrespective of map upgrades.

When you add a new object, it is thus always is added to end of table with a new object ID. When you remove an object, the object ID remains reserved even though the object no longer exists.

This mechanism works well within the ArmA engine, but fails to help at all for conversion of OFP islands unless you methodically and manually enter all of the entries in the correct order. With upwards of 100,000 entries per island, this is practically impossible.

ModelID

Note that this is the unique ID of the ModelID in the object Template. It is not an index into the template structures. Unusual, and slow as a result.

Layer

Layer
{
	ulong		SizeType;			// 0..2 - see below
	String		Name;				// "Base"
	shortBool	DefaultIndicator;	// 0 ... 1

	if (DefaultIndicator == 0)
	{
		ulong	SurfaceTable[TableSize.x*y];
		ulong	TextureTable[TableSize.x*y];
		byte	UnknownTable[(TableSize.x*y/4)];
		ushort	UnknownShort;
	};

	if (DefaultIndicator == 1)
	{
		ulong	NoOfTerrainMaterials;
		TerrainMaterial[NoOfTerrainMaterials]
		{
			ulong	BitFlags;		// 1 = label, 0x40 = rvmatfile,,,,
			String	MaterialName;	// "---sea---", "Layers\P_000-000_L00.rvmat"
			ulong	TypeID;			// 0..3
		};
		ulong	RvmatIndexTable[TableSize.x*y];
	};
};

TableSize = Elevations.TerrainSize >> SizeType;

RvmatIndexTable

The texture table contains 1-based indexes into the rvmats. This is a traditional bis way-of-doing-things in that the 0th 'rvmat' is, by default 'sea' texture and does not have an associated file, nor is it referenced in this table.

The organisation of 'cells' differs from its equivalent wrp. They are the reversed, mirror image of each other. Thus for a pew file with a 'poetic' 4x4 island:

PEW vs WRP format
PEW
C 8 4 0
D 9 5 1
E A 6 2
F B 7 3
WRP
C D E F
8 9 A B
4 5 6 7
0 1 2 3


Unlike a wrp there is no Texture Size (256x256) eg. It is a derived value from the Elevations size (ergo the TerrainSize) (1024x1024 eg) The size of this table, the 'Texture Size' is defined as a ratio via LayerSizeType.

  • 0 same
  • 1 half
  • 2 quarter

Rvmat Conventions

Naming of rvmat files (generally) follows a simple convention largely because the files are auto_generated when importing the satmask. The resolved Texture size (dependent on the pixels and resoltion wanted) are divided into x and y numbered co-ordinates thus

p_(x)00..(x)nn_(y)00..nn_L00..zz

where:

(x) and (y) are the cellgrid position (and not part of the label)

Lzz is the layer

For a mythical single layer island with an 8x8 TEXTURE , files names will range from

p_00_00_L00 to p_07_07_L00


PxxPyy

RoadNetworks

A 'RoadNetwork' essentially is comprised of a 'KeyPart' and 1-4 Directions. A Direction comprsises 0 to 'N' number of 'Parts'. When the Visitor3 user starts placing a 'RoadNetwork' on a map they are 'forced' to place a 'KeyPart'. Each 'RoadNetwork' has at least 1 'Direction' defined. A 'Direction' may have zero 'RoadParts' placed on the map.

RoadNetworks
{
	shortBool				NetworkDefined;
	if (NetworkDefined)
	{
		shortBool			Always0x01;
		shortBool			Movable;
		ulong				NetworkID;
		float				Network_XZY[3];
		float				Direction;
		shortBool			KeyPartDefined;		// Should always be 1=Yes 'cause you cant start a road without placing a KeyPart
		float				KeyPart_XZY[3];
		float				KeyPart_Direction;
		ulong				KeyPart_TemplateObjectID;
		KeyPartTypeEnum		KeyPart_Type;
		ushort				KeyPart_FamilyType;
		String				KeyPart_RoadNetworkTemplateName;
		String				KeyPart_ModelName;
		RGBAColor			KeyPart_Color;
		shortBool			DirectionsDefined;	// Should always be 0x0100=yes because every RoadNetwork has at least 1 direction.
		ulong				NoOfDirections;
		ulong				Direction_A_Something; //Always 0x0000 0000
		ulong				Direction_B_Something; //Always 0x0000 0000
		ulong				Direction_C_Something; //Always 0x0000 0000
		ulong				Direction_D_Something; //Always 0x0000 0000
		DirectionHeader		DirectionHeaders[NoOfDirections];
		byte				Unknown[92];
		ulong				NoOfDirections;
		Direction			Directions[NoOfDirections];
	}
}

DirectionHeader

DirectionHeader
{
	String	RoadNetworkTemplateName;
	float	DirectionOffsetXZY[3];
	float	DirectionOffsetDirection; // 180.0 degrees.
}

Direction

Direction
{
	ulong		NoOfParts;
	RoadPart	RoadParts[NoOfParts];
	String		RoadNetworkTemplateName;
	float		DirectionOffsetXZY[3];
	float		DirectionOffsetDirection; // 180.0 degrees.
	RGBAColor	KeyPartColor;
	RGBAColor	NormalPartColor;
	shortBool	FilledLine;
	double		MaxAngle;
	double		MaxBankAngle;
}
RoadPart
RoadPart
{
	shortBool	Defined;
	shortBool	Enabled; // Possibly incorrect.
	float		RoadPartXZY[3];
	float		RoadPartDirection;
	ulong		RoadPart_ObjectTemplateID;
	ushort		PartTypeUIListboxIndex;
	String		ModelName;
	byte		Unknown[102];
}

KeyPoint

KeyPoint
{
	ShortBool IsPresent;
	if (IsPresent)
	{
		ShortBool	Always0;
		String		ClassName;	// "Noe_Lany"
		RGBA		AreaColor,OutlineColor;
		ulong		DisplayStyle;	// 0 solid
									// 1..6 hatch-horz,vert,cross,skew right,skew left,skewcross
									// 7 standard
		ShortBool	Visible;
		float		Offset[2];	// map relative
		float		Size[2];	// 250 x 250.0 eg (width and height)
		ulong		ID;			// 0,1,2,3,4,5,6....
		BisString	TownName; 	// "Lipany", "Hill"
		BisString	LocaleType;	// "NameCity" NameCityCapital, NameVillage, NameLocal, VegetationBroadLeaf, Hill, Marine, ViewPoint
		BisString	ClassText;	// "canOcclude=1; BumbleButt='FlowControl2"; ++=)#4555Semi"
	}
}

There is always a classname associated with this Keypoint,

  • Forest_Owls
  • Abel_LaTrinite
  • MyPinkElephant

and in most cases a text name that is 'seen' on the map

"Le Refuge Des Chasseurs"

Viewpoint and Marine types normally don't have names associated with them. There is no "place" in the sea.

Each of these Keypoints have a Locale Type. Some of which are:

  • NameCity
  • NameCityCapital
  • NameVillage
  • VegetationBroadLeaf (Forest)

Background

Background // this structure has not been seen
{
	String		BackgroundFilename;	// "sat_lco.bmp"
	String		BackgroundName;		// "overlay1"
	float		OffsetXY[2];
	float		SizeXY[2];
	ulong		Transparency;
	shortBool	Visible;			// or ulong?
}

Selection

Selection
{
	ushort				strlen;
	char[]				SelectionName[strlen]; // NOT null terminated
	ulong				nObjects;
	SelectionObject		SelectionObjects[nObjects]
}

SelectionObject

SelectionObject
{
	ulong	ObjectInstanceID;
	byte	Unknown[8];
}

Enums

ObjectTemplateTypeEnum

enum ObjectTemplateTypeEnum
{
	Undefined = 0,
	Natural = 1,
	Artificial = 2,
	Road = 3,
	Forest = 4,
	Road2 = 5
}

MarkerTypeEnum

enum MarkerTypeEnum
{
	Rectangular = 0,
	Elliptical = 1
}

StraightPartEnum

enum StraightPartEnum : ushort
{
	SixBy25,	// 6,25m
	TwelveBy5,	// 12,5m
	TwentyFive	// 25m
}

CurvePartEnum

enum CurvePartEnum : ushort
{
	Radius25m,
	Radius50m,
	Radius75m,
	Radius100m
}

SpecialPartEnum

enum SpecialPartEnum : ushort
{
	SixBy25,	// 6,25m
	TwelveBy5,	// 12,5m
	TwentyFive	// 25m
}

KeyPartTypeEnum

enum KeyPartTypeEnum
{
	Crossroad,
	Straight,
	Special,
	Terminator
}