1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 //    names, trademarks, service marks, or product names of the Licensor
11 //    and its affiliates, except as required to comply with Section 4(c) of
12 //    the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 //     http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #include "pxr/usd/usdSkel/skelDefinition.h"
25 
26 #include "pxr/base/arch/hints.h"
27 
28 #include "pxr/usd/usdSkel/utils.h"
29 
30 
31 PXR_NAMESPACE_OPEN_SCOPE
32 
33 
34 namespace {
35 
36 
37 enum _Flags {
38     _HaveBindPose = 1 << 0,
39     _HaveRestPose = 1 << 1,
40     // Matrix4dArray computations
41     _SkelRestXforms4dComputed = 1 << 2,
42     _WorldInverseBindXforms4dComputed = 1 << 3,
43     _LocalInverseRestXforms4dComputed = 1 << 4,
44     // Matrix4fArray computations
45     _SkelRestXforms4fComputed = 1 << 5,
46     _WorldInverseBindXforms4fComputed = 1 << 6,
47     _LocalInverseRestXforms4fComputed = 1 << 7,
48 };
49 
50 
51 template <typename Matrix4>
52 void
_InvertTransforms(const VtArray<Matrix4> & xforms,VtArray<Matrix4> * inverseXforms)53 _InvertTransforms(const VtArray<Matrix4>& xforms,
54                   VtArray<Matrix4>* inverseXforms)
55 {
56     inverseXforms->resize(xforms.size());
57     Matrix4* dst = inverseXforms->data();
58     for (size_t i = 0; i < xforms.size(); ++i) {
59         dst[i] = xforms[i].GetInverse();
60     }
61 }
62 
63 
64 void
_Convert4dXformsTo4f(const VtMatrix4dArray & matrix4dArray,VtMatrix4fArray * matrix4fArray)65 _Convert4dXformsTo4f(const VtMatrix4dArray& matrix4dArray,
66                      VtMatrix4fArray* matrix4fArray)
67 {
68     matrix4fArray->resize(matrix4dArray.size());
69     GfMatrix4f* dst = matrix4fArray->data();
70     for (size_t i = 0; i < matrix4dArray.size(); ++i) {
71         dst[i] = GfMatrix4f(matrix4dArray[i]);
72     }
73 }
74 
75 
76 } // namespace
77 
78 
79 UsdSkel_SkelDefinitionRefPtr
New(const UsdSkelSkeleton & skel)80 UsdSkel_SkelDefinition::New(const UsdSkelSkeleton& skel)
81 {
82     if(skel) {
83         UsdSkel_SkelDefinitionRefPtr def =
84             TfCreateRefPtr(new UsdSkel_SkelDefinition);
85         if(def->_Init(skel))
86             return def;
87     }
88     return nullptr;
89 }
90 
91 
UsdSkel_SkelDefinition()92 UsdSkel_SkelDefinition::UsdSkel_SkelDefinition()
93     :  _flags(0)
94 {}
95 
96 
97 bool
_Init(const UsdSkelSkeleton & skel)98 UsdSkel_SkelDefinition::_Init(const UsdSkelSkeleton& skel)
99 {
100     TRACE_FUNCTION();
101 
102     skel.GetJointsAttr().Get(&_jointOrder);
103 
104     _topology = UsdSkelTopology(_jointOrder);
105     std::string reason;
106     if (!_topology.Validate(&reason)) {
107         TF_WARN("%s -- invalid topology: %s",
108                 skel.GetPrim().GetPath().GetText(), reason.c_str());
109         return false;
110     }
111 
112     skel.GetBindTransformsAttr().Get(&_jointWorldBindXforms);
113     if (_jointWorldBindXforms.size() == _jointOrder.size()) {
114         _flags = _flags|_HaveBindPose;
115     } else {
116         TF_WARN("%s -- size of 'bindTransforms' attr [%zu] does not "
117                 "match the number of joints in the 'joints' attr [%zu].",
118                 skel.GetPrim().GetPath().GetText(),
119                 _jointWorldBindXforms.size(), _jointOrder.size());
120     }
121 
122     skel.GetRestTransformsAttr().Get(&_jointLocalRestXforms);
123     if (_jointLocalRestXforms.size() == _jointOrder.size()) {
124         _flags = _flags|_HaveRestPose;
125     } else {
126         TF_WARN("%s -- size of 'restTransforms' attr [%zu] does not "
127                 "match the number of joints in the 'joints' attr [%zu].",
128                 skel.GetPrim().GetPath().GetText(),
129                 _jointLocalRestXforms.size(), _jointOrder.size());
130     }
131 
132     _skel = skel;
133     return true;
134 }
135 
136 
137 template <>
138 VtMatrix4dArray&
Get()139 UsdSkel_SkelDefinition::_XformHolder::Get<GfMatrix4d>()
140 { return xforms4d; }
141 
142 template <>
143 const VtMatrix4dArray&
Get() const144 UsdSkel_SkelDefinition::_XformHolder::Get<GfMatrix4d>() const
145 { return xforms4d; }
146 
147 template <>
148 VtMatrix4fArray&
Get()149 UsdSkel_SkelDefinition::_XformHolder::Get<GfMatrix4f>()
150 { return xforms4f; }
151 
152 template <>
153 const VtMatrix4fArray&
Get() const154 UsdSkel_SkelDefinition::_XformHolder::Get<GfMatrix4f>() const
155 { return xforms4f; }
156 
157 
158 template <>
159 bool
GetJointLocalRestTransforms(VtMatrix4dArray * xforms)160 UsdSkel_SkelDefinition::GetJointLocalRestTransforms(VtMatrix4dArray* xforms)
161 {
162     const int flags = _flags;
163     if (flags&_HaveRestPose) {
164 
165         if (!xforms) {
166             TF_CODING_ERROR("'xforms' pointer is null.");
167             return false;
168         }
169 
170         // double-precision rest xforms are pre-computed.
171         *xforms = _jointLocalRestXforms;
172         return true;
173     }
174     return false;
175 }
176 
177 
178 template <>
179 bool
GetJointLocalRestTransforms(VtMatrix4fArray * xforms)180 UsdSkel_SkelDefinition::GetJointLocalRestTransforms(VtMatrix4fArray* xforms)
181 {
182     if (!xforms) {
183         TF_CODING_ERROR("'xforms' pointer is null.");
184         return false;
185     }
186 
187     // float-precision uses uncached conversion from double-precision.
188     VtMatrix4dArray xforms4d;
189     if (GetJointLocalRestTransforms(&xforms4d)) {
190         _Convert4dXformsTo4f(xforms4d, xforms);
191         return true;
192     }
193     return false;
194 }
195 
196 
197 template <int ComputeFlag, typename Matrix4>
198 bool
_GetJointSkelRestTransforms(VtArray<Matrix4> * xforms)199 UsdSkel_SkelDefinition::_GetJointSkelRestTransforms(VtArray<Matrix4>* xforms)
200 {
201     const int flags = _flags;
202     if (flags&_HaveRestPose) {
203 
204         if (!xforms) {
205             TF_CODING_ERROR("'xforms' pointer is null.");
206             return false;
207         }
208 
209         if (ARCH_UNLIKELY(!(flags&ComputeFlag))) {
210             if (!_ComputeJointSkelRestTransforms<ComputeFlag,Matrix4>()) {
211                 return false;
212             }
213         }
214         *xforms = _jointSkelRestXforms.Get<Matrix4>();
215         return true;
216     }
217     return false;
218 }
219 
220 
221 template <>
222 bool
GetJointSkelRestTransforms(VtMatrix4dArray * xforms)223 UsdSkel_SkelDefinition::GetJointSkelRestTransforms(VtMatrix4dArray* xforms)
224 {
225     return _GetJointSkelRestTransforms<_SkelRestXforms4dComputed>(xforms);
226 }
227 
228 
229 template <>
230 bool
GetJointSkelRestTransforms(VtMatrix4fArray * xforms)231 UsdSkel_SkelDefinition::GetJointSkelRestTransforms(VtMatrix4fArray* xforms)
232 {
233     return _GetJointSkelRestTransforms<_SkelRestXforms4fComputed>(xforms);
234 }
235 
236 
237 template <int ComputeFlag, typename Matrix4>
238 bool
_ComputeJointSkelRestTransforms()239 UsdSkel_SkelDefinition::_ComputeJointSkelRestTransforms()
240 {
241     TRACE_FUNCTION();
242 
243     VtArray<Matrix4> jointLocalRestXforms;
244     if (TF_VERIFY(GetJointLocalRestTransforms(&jointLocalRestXforms))) {
245 
246         std::lock_guard<std::mutex> lock(_mutex);
247 
248         VtArray<Matrix4>& skelXforms = _jointSkelRestXforms.Get<Matrix4>();
249         skelXforms.resize(_topology.size());
250 
251         const bool success =
252             UsdSkelConcatJointTransforms(_topology, jointLocalRestXforms,
253                                          skelXforms);
254 
255         // XXX: Topology was validated when the definition was constructed,
256         /// so this should not have failed.
257         TF_VERIFY(success);
258 
259         _flags = _flags|ComputeFlag;
260 
261         return true;
262     }
263     return false;
264 }
265 
266 
267 template <>
268 bool
GetJointWorldBindTransforms(VtMatrix4dArray * xforms)269 UsdSkel_SkelDefinition::GetJointWorldBindTransforms(VtMatrix4dArray* xforms)
270 {
271     const int flags = _flags;
272     if (flags&_HaveBindPose) {
273 
274         if (!xforms) {
275             TF_CODING_ERROR("'xforms' pointer is null.");
276             return false;
277         }
278 
279         // double-precision bind xforms are pre-computed.
280         *xforms = _jointWorldBindXforms;
281         return true;
282     }
283     return false;
284 }
285 
286 
287 template <>
288 bool
GetJointWorldBindTransforms(VtMatrix4fArray * xforms)289 UsdSkel_SkelDefinition::GetJointWorldBindTransforms(VtMatrix4fArray* xforms)
290 {
291     if (!xforms) {
292         TF_CODING_ERROR("'xforms' pointer is null.");
293         return false;
294     }
295 
296     // float-precision uses uncached conversion from double-precision.
297     VtMatrix4dArray xforms4d;
298     if (GetJointWorldBindTransforms(&xforms4d)) {
299         _Convert4dXformsTo4f(xforms4d, xforms);
300         return true;
301     }
302     return false;
303 }
304 
305 
306 template <int ComputeFlag, typename Matrix4>
307 bool
_GetJointWorldInverseBindTransforms(VtArray<Matrix4> * xforms)308 UsdSkel_SkelDefinition::_GetJointWorldInverseBindTransforms(
309     VtArray<Matrix4>* xforms)
310 {
311     const int flags = _flags;
312     if (flags&_HaveBindPose) {
313 
314         if (!xforms) {
315             TF_CODING_ERROR("'xforms' pointer is null.");
316             return false;
317         }
318 
319         if (ARCH_UNLIKELY(!(flags&ComputeFlag))) {
320             if (!_ComputeJointWorldInverseBindTransforms<
321                     ComputeFlag,Matrix4>()) {
322                 return false;
323             }
324         }
325         *xforms = _jointWorldInverseBindXforms.Get<Matrix4>();
326         return true;
327     }
328     return false;
329 }
330 
331 
332 template <>
333 bool
GetJointWorldInverseBindTransforms(VtMatrix4dArray * xforms)334 UsdSkel_SkelDefinition::GetJointWorldInverseBindTransforms(
335     VtMatrix4dArray* xforms)
336 {
337     return _GetJointWorldInverseBindTransforms<
338         _WorldInverseBindXforms4dComputed>(xforms);
339 }
340 
341 
342 template <>
343 bool
GetJointWorldInverseBindTransforms(VtMatrix4fArray * xforms)344 UsdSkel_SkelDefinition::GetJointWorldInverseBindTransforms(
345     VtMatrix4fArray* xforms)
346 {
347     return _GetJointWorldInverseBindTransforms<
348         _WorldInverseBindXforms4fComputed>(xforms);
349 }
350 
351 
352 template <int ComputeFlag, typename Matrix4>
353 bool
_ComputeJointWorldInverseBindTransforms()354 UsdSkel_SkelDefinition::_ComputeJointWorldInverseBindTransforms()
355 {
356     TRACE_FUNCTION();
357 
358     VtArray<Matrix4> jointWorldBindXforms;
359     if (TF_VERIFY(GetJointWorldBindTransforms(&jointWorldBindXforms))) {
360 
361         std::lock_guard<std::mutex> lock(_mutex);
362 
363         _InvertTransforms<Matrix4>(
364             jointWorldBindXforms,
365             &_jointWorldInverseBindXforms.Get<Matrix4>());
366 
367         _flags = _flags|ComputeFlag;
368         return true;
369     }
370     return false;
371 }
372 
373 
374 template <int ComputeFlag, typename Matrix4>
375 bool
_GetJointLocalInverseRestTransforms(VtArray<Matrix4> * xforms)376 UsdSkel_SkelDefinition::_GetJointLocalInverseRestTransforms(
377     VtArray<Matrix4>* xforms)
378 {
379     const int flags = _flags;
380     if (flags&_HaveRestPose) {
381 
382         if (!xforms) {
383             TF_CODING_ERROR("'xforms' pointer is null.");
384             return false;
385         }
386 
387         if (ARCH_UNLIKELY(!(flags&ComputeFlag))) {
388             if (!_ComputeJointLocalInverseRestTransforms<
389                     ComputeFlag,Matrix4>()) {
390                 return false;
391             }
392         }
393         *xforms = _jointLocalInverseRestXforms.Get<Matrix4>();
394         return true;
395     }
396     return false;
397 }
398 
399 
400 template <>
401 bool
GetJointLocalInverseRestTransforms(VtMatrix4dArray * xforms)402 UsdSkel_SkelDefinition::GetJointLocalInverseRestTransforms(
403     VtMatrix4dArray* xforms)
404 {
405     return _GetJointLocalInverseRestTransforms<
406         _LocalInverseRestXforms4dComputed>(xforms);
407     return false;
408 }
409 
410 
411 template <>
412 bool
GetJointLocalInverseRestTransforms(VtMatrix4fArray * xforms)413 UsdSkel_SkelDefinition::GetJointLocalInverseRestTransforms(
414     VtMatrix4fArray* xforms)
415 {
416     return _GetJointLocalInverseRestTransforms<
417         _LocalInverseRestXforms4fComputed>(xforms);
418     return false;
419 }
420 
421 
422 template <int ComputeFlag, typename Matrix4>
423 bool
_ComputeJointLocalInverseRestTransforms()424 UsdSkel_SkelDefinition::_ComputeJointLocalInverseRestTransforms()
425 {
426     TRACE_FUNCTION();
427 
428     VtArray<Matrix4> jointLocalRestXforms;
429     if (TF_VERIFY(GetJointLocalRestTransforms(&jointLocalRestXforms))) {
430 
431         std::lock_guard<std::mutex> lock(_mutex);
432 
433         _InvertTransforms<Matrix4>(
434             jointLocalRestXforms,
435             &_jointLocalInverseRestXforms.Get<Matrix4>());
436 
437         _flags = _flags|ComputeFlag;
438 
439         return true;
440     }
441     return false;
442 }
443 
444 
445 bool
HasBindPose()446 UsdSkel_SkelDefinition::HasBindPose()
447 {
448     return _flags&_HaveBindPose;
449 }
450 
451 bool
HasRestPose()452 UsdSkel_SkelDefinition::HasRestPose()
453 {
454     return _flags&_HaveRestPose;
455 }
456 
457 
458 PXR_NAMESPACE_CLOSE_SCOPE
459