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