Changes
From Final Fantasy Inside
no edit summary
PFF7FrameMiniHeader pfmhMiniHeader =
(PFF7FrameMiniHeader)pbAnimBuffer; SHORT sSize = pfmhMiniHeader->sSize; BYTE bKeyBits = pfmhMiniHeader->bKey;
// Skip the first 5 bytes because they are part of the frame header.
if ( iBitStart == 0 ) { // First frame?
// The first frame is uncompressed and each value is the
// actual rotation. pfbFrameBuffer->svPosOffset.sX = GetBitsFixed( pbThisBuffer, dwThisBitStart, 16 ); // Always 16 bits here.
pfbFrameBuffer->svPosOffset.sY = GetBitsFixed( pbThisBuffer, dwThisBitStart, 16 );
pfbFrameBuffer->svPosOffset.sZ = GetBitsFixed( pbThisBuffer, dwThisBitStart, 16 );
// This function will set the FLOAT values for the
// positions.
// Any scaling that needs to be done would be done here.
pfbFrameBuffer->svPosOffset.fX = (FLOAT)pfbFrameBuffer->svPosOffset.sX;
pfbFrameBuffer->svPosOffset.fY = (FLOAT)pfbFrameBuffer->svPosOffset.sY;
// If we did not read as many bits as there are in the frame,
// return the location where the bits should start for the
// next frame.
if ( (SHORT)(dwThisBitStart / 8) < sSize ) {
return dwThisBitStart;
return 0;
}
</pre></code>
2.
This is an example loop that could be used to load a full animation.
<code></pre>
FF7FrameHeader fhHeader;
ReadFile( hFile, &fhHeader, sizeof( fhHeader ), &ulBytesRead,
// will load diretly into it.
// Every frame after that will actually use it with the
// offsets loaded to determine the final result of that // frame. iBits = LoadFrames( &fbFrameBuffer, fhHeader.dwBones,iBits, baData );
// Reverse the Y offset (required).
fbFrameBuffer.svPosOffset.fY = 0.0f –fbFrameBuffer.svPosOffset.fY;
// The first rotation set is skipped. It is not part of
== Part IV: Qhimm’s Input==
Qhimm has taken the time to rewrite two of these functions used in decoding, so it is easier to understand for people who know C++ better than they know assembly (despite my comments being in the assembly code).
He has also written a more in-depth look at the logistics behind the rotation compression format and explains its limitations
// Collect one more byte from the stream.
dwNextStreamBytes = dwNextStreamBytes << 8 |
pStreamBytes[dwStreamByteOffset + 2];
// Shift the delta value into place.
sValue = (dwNextStreamBytes << (dwCurrentBitsEaten + 1)) >> 8;
{
unsigned int uType = GetBitsFromStream( pStreamBytes,
pdwStreamBitOffset, 3 ) & 7;
switch (uType)
{
case 0:
// Return the smallest possible decrement delta (at given
// precision).
return (-1 << nLoweredPrecisionBits);
// Read a corresponding number of bits from the stream.
int iTemp = GetBitsFromStream( pStreamBytes,
pdwStreamBitOffset, nBits );
// Transform the value into the full seven-bit value, using the bit
// length
// as part of the encoding scheme (see notes).
if (iTemp < 0) iTemp -= 1 << (nBits - 1);
case 7:
// Read an uncompressed value from the stream (at requested
// precision), and return.
iTemp = GetBitsFromStream( pStreamBytes,
pdwStreamBitOffset, 12 - nLoweredPrecisionBits );
return (iTemp << nLoweredPrecisionBits);
default:
encodings available for small deltas. The smallest 128 [-64,63] sizes of deltas
can be stored in compressed form instead of as raw values. This method is
efficient
since a majority of the rotational deltas involved in skeletal character animation
will be small, and thus doubly effective if used with reduced precision. Precision
First, a single bit tells us if the delta is non-zero. If this bit is zero, there
is no delta value (0) and the decoding is done. Otherwise, a 3 bit integer
follows, detailing how the delta value is encoded. This has 8 different meanings, as follows:
Type Meaning
------ -------------------------------------------------------
0 The delta is the smallest possible decrement (under the current precision)
1-6 The delta is encoded using this many bytes
7 The delta is stored in raw form (in the current precision)
The encoding of small deltas works as follows: The encoded delta can be stored
using 1-6 bits, giving us a total of 2+4+8+16+32+64 = 126 possible different
values, which during this explanation will be explained as simple integers (the lowest bits of the delta, in current precision). The values 0 (no change) and -1 (minimal decrement) are already covered, leaving the other 126 values to neatly fill out the entire 7 bit range. We do this by encoding each value like follows:
- The magnitude of the delta is defined as the value of its most significant
have a magnitude of 32. For simplicity, we also define the 'signed magnitude' as
the magnitude multiplied by the sign of the value (so '-2' has a signed
- When encoding a value, we subtract its signed magnitude; essentially pushing
everything down one notch towards zero, setting the most significant value bit
- The transformed value is then stored starting from its magnitude bit (normally,
you would have to start one bit higher to include the sign bit and prevent
When decoding, you only need to know the number of bits of the encoded value, use