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/animMapper.h"
25 
26 #include "pxr/base/gf/matrix4d.h"
27 #include "pxr/base/gf/matrix4f.h"
28 #include "pxr/base/tf/type.h"
29 
30 #include <algorithm>
31 #include <unordered_map>
32 
33 
34 PXR_NAMESPACE_OPEN_SCOPE
35 
36 namespace {
37 
38 
39 enum _MapFlags {
40     _NullMap = 0,
41 
42     _SomeSourceValuesMapToTarget = 0x1,
43     _AllSourceValuesMapToTarget = 0x2,
44     _SourceOverridesAllTargetValues = 0x4,
45     _OrderedMap = 0x8,
46 
47     _IdentityMap = (_AllSourceValuesMapToTarget|
48                     _SourceOverridesAllTargetValues|_OrderedMap),
49 
50     _NonNullMap = (_SomeSourceValuesMapToTarget|_AllSourceValuesMapToTarget)
51 };
52 
53 
54 } // namespace
55 
56 
UsdSkelAnimMapper()57 UsdSkelAnimMapper::UsdSkelAnimMapper()
58     : _targetSize(0), _offset(0), _flags(_NullMap)
59 {}
60 
61 
UsdSkelAnimMapper(size_t size)62 UsdSkelAnimMapper::UsdSkelAnimMapper(size_t size)
63     : _targetSize(size), _offset(0), _flags(_IdentityMap)
64 {}
65 
66 
UsdSkelAnimMapper(const VtTokenArray & sourceOrder,const VtTokenArray & targetOrder)67 UsdSkelAnimMapper::UsdSkelAnimMapper(const VtTokenArray& sourceOrder,
68                                      const VtTokenArray& targetOrder)
69     : UsdSkelAnimMapper(sourceOrder.cdata(), sourceOrder.size(),
70                         targetOrder.cdata(), targetOrder.size())
71 {}
72 
73 
UsdSkelAnimMapper(const TfToken * sourceOrder,size_t sourceOrderSize,const TfToken * targetOrder,size_t targetOrderSize)74 UsdSkelAnimMapper::UsdSkelAnimMapper(const TfToken* sourceOrder,
75                                      size_t sourceOrderSize,
76                                      const TfToken* targetOrder,
77                                      size_t targetOrderSize)
78     : _targetSize(targetOrderSize), _offset(0)
79 {
80     if(sourceOrderSize == 0 || targetOrderSize == 0) {
81         _flags = _NullMap;
82         return;
83     }
84 
85     {
86         // Determine if this an ordered mapping of the source
87         // onto the target, with a simple offset.
88         // This includes identity maps.
89 
90         // Find where the first source element begins on the target.
91         const auto it = std::find(targetOrder, targetOrder + targetOrderSize,
92                                   sourceOrder[0]);
93         const size_t pos = it - targetOrder;
94         if((pos + sourceOrderSize) <= targetOrderSize) {
95             if(std::equal(sourceOrder, sourceOrder+sourceOrderSize, it)) {
96                 _offset = pos;
97 
98                 _flags = _OrderedMap | _AllSourceValuesMapToTarget;
99 
100                 if(pos == 0 && sourceOrderSize == targetOrderSize) {
101                     _flags |= _SourceOverridesAllTargetValues;
102                 }
103                 return;
104             }
105         }
106     }
107 
108     // No ordered mapping can be produced.
109     // Settle for an unordered, indexed mapping.
110 
111     // Need a map of path->targetIndex.
112     std::unordered_map<TfToken,int,TfToken::HashFunctor> targetMap;
113     for(size_t i = 0; i < targetOrderSize; ++i) {
114         targetMap[targetOrder[i]] = static_cast<int>(i);
115     }
116 
117     _indexMap.resize(sourceOrderSize);
118     int* indexMap = _indexMap.data();
119     size_t mappedCount = 0;
120     std::vector<bool> targetMapped(targetOrderSize);
121     for(size_t i = 0; i < sourceOrderSize; ++i) {
122         auto it = targetMap.find(sourceOrder[i]);
123         if(it != targetMap.end()) {
124             indexMap[i] = it->second;
125             targetMapped[it->second] = true;
126             ++mappedCount;
127         } else {
128             indexMap[i] = -1;
129         }
130     }
131     _flags = mappedCount == sourceOrderSize ?
132         _AllSourceValuesMapToTarget : _SomeSourceValuesMapToTarget;
133 
134     if(std::all_of(targetMapped.begin(), targetMapped.end(),
135                    [](bool val) { return val; })) {
136         _flags |= _SourceOverridesAllTargetValues;
137     }
138 }
139 
140 
141 bool
IsIdentity() const142 UsdSkelAnimMapper::IsIdentity() const
143 {
144     return (_flags&_IdentityMap) == _IdentityMap;
145 }
146 
147 bool
IsSparse() const148 UsdSkelAnimMapper::IsSparse() const
149 {
150     return !(_flags&_SourceOverridesAllTargetValues);
151 }
152 
153 
154 bool
IsNull() const155 UsdSkelAnimMapper::IsNull() const
156 {
157     return !(_flags&_NonNullMap);
158 }
159 
160 
161 bool
_IsOrdered() const162 UsdSkelAnimMapper::_IsOrdered() const
163 {
164     return _flags&_OrderedMap;
165 }
166 
167 
168 template <typename T>
169 bool
_UntypedRemap(const VtValue & source,VtValue * target,int elementSize,const VtValue & defaultValue) const170 UsdSkelAnimMapper::_UntypedRemap(const VtValue& source,
171                                  VtValue* target,
172                                  int elementSize,
173                                  const VtValue& defaultValue) const
174 {
175     TF_DEV_AXIOM(source.IsHolding<VtArray<T> >());
176 
177     if (!target) {
178         TF_CODING_ERROR("'target' pointer is null.");
179         return false;
180     }
181 
182     if (target->IsEmpty()) {
183         *target = VtArray<T>();
184     } else if (!target->IsHolding<VtArray<T> >()) {
185         TF_CODING_ERROR("Type of 'target' [%s] did not match the type of "
186                         "'source' [%s].", target->GetTypeName().c_str(),
187                         source.GetTypeName().c_str());
188         return false;
189     }
190 
191     const T* defaultValueT = nullptr;
192     if (!defaultValue.IsEmpty()) {
193         if (defaultValue.IsHolding<T>()) {
194             defaultValueT = &defaultValue.UncheckedGet<T>();
195         } else {
196             TF_CODING_ERROR("Unexpected type [%s] for defaultValue: expecting "
197                             "'%s'.", defaultValue.GetTypeName().c_str(),
198                             TfType::Find<T>().GetTypeName().c_str());
199             return false;
200         }
201     }
202 
203     const auto& sourceArray = source.UncheckedGet<VtArray<T> >();
204     auto targetArray = target->UncheckedGet<VtArray<T> >();
205     if (Remap(sourceArray, &targetArray, elementSize, defaultValueT)) {
206         *target = targetArray;
207         return true;
208     }
209     return false;
210 }
211 
212 
213 bool
Remap(const VtValue & source,VtValue * target,int elementSize,const VtValue & defaultValue) const214 UsdSkelAnimMapper::Remap(const VtValue& source,
215                          VtValue* target,
216                          int elementSize,
217                          const VtValue& defaultValue) const
218 {
219 #define _UNTYPED_REMAP(r, unused, elem)                                 \
220     if(source.IsHolding<SDF_VALUE_CPP_ARRAY_TYPE(elem)>()) {            \
221         return _UntypedRemap<SDF_VALUE_CPP_TYPE(elem)>(                 \
222             source, target, elementSize, defaultValue);                 \
223     }
224 
225 BOOST_PP_SEQ_FOR_EACH(_UNTYPED_REMAP, ~, SDF_VALUE_TYPES);
226 #undef _UNTYPED_REMAP
227 
228     return false;
229 }
230 
231 
232 template <typename Matrix4>
233 bool
RemapTransforms(const VtArray<Matrix4> & source,VtArray<Matrix4> * target,int elementSize) const234 UsdSkelAnimMapper::RemapTransforms(const VtArray<Matrix4>& source,
235                                    VtArray<Matrix4>* target,
236                                    int elementSize) const
237 {
238     static const Matrix4 identity(1);
239     return Remap(source, target, elementSize, &identity);
240 }
241 
242 
243 template USDSKEL_API bool
244 UsdSkelAnimMapper::RemapTransforms(const VtMatrix4dArray&,
245                                    VtMatrix4dArray*, int) const;
246 
247 template USDSKEL_API bool
248 UsdSkelAnimMapper::RemapTransforms(const VtMatrix4fArray&,
249                                    VtMatrix4fArray*, int) const;
250 
251 
252 bool
operator ==(const UsdSkelAnimMapper & o) const253 UsdSkelAnimMapper::operator==(const UsdSkelAnimMapper& o) const
254 {
255     return _targetSize == o._targetSize &&
256            _offset == o._offset &&
257            _flags == o._flags &&
258            _indexMap == o._indexMap;
259 }
260 
261 
262 PXR_NAMESPACE_CLOSE_SCOPE
263