P3D File Format - ODOLV4x: Difference between revisions

From Bohemia Interactive Community
Jump to navigation Jump to search
(→‎ODOLv4xLod: noted that LodItems is no longer compressed after v64)
(Replaced content with "This page has been removed to hinder the thieves, lowlife, and parasites reverse engineering p3ds to the detriment of the community.")
Line 1: Line 1:
{{unsupported-doc}}
This page has been removed to hinder the thieves, lowlife, and parasites reverse engineering p3ds to the detriment of the community.
 
== Introduction ==
===Acknowledgements===
This body of work is due to Synide's sweat and tears. To whom, all honour and glory.
Ably assisted by T_D and Mikero that further detailed the data and gave this article a more general and correct structure.
 
===General===
The general format of an ArmA ODOLV4x p3d model is similar to the ODOLV7 format. The '''major''' differences are that ArmA models have
 
*an optional model.cfg, and
*Lods occur in the file from highest to lowest LodType value.
 
==== Legend ====
see [[Generic FileFormat Data Types]]
==== Relative Coordinates ====
 
All coordinates are '''relative''' to [[P3D Model Info|ModelInfo]].CentreOfGravity
 
====File Paths====
 
The PrefixRoot\ folder.
 
Life for modellers would be far less tedious if filenames could also be relative to the p3d they are encountered in. Altering or moving or renaming the pbo (and specifically it's prefix) would not alter the relative location of the paa's it contains.
 
BI choose to use hard-wired Pbo-Prefix-addressing ONLY.
 
All hardwired addressing is relative to a built-in-situ (ie virtual) PrefixRoot\ folder
 
Each and every pbo in Arma contains a unique identity name, a prefix. Irrespective of the name of the pbo, the prefixname is THE name of the pbo from the perspective of the engine. In most cases, the prefixname is, conveniently, the filename. One huge advantage of this mechanism, sorely sorely missed in OFP. is that self-documenting increasing revisions of an addonV123.pbo can be supplied to Arma, with no changes to the mission sqms and other pbos that refer to it.
 
The PrefixRoot\ folder contains the prefix names of all pbos encountered (almost) ANYWHERE.
 
Thus the pbos in the Official Addons folder, the Oem Mods\Addons folder(s), the Dta core and bin pbo's, are all examined for their unique prefix names. These prefix names become the dictionary index of where the pbo really is, AND, what filename it actually is.
 
Thus all filename references in a p3d, *unconditionally* contain a prefixname\someFile\SomeWhere.
 
In most cases they refer to the very same pbo as the containing p3d and a great pity that the extraneous information could not have been removed by (optional) relative addressing as it requires a great deal of fiddling about when modifying models.
 
Note also that there is some inconsistency in filename paths. Most do not have a leading \. Some, require it. Both are indeed \hardwired
 
An Example:
P3dProxyName ="\ca\a10\agm65";
 
The immediate (and unfortunate) impression is that there is an A10 folder inside the official CA.pbo addon.
In fact, the prefix of the A10.pbo = "ca\A10". Thus this reference is to the A10.pbo within which, is a agm65.p3d in it's root folder. (and again, this reference is in fact an extraneous reference to itself since the referring p3d (A10.p3d) is in the same pbo)
===Versions===
This Document covers ODOL versions:
 
====V40 (Arma1) ====
 
* Original Arma1 binarised p3d
 
====VBS2 ====
• [[P3D Model Info|ModelInfo]] now has a 24 byte thermal profile appended
 
====V43 (Arma2a) ====
 
• As per VBS2 plus
 
• An extra byte at end of Skeleton structure: always 0
 
* LZSS compression is still used at this level
 
====V47 (Arma2b LZO) ====
 
As per V43 plus:
 
• all compressed blocks are LZO compressed
 
• CompressedMinMax block is now nMinMax*8 in size
 
• CompressedNormals block is now nNormals*4 in size
 
* LodFrame has 4 extra floats
 
• UVSet structure changed to:
 
LodUV
{
  float  uvScaling[4];
  ulong  nVertices;
  tbool  DefaultFill;
  if (DefaultFill)
  float                        UV;              // default fill for all nVertices
  else
  float                        UV[nVertices];  // potentially compressed
}
 
 
====V48 (Arma2c) ====
 
As per V47 plus:
 
• [[P3D Model Info|ModelInfo]] has a 4 byte appendix
 
Arma2c format is the mainstay of Arma2. Types 43 and 47 are rarely encountered being works-in-progress in the initial release.
 
====V49 (Arrowhead) ====
 
As per V48. No known differences apart from version number
 
====V50 (Arrowhead DLC) ====
 
Introduced in pmc and baf DLC
*additional count after usedbones
lodPointFlags swapped around
 
 
====V52 (TOH) ====
 
intoduced in patch to BAF DLC, used mostly in TOH
*additional float after usedbones in each lod
*ModelInfo.PixelShaders additional 24 bytes
*LODFaceDefaults additional count and float
*LodStageTextures additional bool for type 11's
 
====V56 (Arma3) ====
same as V52 Plus:
 
*thermal profile split into two chunks (same overall size as v52)
*unknown byte indices increased from 12 to 14
*animation class always four floats
*physx data added at end of file
 
====V58 (Arma3) ====
*prefix added to header
*default indicators added at end of headerinfo
====V59 (Arma3) ====
*no genuine changes simply an alteration of the type value from 32 to 64 bits
====V60 (Arma3) ====
*alteration to the physx data at end of file
====V64 (Arma3) ====
*Compressed sections no longer follow the 1024 byte rule, they now have a byte field for compressed or not
====V67 (Arma3) ====
*LOD sections have an added 4 bytes
*LOD struct has additional 4 bytes at the end
====V68 (Arma3) ====
*LOD struct has an additional byte at the end
----
 
== File Format ==
 
ODOLv4x
{
  StandardP3DHeader Header;
  ModelInfo        [[P3D Model Info]];
  Animations        Animations;
  ulong            StartAddressOfLods[Header.NoOfLods];// offset relative to start of file.
  ulong            EndAddressOfLods  [Header.NoOfLods];
  LODFaceDefaults  LODFaceDefaults;
  ODOLv40Lod        ODOLv40Lods[Header.NoOfLods]; 
  if (any arma3 type)
  {
      long          Always0;
      A3_Physx      A3_Physx[...];// optional if not v60
  }
}//EndOfFile
 
== Structures ==
 
=== StandardP3DHeader ===
 
common header structure for all P3D file formats
 
struct
{
  char[4]  Filetype; // "ODOL"
  ulong    Version;  // 40
  if TYPE58 (arma3)
    Asciiz  P3dPrefix;//\a3\data_f\proxies\muzzle_flash\muzzle_flash_rifle_mk20
  endif
  ulong    NoOfLods; // alias NoOfResolutions;
}
 
An '''optional''' prefix declaring the actual location of the p3d was introduced for arma3 (2nd version). Idiotically, it means the p3d cannot be moved out of it's current pbo.
 
The prefix is optional in the sense that it may be null. ("\0")
 
===Animations===
Animations
{
  tbool            AnimsExist;
  if (AnimsExist)
  {
  ulong            nAnimationClasses; // eg NoOfAnimSelections;
  AnimationClass  AnimationClasses[nAnimationClasses];
  long            NoOfResolutions;// is -1 if nAnimationClasses == 0
  Bones2Anims      Bones2Anims[NoOfResolutions];
  Anims2Bones      Anims2Bones[NoOfResolutions];
  //For every bone there is a list of Animations for each resolution
  //And, a reversed table of every Animation gets a Bone.
  //The reversed table optionally appends axis info dependent on the AnimTransformType
  }
}
 
===AnimationClass===
  AnimationClass
  {
    ulong      AnimTransformType;
    asciiz      AnimClassName;  // "RightDoor"
    asciiz  AnimSource;    // "rotor"
    float    MinMaxValue[2];
    float    MinMaxPhase[2];
    ulong  junk; //used to be sourceAddress, no longer, always 953267991
    IF ARMA3
    ulong  Always0; // no idea what this is used for
    ulong  sourceAddress; //this is the actual source address, 0 = clamp, 1 = mirror, 2 = loop
    endif
   
    switch(AnimTransformType)
    case 0://rotaton
    case 1://rotationX
    case 2://rotationY
    case 3://rotationZ
      float angle0;
      float angle1;
      break;
    case 4://translation
    case 5://translationX
    case 6://translationY
    case 7://translationZ
      float offset0;
      float offset1;
      break;
    case 8: //"direct"
      float axisPos[3];
      float axisDir[3];
      float angle; //in radians whereas the model.cfg entry is in degrees
      float axisOffset;
      break;
    case 9: //"hide"
      float hideValue;
      break;
  }
 
 
corresponds to model.cfg
class CfgModels
{
  ....
  class whateverModel: Default
  {
  ...
  class Animations
  {
    class RightDoor //AnimClassName
    {
      type = "translation";//AnimTransformType
      source = "rotor";    //AnimSource
      etc
 
 
 
 
====Bones2Anims====
Bones2Anims
{
  ulong        NoOfBones;
  Bone2AnimClassList  Bone2AnimClassLists[NoOfBones];
}
====Bone2AnimClassList====
Bone2AnimClassList
{
  ulong NoOfAnimClasses;
  ulong AnimationClassIndex[NoOfAnimClasses]; // a (sometimes repeating) list of zero based indexes into above animation classes
}
 
====Anims2Bones====
Anims2Bones
{
  AnimBones AnimBones[Animations.nAnimationClasses];
}
 
====AnimBones====
 
every lod contains an identical list of animation entries that declare the position and axis of the each animation classes
 
AnimBones
{
  long SkeletonBoneNameIndex; // zero based index to the SkeletonBoneName name & parentname
  // equivalent to selection = "LeftDoor"; eg in the model.cfg
  /*
  ** SkeletonBoneNameIndex== -1 when no skeleton bone is for this Anim and (obviously?) no axis information follows.
  */
  if (SkeletonBoneNameIndex!= -1) && (AnimationClass.AnimTransformType != 8 || 9)
  {
  /*
  ** AnimationClass.AnimTransformType 8 (direct) and 9 (hide) never require axis information.
  ** This because the "direct" (type 8) already has axis info in it's AnimationClass structure,
  ** and "hidden" (type 9) clearly doesn't need it.
  */
    XYZTriplet axisPos; //describes the position of the axis used for this anim
    XYZTriplet axisDir;
  }
}
 
===LODFaceDefaults===
  tbool            UseDefault[Header.NoOfLods];
  FaceData
  {
  ulong  HeaderFaceCount;
  ulong  aDefaultLong;    //ffffffff or 6f 7a 80 fa eg
  byte    UnknownByte;      //generally zero
  byte    aFlag;            // zero or one
  bytes  Zeroes[7];
  ======if v52 =========
  ulong  AnotherCount;
  float  AnotherFloat;
  =======endif===========
  }[Number of false UseDefault's];
 
A face data struct only exists for those lods who's UseDefault is zero
 
===ODOLv4xLod===
*Lod layout corresponds to Arma1 (type40). The differences in a2 are in the nitty gritty of the structures themselves. Arrowhead(v50) has some changes.
*TrueArma2 == type 47 or greater (lzo compression)
*Type 43 was a preliminary p3d prior to lzo compression. rarely encountered
 
  ODOLv4xLod
  {
    ulong                        nProxies;
    LodProxy                      LodProxies[nProxies];              // see [[P3D Lod Proxies]]
    ulong                        nLodItems;
    ulong                        LodItems[nLodItems];              // potentially compressed, except for v64 and later
    ulong                        nBoneLinks;
    LodBoneLink                  LodBoneLinks[nBoneLinks];
  =========if v5x==========
    ulong                        LodPointCount;
      if v52
    float                        UnknownV52Float;
    endif
    else
    LodPointFlags                LodPointFlags;                    // Potentially compressed
===========endif==========
    float                        UnknownFloat1;
    float                        UnknownFloat2;
    XYZTriplet                    MinPos;
    XYZTriplet                    MaxPos;
    XYZTriplet                    AutoCenterPos;
    float                        Sphere;                            // same as geo or mem values in modelinfo, if this lod is geo or memlod of course
    ulong                        NoOfTextures;
    asciiz                        LodPaaTextureNames[NoOfTextures];  //"ca\characters\hhl\hhl_01_co.paa"
    ulong                        NoOfMaterials;
    LodMaterial                  LodMaterials[NoOfMaterials];
    LodEdges                      LodEdges;                          // compressed see [[P3D Lod Edges]]
    ulong                        NoOfFaces;
    ulong                        OffsetToSectionsStruct;            // see below
    ushort                        AlwaysZero;
    LodFace                      LodFace[NoOfFaces];                // see [[P3D Lod Faces]]
    ulong                        nSections;
    LodSection                    LodSections[nSections];            // see [[P3D Lod Sections]]
    ulong                        nNamedSelections;
    LodNamedSelection            LodNamedSelections[nNamedSelections]; //See [[P3D Named Selections]] potentially compressed
    ulong                        nTokens;
    NamedProperty                NamedProperties[nTokens];          //See [[Named Properties]]
    ulong                        nFrames;
    LodFrame                      LodFrames[nFrames];                //see [[P3D Lod Frames]]
    ulong                        IconColor;
    ulong                        SelectedColor;
    ulong                        UnknownResidue
    byte                          UnknownArmaByte;
    ulong                        sizeOfVertexTable;                //(including these 4 bytes)
    if (v5x)
    LodPointFlags                LodPointFlags;                    // Potentially compressed
    endif
    VertexTable                  VertexTable;
  }
====VertexTable====
 
all arrays are subject to compression
 
struct
{
    UvSet                        DefaultUVset;
    ulong                        nUVs;                              //in error, V47 sometimes sets nUV's as 0 but means 1
    UvSet                        UVSets[nUVs-1];
    ulong                        NoOfPoints;
    XYZTriplet                    LodPoints[NoOfPoints];
    ulong                        nNormals;
    (A2)LodNormals                LodNormals[nNormals];
    ulong                        nMinMax;
    (A2)LodMinMax                MinMax[nMinMax];                  //optional
    ulong                        nProperties;
    VertProperty                  VertProperties[nProperties];      //optional related to skeleton
    ulong                        Count;
    UnknownVtxStruct              UnknownVtxStructs[Count];          //optional
  }
 
*All non zero counts counts are the same.
*Points,PointFlags, Normals and UV1 arrays are an integral group, they are either all there, or not specified (RacetK.p3d, a [[P3D Lod Frames|FrameTime]] lod has no counts at all)
*UV2,MinMax, VertProperties and Unknown are optional in the sense that their counts can individually be zero, else they are the same as the others
*In Odol7 PointFlags are part of this stucture, in Arma, they are a separated table.
 
====CompressedFill Arrays====
 
LodPointFlags, LodUV's and LodNormals arrays are not only subject to the standard 1024 rule compression, but also have a fill byte.
 
struct
{
  ulong                        Count;
  tbool                        DefaultFill;
  if (DefaultFill)
  type                        Array;          // default fill for all Counts
  else
  type                        Array[Count];  // potentially compressed
}
 
The structure either contains a single set of type variables, or, an array of type variables. If a full array is declared (DefaultFill =false) then that array is subject to the 1024 rule as per normal.
====UVset====
if TrueARMA2
    float                        UVScale[4];
endif
    (A2)LodUV                    LodUV;
 
====LodUV====
CompressedFill type = UVPair // eg float U,V;
====A2LodUV====
CompressedFill type = float // eg float UV;
====LodNormals====
  CompressedFill type = XYZTriplet
====A2LodNormals====
  CompressedFill type = CompressedXYZTriplet
 
=====CompressedXYZTriplet=====
 
contains 3 x 10 bit fields in a 32bit 'integer'
 
code for converting back to a standard XYZTriplet is:
 
void DecodeXYZ(ulong CompressedXYZ, XYZTriplet *triplet)
{
    double scaleFactor = -1.0 /511;
    trp->X=trp->Y=trp->Z=0.0;
    int x=  CompressedXYZ      & 0x3FF;
    int y = (CompressedXYZ>> 10) & 0x3FF;
    int z = (CompressedXYZ>> 20) & 0x3FF;
    if (x > 511) x -= 1024;
    if (y > 511) y -= 1024;
    if (z > 511) z -= 1024;
    if (x) trp->X = (float)(x * scaleFactor);
    if (y) trp->Y = (float)(y * scaleFactor);
    if (x) trp->Z = (float)(z * scaleFactor);
}
 
====LodPointFlags====
CompressedFill type = ulong bits
 
This table is the equivalent of Oxygen's points->properties dialog box. It specifically stores the user values and other flags for that point.
 
In ODOl7 it was part of the vertex table. In Arma, it is separate.
 
See [[P3D Point and Face Flags]]
 
====LodMinMax====
CompressedArray
{
  XYZTriplet    MinMax[Count][2]; // 2 == min vs max
}
 
====A2LodMinMax====
CompressedArray
{
  float        MinMax[Count][2]; // 2 == min vs max
}
 
====VertProperty====
CompressedArray
{
  ulong  index;// seen range 0..4
  ulong  a,b; // definite not floats. might be flags, or indices
}
 
====UnknownVtxStruct====
CompressedArray
{
  ulong  Unknown[2][4]; // seems to be arranged as 2* {flag,0, 0, 0}
}
 
====LodBoneLink====
 
LodBoneLink
{
  ulong NoOfLinks;        //range 0..3
  ulong Value[NoOfLinks];  //the 'Value' seems to reference the 'LodItems' structure, resulting in a circular-reference.
}
 
====LodMaterial====
Basically... A direct replication of the information in the given .rvmat file
 
The stages in the p3d include a default stage and a TI stage that are not normally listed in the rvmat.
:The first stage (in the p3d) is unconditionally the default stage. It is defaulted to empty (RvMatName=""), unless, specified in the rvmat
:The last stage is the TI stage, and is also defaulted empty, unless specified in the rvmat.
::TI Stages were introduced for operation arrowhead. Lod Material Types 9 and 10 (Arma1 and Arma2) do not have a TI stage at all.
Neither of these two special, hidden, stage types use uvsets. The transform matrix for them is defaulted empty (so-called 'TexGen0').
 
When specified in the rvmat (class Stage0 and StageTI respectively), no  class uvTransform is declared for them. It is assumed default empty.
 
In an rvmat, uvTransforms are ordinarily declared within each stage body.
 
In a P3D, identical UVTransforms are declared once, and multiple 'stages' refer to them. There is, always, a default UVSet0 Transform as the 1st entry. (IE some stages dont require uvsets)
 
This P3D style can, if preferred, be used in rvmat syntax as
class TexGenX
{
  .......
};
 
class StageZ
{
  .........
  Texgen=X;
};
 
where X and Z are numbers
 
 
 
  LodMaterial
  {
    asciiz            RvMatName;    // "ca\characters\data\soldier_captive_hhl.rvmat"
    ulong            Type;          // 9 == Arma, 10==VBS2,11==Arrowhead
    D3DCOLORVALUE    Emissive;
    D3DCOLORVALUE    Ambient;
    D3DCOLORVALUE    Diffuse;
    D3DCOLORVALUE    forcedDiffuse;
    D3DCOLORVALUE    Specular;
    D3DCOLORVALUE    Specular2;      //Usually same as Specular
    float            SpecularPower;
    ulong            PixelShaderId;  //See enumPixelShaderId
    ulong            VertexShaderId;  //See enumVertexShaderId
    LongBool          Arma1UnKnownBool;//A2 deprecated, always 1
                                      //A1 mostly 1 otherwise 0
    ulong            Arma1AnIndex;    //A2 deprecated, always 1
                                      //A1 0,1 or 2
    asciiz            BiSurfaceName;  // "ca\data\Penetration\plastic.bisurf"
    LongBool          Arma1Mostly0x01; //A2 deprecated, always 1
                                      //A1 rarely zero
    ulong            RenderFlags;    //Generally 0
    ulong            nTextures;
    ulong            nTransforms;    // always same as nTextures
    LodStageTexture  StageTextures  [nTextures];
    LodStageTransform StageTransforms[nTransforms];
    if type>=10//vbs2/arma2
    LodStageTexture  DummyStageTexture;// see special, additional byte for THIS stagetexture
    endif 
  } 
 
:Each lodmaterial entry contains a default StageTexture and StageTransform as the first entry. It is not shown in the rvmat file and has no PaaTexture
:It is the only entry if a SurfaceName exists.
 
===A3_Physics Type1 (optional)===
 
  {
    A3_stanza A3_stanzas[...]; // optional
    float  aFloat; 
  }
*The type1 structure may not be present at all, or, only contain the single ending float
 
====A3 stanza====
 
{
  //header//////
  long  Xcount,Ycount,Zcount;   
  float  floats[4];
  long  minCount; //Always2;
  long  maxCount; //Always4;
  //////////////
  float  frames[Xcount*Ycount*Zcount][5];
  }
 
A header with no frames is legal, it's XYZcounts (and floats[4]) are zero.
 
A 'stanza' consists of 5 float values. The amount of stanzas (if any) are determined by the 3 counts.
 
The range of each count value varies between 2,3 and 4.
 
 
===A3 Physx type60===
Introduced for format 60
{
  long      signature; // 0x03020400
  long      nStanzas;
  stanza60  stanza60s[nStanzas];
  long      signature; // same as above
  long      nStanzas2;
  stanza60  stanza60s2[nStanzas2];
};
====stanza60====
{
  {// 1st stanza
  long    signature;//0x03020400
  long    size;
  bytes  phsyx_data[size];
  }
  {// 2nd stanza
  long    signature;// as above
  long    size;
  bytes  phsyx_data2[size];
  }
}
* the signatures and sizes are NOT optional. the data is
=====phsyx_data=====
{
  phsyx_header
  {
    {
      byte id[8]; // 'NXS.CVXM'
      long Always13;
      long Always0;
    }
    {
      byte id[8]; // 'ICE.CLHL'
      long Always6;
    }
    {
      byte id[8]; // always 'ICE.CVHL'
      long Always6;
    }
    long nTriplets;
    long count;
    long nFrames;
    long 2xcount;  // always dbl 'count'
  }
  tripletXYZ triplets[nTriplets];
  short 00;
  frames
  {
    float floats[4];
    long  value;
  }frames[nFrames];
  byte  index[variable length];
  //25x4 byte ending sequence
  float generally_zero;
  float f;
  long  value;
  float floats[7];
  long  value2;
  float floats[14];
};
*the amount of index bytes can be determined by end of frame data to the start of the fixed 25x4 offset at end of lod
 
===D3DCOLORVALUE===
D3DCOLORVALUE
{
  float r,g,b,a;
}
=====RenderFlags=====
:*Bit0:AlwaysInShadow (A1 only)
:*Bit1:NoZWrite
:*Bit4:NoColorWrite
:*Bit5:NoAlphaWrite
:*Bit6:AddBlend
:*Bit7:AlphaTest (clutter)
:*Bit8:AlphaTest64 (clutter)
:*Bit19:Road      (a1only)
:*Bit11:NoTiWrite
 
=====LodStageTexture=====
LodStageTexture
{
  ulong  TextureFilter; // see below
  asciiz PaaTexture;    // "ca\characters\data\civil_tvreport_body_as.paa
                        // alternatively "#(argb,8,8,3)color(0,0,0,1,CO)" (eg)
  ulong  TransformIndex;      // zero based, see below
if =======Type11 AND V52 OR Type11 AND last(dummy) stage Texture ===================
  byte  V52Type11bool;  // only for arrowhead/pmc . and only for material types 11
endif
};
 
:The first stageTexture is a dummy entry. For N humanly readable stage classes, there are 1+N LodStageTextures
 
:Later p3d formats (VBS2, Operation Arrowhead) append an additional classTI LodStageTexture. if not present or declared in the rvmat file, it is a dummy entry. The rvmat gui editor from BisTools is not able to display this.
 
:The TransformIndex is generally iterative (linear sequential). 1st entry is 0, 2nd 1, 3rd 2, etc. It refers to the nTH Transform Matrix
 
:TextureFilter maybe 1 of the following values.
:*0: Point // sometimes
:*1: Linear  // rarely
:*2: TriLinear // not seen
:*3: Anisotropic (default)
 
=====LodStageTransform=====
  LodStageTransform
  {
    ulong UVSource;
    float Transform[4][3];//a DirectX texture space transform matrix
  };
 
:UVSource corresponds to the 8 possible uvsets available
 
:*0 "None"
:*1 "Tex" default
:*2: "Tex2"
:*........
:*8:"Tex8"
 
:*Tex1..8 cannot be taken literally as uvsource 1..8. They can mean anything, according to the template and are scarcely encountered
 
====NamedProperty====
  struct
  {
    Asciiz Property;// "noshadow" = "1" eg
    Asciiz Value;
  }
 
*See [[Named Properties]]
 
== Decompression ==
 
see [[Compressed LZSS File Format]]
 
see [[Compressed LZO File Format]]
 
 
In ODOL v40 and v43 format files, some of the data structures present in the file are compressed by using LZSS compression.
ODOL v47 and v48 use LZO compression. This is represented as
 
Unlike pbo compression, in ArmA model files, one only knows the number of items to decompress, the expected output size (in bytes) and the expected checksum.
With this information and the size of a given data item one has the necessary information to expand the data to it's original format and size.
 
<b>''Note:- Data structures that are identified as being compressible will only be compressed if the 'expectedSize' is >= 1024 bytes.''</b>
 
<b>V64+</b>
v64 implements a new flag for all compressed blobs. They no longer follow the 1024 byte rule. All possibly compressed arrays are now:
 
ulong elementCount
byte  compressed
    0 - not compressed
    2 - compressed
byte  data[elementCount]
 
As an example if one was expanding the array of vertices positions...
 
* A vertex is described by it's x,y,z coordinates which are floats. A float is a 32bit (4 byte) number.
* If we were processing 1968 vertices then our expected output size would be 1968 * (3 * 4) = 23,616 bytes.
 
This 'expectedSize' is the only necessary information one would need to pass to a processing sub-routine or function.
 
 
 
== Reference Tables ==
 
 
=== Material Stages ===
 
The number of material stages is dependant on the type of Shader that is used to process the material by the ArmA game engine.
A reference table is used when processing materials where depending on the shader specified the given number of stages should be processed.
 
<code><nowiki>
refShaderStages
{
  int PixelShaderId;
  int NoOfStages;
};
</nowiki></code>
 
{| class="wikitable" border="0"
!align="left"|ID (Hex/Decimal)
!width="250" align="left"|Name
!width="350" align="left"|Description
!width="50" align="left"|NoOfStages
|-
|-
|align="left"|0x00, 0||align="left"|Normal||align="left"|diffuse color modulate, alpha replicate||align="left"|0
|-
|align="left"|0x01, 1||align="left"|NormalDXTA||align="left"|diffuse color modulate, alpha replicate, DXT alpha correction||align="left"|0
|-
|align="left"|0x02, 2||align="left"|NormalMap||align="left"|normal map shader||align="left"|3
|-
|align="left"|0x03, 3||align="left"|NormalMapThrough||align="left"|normal map shader - through lighting||align="left"|3
|-
|align="left"|0x04, 4||align="left"|NormalMapSpecularDIMap||align="left"|VBS2 only||align="left"|2
|-
|align="left"|0x05, 5||align="left"|NormalMapDiffuse||align="left"|?||align="left"|2
|-
|align="left"|0x06, 6||align="left"|Detail||align="left"|?||align="left"|1
|-
|align="left"|0x07, 7||align="left"|?||align="left"|?||align="left"|?
|-
|align="left"|0x08, 8||align="left"|Water||align="left"|A1 only sea water||align="left"|2
|-
|align="left"|0x09, 9||align="left"|?||align="left"|vbs2||align="left"|?
|-
|align="left"|0x0A, 10||align="left"|White||align="left"|A1 only||align="left"|0
|-
|align="left"|0x0B, 11||align="left"|?||align="left"|vbs2||align="left"|?
|-
|align="left"|0x0C, 12||align="left"|AlphaShadow||align="left"|shadow alpha write||align="left"|0
|-
|align="left"|0x0D, 13||align="left"|AlphaNoShadow||align="left"|shadow alpha (no shadow) write||align="left"|0
|-
|align="left"|0x0E, 14||align="left"|?||align="left"|vbs2||align="left"|?
|-
|align="left"|0x0F, 15||align="left"|DetailMacroAS||align="left"|?||align="left"|3
|-
|align="left"|0x10, 16||align="left"|?||align="left"|vbs2||align="left"|?
|-
|align="left"|0x11, 17||align="left"|?||align="left"|vbs2||align="left"|?
|-
|align="left"|0x12, 18||align="left"|NormalMapSpecularMap||align="left"|?||align="left"|2
|-
|align="left"|0x13, 19||align="left"|NormalMapDetailSpecularMap||align="left"|Similar to NormalMapDiffuse||align="left"|3
|-
|align="left"|0x14, 20||align="left"|NormalMapMacroASSpecularMap||align="left"|?||align="left"|4
|-
|align="left"|0x15, 21||align="left"|NormalMapDetailMacroASSpecularMap||align="left"|?||align="left"|5
|-
|align="left"|0x16, 22||align="left"|NormalMapSpecularDIMap||align="left"|Same as NormalMapSpecularMap, but uses _SMDI texture||align="left"|2
|-
|align="left"|0x17, 23||align="left"|NormalMapDetailSpecularDIMap||align="left"|?||align="left"|3
|-
|align="left"|0x18, 24||align="left"|NormalMapMacroASSpecularDIMap||align="left"|?||align="left"|4
|-
|align="left"|0x19, 25||align="left"|NormalMapDetailMacroASSpecularDIMap||align="left"|?||align="left"|5
|-
|align="left"|0x38, 56||align="left"|Glass||align="left"|?||align="left"|2
|-
|align="left"|0x3A, 58||align="left"|NormalMapSpecularThrough||align="left"|?||align="left"|3
|-
|align="left"|0x3B, 59||align="left"|Grass||align="left"|Special shader to allow volumetric shadows to be cast on grass clutter||align="left"|0
|-
|align="left"|0x3C, 60||align="left"|NormalMapThroughSimple||align="left"|?||align="left"|0
|-
|align="left"|0xxx, 102||align="left"|Super||align="left"|Arrowhead||align="left"|0
|-
|align="left"|0xxx, 103||align="left"|Multi||align="left"|Arrowhead||align="left"|0
|-
|align="left"|0xxx, 107||align="left"|Tree||align="left"|Arrowhead||align="left"|0
|-
|align="left"|0xxx, 110||align="left"|Skin||align="left"|Arrowhead||align="left"|0
|-
|align="left"|0x6F, 111||align="left"|CalmWater||align="left"|Arrowhead||align="left"|7
|-
|align="left"|0xxx, 114||align="left"|TreeAdv||align="left"|Arrowhead||align="left"|0
|-
|align="left"|0xxx, 116||align="left"|TreeAdvTrunk||align="left"|Arrowhead||align="left"|0
|-
|-
|}
 
----
 
== Enums ==
 
 
 
<code><nowiki>
int enum VertexShaderId
{
case 0: return "Basic";
case 1: return "NormalMap";
case 2: return "NormalMapDiffuse";
case 3: return "Grass";
case 8: return "Water";
case 11: return  "NormalMapThrough";
case 15: return "NormalMapAS";
case 14: return "BasicAS";
case 17: return "Glass";
case 18: return "NormalMapSpecularThrough";
case 19: return "NormalMapThroughNoFade";
case 20: return "NormalMapSpecularThroughNoFade";
case 23: return "Super";
case 24: return "Multi";
case 25: return "Tree";
case 30: return "CalmWater";
case 26: return "TreeNoFade";
case 29: return "Skin";
case 31: return "TreeAdv";
case 32: return "TreeAdvTrunk";
}
</nowiki></code>
 
----
 
== Links ==
 
[[User:Sy|Article Author - Sy (Synide)]] -- [[User:Sy|Sy]] 17:16, 11 August 2007 (CEST)
 
[[P3D File Format - ODOLV40|Original ODOLv40 Article detailed by Bxbx (Biki'd by Mikero)]]
[[Category:BIS_File_Formats]]
[[Category:ArmA: File Formats]]

Revision as of 07:48, 25 June 2016

This page has been removed to hinder the thieves, lowlife, and parasites reverse engineering p3ds to the detriment of the community.