public KeyframeEntry SetFrameValue(KeyFrameMode mode, int index, float value) { KeyframeEntry entry = null, root; for (int x = (int)mode & 0xF, y = x + ((int)mode >> 4); x < y; x++) { root = _keyRoots[x]; if ((root._prev == root) || (root._prev._index < index)) { entry = root; } else { for (entry = root._next; (entry != root) && (entry._index <= index); entry = entry._next) { ; } } entry = entry._prev; if (entry._index != index) { _keyCounts[x]++; entry.InsertAfter(entry = new KeyframeEntry(index, value)); } else { entry._value = value; } } return(entry); }
public void InsertBefore(KeyframeEntry entry) { _prev._next = entry; entry._prev = _prev; entry._next = this; _prev = entry; }
public KeyframeEntry Remove(KeyFrameMode mode, int index) { KeyframeEntry entry = null, root; for (int x = (int)mode & 0xF, y = x + ((int)mode >> 4); x < y; x++) { root = _keyRoots[x]; for (entry = root._next; (entry != root) && (entry._index < index); entry = entry._next) { ; } if (entry._index == index) { entry.Remove(); _keyCounts[x]--; } else { entry = null; } } return(entry); }
public float GetFrameValue(KeyFrameMode mode, int index, bool linear, bool loop) { KeyframeEntry entry, root = _keyRoots[(int)mode & 0xF]; if (index >= root._prev._index) { //if (!loop || root._prev == root._next) return(root._prev._value); } //else // return root._prev.Interpolate2(_frameCount - index + root._next._index, _linearRot || linear, _frameCount); if (index <= root._next._index) { //if (!loop || root._prev == root._next) return(root._next._value); } //else // return root._prev.Interpolate2(_frameCount - root._prev._index + index, _linearRot || linear, _frameCount); for (entry = root._next; (entry != root) && (entry._index < index); entry = entry._next) { if (entry._index == index) { return(entry._value); } } return(entry._prev.Interpolate(index - entry._prev._index, _linearRot || linear)); }
public KeyframeEntry SetFrameValue(int index, float value) { KeyframeEntry entry = null; if ((_keyRoot._prev == _keyRoot) || (_keyRoot._prev._index < index)) { entry = _keyRoot; } else { for (entry = _keyRoot._next; (entry != _keyRoot) && (entry._index <= index); entry = entry._next) { ; } } entry = entry._prev; if (entry._index != index) { _keyCount++; entry.InsertAfter(entry = new KeyframeEntry(index, value)); } else { entry._value = value; } return(entry); }
public float GetFrameValue(KeyFrameMode mode, int index) { KeyframeEntry entry, root = _keyRoots[(int)mode & 0xF]; if (index >= root._prev._index) { return(root._prev._value); } if (index <= root._next._index) { return(root._next._value); } for (entry = root._next; (entry != root) && (entry._index < index); entry = entry._next) { ; } if (entry._index == index) { return(entry._value); } return(entry._prev.Interpolate(index - entry._prev._index, _linearRot)); }
public void InsertAfter(KeyframeEntry entry) { _next._prev = entry; entry._next = _next; entry._prev = this; _next = entry; }
public float GetFrameValue(KeyFrameMode mode, int index) { KeyframeEntry entry, root = _keyRoots[(int)mode & 0xF]; if (index >= root._prev._index) { return(root._prev._value); } if (index <= root._next._index) { return(root._next._value); } //Find the entry just before the specified index for (entry = root._next; //Get the first entry (entry != root) && //Make sure it's not the root (entry._index < index); //Its index must be less than the current index entry = entry._next) //Get the next entry { if (entry._index == index) //The index is a keyframe { return(entry._value); //Return the value of the keyframe. } } //There was no keyframe... interpolate! return(entry._prev.Interpolate(index - entry._prev._index, _linearRot)); }
public static void Serialize(CHR0Node node, bool bake, string output) { using (StreamWriter file = new StreamWriter(output)) { file.WriteLine("animVersion 1.1;"); file.WriteLine("mayaVersion 2014 x64;"); file.WriteLine("timeUnit ntsc;"); file.WriteLine("linearUnit cm;"); file.WriteLine("angularUnit deg;"); file.WriteLine("startTime 1;"); file.WriteLine(String.Format("endTime {0};", node.FrameCount)); foreach (CHR0EntryNode e in node.Children) { KeyframeCollection c = e.Keyframes; for (int index = 0; index < 9; index++) { KeyFrameMode m = (KeyFrameMode)(index + 0x10); if (c[m] <= 0) { continue; } file.WriteLine(String.Format("anim {0}.{0}{1} {0}{1} {2} {3} {4} {5}", types[index / 3], axes[index % 3], e.Name, e.Index, index / 3, index % 3)); file.WriteLine("animData {"); file.WriteLine(" input time;"); file.WriteLine(String.Format(" output {0};", index > 2 && index < 6 ? "angular" : "linear")); file.WriteLine(" weighted 1;"); file.WriteLine(" preInfinity constant;"); file.WriteLine(" postInfinity constant;"); file.WriteLine(" keys {"); for (KeyframeEntry entry = c._keyRoots[index]._next; (entry != c._keyRoots[index]); entry = entry._next) { float angle = (float)Math.Atan(entry._tangent) * Maths._rad2degf; file.WriteLine(String.Format(" {0} {1} {2} {3} {4} {5} {6} {7} {8} {9} {10};", entry._index + 1, entry._value.ToString(CultureInfo.InvariantCulture.NumberFormat), "fixed", "fixed", "1", "1", "0", angle.ToString(CultureInfo.InvariantCulture.NumberFormat), (Math.Abs(entry._tangent) + 1).ToString(CultureInfo.InvariantCulture.NumberFormat), angle.ToString(CultureInfo.InvariantCulture.NumberFormat), (Math.Abs(entry._tangent) + 1).ToString(CultureInfo.InvariantCulture.NumberFormat))); } file.WriteLine(" }"); file.WriteLine("}"); } } } }
public KeyframeEntry GetKeyframe(KeyFrameMode mode, int index) { KeyframeEntry entry, root = _keyRoots[(int)mode & 0xF]; for (entry = root._next; (entry != root) && (entry._index < index); entry = entry._next) { ; } if (entry._index == index) { return(entry); } return(null); }
public void Delete(int index) { KeyframeEntry entry = null; for (entry = _keyRoot._prev; (entry != _keyRoot) && (entry._index >= index); entry = entry._prev) { if ((entry._index == index) || (--entry._index < 0)) { entry = entry._next; entry._prev.Remove(); _keyCount--; } } }
public void Insert(int index) { KeyframeEntry entry = null; for (entry = _keyRoot._prev; (entry != _keyRoot) && (entry._index >= index); entry = entry._prev) { if (++entry._index >= _frameLimit) { entry = entry._next; entry._prev.Remove(); _keyCount--; } } }
public float Interpolate(float offset, float span, KeyframeEntry next, bool forceLinear = false) { //Return this value if no offset from this keyframe if (offset == 0) { return(_value); } //Return next value if offset is to the next keyframe if (offset == span) { return(next._value); } //Get the difference in values float diff = next._value - _value; //Calculate a percentage from this keyframe to the next float time = offset / span; //Normalized, 0 to 1 bool prevDouble = _prev._index >= 0 && _prev._index == _index - 1; bool nextDouble = next._next._index >= 0 && next._next._index == next._index + 1; bool oneApart = _next._index == _index + 1; if (forceLinear) { return(_value + diff * time); } float tan = _tangent, nextTan = next._tangent; if (prevDouble || oneApart) { tan = (next._value - _value) / (next._index - _index); } if (nextDouble || oneApart) { nextTan = (next._value - _value) / (next._index - _index); } //Interpolate using a hermite curve float inv = time - 1.0f; //-1 to 0 return(_value + (offset * inv * ((inv * tan) + (time * nextTan))) + ((time * time) * (3.0f - 2.0f * time) * diff)); }
public void Insert(KeyFrameMode mode, int index) { KeyframeEntry entry = null, root; for (int x = (int)mode & 0xF, y = x + ((int)mode >> 4); x < y; x++) { root = _keyRoots[x]; for (entry = root._prev; (entry != root) && (entry._index >= index); entry = entry._prev) { if (++entry._index >= _frameLimit) { entry = entry._next; entry._prev.Remove(); _keyCounts[x]--; } } } }
public void Delete(int index, params int[] arrays) { KeyframeEntry entry = null, root; foreach (int x in arrays) { root = _keyArrays[x]._keyRoot; for (entry = root._prev; (entry != root) && (entry._index >= index); entry = entry._prev) { if ((entry._index == index) || (--entry._index < 0)) { entry = entry._next; entry._prev.Remove(); _keyArrays[x]._keyCount--; } } } }
public void Delete(KeyFrameMode mode, int index) { KeyframeEntry entry = null, root; for (int x = (int)mode & 0xF, y = x + ((int)mode >> 4); x < y; x++) { root = _keyRoots[x]; for (entry = root._prev; (entry != root) && (entry._index >= index); entry = entry._prev) { if ((entry._index == index) || (--entry._index < 0)) { entry = entry._next; entry._prev.Remove(); _keyCounts[x]--; } } } }
public void Insert(int index, params int[] arrays) { KeyframeEntry entry = null, root; foreach (int x in arrays) { root = _keyArrays[x]._keyRoot; for (entry = root._prev; (entry != root) && (entry._index >= index); entry = entry._prev) { if (++entry._index >= _frameLimit) { entry = entry._next; entry._prev.Remove(); _keyArrays[x]._keyCount--; } } } }
public KeyframeEntry SetFrameValue(int index, float value, bool parsing = false) { KeyframeEntry entry = null; if ((_keyRoot._prev == _keyRoot) || (_keyRoot._prev._index < index)) { entry = _keyRoot; } else { for (entry = _keyRoot._next; (entry != _keyRoot) && (entry._index <= index); entry = entry._next) { ; } } entry = entry._prev; if (entry._index != index) { _keyCount++; entry.InsertAfter(entry = new KeyframeEntry(index, value)); } else { //There can be up to two keyframes with the same index. if (!parsing) { entry._value = value; //Do this when editing } else { //And this when parsing _keyCount++; KeyframeEntry temp = new KeyframeEntry(index, value); entry.InsertAfter(temp); entry = temp; } } return(entry); }
public KeyframeEntry Remove(int index) { KeyframeEntry entry = null; for (entry = _keyRoot._next; (entry != _keyRoot) && (entry._index < index); entry = entry._next) { ; } if (entry._index == index) { entry.Remove(); _keyCount--; } else { entry = null; } return(entry); }
internal KeyframeEntry Remove(int arrayIndex, int index) { KeyframeEntry entry = null, root = _keyArrays[arrayIndex]._keyRoot; for (entry = root._next; (entry != root) && (entry._index < index); entry = entry._next) { ; } if (entry._index == index) { entry.Remove(); _keyArrays[arrayIndex]._keyCount--; } else { entry = null; } return(entry); }
protected override void OnMouseDown(MouseEventArgs e) { bool t = _selKey != _hiKey; if (AllKeyframes) _dragging = (_selKey = _hiKey) != null || Cursor == Cursors.VSplit || _slopePoint != null; else { if (_hiKey != null) _selKey = _hiKey; _dragging = _selKey != null && (_slopePoint != null || Cursor == Cursors.Hand); } if (_selKey != null) { if (_slopePoint == null) { int min = GetKeyframeMinIndex(); _prevX = _selKey._index - min; _prevY = _selKey._value; } _frame = _selKey._index; if ((_dragging && !Has3PlusVals()) || _slopePoint != null) _lockIncs = true; } if (t) { Invalidate(); if (SelectedKeyframeChanged != null) SelectedKeyframeChanged(this, null); } }
private static int EvaluateSRT0Group(ref SRT0Code code, KeyframeCollection kf, int group, ref int entrySize) { //SRT0s always use I12 //group //0 = scale //1 = rot //2 = trans int index = group * 3; int numFrames = kf.FrameCount; int dataLen = 0; KeyframeEntry[] roots = new KeyframeEntry[2]; bool exist = false; bool isotropic = group == 0; int* count = stackalloc int[2]; bool* isExist = stackalloc bool[2]; bool* isFixed = stackalloc bool[2]; for (int i = 0; i < (group == 1 ? 1 : 2); i++) { roots[i] = kf._keyRoots[index + i]; count[i] = kf._keyCounts[index + i]; isExist[i] = count[i] > 0; isFixed[i] = count[i] <= 1; } if (exist = isExist[0] || isExist[1]) { if (group == 0) { if (isFixed[0] != isFixed[1]) isotropic = false; else if (count[0] != count[1]) isotropic = false; else { KeyframeEntry e1 = roots[0], e2 = roots[1]; for (int i = count[0]; i-- > 0; ) { e1 = e1._next; e2 = e2._next; if ((e1._index != e2._index) || (e1._value != e2._value)) { isotropic = false; break; } } } } } if (group == 0 && !isotropic) code.ScaleIsotropic = false; for (int i = 0; i < (group == 1 ? 1 : 2); i++) { if (exist) { switch (group) { case 0: code.NoScale = false; break; case 1: code.NoRotation = false; break; case 2: code.NoTranslation = false; break; } if (!(group == 0 && i == 1 && code.ScaleIsotropic)) entrySize += 4; if (!isFixed[i]) { switch (group) { case 0: switch (i) { case 0: code.FixedScaleX = false; break; case 1: code.FixedScaleY = false; break; } break; case 1: code.FixedRotation = false; break; case 2: switch (i) { case 0: code.FixedX = false; break; case 1: code.FixedY = false; break; } break; } if (!(group == 0 && i == 1 && code.ScaleIsotropic)) dataLen += 8 + (count[i] * 12); } } } return dataLen; }
private static void DecodeCHR0Frames(KeyframeCollection kf, void *dataAddr, AnimDataFormat format, KeyFrameMode mode) { int fCount; float vStep, vBase; switch (format) { case AnimDataFormat.I4: { I4Header *header = (I4Header *)dataAddr; fCount = header->_entries; vStep = header->_step; vBase = header->_base; I4Entry *entry = header->Data; for (int i = 0; i < fCount; i++, entry++) { kf.SetFrameValue(mode, entry->FrameIndex, vBase + (entry->Step * vStep))._tangent = entry->Tangent; } break; } case AnimDataFormat.I6: { I6Header *header = (I6Header *)dataAddr; fCount = header->_numFrames; vStep = header->_step; vBase = header->_base; I6Entry *entry = header->Data; for (int i = 0; i < fCount; i++, entry++) { kf.SetFrameValue(mode, entry->FrameIndex, vBase + (entry->_step * vStep))._tangent = entry->Tangent; } break; } case AnimDataFormat.I12: { I12Header *header = (I12Header *)dataAddr; fCount = header->_numFrames; I12Entry *entry = header->Data; for (int i = 0; i < fCount; i++, entry++) { kf.SetFrameValue(mode, (int)entry->_index, entry->_value)._tangent = entry->_tangent; } break; } case AnimDataFormat.L1: { L1Header *header = (L1Header *)dataAddr; vStep = header->_step; vBase = header->_base; byte *sPtr = header->Data; for (int i = 0; i < kf.FrameCount; i++) { kf[mode, i] = vBase + (*sPtr++ *vStep); } KeyframeEntry root = kf._keyRoots[(int)mode & 0xF]; for (KeyframeEntry entry = root._next; entry != root; entry = entry._next) { entry.GenerateTangent(); } break; } case AnimDataFormat.L2: { L1Header *header = (L1Header *)dataAddr; vStep = header->_step; vBase = header->_base; bushort *sPtr = (bushort *)header->Data; for (int i = 0; i < kf.FrameCount; i++) { kf[mode, i] = vBase + (*sPtr++ *vStep); } KeyframeEntry root = kf._keyRoots[(int)mode & 0xF]; for (KeyframeEntry entry = root._next; entry != root; entry = entry._next) { entry.GenerateTangent(); } break; } case AnimDataFormat.L4: { bfloat *sPtr = (bfloat *)dataAddr; for (int i = 0; i < kf.FrameCount; i++) { kf[mode, i] = *sPtr++; } KeyframeEntry root = kf._keyRoots[(int)mode & 0xF]; for (KeyframeEntry entry = root._next; entry != root; entry = entry._next) { entry.GenerateTangent(); } break; } } }
public KeyframeEntry(int index, float value) { _index = index; _prev = _next = this; _value = value; }
public static void Serialize(CHR0Node node, string output, MDL0Node model) { model.Populate(); using (StreamWriter file = new StreamWriter(output)) { file.WriteLine("animVersion 1.1;"); file.WriteLine("mayaVersion 2015;"); file.WriteLine("timeUnit ntscf;"); file.WriteLine("linearUnit cm;"); file.WriteLine("angularUnit deg;"); file.WriteLine("startTime 0;"); file.WriteLine($"endTime {node.FrameCount - 1};"); foreach (MDL0BoneNode b in model.AllBones) { CHR0EntryNode e = node.FindChild(b.Name, true) as CHR0EntryNode; if (e == null) { file.WriteLine($"anim {b.Name} 0 {b.Children.Count} 0;"); continue; } KeyframeCollection c = e.Keyframes; int counter = 0; for (int index = 0; index < 9; index++) { KeyframeArray array = c._keyArrays[index]; if (array._keyCount <= 0) { continue; } file.WriteLine("anim {0}.{0}{1} {0}{1} {2} {3} {4} {5};", types[index / 3], axes[index % 3], e.Name, 0, b.Children.Count, counter); file.WriteLine("animData {"); file.WriteLine(" input time;"); file.WriteLine($" output {(index > 2 && index < 6 ? "angular" : "linear")};"); file.WriteLine(" weighted 1;"); file.WriteLine(" preInfinity constant;"); file.WriteLine(" postInfinity constant;"); file.WriteLine(" keys {"); for (KeyframeEntry entry = array._keyRoot._next; entry != array._keyRoot; entry = entry._next) { float angle = (float)Math.Atan(entry._tangent) * Maths._rad2degf; file.WriteLine(" {0} {1} {2} {3} {4} {5} {6} {7} {8} {9} {10};", entry._index, entry._value.ToString(CultureInfo.InvariantCulture.NumberFormat), "fixed", "fixed", "1", "1", "0", angle.ToString(CultureInfo.InvariantCulture.NumberFormat), "1", angle.ToString(CultureInfo.InvariantCulture.NumberFormat), "1"); } file.WriteLine(" }"); file.WriteLine("}"); counter++; } } } }
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); }
private static int EncodeEntry(int index, AnimDataFormat format, KeyframeCollection kf, VoidPtr addr) { int numFrames = kf.FrameLimit; KeyframeEntry frame, root = kf._keyArrays[index]._keyRoot; bfloat * pVal = (bfloat *)addr; float val, frameScale = numFrames <= 1 ? 1 : 1.0f / (numFrames - 1); float min, max, stride, step; int span, i; int keyCount = kf._keyArrays[index]._keyCount; if (format == AnimDataFormat.L4) { //Use all frames, just in case not all frames are key. for (i = 0; i < numFrames; i++) { *pVal++ = kf[i, index]; } return(numFrames * 4); } if (format == AnimDataFormat.I12) { I12Header *header = (I12Header *)addr; * header = new I12Header(keyCount, frameScale); I12Entry *entry = header->Data; for (frame = root._next; frame._index != -1; frame = frame._next) { *entry++ = new I12Entry(frame._index, frame._value, frame._tangent); } return(keyCount * 12 + 8); } //Get floor/ceil/stride min = float.MaxValue; max = float.MinValue; for (frame = root._next; frame != root; frame = frame._next) { val = frame._value; if (val > max) { max = val; } if (val < min) { min = val; } } stride = max - min; if (format == AnimDataFormat.L1) { //Find best span span = EvalSpan(255, 32, min, stride, root, true); step = stride / span; L1Header *header = (L1Header *)addr; * header = new L1Header(step, min); byte *dPtr = header->Data; for (i = 0; i < numFrames; i++) { *dPtr++ = (byte)((kf[i, index] - min) / step + 0.5f); } //Fill remaining bytes while ((i++ & 3) != 0) { *dPtr++ = 0; } return((8 + numFrames).Align(4)); } if (format == AnimDataFormat.I4) { //Find best span span = EvalSpan(4095, 32, min, stride, root, false); step = stride / span; I4Header *header = (I4Header *)addr; * header = new I4Header(keyCount, frameScale, step, min); I4Entry *entry = header->Data; for (frame = root._next; frame._index != -1; frame = frame._next) { val = (frame._value - min) / step; val += val < 0 ? -0.5f : 0.5f; *entry++ = new I4Entry(frame._index, (int)val, frame._tangent); } return(keyCount * 4 + 16); } if (format == AnimDataFormat.I6) { //Find best span span = EvalSpan(65535, 32, min, stride, root, false); step = stride / span; I6Header *header = (I6Header *)addr; * header = new I6Header(keyCount, frameScale, step, min); I6Entry *entry = header->Data; for (frame = root._next; frame._index != -1; frame = frame._next) { val = (frame._value - min) / step; val += val < 0 ? -0.5f : 0.5f; *entry++ = new I6Entry(frame._index, (int)val, frame._tangent); } //Fill remaining bytes if ((keyCount & 1) != 0) { entry->_data = 0; } return((keyCount * 6 + 16).Align(4)); } return(0); }
public KeyframeEntry SetFrameValue(KeyFrameMode mode, int index, float value) { KeyframeEntry entry = null, root; for (int x = (int)mode & 0xF, y = x + ((int)mode >> 4); x < y; x++) { root = _keyRoots[x]; if ((root._prev == root) || (root._prev._index < index)) entry = root; else for (entry = root._next; (entry != root) && (entry._index <= index); entry = entry._next) ; entry = entry._prev; if (entry._index != index) { _keyCounts[x]++; entry.InsertAfter(entry = new KeyframeEntry(index, value)); } else entry._value = value; } return entry; }
public KeyframeEntry(int index, float value) { _index = index; _prev = _next = this; _value = value; }
public void InsertAfter(KeyframeEntry entry) { _next._prev = entry; entry._next = _next; entry._prev = this; _next = entry; }
public void InsertBefore(KeyframeEntry entry) { _prev._next = entry; entry._prev = _prev; entry._next = this; _prev = entry; }
private static int EvaluateCHR0Group(ref AnimationCode code, KeyframeCollection kf, int group, ref int entrySize) { int index = group * 3; int numFrames = kf.FrameCount; 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 = stackalloc int[3]; bool* isExist = stackalloc bool[3]; bool* isFixed = stackalloc bool[3]; bool* isScalable = stackalloc bool[3]; float* floor = stackalloc float[3]; float* ceil = stackalloc 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._keyRoots[index + i]; count[i] = kf._keyCounts[index + i]; 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[KeyFrameMode.ScaleX + index + i, x]; 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; }
private void DrawTangent(KeyframeEntry e, float xMin) { int xVal = e._index; float yVal = e._value; float tan = e._tangent; float i1 = -(_tanLen / 2); float i2 = (_tanLen / 2); float p = (float)Math.Sqrt(_precision / 4.0f); Vector2 one = new Vector2((xVal + i1 * p - xMin) * _xScale, (yVal - _minVal + tan * i1 * p) * _yScale); Vector2 two = new Vector2((xVal + i2 * p - xMin) * _xScale, (yVal - _minVal + tan * i2 * p) * _yScale); if (e == _selKey) { GL.Color4(Color.Purple); GL.Begin(BeginMode.Points); GL.Vertex2(one._x, one._y); GL.Vertex2(two._x, two._y); GL.End(); } else { GL.Color4(Color.Green); float angle = (float)Math.Atan((tan * _yScale) / _xScale) * Maths._rad2degf; GL.PushMatrix(); GL.Translate(one._x, one._y, 0.0f); GL.Rotate(angle - 180.0f, 0, 0, 1); GL.Begin(BeginMode.LineStrip); GL.Vertex2(-7.0f, 3.5f); GL.Vertex2(0.0f, 0.0f); GL.Vertex2(-7.0f, -3.5f); GL.End(); GL.PopMatrix(); GL.PushMatrix(); GL.Translate(two._x, two._y, 0.0f); GL.Rotate(angle, 0, 0, 1); GL.Begin(BeginMode.LineStrip); GL.Vertex2(-7.0f, 3.5f); GL.Vertex2(0.0f, 0.0f); GL.Vertex2(-7.0f, -3.5f); GL.End(); GL.PopMatrix(); } GL.Begin(BeginMode.LineStrip); GL.Vertex2(one._x, one._y); GL.Vertex2(two._x, two._y); GL.End(); }
public KeyframeEntry SetFrameValue(int index, float value) { KeyframeEntry entry = null; if ((_keyRoot._prev == _keyRoot) || (_keyRoot._prev._index < index)) entry = _keyRoot; else for (entry = _keyRoot._next; (entry != _keyRoot) && (entry._index <= index); entry = entry._next) ; entry = entry._prev; if (entry._index != index) { _keyCount++; entry.InsertAfter(entry = new KeyframeEntry(index, value)); } else entry._value = value; return entry; }
public static void Serialize(CHR0Node node, bool bake, string output) { MDL0Node model; OpenFileDialog dlgOpen = new OpenFileDialog(); dlgOpen.Filter = "MDL0 Model (*.mdl0)|*.mdl0"; dlgOpen.Title = "Select the model this animation is for..."; if (dlgOpen.ShowDialog() != DialogResult.OK || (model = (MDL0Node)NodeFactory.FromFile(null, dlgOpen.FileName)) == null) { return; } using (StreamWriter file = new StreamWriter(output)) { file.WriteLine("animVersion 1.1;"); file.WriteLine("mayaVersion 2015;"); file.WriteLine("timeUnit ntsc;"); file.WriteLine("linearUnit cm;"); file.WriteLine("angularUnit deg;"); file.WriteLine("startTime 1;"); file.WriteLine(String.Format("endTime {0};", node.FrameCount)); foreach (CHR0EntryNode e in node.Children) { MDL0BoneNode bone = model.FindChild("Bones/" + e.Name, true) as MDL0BoneNode; if (bone == null) { continue; } KeyframeCollection c = e.Keyframes; for (int index = 0; index < 9; index++) { KeyframeArray array = c._keyArrays[index]; if (array._keyCount <= 0) { continue; } file.WriteLine(String.Format("anim {0}.{0}{1} {0}{1} {2} {3} {4} {5}", types[index / 3], axes[index % 3], e.Name, 0, bone.Children.Count, index < 6 ? (index + 3) : index - 6)); file.WriteLine("animData {"); file.WriteLine(" input time;"); file.WriteLine(String.Format(" output {0};", index > 2 && index < 6 ? "angular" : "linear")); file.WriteLine(" weighted 0;"); file.WriteLine(" preInfinity constant;"); file.WriteLine(" postInfinity constant;"); file.WriteLine(" keys {"); for (KeyframeEntry entry = array._keyRoot._next; (entry != array._keyRoot); entry = entry._next) { bool single = entry._next._index < 0 && entry._prev._index < 0; //float angle = (float)Math.Atan(entry._tangent) * Maths._rad2degf; //if (single) { file.WriteLine(String.Format(" {0} {1} {2} {2} {3} {4} {5};", entry._index + 1, entry._value.ToString(CultureInfo.InvariantCulture.NumberFormat), "auto",//single ? "auto" : "fixed", "1", "1", "0")); } } file.WriteLine(" }"); file.WriteLine("}"); } } } }
public FloatKeyframe(KeyframeEntry e) { _entry = e; }
public static int EvalSpan(int maxSpan, int maxIterations, float valBase, float valStride, KeyframeEntry root, bool evalAll) { KeyframeEntry entry; float bestError = float.MaxValue; float worstError; float step, error, val; int bestSpan = maxSpan, count; if (maxIterations <= 0) { maxIterations = maxSpan - 2; } for (int i = 0; i < maxIterations; i++) { worstError = float.MinValue; step = valStride / maxSpan; for (entry = root._next; entry != root; entry = entry._next) { if (evalAll) { count = entry._next == root ? 1 : entry._next._index - entry._index; } else { count = 1; } for (int x = 0; x < count; x++) { val = entry.Interpolate(x); error = (val - valBase) / step + 0.5f; error = Math.Abs(val - (valBase + (int)error * step)); if (error > scaleError) { goto Next; } if (error > worstError) { worstError = error; } } } if (worstError < bestError) { bestError = worstError; bestSpan = maxSpan; } Next: maxSpan--; } return(bestSpan); }
public FloatKeyframe() { _entry = new KeyframeEntry(-1, 0); }
private static int EvaluateSRT0Group(ref SRT0Code code, KeyframeCollection kf, int group, ref int entrySize) { //SRT0s always use I12 //group //0 = scale //1 = rot //2 = trans int index = group == 0 ? 0 : group == 1 ? 2 : 3; int numFrames = kf.FrameLimit; int dataLen = 0; KeyframeEntry[] roots = new KeyframeEntry[2]; bool exist = false; bool isotropic = group == 0; int[] count = new int[2]; bool[] isExist = new bool[2]; bool[] isFixed = new bool[2]; for (int i = 0; i < (group == 1 ? 1 : 2); i++) { 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 (exist = isExist[0] || isExist[1]) { if (group == 0) { if (isFixed[0] != isFixed[1]) { isotropic = false; } else if (count[0] != count[1]) { isotropic = false; } else { KeyframeEntry e1 = roots[0], e2 = roots[1]; for (int i = count[0]; i-- > 0;) { e1 = e1._next; e2 = e2._next; if (e1._index != e2._index || e1._value != e2._value) { isotropic = false; break; } } } } } if (group == 0 && !isotropic) { code.ScaleIsotropic = false; } for (int i = 0; i < (group == 1 ? 1 : 2); i++) { if (exist) { switch (group) { case 0: code.NoScale = false; break; case 1: code.NoRotation = false; break; case 2: code.NoTranslation = false; break; } if (!(group == 0 && i == 1 && code.ScaleIsotropic)) { entrySize += 4; } if (!isFixed[i]) { switch (group) { case 0: switch (i) { case 0: code.FixedScaleX = false; break; case 1: code.FixedScaleY = false; break; } break; case 1: code.FixedRotation = false; break; case 2: switch (i) { case 0: code.FixedX = false; break; case 1: code.FixedY = false; break; } break; } if (!(group == 0 && i == 1 && code.ScaleIsotropic)) { dataLen += 8 + count[i] * 12; } } } } return(dataLen); }
public KeyframeArray(int limit, float defaultValue = 0) { _frameLimit = limit; _keyRoot = new KeyframeEntry(-1, defaultValue); }
public static CHR0Node Read(string input) { CHR0Node node = new CHR0Node { _name = Path.GetFileNameWithoutExtension(input) }; using (StreamReader file = new StreamReader(input)) { float start = 0.0f; float end = 0.0f; string line; while (true) { line = file.ReadLine(); if (line == null) { break; } int i = line.IndexOf(' '); string tag = line.Substring(0, i); if (tag == "anim") { break; } string val = line.Substring(i + 1, line.IndexOf(';') - i - 1); switch (tag) { case "startTime": case "startUnitless": float.TryParse(val, out start); break; case "endTime": case "endUnitless": float.TryParse(val, out end); break; case "animVersion": case "mayaVersion": case "timeUnit": case "linearUnit": case "angularUnit": default: break; } } int frameCount = (int)(end - start + 1.5f); node.FrameCount = frameCount; while (true) { if (line == null) { break; } string[] anim = line.Split(' '); if (anim.Length != 7) { while ((line = file.ReadLine()) != null && !line.StartsWith("anim ")) { ; } continue; } string t = anim[2]; string bone = anim[3]; int mode = -1; if (t.StartsWith("scale")) { if (t.EndsWith("X")) { mode = 0; } else if (t.EndsWith("Y")) { mode = 1; } else if (t.EndsWith("Z")) { mode = 2; } } else if (t.StartsWith("rotate")) { if (t.EndsWith("X")) { mode = 3; } else if (t.EndsWith("Y")) { mode = 4; } else if (t.EndsWith("Z")) { mode = 5; } } else if (t.StartsWith("translate")) { if (t.EndsWith("X")) { mode = 6; } else if (t.EndsWith("Y")) { mode = 7; } else if (t.EndsWith("Z")) { mode = 8; } } if (mode == -1) { while ((line = file.ReadLine()) != null && !line.StartsWith("anim ")) { ; } continue; } line = file.ReadLine(); if (line.StartsWith("animData")) { CHR0EntryNode e; if ((e = node.FindChild(bone, false) as CHR0EntryNode) == null) { e = new CHR0EntryNode { _name = bone }; node.AddChild(e); } while (true) { line = file.ReadLine().TrimStart(); int i = line.IndexOf(' '); if (i < 0) { break; } string tag = line.Substring(0, i); if (tag == "keys") { List <KeyframeEntry> l = new List <KeyframeEntry>(); while (true) { line = file.ReadLine().TrimStart(); if (line == "}") { break; } string[] s = line.Split(' '); for (int si = 0; si < s.Length; si++) { s[si] = s[si].Trim('\n', ';', ' '); } float.TryParse(s[0], NumberStyles.Number, CultureInfo.InvariantCulture, out float inVal); float.TryParse(s[1], NumberStyles.Number, CultureInfo.InvariantCulture, out float outVal); float weight1 = 0; float weight2 = 0; float angle1 = 0; float angle2 = 0; bool firstFixed = false; bool secondFixed = false; switch (s[2]) { case "linear": case "spline": case "auto": break; case "fixed": firstFixed = true; float.TryParse(s[7], NumberStyles.Number, CultureInfo.InvariantCulture, out angle1); float.TryParse(s[8], NumberStyles.Number, CultureInfo.InvariantCulture, out weight1); break; } switch (s[3]) { case "linear": case "spline": case "auto": break; case "fixed": secondFixed = true; if (firstFixed) { float.TryParse(s[9], NumberStyles.Number, CultureInfo.InvariantCulture, out angle2); float.TryParse(s[10], NumberStyles.Number, CultureInfo.InvariantCulture, out weight2); } else { float.TryParse(s[7], NumberStyles.Number, CultureInfo.InvariantCulture, out angle2); float.TryParse(s[8], NumberStyles.Number, CultureInfo.InvariantCulture, out weight2); } break; } bool anyFixed = secondFixed || firstFixed; bool bothFixed = secondFixed && firstFixed; KeyframeEntry x = e.SetKeyframe(mode, (int)(inVal - 0.5f), outVal, true); if (!anyFixed) { l.Add(x); } else { if (bothFixed) { x._tangent = (float)Math.Tan((angle1 + angle2) / 2 * Maths._deg2radf) * ((weight1 + weight2) / 2); } else if (firstFixed) { x._tangent = (float)Math.Tan(angle1 * Maths._deg2radf) * weight1; } else { x._tangent = (float)Math.Tan(angle2 * Maths._deg2radf) * weight2; } } } foreach (KeyframeEntry w in l) { w.GenerateTangent(); } } else { int z = line.IndexOf(';') - i - 1; if (z < 0) { continue; } string val = line.Substring(i + 1, z); switch (tag) { case "input": break; case "output": break; case "weighted": break; case "inputUnit": break; case "outputUnit": break; case "preInfinity": case "postInfinity": default: break; } } } } line = file.ReadLine(); } } return(node); }
public static int EvalSpan(int maxSpan, int maxIterations, float valBase, float valStride, KeyframeEntry root, bool evalAll, bool linear) { KeyframeEntry entry; float bestError = float.MaxValue; float worstError; float step, error, val; int bestSpan = maxSpan, count; if (maxIterations <= 0) maxIterations = maxSpan - 2; for (int i = 0; i < maxIterations; i++) { worstError = float.MinValue; step = valStride / maxSpan; for (entry = root._next; entry != root; entry = entry._next) { if (evalAll) count = (entry._next == root) ? 1 : (entry._next._index - entry._index); else count = 1; for (int x = 0; x < count; x++) { val = entry.Interpolate(x, linear); error = (val - valBase) / step + 0.5f; error = Math.Abs(val - (valBase + ((int)error * step))); if (error > scaleError) goto Next; if (error > worstError) worstError = error; } } if (worstError < bestError) { bestError = worstError; bestSpan = maxSpan; } Next: maxSpan--; } return bestSpan; }