Motive Animation System
An open source project by FPL.
 All Classes Functions Variables Typedefs Friends Pages
processor.h
1 // Copyright 2014 Google Inc. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef MOTIVE_PROCESSOR_H_
16 #define MOTIVE_PROCESSOR_H_
17 
18 #include <vector>
19 
20 #include "fplutil/index_allocator.h"
21 #include "motive/common.h"
22 #include "motive/math/compact_spline.h"
23 #include "motive/math/vector_converter.h"
24 #include "motive/target.h"
25 
26 namespace motive {
27 
28 class MatrixOpArray;
29 class Motivator;
30 class MotiveEngine;
31 class RigAnim;
32 
33 /// @class MotiveProcessor
34 /// @brief A MotiveProcessor processes *all* instances of one type of Motivator.
35 ///
36 /// Each derivation of MotiveProcessor is one animation algorithm. It holds
37 /// all the data for all Motivators that are currently using that animation
38 /// algorithm.
39 ///
40 /// We pool the processing for potential optimization opportunities. We may have
41 /// hundreds of smoothly-interpolating one-dimensional Motivators, for example.
42 /// It's nice to be able to update those 4 or 8 or 16 at a time using SIMD.
43 /// And it's nice to have the data gathered in one spot if we want to use
44 /// multiple threads.
45 ///
46 /// MotiveProcessors exists in the internal API. For the external API, please
47 /// see Motivator.
48 ///
49 /// Users can create their own Motivator algorithms by deriving from
50 /// MotiveProcessor. MotiveProcessors must have a factory that's registered with
51 /// the MotiveEngine (please see MotiveEngine for details). Once registered,
52 /// you can use your new Motivator algorithm by calling Motivator::Initialize()
53 /// with Init::type set to your MotiveProcessor's MotivatorType.
54 ///
55 /// MotiveProcessors run on mathfu types. Please see the specializations below
56 /// for MotiveProcessors of various dimensions.
57 ///
59  public:
61  : index_allocator_(allocator_callbacks_),
62  benchmark_id_for_advance_frame_(-1),
63  benchmark_id_for_init_(-1) {
64  allocator_callbacks_.set_processor(this);
65  }
66  virtual ~MotiveProcessor();
67 
68  /// Instantiate motivator data inside the MotiveProcessor, and initialize
69  /// `motivator` as a reference to that data.
70  ///
71  /// This function should only be called by Motivator::Initialize().
72  ///
73  /// @param init The initialization parameters for the Motivator. Each
74  /// MotiveProcessor has its own derivation of MotivatorInit,
75  /// and InitializeMotivator will only ever be called with that
76  /// derivation.
77  /// @param engine The owner of all the MotiveProcessors. An engine holds at
78  /// most one of any type of MotiveProcessor. The engine can be
79  /// used to create child Motivators that drive `motivator`.
80  /// @param motivator The Motivator that is initialized to reference into
81  /// This MotiveProcessor. The MotiveProcessor also keeps
82  /// a reference to `motivator` in case it shuffles around
83  /// internal data.
84  /// @param dimensions The number of slots to consume in the MotiveProcessor.
85  /// For example, a 3D vector would consume three slots in
86  /// a MotiveProcessor of floats.
87  void InitializeMotivator(const MotivatorInit& init, MotiveEngine* engine,
88  Motivator* motivator, MotiveDimension dimensions);
89 
90  /// Remove an motivator and return its index to the pile of allocatable
91  /// indices.
92  ///
93  /// This function should only be called by Motivator::Invalidate().
94  ///
95  /// @param index Reference into the MotiveProcessor's internal arrays.
96  void RemoveMotivator(MotiveIndex index);
97 
98  /// Transfer ownership of the motivator at `index` to 'new_motivator'.
99  /// Resets the Motivator that currently owns `index` and initializes
100  /// 'new_motivator'.
101  ///
102  /// This function should only be called by Motivator's copy operations.
103  ///
104  /// @param index Reference into the MotiveProcessor's internal arrays.
105  /// @param new_motivator The Motivator that is initialized to reference
106  /// `index`.
107  void TransferMotivator(MotiveIndex index, Motivator* new_motivator);
108 
109  /// Returns true if `index` is currently driving a motivator. Does not do
110  /// any validity checking, however, like ValidMotivatorIndex() does.
111  /// @param index Reference into the MotiveProcessor's internal arrays.
112  bool IsMotivatorIndex(MotiveIndex index) const;
113 
114  /// Returns true if `index` is currently in a block of indices driven by
115  /// a motivator.
116  /// @param index Reference into the MotiveProcessor's internal arrays.
117  bool ValidIndex(MotiveIndex index) const;
118 
119  /// Returns true if a Motivator is referencing this index.
120  /// That is, if this index is part of a block of indices
121  /// (for example a block of 3 indices referenced by a Motivator3f),
122  /// then this index is the *first* index in that block.
123  bool ValidMotivatorIndex(MotiveIndex index) const;
124 
125  /// Returns true if `index` is currently driving `motivator`.
126  /// @param index Reference into the MotiveProcessor's internal arrays.
127  /// @param motivator Motivator to verify points to `index`.
128  bool ValidMotivator(MotiveIndex index, const Motivator* motivator) const {
129  return ValidIndex(index) && motivators_[index] == motivator;
130  }
131 
132  /// Advance the simulation by `delta_time`.
133  ///
134  /// This function should only be called by MotiveEngine::AdvanceFrame.
135  ///
136  /// @param delta_time Time since the last call to AdvanceFrame(). Time units
137  /// are determined by the user.
138  virtual void AdvanceFrame(MotiveTime delta_time) = 0;
139 
140  /// Should return kType of the MotivatorInit class for the derived processor.
141  /// kType is defined by the macro MOTIVE_INTERFACE, which is put in
142  /// a processor's MotivatorInit derivation.
143  virtual MotivatorType Type() const = 0;
144 
145  /// The lower the number, the sooner the MotiveProcessor gets updated.
146  /// Should never change. We want a static ordering of processors.
147  /// Some MotiveProcessors use the output of other MotiveProcessors, so
148  /// we impose a strict ordering here.
149  virtual int Priority() const = 0;
150 
151  /// The number of slots occupied in the MotiveProcessor. For example,
152  /// a position in 3D space would return 3. A single 4x4 matrix would return 1.
153  MotiveDimension Dimensions(MotiveIndex index) const {
154  return index_allocator_.CountForIndex(index);
155  }
156 
157  /// Ensure that the internal state is consistent. Call periodically when
158  /// debugging problems where the internal state is corrupt.
159  void VerifyInternalState() const;
160 
161  // For internal use. Called by the MotiveEngine to profile each processor.
162  void RegisterBenchmarks();
163  int benchmark_id_for_advance_frame() const {
164  return benchmark_id_for_advance_frame_;
165  }
166  int benchmark_id_for_init() const { return benchmark_id_for_init_; }
167 
168  protected:
169  /// Initialize data at [index, index + dimensions).
170  /// The meaning of `index` is determined by the MotiveProcessor
171  /// implementation (most likely it is the index into one or more data_ arrays
172  /// though). MotiveProcessor tries to keep the `index` as low as possible, by
173  /// recycling ones that have been freed, and by providing a Defragment()
174  /// function to move later indices to indices that have been freed.
175  virtual void InitializeIndices(const MotivatorInit& init, MotiveIndex index,
176  MotiveDimension dimensions,
177  MotiveEngine* engine) = 0;
178 
179  /// Reset data at [index, index + dimensions).
180  /// See comment above InitializeIndex for meaning of `index`.
181  /// If your MotiveProcessor stores data in a plain array, you probably have
182  /// nothing to do. But if you use dynamic memory per index,
183  /// (which you really shouldn't - too slow!), you should deallocate it here.
184  /// For debugging, it might be nice to invalidate the data.
185  virtual void RemoveIndices(MotiveIndex index, MotiveDimension dimensions) = 0;
186 
187  /// Move the data chunk of length `dimensions` from `old_index` into
188  /// `new_index`. Used by Defragment().
189  /// Note that the index range starting at `new_index` is guaranteed to be
190  /// inactive.
191  virtual void MoveIndices(MotiveIndex old_index, MotiveIndex new_index,
192  MotiveDimension dimensions) = 0;
193 
194  /// Increase or decrease the total number of indices.
195  /// If decreased, existing indices >= num_indices should be uninitialized.
196  /// If increased, internal arrays should be extended to new_indices, and
197  /// new items in the arrays should be initialized as reset.
198  virtual void SetNumIndices(MotiveIndex num_indices) = 0;
199 
200  /// When an index is moved, the Motivator that references that index is
201  /// updated. Can be called at the discretion of your MotiveProcessor,
202  /// but normally called at the beginning of your
203  /// MotiveProcessor::AdvanceFrame.
204  void Defragment() { index_allocator_.Defragment(); }
205 
206  private:
207  typedef fplutil::IndexAllocator<MotiveIndex> MotiveIndexAllocator;
208  typedef MotiveIndexAllocator::IndexRange IndexRange;
209 
210  /// Don't notify derived class.
211  void RemoveMotivatorWithoutNotifying(MotiveIndex index);
212 
213  /// Handle callbacks from IndexAllocator.
214  void MoveIndexRangeBase(const IndexRange& source, MotiveIndex target);
215  void SetNumIndicesBase(MotiveIndex num_indices);
216 
217  /// Proxy callbacks from IndexAllocator into MotiveProcessor.
218  class AllocatorCallbacks : public MotiveIndexAllocator::CallbackInterface {
219  public:
220  AllocatorCallbacks() : processor_(nullptr) {}
221  void set_processor(MotiveProcessor* processor) { processor_ = processor; }
222  virtual void SetNumIndices(MotiveIndex num_indices) {
223  processor_->SetNumIndicesBase(num_indices);
224  }
225  virtual void MoveIndexRange(const IndexRange& source, MotiveIndex target) {
226  processor_->MoveIndexRangeBase(source, target);
227  }
228 
229  private:
230  MotiveProcessor* processor_;
231  };
232 
233  /// Back-pointer to the Motivators for each index. The Motivators reference
234  /// this MotiveProcessor and a specific index into the MotiveProcessor,
235  /// so when the index is moved, or when the MotiveProcessor itself is
236  /// destroyed, we need to update the Motivator.
237  /// Note that we only keep a reference to a single Motivator per index.
238  /// When a copy of an Motivator is made, the old Motivator is Reset and the
239  /// reference here is updated.
240  std::vector<Motivator*> motivators_;
241 
242  /// Proxy calbacks into MotiveProcessor. The other option is to derive
243  /// MotiveProcessor from IndexAllocator::CallbackInterface, but that would
244  /// create a messier API, and not be great OOP.
245  /// This member should be initialized before index_allocator_ is initialized.
246  AllocatorCallbacks allocator_callbacks_;
247 
248  /// When an index is freed, we keep track of it here. When an index is
249  /// allocated, we use one off this array, if one exists.
250  /// When Defragment() is called, we empty this array by filling all the
251  /// unused indices with the highest allocated indices. This reduces the total
252  /// size of the data arrays.
253  MotiveIndexAllocator index_allocator_;
254 
255  int benchmark_id_for_advance_frame_;
256  int benchmark_id_for_init_;
257 };
258 
259 /// @class MotiveProcessorNf
260 /// @brief Interface for motivator types that drive a single float value.
261 ///
262 /// That is, for MotiveProcessors that interface with MotivatorNf or
263 /// MotivatorXf.
265  public:
266  // Convenience functions for getting a single value. Prefer calling the
267  // bulk values, especially when inside a loop. They avoid the virtual
268  // function call overhead, and offer more opportunities for optimizations.
269  float Value(MotiveIndex index) const { return Values(index)[0]; }
270  float Velocity(MotiveIndex index) const {
271  float v;
272  Velocities(index, 1, &v);
273  return v;
274  }
275  float Direction(MotiveIndex index) const {
276  float v;
277  Directions(index, 1, &v);
278  return v;
279  }
280  float TargetValue(MotiveIndex index) const {
281  float v;
282  TargetValues(index, 1, &v);
283  return v;
284  }
285  float TargetVelocity(MotiveIndex index) const {
286  float v;
287  TargetVelocities(index, 1, &v);
288  return v;
289  }
290  float Difference(MotiveIndex index) const {
291  float v;
292  Differences(index, 1, &v);
293  return v;
294  }
295 
296  virtual const float* Values(MotiveIndex index) const = 0;
297  virtual void Velocities(MotiveIndex index, MotiveDimension dimensions,
298  float* out) const = 0;
299  virtual void Directions(MotiveIndex index, MotiveDimension dimensions,
300  float* out) const {
301  Velocities(index, dimensions, out);
302  }
303  virtual void TargetValues(MotiveIndex index, MotiveDimension dimensions,
304  float* out) const = 0;
305  virtual void TargetVelocities(MotiveIndex index, MotiveDimension dimensions,
306  float* out) const = 0;
307  virtual void Differences(MotiveIndex index, MotiveDimension dimensions,
308  float* out) const = 0;
309 
310  virtual MotiveTime TargetTime(MotiveIndex index,
311  MotiveDimension dimensions) const = 0;
312  virtual MotiveTime SplineTime(MotiveIndex /*index*/) const { return 0; }
313 
314  virtual MotiveCurveShape MotiveShape(MotiveIndex /*index*/) const {
315  return MotiveCurveShape();
316  }
317 
318  // At least one of SetTargets, SetTargetWithShape, or SetSplines should be
319  // implemented by the derived class. Otherwise, there will be no way to drive
320  // the Motivator towards a target.
321  //
322  // Set the current and future values that we want the Motivator to achieve.
323  virtual void SetTargets(MotiveIndex /*index*/, MotiveDimension /*dimensions*/,
324  const MotiveTarget1f* /*ts*/) {}
325 
326  // Set the target we want the Motivator to achieve and describe the curve
327  // shape it should use to get there.
328  virtual void SetTargetWithShape(MotiveIndex /*index*/,
329  MotiveDimension /*dimensions*/,
330  const float* /*target_values*/,
331  const float* /*target_velocities*/,
332  const MotiveCurveShape& /*shape*/) {}
333 
334  // Drive the Motivator by following splines specified in the playback.
335  virtual void SetSplines(MotiveIndex /*index*/, MotiveDimension /*dimensions*/,
336  const CompactSpline* /*splines*/,
337  const SplinePlayback& /*playback*/) {}
338 
339  // Gather the splines currently being played back. If dimension is not being
340  // driven by a spline, returns nullptr at that dimension.
341  virtual void Splines(MotiveIndex /*index*/, MotiveIndex count,
342  const CompactSpline** splines) const {
343  for (MotiveIndex i = 0; i < count; ++i) splines[i] = nullptr;
344  }
345 
346  // For each i from 0..dimensions-1, drive the value with with splines[i]
347  // when splines[i] != NULL, and with targets[i] otherwise.
348  virtual void SetSplinesAndTargets(MotiveIndex /*index*/,
349  MotiveDimension /*dimensions*/,
350  const CompactSpline* const* /*splines*/,
351  const SplinePlayback& /*playback*/,
352  const MotiveTarget1f* /*targets*/) {}
353 
354  virtual void SetSplineTime(MotiveIndex /*index*/,
355  MotiveDimension /*dimensions*/,
356  MotiveTime /*time*/) {}
357  virtual void SetSplinePlaybackRate(MotiveIndex /*index*/,
358  MotiveDimension /*dimensions*/,
359  float /*playback_rate*/) {}
360 };
361 
362 /// @class MatrixProcessor4f
363 /// @brief Interface for motivator types that drive a 4x4 float matrix.
364 /// That is, for MotiveProcessors that interface with MatrixMotivator4f's.
366  public:
367  /// Get the current matrix value from the processor.
368  virtual const mathfu::mat4& Value(MotiveIndex index) const = 0;
369 
370  /// Get the number of matrix operations performed by this motivator.
371  virtual int NumChildren(MotiveIndex index) const = 0;
372 
373  /// Get current values of the components that create the matrix.
374  virtual void ChildValues(MotiveIndex index, MotiveChildIndex child_index,
375  MotiveChildIndex count, float* values) const = 0;
376 
377  /// Get the Motivator1f driving this child, if this child is driven by
378  /// a Motivator1f, or nullptr otherwise.
379  virtual const Motivator* ChildMotivator1f(
380  MotiveIndex index, MotiveChildIndex child_index) const = 0;
381 
382  /// Set child values. Matrices are composed from child components.
383  virtual void SetChildTarget1f(MotiveIndex /*index*/,
384  MotiveChildIndex /*child_index*/,
385  const MotiveTarget1f& /*t*/) {}
386  virtual void SetChildValues(MotiveIndex index, MotiveChildIndex child_index,
387  MotiveChildIndex count, const float* values) = 0;
388 
389  /// Smoothly transition to the operations specified in `ops`.
390  virtual void BlendToOps(MotiveIndex /*index*/, const MatrixOpArray& /*ops*/,
391  const motive::SplinePlayback& /*playback*/) {}
392 
393  /// Instantly change the playback speed of this animation.
394  virtual void SetPlaybackRate(MotiveIndex index, float playback_rate) = 0;
395 };
396 
398  public:
399  /// Returns an array of length `DefiningAnim.NumBones()`.
400  /// The i'th element of the array represents the transform from the root
401  /// bone to the bone-space on the i'th bone.
402  virtual const mathfu::AffineTransform* GlobalTransforms(
403  MotiveIndex index) const = 0;
404 
405  /// Return the time remaining in the current matrix animation.
406  virtual MotiveTime TimeRemaining(MotiveIndex index) const = 0;
407 
408  /// Return the animation that defines the rig.
409  virtual const RigAnim* DefiningAnim(MotiveIndex index) const = 0;
410 
411  /// Smoothly transition to the animation in `anim`.
412  virtual void BlendToAnim(MotiveIndex index, const RigAnim& anim,
413  const motive::SplinePlayback& playback) = 0;
414 
415  /// Instantly change the playback speed of this animation.
416  virtual void SetPlaybackRate(MotiveIndex index, float playback_rate) = 0;
417 
418  virtual std::string CsvHeaderForDebugging(MotiveIndex /*index*/) const {
419  return std::string();
420  }
421  virtual std::string CsvValuesForDebugging(MotiveIndex /*index*/) const {
422  return std::string();
423  }
424  virtual std::string LocalTransformsForDebugging(MotiveIndex /*index*/,
425  BoneIndex /*bone*/) const {
426  return std::string();
427  }
428 };
429 
430 /// Static functions in MotiveProcessor-derived classes.
431 typedef MotiveProcessor* MotiveProcessorCreateFn();
432 typedef void MotiveProcessorDestroyFn(MotiveProcessor* p);
433 
435  MotiveProcessorCreateFn* create;
436  MotiveProcessorDestroyFn* destroy;
437 
438  MotiveProcessorFunctions(MotiveProcessorCreateFn* create,
439  MotiveProcessorDestroyFn* destroy)
440  : create(create), destroy(destroy) {}
441 };
442 
443 } // namespace motive
444 
445 #endif // MOTIVE_PROCESSOR_H_
virtual const Motivator * ChildMotivator1f(MotiveIndex index, MotiveChildIndex child_index) const =0
Interface for motivator types that drive a single float value.
Definition: processor.h:264
bool IsMotivatorIndex(MotiveIndex index) const
void Defragment()
Definition: processor.h:204
virtual void SetChildTarget1f(MotiveIndex, MotiveChildIndex, const MotiveTarget1f &)
Set child values. Matrices are composed from child components.
Definition: processor.h:383
virtual int NumChildren(MotiveIndex index) const =0
Get the number of matrix operations performed by this motivator.
virtual int Priority() const =0
virtual void MoveIndices(MotiveIndex old_index, MotiveIndex new_index, MotiveDimension dimensions)=0
bool ValidIndex(MotiveIndex index) const
virtual void BlendToAnim(MotiveIndex index, const RigAnim &anim, const motive::SplinePlayback &playback)=0
Smoothly transition to the animation in anim.
virtual void SetPlaybackRate(MotiveIndex index, float playback_rate)=0
Instantly change the playback speed of this animation.
virtual const mathfu::AffineTransform * GlobalTransforms(MotiveIndex index) const =0
virtual const mathfu::mat4 & Value(MotiveIndex index) const =0
Get the current matrix value from the processor.
virtual MotiveTime TimeRemaining(MotiveIndex index) const =0
Return the time remaining in the current matrix animation.
A MotiveProcessor processes all instances of one type of Motivator.
Definition: processor.h:58
Definition: processor.h:397
Animation for a RigMotivator. Drives a fully rigged model.
Definition: anim.h:72
bool ValidMotivator(MotiveIndex index, const Motivator *motivator) const
Definition: processor.h:128
virtual MotivatorType Type() const =0
A target curve shape for the motivator.
Definition: target.h:29
Definition: processor.h:434
void RemoveMotivator(MotiveIndex index)
virtual void BlendToOps(MotiveIndex, const MatrixOpArray &, const motive::SplinePlayback &)
Smoothly transition to the operations specified in ops.
Definition: processor.h:390
Hold and update all animation data.
Definition: engine.h:36
virtual void ChildValues(MotiveIndex index, MotiveChildIndex child_index, MotiveChildIndex count, float *values) const =0
Get current values of the components that create the matrix.
virtual void AdvanceFrame(MotiveTime delta_time)=0
Parameters to specify how a spline should be traversed.
Definition: compact_spline.h:590
virtual void RemoveIndices(MotiveIndex index, MotiveDimension dimensions)=0
virtual void SetNumIndices(MotiveIndex num_indices)=0
MotiveDimension Dimensions(MotiveIndex index) const
Definition: processor.h:153
void InitializeMotivator(const MotivatorInit &init, MotiveEngine *engine, Motivator *motivator, MotiveDimension dimensions)
Interface for motivator types that drive a 4x4 float matrix. That is, for MotiveProcessors that inter...
Definition: processor.h:365
Drives a value towards a target value, or along a path.
Definition: motivator.h:47
Definition: common.h:92
void TransferMotivator(MotiveIndex index, Motivator *new_motivator)
Set the current and/or target state for a one-dimensional Motivator.
Definition: target.h:98
Represent a smooth curve in a small amount of memory.
Definition: compact_spline.h:73
void VerifyInternalState() const
bool ValidMotivatorIndex(MotiveIndex index) const
virtual const RigAnim * DefiningAnim(MotiveIndex index) const =0
Return the animation that defines the rig.
Definition: init.h:424
virtual void InitializeIndices(const MotivatorInit &init, MotiveIndex index, MotiveDimension dimensions, MotiveEngine *engine)=0
virtual void SetPlaybackRate(MotiveIndex index, float playback_rate)=0
Instantly change the playback speed of this animation.