P3D Named Selections: Difference between revisions

From Bohemia Interactive Community
Jump to navigation Jump to search
No edit summary
 
m (Text replacement - " (\=+)([a-zA-Z0-9][^ ]+[a-zA-Z0-9])(\=+) " to " $1 $2 $3 ")
 
(8 intermediate revisions by 2 users not shown)
Line 1: Line 1:
{{unsupported-doc}}
{{Feature|UnsupportedDoc}}
==Intro==
= Intro =
placeholder till better organsied
= MLOD =


currently a place holder until this is better organised
Named Selections are contained in the Taggs structure in MLOD file format. Every Tagg-name that doesn't have the form #Name# is a named selection. The name
of the selection is simply the Tagg-name.


==MLOD==
    ulong      NoOfBytes;            //eg. Will always be lod.NoOfPoints + lod.NoOfFaces
    byte      SelectedWeightedPoints[NoOfPoints];
    byte      SelectedFaces[NoOfFaces];


Named Selections are contained in the Taggs structure in MLOD file format
The weights are 'compressed' floating point values; the following functions may be used to encode/decode those values. The conversion functions were found by experimenting and are not guaranteed to yield the correct results.


<code><nowiki>
struct structTag_SelectedWeighted
{
    TinyBool                  Active;              //Always true
    asciiz                    "<Any Ascii Characters>\0";
    ulong                      NoOfBytes;            //eg. Will always be NoOfPoints + NoOfFaces
    byte[NoOfPoints]          SelectedWeightedPoints;
    byte[NoOfFaces]            SelectedFaces;
}
</nowiki></code>


