HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
GU_MotionClip.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: GU_MotionClip.h ( GU Library, C++)
7  *
8  */
9 
10 #ifndef __GU_MOTIONCLIP_H_INCLUDED__
11 #define __GU_MOTIONCLIP_H_INCLUDED__
12 
13 #include "GU_API.h"
14 
15 #include "GU_AgentClip.h"
16 #include "GU_MotionClipUtil.h"
17 #include "GU_Hierarchy.h"
18 
19 #include <GA/GA_Types.h>
20 #include <GA/GA_AttributeFilter.h>
21 
22 #include <GOP/GOP_Manager.h>
23 
24 #include <UT/UT_Array.h>
25 #include <UT/UT_Lock.h>
26 #include <UT/UT_StringHolder.h>
27 #include <UT/UT_StringMap.h>
28 
29 #include <SYS/SYS_Inline.h>
30 #include <SYS/SYS_Types.h>
31 
32 #include <utility>
33 
35 {
36 public:
37  /// clipinfo will override the gdp's clipinfo detail attribute
39  const GU_Detail *gdp,
40  UT_WorkBuffer &err_msg,
41  bool can_evaluate = true,
42  GU_MotionClipInfo *clipinfo = nullptr);
43 
44  ~GU_MotionClipRO() = default;
45 
46  /// Appends the unpacked toplogy geometry to dest
47  ///
48  void getTopology(fpreal &time, GU_Detail *dest,
49  const GA_AttributeFilter* skip = nullptr);
50 
51  bool hasTopology() const { return myHasTopology; }
52 
53  /// This will compute the frame at the given time, and
54  /// then copy the P+transform attributes of the ith
55  /// point in topologyPts into the ith point in resultPts.
56  ///
57  /// It will also include whatever extra attribs you request
58  /// as long as there is no current active GU_MotionClipBuilder
59  ///
60  /// @pre resultPts and topologyPts must correspond
61  /// to the same points in their respective
62  /// geometries, in the same order.
64  const GA_PointGroup *result_pts=nullptr,
65  const GA_PointGroup *topology_pts=nullptr,
66  const GA_AttributeFilter* extra_attribs_to_unpack=nullptr,
69  {
70  UT_AutoLock lock(myLock);
71  myEvaluator.evaluate(time, result, result_pts,
72  getFrameDetail(-1), topology_pts,
73  myHierarchyCache, extra_attribs_to_unpack,
74  left_end_behavior, right_end_behavior);
75  }
76 
77  // This will re-compute the localtransforms of each frame in the
78  // evaluator so that each frame evaluates to the correct position
79  // while using a scaleinheritance (model) of 0.
80  void clearModel()
81  {
82  UT_AutoLock lock(myLock);
83  myEvaluator.clearModel(getFrameDetail(-1),
84  myHierarchyCache);
85  }
86 
87  /// This computes the local transforms of each joint at the given
88  /// time. The ith element defines represents the ith joint in the
89  /// topology detail. getJointIndex can be used to check this
92  {
93  UT_AutoLock lock(myLock);
94  myEvaluator.computeLocalTransforms(time, result);
95  }
96 
97  /// Returns the index of the given joint name within the
98  /// topology detail
99  exint getJointIndex(const UT_StringHolder& joint_name) const
100  {
101  if (!myNameToJointIdx.contains(joint_name))
102  return -1;
103  return myNameToJointIdx.at(joint_name);
104  }
105 
106  /// Returns a point group of the topology detail based
107  /// on the given pattern
108  const GA_PointGroup* getJointGroup(
109  GOP_Manager &gop, const UT_StringHolder& pattern) const;
110 
111  /// returns false if there was an error during initialization
112  ///
113  bool isInitialised() const
114  {
115  return myIsInitialised;
116  }
117 
118  exint numJoints() const
119  {
120  return myNumJoints;
121  }
122 
123  /// returns the sample at time, or nullptr if not found
124  const GU_Detail *getSample(fpreal time) const;
125  const GU_Detail *restFrame() const { return getFrameDetail(-1); }
126 
128  return myEvaluator.getSampleTimes();
129  }
130 
131 protected:
132  const GU_Detail * const ourGdp;
133 
134 private:
135  friend class GU_MotionClipRW;
136  friend class GU_MotionClipBuilder;
137 
138  /// Returns the time in seconds of the indexth frame
139  fpreal getFrameTime(exint index) const;
140  const GU_Detail* getFrameDetail(exint frame) const;
141  GA_Offset getFrameOffset(exint frame) const;
142 
143  /// Returns the highest frame index with a time
144  /// less than or equal to time or -1 if no such index exists
145  exint getFrameAtOrBefore(fpreal time) const;
146 
147  /// We use this class to separate the evaluation data
148  /// from the other members so that we can safely evaluate
149  /// while a MotionClipBuilder is manipulating the rest of
150  /// the object. This also makes it clear what data you
151  /// can skip updating when myCanEvaluate is false
152  ///
153  /// However if we need to unpack extra attributes we
154  /// need to find them within the gdp which is impossible
155  /// while there is a MotionClip builder operating on it...
156  /// Because of this we store a ptr to the clip and set it to
157  /// null whenever the Evaluator is out of date - when it is
158  /// null evaluate will skip unpacking attribs. The caller should
159  /// ensure that this is not allowed
160  class Evaluator
161  {
162  public:
163  Evaluator();
164 
165  void computeLocalTransforms(fpreal time,
167  void evaluate(fpreal time, GU_Detail *result,
168  const GA_PointGroup *result_pts,
169  const GU_Detail *topology,
170  const GA_PointGroup *topology_pts,
171  GU_HierarchyCache &sopcache,
172  const GA_AttributeFilter* extra_attribs_to_unpack,
173  GU_MotionClipEndBehavior left_end_behavior,
174  GU_MotionClipEndBehavior right_end_behavior);
175  void clearModel(const GU_Detail *topology,
176  GU_HierarchyCache &sopcache);
177  void update(const GU_MotionClipRO &clip);
178  void setDirty()
179  {
180  myClip = nullptr;
181  }
182  const UT_Array<fpreal>& getSampleTimes() {
183  return myFrameTimes;
184  }
185 
186  private:
187  /// Returns the highest frame index with a time
188  /// less than or equal to time or -1 if no such index exists
189  exint getFrameAtOrBefore(fpreal time) const;
190 
191  /// myFrameTransforms[frame_idx][joint_idx] represents
192  /// joint_idx's decomposed local space transform in frame
193  /// frame_idx, even if the joint does not exist in the sample
194  UT_Array<UT_Array<GU_AgentXformD>> myFrameTransforms;
195 
196  /// myInterpFrames[frame_idx][joint_idx] contains a pair
197  /// containing the two sample indices used when interpolating
198  /// the position of this joint.
199  /// the first index will be strictly less than frame_idx
200  /// the second will be greater than or equal to frame_idx
202  UT_Array<fpreal> myFrameTimes;
203 
204  /// maps a joint name to the corresponding point offset
205  /// within each sample
206  UT_Array<UT_StringMap<GA_Offset>> myFrameJointOffsets;
207  fpreal myLastEvalTime;
208  exint myLastEvalFrame;
209  UT_Vector2R myClipRange;
210 
211  /// these are always outputted
212  GA_AttributeFilter myIsAttribExtra;
213 
214  // This is a flag to indicate whether the clearModel method has
215  // been called since the last time the evaluator was updated.
216  // This is needed so that the MotionClip can be evaluated properly.
217  bool myIsModelClear;
218 
219  // We need the clip to fetch additional attributes. However
220  // we can not safely use it when the evaluator is dirty.
221  // We'll set this to null whenever it is unsafe to use
222  const GU_MotionClipRO *myClip;
223  };
224 
225  Evaluator myEvaluator;
226 
227  GU_HierarchyCache myHierarchyCache;
228  GU_MotionClipInfo myClipinfo;
229  UT_Lock myLock;
230  bool myHasTopology;
231 
232  /// myUsedJoints[frame_idx][joint_idx] represents whether
233  /// joint_idx is is present in frame frame_idx
234  UT_Array<UT_BitArray> myUsedJoints;
235 
236  UT_StringMap<exint> myNameToJointIdx;
237 
238  exint myNumJoints;
239  exint myNumFrames;
240 
241  bool myIsInitialised;
242 
243  /// If we never evaluate we can skip a bunch of
244  /// slow useless computations (updating myEvaluator)
245  const bool myCanEvaluate;
246 };
247 
248 /// MotionClip object which allows for modifications
249 ///
250 /// You can add/remove frames by passing an instance of this
251 /// into GU_MotionBuilder
253 {
254 public:
255  friend class GU_MotionClipBuilder;
256 
258  GU_Detail *gdp,
259  UT_WorkBuffer &err_msg,
260  bool can_evaluate = true,
261  GU_MotionClipInfo *clipinfo = nullptr);
262 
263  ~GU_MotionClipRW() = default;
264 
265  /// Sets the topology to the sample geometry,
266  /// marking the packed primitive with the given time attribute
267  ///
268  /// If there is already an existing topology sample must
269  /// contain only the same joints.
270  ///
271  /// The topology must be set before attempting to add frames
272  ///
273  /// returns false on error
274  bool setTopology(fpreal time, const GU_Detail *sample,
275  UT_WorkBuffer &error_msg);
276 
277 private:
279  {
280  // the const cast should be safe because an instance of
281  // GU_MotionClipRW can only be created with a non-const gdp
282  return SYSconst_cast(ourGdp);
283  }
284 
285 };
286 
287 /// Used to make a batch of modifications to a motion clip.
288 ///
289 /// It will store the changes in the clip object and then flush
290 /// them to the clip's evaluator when it is destroyed
291 ///
292 /// Each call to add/removeSample will update the clip's GDP, etc
293 /// but the evaluator's internal data structures will not
294 /// be updated until the flush - so we can safely keep evaluating the
295 /// the clip which we are adding frames, but the new frames will not
296 /// be reflected in the evaluated animation until this object is destroyed
297 ///
298 /// Note that the evaluator will not be able to unpack attributes until
299 /// this is destructed
301 {
302 public:
303  /// @pre Clip must outlive this instance
304  ///
306  : clip(clip) {}
307 
308  /// This will update clip to store the new samples
309  ///
311 
312  /// Adds a sample/keyframe into the clip at the given time
313  ///
314  /// If the a sample at the given time exists it will be replaced
315  /// returns false on error
316  ///
317  /// @pre Each point's name attrib must correspond to one
318  /// of the topology's joint names
319  /// @pre Sample must either provide a localtransform attribute
320  /// or have the same topology as our class so we can compute it
321  bool addSample(fpreal time, const GU_Detail *sample,
322  UT_WorkBuffer &error_msg,
323  GA_AttributeFilter extra_attribs,
324  const GA_PointGroup *pts = nullptr);
325 
326  /// Removes the sample at time
327  ///
328  /// returns false on error/missing sample
329  bool removeSample(fpreal time, UT_WorkBuffer &error_msg);
330 
331 private:
333 };
334 
335 #endif
const GU_Detail *const ourGdp
bool hasTopology() const
Definition: GU_MotionClip.h:51
void skip(T &in, int n)
Definition: ImfXdr.h:885
GT_API const UT_StringHolder time
GLuint index
Definition: glew.h:1814
SYS_FORCE_INLINE T * SYSconst_cast(const T *foo)
Definition: SYS_Types.h:136
int64 exint
Definition: SYS_Types.h:125
GA_Size GA_Offset
Definition: GA_Types.h:639
const UT_Array< fpreal > & getSampleTimes()
friend class GU_MotionClipRW
void computeLocalTransforms(fpreal time, UT_Array< GU_AgentXformD > &result)
Definition: GU_MotionClip.h:90
GU_MotionClipEndBehavior
GT_API const UT_StringHolder topology
#define SYS_FORCE_INLINE
Definition: SYS_Inline.h:45
#define GU_API
Definition: GU_API.h:14
exint getJointIndex(const UT_StringHolder &joint_name) const
Definition: GU_MotionClip.h:99
exint numJoints() const
IMATH_INTERNAL_NAMESPACE_HEADER_ENTER T clip(const T &p, const Box< T > &box)
Definition: ImathBoxAlgo.h:89
fpreal64 fpreal
Definition: SYS_Types.h:277
void evaluate(fpreal time, GU_Detail *result, const GA_PointGroup *result_pts=nullptr, const GA_PointGroup *topology_pts=nullptr, const GA_AttributeFilter *extra_attribs_to_unpack=nullptr, GU_MotionClipEndBehavior left_end_behavior=GU_MotionClipEndBehavior::Clamp, GU_MotionClipEndBehavior right_end_behavior=GU_MotionClipEndBehavior::Clamp)
Definition: GU_MotionClip.h:63
const GU_Detail * restFrame() const
GLuint64EXT * result
Definition: glew.h:14007
GLubyte * pattern
Definition: glew.h:5711
bool isInitialised() const
GU_MotionClipBuilder(GU_MotionClipRW *clip)