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/bindingAPI.h"
25 #include "pxr/usd/usd/schemaRegistry.h"
26 #include "pxr/usd/usd/typed.h"
27 #include "pxr/usd/usd/tokens.h"
28 
29 #include "pxr/usd/sdf/types.h"
30 #include "pxr/usd/sdf/assetPath.h"
31 
32 PXR_NAMESPACE_OPEN_SCOPE
33 
34 // Register the schema with the TfType system.
TF_REGISTRY_FUNCTION(TfType)35 TF_REGISTRY_FUNCTION(TfType)
36 {
37     TfType::Define<UsdSkelBindingAPI,
38         TfType::Bases< UsdAPISchemaBase > >();
39 
40 }
41 
42 TF_DEFINE_PRIVATE_TOKENS(
43     _schemaTokens,
44     (SkelBindingAPI)
45 );
46 
47 /* virtual */
~UsdSkelBindingAPI()48 UsdSkelBindingAPI::~UsdSkelBindingAPI()
49 {
50 }
51 
52 /* static */
53 UsdSkelBindingAPI
Get(const UsdStagePtr & stage,const SdfPath & path)54 UsdSkelBindingAPI::Get(const UsdStagePtr &stage, const SdfPath &path)
55 {
56     if (!stage) {
57         TF_CODING_ERROR("Invalid stage");
58         return UsdSkelBindingAPI();
59     }
60     return UsdSkelBindingAPI(stage->GetPrimAtPath(path));
61 }
62 
63 
64 /* virtual */
_GetSchemaKind() const65 UsdSchemaKind UsdSkelBindingAPI::_GetSchemaKind() const
66 {
67     return UsdSkelBindingAPI::schemaKind;
68 }
69 
70 /* static */
71 bool
CanApply(const UsdPrim & prim,std::string * whyNot)72 UsdSkelBindingAPI::CanApply(
73     const UsdPrim &prim, std::string *whyNot)
74 {
75     return prim.CanApplyAPI<UsdSkelBindingAPI>(whyNot);
76 }
77 
78 /* static */
79 UsdSkelBindingAPI
Apply(const UsdPrim & prim)80 UsdSkelBindingAPI::Apply(const UsdPrim &prim)
81 {
82     if (prim.ApplyAPI<UsdSkelBindingAPI>()) {
83         return UsdSkelBindingAPI(prim);
84     }
85     return UsdSkelBindingAPI();
86 }
87 
88 /* static */
89 const TfType &
_GetStaticTfType()90 UsdSkelBindingAPI::_GetStaticTfType()
91 {
92     static TfType tfType = TfType::Find<UsdSkelBindingAPI>();
93     return tfType;
94 }
95 
96 /* static */
97 bool
_IsTypedSchema()98 UsdSkelBindingAPI::_IsTypedSchema()
99 {
100     static bool isTyped = _GetStaticTfType().IsA<UsdTyped>();
101     return isTyped;
102 }
103 
104 /* virtual */
105 const TfType &
_GetTfType() const106 UsdSkelBindingAPI::_GetTfType() const
107 {
108     return _GetStaticTfType();
109 }
110 
111 UsdAttribute
GetGeomBindTransformAttr() const112 UsdSkelBindingAPI::GetGeomBindTransformAttr() const
113 {
114     return GetPrim().GetAttribute(UsdSkelTokens->primvarsSkelGeomBindTransform);
115 }
116 
117 UsdAttribute
CreateGeomBindTransformAttr(VtValue const & defaultValue,bool writeSparsely) const118 UsdSkelBindingAPI::CreateGeomBindTransformAttr(VtValue const &defaultValue, bool writeSparsely) const
119 {
120     return UsdSchemaBase::_CreateAttr(UsdSkelTokens->primvarsSkelGeomBindTransform,
121                        SdfValueTypeNames->Matrix4d,
122                        /* custom = */ false,
123                        SdfVariabilityVarying,
124                        defaultValue,
125                        writeSparsely);
126 }
127 
128 UsdAttribute
GetJointsAttr() const129 UsdSkelBindingAPI::GetJointsAttr() const
130 {
131     return GetPrim().GetAttribute(UsdSkelTokens->skelJoints);
132 }
133 
134 UsdAttribute
CreateJointsAttr(VtValue const & defaultValue,bool writeSparsely) const135 UsdSkelBindingAPI::CreateJointsAttr(VtValue const &defaultValue, bool writeSparsely) const
136 {
137     return UsdSchemaBase::_CreateAttr(UsdSkelTokens->skelJoints,
138                        SdfValueTypeNames->TokenArray,
139                        /* custom = */ false,
140                        SdfVariabilityUniform,
141                        defaultValue,
142                        writeSparsely);
143 }
144 
145 UsdAttribute
GetJointIndicesAttr() const146 UsdSkelBindingAPI::GetJointIndicesAttr() const
147 {
148     return GetPrim().GetAttribute(UsdSkelTokens->primvarsSkelJointIndices);
149 }
150 
151 UsdAttribute
CreateJointIndicesAttr(VtValue const & defaultValue,bool writeSparsely) const152 UsdSkelBindingAPI::CreateJointIndicesAttr(VtValue const &defaultValue, bool writeSparsely) const
153 {
154     return UsdSchemaBase::_CreateAttr(UsdSkelTokens->primvarsSkelJointIndices,
155                        SdfValueTypeNames->IntArray,
156                        /* custom = */ false,
157                        SdfVariabilityVarying,
158                        defaultValue,
159                        writeSparsely);
160 }
161 
162 UsdAttribute
GetJointWeightsAttr() const163 UsdSkelBindingAPI::GetJointWeightsAttr() const
164 {
165     return GetPrim().GetAttribute(UsdSkelTokens->primvarsSkelJointWeights);
166 }
167 
168 UsdAttribute
CreateJointWeightsAttr(VtValue const & defaultValue,bool writeSparsely) const169 UsdSkelBindingAPI::CreateJointWeightsAttr(VtValue const &defaultValue, bool writeSparsely) const
170 {
171     return UsdSchemaBase::_CreateAttr(UsdSkelTokens->primvarsSkelJointWeights,
172                        SdfValueTypeNames->FloatArray,
173                        /* custom = */ false,
174                        SdfVariabilityVarying,
175                        defaultValue,
176                        writeSparsely);
177 }
178 
179 UsdAttribute
GetBlendShapesAttr() const180 UsdSkelBindingAPI::GetBlendShapesAttr() const
181 {
182     return GetPrim().GetAttribute(UsdSkelTokens->skelBlendShapes);
183 }
184 
185 UsdAttribute
CreateBlendShapesAttr(VtValue const & defaultValue,bool writeSparsely) const186 UsdSkelBindingAPI::CreateBlendShapesAttr(VtValue const &defaultValue, bool writeSparsely) const
187 {
188     return UsdSchemaBase::_CreateAttr(UsdSkelTokens->skelBlendShapes,
189                        SdfValueTypeNames->TokenArray,
190                        /* custom = */ false,
191                        SdfVariabilityUniform,
192                        defaultValue,
193                        writeSparsely);
194 }
195 
196 UsdRelationship
GetAnimationSourceRel() const197 UsdSkelBindingAPI::GetAnimationSourceRel() const
198 {
199     return GetPrim().GetRelationship(UsdSkelTokens->skelAnimationSource);
200 }
201 
202 UsdRelationship
CreateAnimationSourceRel() const203 UsdSkelBindingAPI::CreateAnimationSourceRel() const
204 {
205     return GetPrim().CreateRelationship(UsdSkelTokens->skelAnimationSource,
206                        /* custom = */ false);
207 }
208 
209 UsdRelationship
GetSkeletonRel() const210 UsdSkelBindingAPI::GetSkeletonRel() const
211 {
212     return GetPrim().GetRelationship(UsdSkelTokens->skelSkeleton);
213 }
214 
215 UsdRelationship
CreateSkeletonRel() const216 UsdSkelBindingAPI::CreateSkeletonRel() const
217 {
218     return GetPrim().CreateRelationship(UsdSkelTokens->skelSkeleton,
219                        /* custom = */ false);
220 }
221 
222 UsdRelationship
GetBlendShapeTargetsRel() const223 UsdSkelBindingAPI::GetBlendShapeTargetsRel() const
224 {
225     return GetPrim().GetRelationship(UsdSkelTokens->skelBlendShapeTargets);
226 }
227 
228 UsdRelationship
CreateBlendShapeTargetsRel() const229 UsdSkelBindingAPI::CreateBlendShapeTargetsRel() const
230 {
231     return GetPrim().CreateRelationship(UsdSkelTokens->skelBlendShapeTargets,
232                        /* custom = */ false);
233 }
234 
235 namespace {
236 static inline TfTokenVector
_ConcatenateAttributeNames(const TfTokenVector & left,const TfTokenVector & right)237 _ConcatenateAttributeNames(const TfTokenVector& left,const TfTokenVector& right)
238 {
239     TfTokenVector result;
240     result.reserve(left.size() + right.size());
241     result.insert(result.end(), left.begin(), left.end());
242     result.insert(result.end(), right.begin(), right.end());
243     return result;
244 }
245 }
246 
247 /*static*/
248 const TfTokenVector&
GetSchemaAttributeNames(bool includeInherited)249 UsdSkelBindingAPI::GetSchemaAttributeNames(bool includeInherited)
250 {
251     static TfTokenVector localNames = {
252         UsdSkelTokens->primvarsSkelGeomBindTransform,
253         UsdSkelTokens->skelJoints,
254         UsdSkelTokens->primvarsSkelJointIndices,
255         UsdSkelTokens->primvarsSkelJointWeights,
256         UsdSkelTokens->skelBlendShapes,
257     };
258     static TfTokenVector allNames =
259         _ConcatenateAttributeNames(
260             UsdAPISchemaBase::GetSchemaAttributeNames(true),
261             localNames);
262 
263     if (includeInherited)
264         return allNames;
265     else
266         return localNames;
267 }
268 
269 PXR_NAMESPACE_CLOSE_SCOPE
270 
271 // ===================================================================== //
272 // Feel free to add custom code below this line. It will be preserved by
273 // the code generator.
274 //
275 // Just remember to wrap code in the appropriate delimiters:
276 // 'PXR_NAMESPACE_OPEN_SCOPE', 'PXR_NAMESPACE_CLOSE_SCOPE'.
277 // ===================================================================== //
278 // --(BEGIN CUSTOM CODE)--
279 
280 
281 #include "pxr/usd/usdGeom/boundable.h"
282 #include "pxr/usd/usdGeom/imageable.h"
283 #include "pxr/usd/usdGeom/tokens.h"
284 
285 #include "pxr/usd/usdSkel/skeleton.h"
286 #include "pxr/usd/usdSkel/utils.h"
287 
288 
289 PXR_NAMESPACE_OPEN_SCOPE
290 
291 
292 UsdGeomPrimvar
GetJointIndicesPrimvar() const293 UsdSkelBindingAPI::GetJointIndicesPrimvar() const
294 {
295     return UsdGeomPrimvar(GetJointIndicesAttr());
296 }
297 
298 
299 UsdGeomPrimvar
CreateJointIndicesPrimvar(bool constant,int elementSize) const300 UsdSkelBindingAPI::CreateJointIndicesPrimvar(bool constant,
301                                              int elementSize) const
302 {
303     return UsdGeomImageable(GetPrim()).CreatePrimvar(
304         UsdSkelTokens->primvarsSkelJointIndices,
305         SdfValueTypeNames->IntArray,
306         constant ? UsdGeomTokens->constant : UsdGeomTokens->vertex,
307         elementSize);
308 }
309 
310 
311 UsdGeomPrimvar
GetJointWeightsPrimvar() const312 UsdSkelBindingAPI::GetJointWeightsPrimvar() const
313 {
314     return UsdGeomPrimvar(GetJointWeightsAttr());
315 }
316 
317 
318 UsdGeomPrimvar
CreateJointWeightsPrimvar(bool constant,int elementSize) const319 UsdSkelBindingAPI::CreateJointWeightsPrimvar(bool constant,
320                                              int elementSize) const
321 {
322     return UsdGeomImageable(GetPrim()).CreatePrimvar(
323         UsdSkelTokens->primvarsSkelJointWeights,
324         SdfValueTypeNames->FloatArray,
325         constant ? UsdGeomTokens->constant : UsdGeomTokens->vertex,
326         elementSize);
327 }
328 
329 
330 bool
SetRigidJointInfluence(int jointIndex,float weight) const331 UsdSkelBindingAPI::SetRigidJointInfluence(int jointIndex, float weight) const
332 {
333     UsdGeomPrimvar jointIndicesPv =
334         CreateJointIndicesPrimvar(/*constant*/ true, /*elementSize*/ 1);
335     UsdGeomPrimvar jointWeightsPv =
336         CreateJointWeightsPrimvar(/*constant*/ true, /*elementSize*/ 1);
337 
338     if (jointIndex < 0) {
339         TF_WARN("Invalid jointIndex '%d'", jointIndex);
340         return false;
341     }
342 
343     return jointIndicesPv.Set(VtIntArray(1, jointIndex)) &&
344            jointWeightsPv.Set(VtFloatArray(1, weight));
345 }
346 
347 
348 namespace {
349 
350 
351 bool
_HasInactiveAncestor(const UsdStagePtr & stage,const SdfPath & path)352 _HasInactiveAncestor(const UsdStagePtr& stage, const SdfPath& path)
353 {
354     if (path.IsAbsolutePath() && path.IsPrimPath()) {
355         for (SdfPath p = path.GetParentPath();
356              p != SdfPath::AbsoluteRootPath(); p = p.GetParentPath()) {
357             if (UsdPrim prim = stage->GetPrimAtPath(p)) {
358                 return !prim.IsActive();
359             }
360         }
361     }
362     return false;
363 }
364 
365 
366 /// Return the a resolved prim for a target in \p targets.
367 UsdPrim
_GetFirstTargetPrimForRel(const UsdRelationship & rel,const SdfPathVector & targets)368 _GetFirstTargetPrimForRel(const UsdRelationship& rel,
369                           const SdfPathVector& targets)
370 {
371     if (targets.size() > 0) {
372         if (targets.size() > 1) {
373             TF_WARN("%s -- relationship has more than one target. "
374                     "Only the first will be used.",
375                     rel.GetPath().GetText());
376         }
377         const SdfPath& target = targets.front();
378         if (UsdPrim prim = rel.GetStage()->GetPrimAtPath(target))
379             return prim;
380 
381         // Should throw a warning about an invalid target.
382         // However, we may not be able to access the prim because one of its
383         // ancestors may be inactive. If so, failing to retrieve the prim is
384         // expected, so we should avoid warning spam.
385         if (!_HasInactiveAncestor(rel.GetStage(), target)) {
386             TF_WARN("%s -- Invalid target <%s>.",
387                     rel.GetPath().GetText(), target.GetText());
388         }
389     }
390     return UsdPrim();
391 }
392 
393 
394 } // namespace
395 
396 
397 bool
GetSkeleton(UsdSkelSkeleton * skel) const398 UsdSkelBindingAPI::GetSkeleton(UsdSkelSkeleton* skel) const
399 {
400     if (!skel) {
401         TF_CODING_ERROR("'skel' pointer is null.");
402         return false;
403     }
404 
405     if (UsdRelationship rel = GetSkeletonRel()) {
406 
407         SdfPathVector targets;
408         if (rel.GetForwardedTargets(&targets)) {
409             if (!targets.empty() || rel.HasAuthoredTargets()) {
410                 UsdPrim prim = _GetFirstTargetPrimForRel(rel, targets);
411                 *skel = UsdSkelSkeleton(prim);
412 
413                 if (prim && !*skel) {
414                     TF_WARN("%s -- target (<%s>) of relationship is not "
415                             "a Skeleton.", rel.GetPath().GetText(),
416                             prim.GetPath().GetText());
417                 }
418                 return true;
419             }
420         }
421     }
422     *skel = UsdSkelSkeleton();
423     return false;
424 }
425 
426 
427 UsdSkelSkeleton
GetInheritedSkeleton() const428 UsdSkelBindingAPI::GetInheritedSkeleton() const
429 {
430     UsdSkelSkeleton skel;
431 
432     if (UsdPrim p = GetPrim()) {
433         for( ; !p.IsPseudoRoot(); p = p.GetParent()) {
434             if (UsdSkelBindingAPI(p).GetSkeleton(&skel)) {
435                 return skel;
436             }
437         }
438     }
439     return skel;
440 }
441 
442 
443 bool
GetAnimationSource(UsdPrim * prim) const444 UsdSkelBindingAPI::GetAnimationSource(UsdPrim* prim) const
445 {
446     if (!prim) {
447         TF_CODING_ERROR("'prim' pointer is null.");
448         return false;
449     }
450 
451     if (UsdRelationship rel = GetAnimationSourceRel()) {
452 
453         SdfPathVector targets;
454         if (rel.GetForwardedTargets(&targets)) {
455             if (!targets.empty() || rel.HasAuthoredTargets()) {
456                 *prim = _GetFirstTargetPrimForRel(rel, targets);
457 
458                 if (*prim && !UsdSkelIsSkelAnimationPrim(*prim)) {
459                     TF_WARN("%s -- target (<%s>) of relationship is not a valid "
460                             "skel animation source.",
461                             rel.GetPath().GetText(),
462                             prim->GetPath().GetText());
463                     *prim = UsdPrim();
464                 }
465                 return true;
466             }
467         }
468     }
469     *prim = UsdPrim();
470     return false;
471 }
472 
473 
474 UsdPrim
GetInheritedAnimationSource() const475 UsdSkelBindingAPI::GetInheritedAnimationSource() const
476 {
477     UsdPrim animPrim;
478 
479     if (UsdPrim p = GetPrim()) {
480         for( ; !p.IsPseudoRoot(); p = p.GetParent()) {
481             if (UsdSkelBindingAPI(p).GetAnimationSource(&animPrim)) {
482                 return animPrim;
483             }
484         }
485     }
486     return animPrim;
487 }
488 
489 
490 bool
ValidateJointIndices(TfSpan<const int> indices,size_t numJoints,std::string * reason)491 UsdSkelBindingAPI::ValidateJointIndices(TfSpan<const int> indices,
492                                         size_t numJoints,
493                                         std::string* reason)
494 {
495     for (size_t i = 0; i < indices.size(); ++i) {
496         const int jointIndex = indices[i];
497         if (jointIndex < 0 || static_cast<size_t>(jointIndex) >= numJoints) {
498             if (reason) {
499                 *reason = TfStringPrintf(
500                     "Index [%d] at element %td is not in the range [0,%zu)",
501                     jointIndex, i, numJoints);
502             }
503             return false;
504         }
505     }
506     return true;
507 }
508 
509 
510 PXR_NAMESPACE_CLOSE_SCOPE
511