NB: The byte array's indicate a zero-based offset into the corresponding '''Points''' & '''Faces''' structures.
NB: The byte array's indicate a zero-based offset into the corresponding '''Points''' & '''Faces''' structures.
Line 43: Line 38:




Following is some appropriate ''pseudo-code'' to illustrate.


'''byte2weight'''


<code><nowiki>
 
float32 byte2weight = (256 - weight)/255;
float32 byte2weight = (256 - weight)/255;
if (byte2weight > 1.0) then byte2weight = 0;
if (byte2weight > 1.0) then byte2weight = 0;


Where 'weight' is a unit8 (single byte) in the range...  0 >= weight <= 255 or 0x00 >= weight <= 0xFF.
Where 'weight' is a unit8 (single byte) in the range...  0 >= weight <= 255 or 0x00 >= weight <= 0xFF.
</nowiki></code>


'''weight2byte'''


<code><nowiki>
  float decodeWeight( uint8 b )
  {
    if( b == 0 ) return  0.0f;
    else if( b == 2 ) return 1.0f;
    else if( b > 2 ) return 1.0f - round( (b-2) / 2.55555f )*0.01f;
    else if( b < 0 ) return -round( b / 2.55555f ) * 0.01f;
    else assert(false); // b == 1 does not occur?
  }
unit8 weight2byte = round(256 - (255 x weight),0);
unit8 weight2byte = round(256 - (255 x weight),0);
if (weight2byte == 256) then weight2byte = 0;
if (weight2byte == 256) then weight2byte = 0;


Where 'weight' is a float32 in the range...  0.0 >= weight <= 1.0.
Where 'weight' is a float32 in the range...  0.0 >= weight <= 1.0.
</nowiki></code>


==ODOL==
 
  uint8 encodeWeight( float f )
  {
    // assume clamped value from 0.0 to 1.0
    if( f < 0.01 ) return 0;
    else if( f > 0.99 ) return 2;
    else if( f > 0.5 ) return 0xff & (int)floor((1.0f - f) * 255.55f + 2);
    else if( f > 0.49 ) return -127;
    else return 0xff & (int)floor(f*2.5555f);
  }
 
 
 
 
 
= ODOL =


All arrays are subject to the 1024 rule. Which type of compression depends on odol version
All arrays are subject to the 1024 rule. Which type of compression depends on odol version
Line 70: Line 83:
*Arma2: LZO compressed.
*Arma2: LZO compressed.


===ODOL7===
NamedSelection
{
  asciiz NamedSelectionName;
  ulong  Count;
  ushort Vertices[Count];
  ulong  Count; 
  ushort Unknown[Count];
  ulong  Count;
  ulong  Unknown[Count];
  byte  IsSectional;
  ulong  Count;
  ulong  Unknown[Count];
  ulong  Count; 
  ushort Faces[Count];
  ulong  Count;     
  byte  TextureWeights[Count];//probably
};
===ODOL4x===
   LodNamedSelection
   LodNamedSelection
   {
   {
     asciiz      NamedSelectionName;                         // "rightleg" or "neck" eg
     asciiz      SelectedName;                       // "rightleg" or "neck" eg
     ulong      NoOfSelectedFaces;
     ulong      NoOfFaces;
     ushort      SelectedFaceIndexes[NoOfSelectedFaces];
     ushort      FaceIndexes[NoOfFaces];             // indexing into the LodFaces Table
     ulong      Always0Count;
     ulong      Always0Count;
     unknownType Array[Always0Count]
     unknownType Array[Always0Count]                 //IsSectional must be true
     tbool      IsSectional;                                 //Appears in the sections[]= list of a model.cfg
    ///// ODOL7 only ///////////////////
    ulong      Count;
    ulong      UnknownV7Array[Count];
    ////////////////////////////////////
     tbool      IsSectional;                       //Appears in the sections[]= list of a model.cfg
     ulong      NoOfUlongs;
     ulong      NoOfUlongs;
     ulong      UnknownArray[NoOfUlongs];                   // compression. none seen so far
     ulong      SectionIndex[NoOfUlongs];         //IsSectional must be true. Indexes into the LodSections Table
     ulong      nSelectedVertices;
     ulong      nVertices;
     ushort      SelectedVerticesIndexes[nSelectedVertices];
     ushort      VertexTableIndexes[nVertices];
     ulong      nTextureWeights;
     ulong      nTextureWeights;
     byte        SelectedVerticesWeights[nTextureWeights];
     byte        VerticesWeights[nTextureWeights]; // if present they correspond to (are exentsions of) the VertexTableIndexes
   }
   }


[[Category:BIS_File_Formats]]
[[Category:BIS_File_Formats]]
[[Category:ArmA: File Formats]]
{{GameCategory|arma1|File Formats}}

Latest revision as of 16:39, 17 November 2021

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.

Intro

placeholder till better organsied

MLOD

Named Selections are contained in the Taggs structure in MLOD file format. Every Tagg-name that doesn't have the form #Name# is a named selection. The name of the selection is simply the Tagg-name.

   ulong      NoOfBytes;            //eg. Will always be lod.NoOfPoints + lod.NoOfFaces
   byte       SelectedWeightedPoints[NoOfPoints];
   byte       SelectedFaces[NoOfFaces];

The weights are 'compressed' floating point values; the following functions may be used to encode/decode those values. The conversion functions were found by experimenting and are not guaranteed to yield the correct results.


NB: The byte array's indicate a zero-based offset into the corresponding Points & Faces structures.

To clarify, the purpose of this 'chunk' is to denote which points & faces belong to a given 'Named Selection' and also to denote the 'per-point-weight' associated with this selection.

Each byte in the SelectedWeightedPoints array denotes a value 0 to 255 (0 to FF hex).

And, serves a dual purpose in...

1. Denoting the selectedness and
2. Denoting per point weighting.


  • Zero (0) or 0x00 hex indicates the corresponding point in the LODs Points array is not selected.
Any value other than zero indicates that the point is not only part of the selection but also has a weighting value.


  • One (1) or 0x01 hex indicates the corresponding point in the LODs Points array is selected and has 100% weighting.
Every value between 2 and 255 (0x02 to 0xFF hex) indicates the percentage weight of the corresponding point and that it is part of the selection.
Two (2) being almost 100% weighted and 255 being almost 0% weighted.



float32 byte2weight = (256 - weight)/255; if (byte2weight > 1.0) then byte2weight = 0;

Where 'weight' is a unit8 (single byte) in the range... 0 >= weight <= 255 or 0x00 >= weight <= 0xFF.


 float decodeWeight( uint8 b )
 {
   if( b == 0 ) return  0.0f;
   else if( b == 2 ) return 1.0f;
   else if( b > 2 ) return 1.0f - round( (b-2) / 2.55555f )*0.01f;
   else if( b < 0 ) return -round( b / 2.55555f ) * 0.01f;
   else assert(false); // b == 1 does not occur?
 }

unit8 weight2byte = round(256 - (255 x weight),0); if (weight2byte == 256) then weight2byte = 0;

Where 'weight' is a float32 in the range... 0.0 >= weight <= 1.0.


 uint8 encodeWeight( float f )
 {
   // assume clamped value from 0.0 to 1.0
   if( f < 0.01 ) return 0;
   else if( f > 0.99 ) return 2;
   else if( f > 0.5 ) return 0xff & (int)floor((1.0f - f) * 255.55f + 2);
   else if( f > 0.49 ) return -127;
   else return 0xff & (int)floor(f*2.5555f);
 }



ODOL

All arrays are subject to the 1024 rule. Which type of compression depends on odol version

  • ODOL7 and ODOL40: LZSS compressed
  • Arma2: LZO compressed.
 LodNamedSelection
 {
   asciiz      SelectedName;                       // "rightleg" or "neck" eg
   ulong       NoOfFaces;
   ushort      FaceIndexes[NoOfFaces];             // indexing into the LodFaces Table
   ulong       Always0Count;
   unknownType Array[Always0Count]                 //IsSectional must be true
   ///// ODOL7 only ///////////////////
   ulong       Count;
   ulong       UnknownV7Array[Count];
   ////////////////////////////////////
   tbool       IsSectional;                       //Appears in the sections[]= list of a model.cfg
   ulong       NoOfUlongs;
   ulong       SectionIndex[NoOfUlongs];          //IsSectional must be true. Indexes into the LodSections Table
   ulong       nVertices;
   ushort      VertexTableIndexes[nVertices];
   ulong       nTextureWeights;
   byte        VerticesWeights[nTextureWeights];  // if present they correspond to (are exentsions of) the VertexTableIndexes
 }