Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
AnimationCurveEvaluatorOptimizedGroup.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 SiliconStudio.Core;
5 using SiliconStudio.Core.Collections;
6 using SiliconStudio.Core.Extensions;
7 
8 namespace SiliconStudio.Paradox.DataModel
9 {
10  public abstract class AnimationCurveEvaluatorOptimizedGroup<T> : AnimationCurveEvaluatorGroup
11  {
12  private int animationSortedIndex;
13  private AnimationData<T> animationData;
14  private CompressedTimeSpan currentTime;
15  private FastListStruct<Channel> channels = new FastListStruct<Channel>(8);
16 
17  public void Initialize(AnimationData<T> animationData)
18  {
19  this.animationData = animationData;
20 
21  foreach (var channel in animationData.AnimationInitialValues)
22  {
23  channels.Add(new Channel { InterpolationType = channel.InterpolationType });
24  }
25 
26  // Setting infinite time means next time a rewind will be performed and initial values will be populated properly
27  currentTime = CompressedTimeSpan.MaxValue;
28  }
29 
30  public void Cleanup()
31  {
32  animationData = null;
33  channels.Clear();
34  }
35 
36  public void AddChannel(string name, int offset)
37  {
38  var targetKeys = animationData.TargetKeys;
39  for (int i = 0; i < targetKeys.Length; ++i)
40  {
41  if (targetKeys[i] == name)
42  {
43  var channel = channels.Items[i];
44  channel.Offset = offset;
45  channels.Items[i] = channel;
46  break;
47  }
48  }
49  }
50 
51  public override void Evaluate(CompressedTimeSpan newTime, IntPtr location)
52  {
53  if (animationData == null)
54  return;
55 
56  SetTime(newTime);
57 
58  var channelCount = channels.Count;
59  var channelItems = channels.Items;
60 
61  for (int i = 0; i < channelCount; ++i)
62  {
63  ProcessChannel(ref channelItems[i], newTime, location);
64  }
65  }
66 
67  public override void Evaluate(CompressedTimeSpan newTime, object[] results)
68  {
69  throw new NotImplementedException();
70  }
71 
72  protected void ProcessChannel(ref Channel channel, CompressedTimeSpan currentTime, IntPtr location)
73  {
74  var startTime = channel.ValueStart.Time;
75 
76  // Sampling before start (should not really happen because we add a keyframe at TimeSpan.Zero, but let's keep it in case it changes later.
77  if (currentTime <= startTime)
78  {
79  Utilities.UnsafeWrite(location + channel.Offset, ref channel.ValueStart.Value);
80  return;
81  }
82 
83  var endTime = channel.ValueEnd.Time;
84 
85  // Sampling after end
86  if (currentTime >= endTime)
87  {
88  Utilities.UnsafeWrite(location + channel.Offset, ref channel.ValueEnd.Value);
89  return;
90  }
91 
92  float factor = (float)(currentTime.Ticks - startTime.Ticks) / (float)(endTime.Ticks - startTime.Ticks);
93 
94  ProcessChannel(ref channel, currentTime, location, factor);
95  }
96 
97  protected abstract void ProcessChannel(ref Channel channel, CompressedTimeSpan currentTime, IntPtr location, float factor);
98 
99  private void SetTime(CompressedTimeSpan timeSpan)
100  {
101  // TODO: Add jump frames to do faster seeking.
102  // If user seek back, need to start from beginning
103  if (timeSpan < currentTime)
104  {
105  // Always start from beginning after a reset
106  animationSortedIndex = 0;
107  for (int channelIndex = 0; channelIndex < animationData.AnimationInitialValues.Length; ++channelIndex)
108  {
109  InitializeAnimation(ref channels.Items[channelIndex], ref animationData.AnimationInitialValues[channelIndex]);
110  }
111  }
112 
113  currentTime = timeSpan;
114  var animationSortedValueCount = animationData.AnimationSortedValueCount;
115  var animationSortedValues = animationData.AnimationSortedValues;
116 
117  if (animationSortedValueCount == 0)
118  return;
119 
120  // Advance until requested time is reached
121  while (animationSortedIndex < animationSortedValueCount
122  && animationSortedValues[animationSortedIndex / AnimationData.AnimationSortedValueBlock][animationSortedIndex % AnimationData.AnimationSortedValueBlock].RequiredTime <= currentTime)
123  {
124  //int channelIndex = animationSortedValues[animationSortedIndex / animationSortedValueBlock][animationSortedIndex % animationSortedValueBlock].ChannelIndex;
125  UpdateAnimation(ref animationSortedValues[animationSortedIndex / AnimationData.AnimationSortedValueBlock][animationSortedIndex % AnimationData.AnimationSortedValueBlock]);
126  animationSortedIndex++;
127  }
128 
129  currentTime = timeSpan;
130  }
131 
132  private static void InitializeAnimation(ref Channel animationChannel, ref AnimationInitialValues<T> animationValue)
133  {
134  animationChannel.ValuePrev = animationValue.Value1;
135  animationChannel.ValueStart = animationValue.Value1;
136  animationChannel.ValueEnd = animationValue.Value1;
137  animationChannel.ValueNext = animationValue.Value2;
138  }
139 
140  private void UpdateAnimation(ref AnimationKeyValuePair<T> animationValue)
141  {
142  UpdateAnimation(ref channels.Items[animationValue.ChannelIndex], ref animationValue.Value);
143  }
144 
145  private static void UpdateAnimation(ref Channel animationChannel, ref KeyFrameData<T> animationValue)
146  {
147  animationChannel.ValuePrev = animationChannel.ValueStart;
148  animationChannel.ValueStart = animationChannel.ValueEnd;
149  animationChannel.ValueEnd = animationChannel.ValueNext;
150  animationChannel.ValueNext = animationValue;
151  }
152 
153  protected struct Channel
154  {
155  public int Offset;
161  }
162  }
163 }
AnimationCurveInterpolationType
Describes how a curve should be interpolated.
void ProcessChannel(ref Channel channel, CompressedTimeSpan currentTime, IntPtr location)