P3D Named Selections: Difference between revisions
(merged odol structtures) |
Lou Montana (talk | contribs) m (Text replacement - " (\=+)([a-zA-Z0-9][^ ]+[a-zA-Z0-9])(\=+) " to " $1 $2 $3 ") |
||
(7 intermediate revisions by 2 users not shown) | |||
Line 1: | Line 1: | ||
{{ | {{Feature|UnsupportedDoc}} | ||
== | = 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. | NB: The byte array's indicate a zero-based offset into the corresponding '''Points''' & '''Faces''' structures. | ||
Line 43: | Line 38: | ||
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. | ||
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. | ||
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 72: | Line 85: | ||
LodNamedSelection | LodNamedSelection | ||
{ | { | ||
asciiz SelectedName; | asciiz SelectedName; // "rightleg" or "neck" eg | ||
ulong NoOfFaces; | ulong NoOfFaces; | ||
ushort FaceIndexes[NoOfFaces]; | ushort FaceIndexes[NoOfFaces]; // indexing into the LodFaces Table | ||
ulong Always0Count; | ulong Always0Count; | ||
unknownType Array[Always0Count] | unknownType Array[Always0Count] //IsSectional must be true | ||
///// ODOL7 only /////////////////// | |||
tbool IsSectional; | ulong Count; | ||
ulong UnknownV7Array[Count]; | |||
//////////////////////////////////// | |||
tbool IsSectional; //Appears in the sections[]= list of a model.cfg | |||
ulong NoOfUlongs; | ulong NoOfUlongs; | ||
ulong | ulong SectionIndex[NoOfUlongs]; //IsSectional must be true. Indexes into the LodSections Table | ||
ulong nVertices; | ulong nVertices; | ||
ushort | ushort VertexTableIndexes[nVertices]; | ||
ulong nTextureWeights; | ulong nTextureWeights; | ||
byte VerticesWeights[nTextureWeights]; | byte VerticesWeights[nTextureWeights]; // if present they correspond to (are exentsions of) the VertexTableIndexes | ||
} | } | ||
[[Category:BIS_File_Formats]] | [[Category:BIS_File_Formats]] | ||
{{GameCategory|arma1|File Formats}} |
Latest revision as of 15:39, 17 November 2021
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 }