Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
AnimationData.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under GPL v3. See LICENSE.md for details.
3 using System;
4 using System.Collections.Generic;
5 using System.Linq;
6 using System.Runtime.InteropServices;
7 using SiliconStudio.Core;
8 using SiliconStudio.Core.Collections;
9 using SiliconStudio.Core.Serialization;
10 using SiliconStudio.Core.Serialization.Contents;
11 
12 namespace SiliconStudio.Paradox.DataModel
13 {
14  [DataContract(Inherited = true)]
15  public class AnimationData
16  {
17  public const int AnimationSortedValueBlock = 4096;
18 
19  public int AnimationSortedValueCount { get; set; }
20  public string[] TargetKeys { get; set; }
21  }
22 
23  public class AnimationData<T> : AnimationData
24  {
25  public AnimationInitialValues<T>[] AnimationInitialValues { get; set; }
26  public AnimationKeyValuePair<T>[][] AnimationSortedValues { get; set; }
27 
28  public TimeSpan Duration
29  {
30  get { return AnimationSortedValueCount == 0 ? TimeSpan.FromSeconds(1) : AnimationSortedValues[(AnimationSortedValueCount - 1) / AnimationSortedValueBlock][(AnimationSortedValueCount - 1) % AnimationSortedValueBlock].Value.Time; }
31  }
32 
33  public static AnimationData<T> FromAnimationChannels(IDictionary<string, AnimationCurve<T>> animationChannelsByName)
34  {
35  var result = new AnimationData<T>();
36 
37  // Build target object and target properties lists
38  var animationChannelsKeyValuePair = animationChannelsByName.ToList();
39  var animationChannels = animationChannelsKeyValuePair.Select(x => x.Value).ToList();
40  result.TargetKeys = animationChannelsKeyValuePair.Select(x => x.Key).ToArray();
41 
42  // Complexity _might_ be better by inserting directly in order instead of sorting later.
43  var animationValues = new List<AnimationKeyValuePair<T>>[animationChannels.Count];
44  result.AnimationInitialValues = new AnimationInitialValues<T>[animationChannels.Count];
45  for (int channelIndex = 0; channelIndex < animationChannels.Count; ++channelIndex)
46  {
47  var channel = animationChannels[channelIndex];
48  var animationChannelValues = animationValues[channelIndex] = new List<AnimationKeyValuePair<T>>();
49  if (channel.KeyFrames.Count > 0)
50  {
51  // Copy first two keys for when user start from beginning
52  result.AnimationInitialValues[channelIndex].InterpolationType = channel.InterpolationType;
53  result.AnimationInitialValues[channelIndex].Value1 = channel.KeyFrames[0];
54  result.AnimationInitialValues[channelIndex].Value2 = channel.KeyFrames[channel.KeyFrames.Count > 1 ? 1 : 0];
55 
56  // Copy remaining keys for playback
57  for (int keyIndex = 2; keyIndex < channel.KeyFrames.Count; ++keyIndex)
58  {
59  // We need animation values two keys in advance
60  var requiredTime = channel.KeyFrames[keyIndex - 2].Time;
61 
62  animationChannelValues.Add(new AnimationKeyValuePair<T> { ChannelIndex = channelIndex, RequiredTime = requiredTime, Value = channel.KeyFrames[keyIndex] });
63 
64  // Add last frame again so that we have ValueNext == ValueEnd at end of curve
65  if (keyIndex == channel.KeyFrames.Count - 1)
66  {
67  requiredTime = channel.KeyFrames[keyIndex - 1].Time; // important should not be "keyIndex - 2" or last frame will be skipped by update (two updates in a row)
68  animationChannelValues.Add(new AnimationKeyValuePair<T> { ChannelIndex = channelIndex, RequiredTime = requiredTime, Value = channel.KeyFrames[keyIndex] });
69  }
70  }
71  }
72  }
73 
74  // Gather all channel values in a single sorted array.
75  // Since each channel values is already sorted, we can just merge them preserving sort order.
76  // It is equivalent to:
77  // var animationConcatValues = Concat(animationValues);
78  // animationSortedValues = animationConcatValues.OrderBy(x => x.RequiredTime).ToArray();
79  int animationValueCount = 0;
80 
81  // Setup and counting
82  var animationChannelByNextTime = new MultiValueSortedDictionary<CompressedTimeSpan, KeyValuePair<int, int>>();
83  for (int channelIndex = 0; channelIndex < animationChannels.Count; ++channelIndex)
84  {
85  var animationChannelValues = animationValues[channelIndex];
86  animationValueCount += animationChannelValues.Count;
87  if (animationChannelValues.Count > 0)
88  animationChannelByNextTime.Add(animationChannelValues[0].RequiredTime, new KeyValuePair<int, int>(channelIndex, 0));
89  }
90 
91  // Initialize arrays
92  result.AnimationSortedValueCount = animationValueCount;
93  var animationSortedValues = new AnimationKeyValuePair<T>[(animationValueCount + AnimationSortedValueBlock - 1) / AnimationSortedValueBlock][];
94  result.AnimationSortedValues = animationSortedValues;
95  for (int i = 0; i < animationSortedValues.Length; ++i)
96  {
97  var remainingValueCount = animationValueCount - i * AnimationSortedValueBlock;
98  animationSortedValues[i] = new AnimationKeyValuePair<T>[Math.Min(AnimationSortedValueBlock, remainingValueCount)];
99  }
100 
101  // Fill with sorted values
102  animationValueCount = 0;
103  while (animationChannelByNextTime.Count > 0)
104  {
105  var firstItem = animationChannelByNextTime.First();
106  animationSortedValues[animationValueCount / AnimationSortedValueBlock][animationValueCount % AnimationSortedValueBlock] = animationValues[firstItem.Value.Key][firstItem.Value.Value];
107  animationValueCount++;
108  animationChannelByNextTime.Remove(firstItem);
109 
110  // Add next item for further processing (if any)
111  if (firstItem.Value.Value + 1 < animationValues[firstItem.Value.Key].Count)
112  animationChannelByNextTime.Add(animationValues[firstItem.Value.Key][firstItem.Value.Value + 1].RequiredTime, new KeyValuePair<int, int>(firstItem.Value.Key, firstItem.Value.Value + 1));
113  }
114 
115  return result;
116  }
117  }
118 
119  [DataContract]
120  [StructLayout(LayoutKind.Sequential)]
122  {
123  public string Name { get; set; }
124  }
125 
126  [DataContract]
127  [StructLayout(LayoutKind.Sequential)]
128  public struct AnimationKeyValuePair<T>
129  {
130  // 4 highest bit specifies format:
131  // - 0: float
132  // - 1: Vector3
133  // - 2: Quaternion
134  public int ChannelIndex;
137  }
138 
139  [DataContract]
140  [StructLayout(LayoutKind.Sequential)]
141  public struct AnimationInitialValues<T>
142  {
146  }
147 }
AnimationCurveInterpolationType
Describes how a curve should be interpolated.
static AnimationData< T > FromAnimationChannels(IDictionary< string, AnimationCurve< T >> animationChannelsByName)