public static void EncodeCHR0Keyframes(KeyframeCollection kf, VoidPtr entryAddress, VoidPtr dataAddress) { AnimationCode code = kf._evalCode; //VoidPtr dataAddr = addr + 8; CHR0Entry *header = (CHR0Entry *)entryAddress; header->_code = (uint)code._data; header->_stringOffset = 0; //entryAddress += 8; bint *pOffset = (bint *)entryAddress + 2; //Write values/offset and encode groups for (int i = 0, x = 0; i < 3; i++, x += 3) { if (code.GetExists(i)) { AnimDataFormat format = code.GetFormat(i); if ((i == 0) && (code.GetIsIsotropic(i))) { if (code.GetIsFixed(2)) { *(bfloat *)pOffset++ = kf._keyRoots[2]._next._value; } else { *pOffset++ = (int)(dataAddress - entryAddress); dataAddress += EncodeEntry(x, format, kf, dataAddress); } } else { for (int y = 0, z = x; y < 3; y++, z++) { if (code.GetIsFixed(z)) { *(bfloat *)pOffset++ = kf._keyRoots[z]._next._value; } else { *pOffset++ = (int)(dataAddress - entryAddress); dataAddress += EncodeEntry(z, format, kf, dataAddress); } } } } } }
private static int EvaluateCHR0Group(ref AnimationCode code, KeyframeCollection kf, int group, ref int entrySize) { int index = group * 3; int numFrames = kf.FrameLimit; int dataLen = 0; int maxEntries; int evalCount; int scaleSpan; //bool useLinear = group == 1; bool exist = false; bool isotropic = group == 0; AnimDataFormat format = AnimDataFormat.None; KeyframeEntry[] roots = new KeyframeEntry[3]; KeyframeEntry[][] arr = new KeyframeEntry[3][]; int[] count = new int[3]; bool[] isExist = new bool[3]; bool[] isFixed = new bool[3]; bool[] isScalable = new bool[3]; float[] floor = new float[3]; float[] ceil = new float[3]; KeyframeEntry entry; int eCount = 0; float min; float max; int maxIndex = 0; //Initialize values for (int i = 0; i < 3; i++) { entry = roots[i] = kf._keyArrays[index + i]._keyRoot; count[i] = kf._keyArrays[index + i]._keyCount; isExist[i] = count[i] > 0; isFixed[i] = count[i] <= 1; if (!isFixed[i]) { min = float.MaxValue; max = float.MinValue; for (entry = entry._next; entry._index != -1; entry = entry._next) { min = Math.Min(entry._value, min); max = Math.Max(entry._value, max); } floor[i] = min; ceil[i] = max; maxIndex = Math.Max(entry._prev._index, maxIndex); } } if (exist = isExist[0] || isExist[1] || isExist[2]) { if (group == 0) { if (isFixed[0] != isFixed[1] || isFixed[0] != isFixed[2]) { isotropic = false; } else if (count[0] != count[1] || count[0] != count[2]) { isotropic = false; } else { KeyframeEntry e1 = roots[0], e2 = roots[1], e3 = roots[2]; for (int i = count[0]; i-- > 0;) { e1 = e1._next; e2 = e2._next; e3 = e3._next; if (e1._index != e2._index || e1._index != e3._index || e1._value != e2._value || e1._value != e3._value) { isotropic = false; break; } } } } if (isotropic) { evalCount = 1; maxEntries = count[0]; } else { evalCount = 3; maxEntries = Math.Max(Math.Max(count[0], count[1]), count[2]); //useLinear &= (count[0] == numFrames) && (count[1] == numFrames) && (count[2] == numFrames); } scaleSpan = @group == 1 ? 255 : maxIndex <= 255 ? 4095 : maxIndex <= 2047 ? 65535 : -1; //scaleSpan = useLinear ? 255 : 4095; //Determine if values are scalable for (int i = 0; i < evalCount; i++) { isScalable[i] = true; if (isFixed[i] || scaleSpan == -1) { continue; } //float* pValue = value[i]; eCount = count[i]; float basev, range, step, distance, val; basev = floor[i]; range = ceil[i] - basev; //Evaluate spans until we reach a success. //A success means that compression using that span is possible. //No further evaluation necessary. SpanBegin: int span = scaleSpan; int spanEval = scaleSpan - 32; float tanScale = scaleSpan == 4095 ? 32.0f : 256.0f; if (scaleSpan != 255) { for (entry = roots[i]._next; entry._index != -1; entry = entry._next) { //Ignore entries that don't need interp. if (entry._index - entry._prev._index >= 1 && entry._prev._index != -1 || entry._next._index - entry._index >= 1 && entry._next._index != -1) { val = entry._tangent * tanScale; val += val < 0 ? -0.5f : 0.5f; if (Math.Abs((int)val / tanScale - entry._tangent) > tanError) { span = spanEval; break; } } } } if (span > spanEval && range == 0.0f) { continue; } SpanStep: if (span > spanEval) { step = range / span; //if span <= 255, check every frame instead! if (span <= 255) { for (int x = 0; x < numFrames; x++) { val = kf[x, index + i]; distance = (val - basev) / step + 0.5f; distance = Math.Abs(val - (basev + (int)distance * step)); //If distance is too large change span and retry if (distance > scaleError) { span--; goto SpanStep; } } } else { for (entry = roots[i]._next; entry._index != -1; entry = entry._next) { val = entry._value; distance = (val - basev) / step + 0.5f; distance = Math.Abs(val - (basev + (int)distance * step)); //If distance is too large change span and retry if (distance > scaleError) { span--; goto SpanStep; } } } } else { if (scaleSpan <= 255 && maxIndex <= 255) { scaleSpan = 4095; } else if (scaleSpan <= 4095 && maxIndex <= 2047) { scaleSpan = 65535; } else { scaleSpan = -1; isScalable[i] = false; continue; } goto SpanBegin; } } //Determine format only if there are unfixed entries if (!isFixed[0] || !isFixed[1] || !isFixed[2]) { bool scale = isotropic ? isScalable[0] : isScalable[0] && isScalable[1] && isScalable[2]; float frameSpan = (float)numFrames / maxEntries; if (scale) { if (@group == 1 && scaleSpan <= 255 && frameSpan < 4.0f) { format = AnimDataFormat.L1; } else if (scaleSpan <= 4095 && maxIndex <= 255) { format = AnimDataFormat.I4; } else if (frameSpan > 1.5f && maxIndex <= 2047) { format = AnimDataFormat.I6; } else if (@group == 1 && frameSpan <= 3.0f) { format = AnimDataFormat.L4; } else { format = AnimDataFormat.I12; } } else if (@group == 1 && frameSpan <= 3.0f) { format = AnimDataFormat.L4; } else { format = AnimDataFormat.I12; } } //calculate size for (int i = 0; i < evalCount; i++) { entrySize += 4; if (!isFixed[i]) { switch (format) { case AnimDataFormat.I12: dataLen += 8 + count[i] * 12; break; case AnimDataFormat.I4: dataLen += 16 + count[i] * 4; break; case AnimDataFormat.I6: dataLen += (16 + count[i] * 6).Align(4); break; case AnimDataFormat.L1: dataLen += (8 + numFrames).Align(4); break; case AnimDataFormat.L4: dataLen += numFrames * 4; break; } } } //Should we compress here? } else //Set isotropic to true, so it sets the default value. { isotropic = true; } if (group == 0) { code.IgnoreScale = !exist; } code.SetExists(group, exist); code.SetIsIsotropic(group, isotropic); for (int i = 0; i < 3; i++) { code.SetIsFixed(index + i, isFixed[i]); } code.SetFormat(group, format); return(dataLen); }
public static int CalculateCHR0Size(KeyframeCollection kf, out int entrySize, out AnimationCode code) { int dataSize = 0; entrySize = 8; code = AnimationCode.Default; for (int i = 0; i < 3; i++) { dataSize += EvaluateCHR0Group(ref code, kf, i, ref entrySize); } if (!code.HasRotation && !code.HasTranslation) { code.IgnoreRotAndTrans = true; code.Identity = !code.HasScale; } else { code.IgnoreRotAndTrans = false; code.Identity = false; } return(dataSize); }
public static KeyframeCollection DecodeCHR0Keyframes(CHR0Entry *entry, int numFrames) { KeyframeCollection kf = new KeyframeCollection(9, numFrames, 1, 1, 1); if (entry == null) { return(kf); } bfloat * sPtr = (bfloat *)entry->Data; AnimationCode code = entry->Code; AnimDataFormat format; if (code.HasScale) { format = code.ScaleDataFormat; if (code.IsScaleIsotropic) { if (code.IsScaleZFixed) { kf[0, 0, 1, 2] = *sPtr++; } else { DecodeFrames(kf, (VoidPtr)entry + *(buint *)sPtr++, format, 0, 1, 2); } } else { if (code.IsScaleXFixed) { kf[0, 0] = *sPtr++; } else { DecodeFrames(kf, (VoidPtr)entry + *(buint *)sPtr++, format, 0); } if (code.IsScaleYFixed) { kf[0, 1] = *sPtr++; } else { DecodeFrames(kf, (VoidPtr)entry + *(buint *)sPtr++, format, 1); } if (code.IsScaleZFixed) { kf[0, 2] = *sPtr++; } else { DecodeFrames(kf, (VoidPtr)entry + *(buint *)sPtr++, format, 2); } } } if (code.HasRotation) { format = code.RotationDataFormat; if (code.IsRotationIsotropic) { if (code.IsRotationZFixed) { kf[0, 3, 4, 5] = *sPtr++; } else { DecodeFrames(kf, (VoidPtr)entry + *(buint *)sPtr++, format, 3, 4, 5); } } else { if (code.IsRotationXFixed) { kf[0, 3] = *sPtr++; } else { DecodeFrames(kf, (VoidPtr)entry + *(buint *)sPtr++, format, 3); } if (code.IsRotationYFixed) { kf[0, 4] = *sPtr++; } else { DecodeFrames(kf, (VoidPtr)entry + *(buint *)sPtr++, format, 4); } if (code.IsRotationZFixed) { kf[0, 5] = *sPtr++; } else { DecodeFrames(kf, (VoidPtr)entry + *(buint *)sPtr++, format, 5); } } } if (code.HasTranslation) { format = code.TranslationDataFormat; if (code.IsTranslationIsotropic) { if (code.IsTranslationZFixed) { kf[0, 6, 7, 8] = *sPtr++; } else { DecodeFrames(kf, (VoidPtr)entry + *(buint *)sPtr++, format, 6, 7, 8); } } else { if (code.IsTranslationXFixed) { kf[0, 6] = *sPtr++; } else { DecodeFrames(kf, (VoidPtr)entry + *(buint *)sPtr++, format, 6); } if (code.IsTranslationYFixed) { kf[0, 7] = *sPtr++; } else { DecodeFrames(kf, (VoidPtr)entry + *(buint *)sPtr++, format, 7); } if (code.IsTranslationZFixed) { kf[0, 8] = *sPtr++; } else { DecodeFrames(kf, (VoidPtr)entry + *(buint *)sPtr++, format, 8); } } } return(kf); }
public static KeyframeCollection DecodeCHR0Keyframes(CHR0Entry *entry, int numFrames) { KeyframeCollection kf = new KeyframeCollection(numFrames); bfloat * sPtr = (bfloat *)entry->Data; AnimationCode code = entry->Code; AnimDataFormat format; if (code.HasScale) { format = code.ScaleDataFormat; if (code.IsScaleIsotropic) { if (code.IsScaleZFixed) { kf[KeyFrameMode.ScaleXYZ, 0] = *sPtr++; } else { DecodeCHR0Frames(kf, (VoidPtr)entry + *(buint *)sPtr++, format, KeyFrameMode.ScaleXYZ); } } else { if (code.IsScaleXFixed) { kf[KeyFrameMode.ScaleX, 0] = *sPtr++; } else { DecodeCHR0Frames(kf, (VoidPtr)entry + *(buint *)sPtr++, format, KeyFrameMode.ScaleX); } if (code.IsScaleYFixed) { kf[KeyFrameMode.ScaleY, 0] = *sPtr++; } else { DecodeCHR0Frames(kf, (VoidPtr)entry + *(buint *)sPtr++, format, KeyFrameMode.ScaleY); } if (code.IsScaleZFixed) { kf[KeyFrameMode.ScaleZ, 0] = *sPtr++; } else { DecodeCHR0Frames(kf, (VoidPtr)entry + *(buint *)sPtr++, format, KeyFrameMode.ScaleZ); } } } if (code.HasRotation) { format = code.RotationDataFormat; if (code.IsRotationIsotropic) { if (code.IsRotationZFixed) { kf[KeyFrameMode.RotXYZ, 0] = *sPtr++; } else { DecodeCHR0Frames(kf, (VoidPtr)entry + *(buint *)sPtr++, format, KeyFrameMode.RotXYZ); } } else { if (code.IsRotationXFixed) { kf[KeyFrameMode.RotX, 0] = *sPtr++; } else { DecodeCHR0Frames(kf, (VoidPtr)entry + *(buint *)sPtr++, format, KeyFrameMode.RotX); } if (code.IsRotationYFixed) { kf[KeyFrameMode.RotY, 0] = *sPtr++; } else { DecodeCHR0Frames(kf, (VoidPtr)entry + *(buint *)sPtr++, format, KeyFrameMode.RotY); } if (code.IsRotationZFixed) { kf[KeyFrameMode.RotZ, 0] = *sPtr++; } else { DecodeCHR0Frames(kf, (VoidPtr)entry + *(buint *)sPtr++, format, KeyFrameMode.RotZ); } } } if (code.HasTranslation) { format = code.TranslationDataFormat; if (code.IsTranslationIsotropic) { if (code.IsTranslationZFixed) { kf[KeyFrameMode.TransXYZ, 0] = *sPtr++; } else { DecodeCHR0Frames(kf, (VoidPtr)entry + *(buint *)sPtr++, format, KeyFrameMode.TransXYZ); } } else { if (code.IsTranslationXFixed) { kf[KeyFrameMode.TransX, 0] = *sPtr++; } else { DecodeCHR0Frames(kf, (VoidPtr)entry + *(buint *)sPtr++, format, KeyFrameMode.TransX); } if (code.IsTranslationYFixed) { kf[KeyFrameMode.TransY, 0] = *sPtr++; } else { DecodeCHR0Frames(kf, (VoidPtr)entry + *(buint *)sPtr++, format, KeyFrameMode.TransY); } if (code.IsTranslationZFixed) { kf[KeyFrameMode.TransZ, 0] = *sPtr++; } else { DecodeCHR0Frames(kf, (VoidPtr)entry + *(buint *)sPtr++, format, KeyFrameMode.TransZ); } } } return(kf); }