Rtm Binarised File Format
UnBinarised Format
For unbinarised see Rtm (Animation) File Format
Binarised format
Binarised rtm was introduced for the Arma2 engine.
There are currently two versions.
version 3: Arma2 family version 4: Arma3 (alpha/beta)
Structure
RTMB { RTMBHeader Header; byte Always1; // ?? XYZTriplet Displacement; ulong nFrames; // 55 eg ulong Generally0; // ?? ulong nBones; // same value as NoOfBones ulong NoOfBones; // 128 eg Asciiz BoneNames[NoOfBones]; // "weapon\0\rightarm\leftarm\etc..." if (v4) { ulong Zeroes[2]; // probably 2x count and structure } FrameTimes FrameTimes; // CompressedFloats FramePosition FramePositions[nFrames];// CompressedFrames }
BoneNames are the traditional Bis catenated strings. One after the other separated by '\0'. Unlike most others encountered in Bis file architecture, there is no final terminating double null because the count is already known.
RTMBHeader
RTMBHeader { char[4] Type; //"BMTR" ulong Version; // 3==A2, 4==A3 }
FrameTimes (compressed)
FrameTimes { ulong nFrameTimes; // should always be same as nFrames float Array[nFrameTimes]; }
This is the traditional Bis potentially-compressed lzo structure, where, if, the total bytes stored >=1024, the array is compressed (in lzo format). All bones are 'held' in a position and orientation (specified by FramePosition) for the duration of that frametime period.
FramePosition (compressed)
FramePosition { ulong ThisFrameNoOfBones; // Should always be same as nBones Transform Transforms[ThisFrameNoOfBones]; }FramePositions[nFrames];
Each bone is held in this position and orientation for this frametime. ThisFrameNoOfBones is irrelevant to the engine and always must be the nBones value. It is present however because of efficiencies in using the standard bis lzo compression methods which rely on this 'count'.
Transform
following information supplied by 'Voyager' to whom all honor and glory
transform { short Qnion[4]; //compressed xyzw Rotation short XYZ[3];// Compressed triplet };
Quarternion(qX=Qnion[0]/16384,qY=Qnion[1]/16384,qZ=Qnion[2]/16384,qW=Qnion[3]/16384); Triplet(X=Convert(XYZ[0],Y=Convert(XYZ[1],Z=Convert(XYZ[2]);
double Convert(ushort value) { double sign = ((value & 0x8000) != 0) ? -1 : 1; // S eeeee xxxxxxxxxx ushort exponent = (value & 0x7FFF) >> 10;//5bits double significand = (double)(value & 0x03FF) / (1 << 10); if (exponent == 0) { return (sign / 0x4000) * (0.0 + significand ); } return sign * Pow(2, exponent - 15) * (1 + significand ); } }