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 #ifndef PXR_USD_USD_SKEL_ANIM_MAPPER_H
25 #define PXR_USD_USD_SKEL_ANIM_MAPPER_H
26
27 /// \file usdSkel/animMapper.h
28
29 #include "pxr/pxr.h"
30 #include "pxr/usd/usdSkel/api.h"
31
32 #include "pxr/base/gf/matrix4d.h"
33 #include "pxr/base/gf/matrix4f.h"
34 #include "pxr/base/tf/span.h"
35 #include "pxr/base/vt/array.h"
36 #include "pxr/usd/sdf/types.h"
37
38 #include <type_traits>
39 #include <vector>
40
41
42 PXR_NAMESPACE_OPEN_SCOPE
43
44
45 using UsdSkelAnimMapperRefPtr = std::shared_ptr<class UsdSkelAnimMapper>;
46
47
48 /// \class UsdSkelAnimMap
49 ///
50 /// Helper class for remapping vectorized animation data from
51 /// one ordering of tokens to another.
52 class UsdSkelAnimMapper {
53 public:
54 /// Construct a null mapper.
55 USDSKEL_API
56 UsdSkelAnimMapper();
57
58 /// Construct an identity mapper for remapping a range of \p size elems.
59 /// An identity mapper is used to indicate that no remapping is required.
60 USDSKEL_API
61 UsdSkelAnimMapper(size_t size);
62
63 /// Construct a mapper for mapping data from \p sourceOrder to
64 /// \p targetOrder.
65 USDSKEL_API
66 UsdSkelAnimMapper(const VtTokenArray& sourceOrder,
67 const VtTokenArray& targetOrder);
68
69 /// Construct a mapper for mapping data from \p sourceOrder to
70 /// \p targetOrder, each being arrays of size \p sourceOrderSize
71 /// and \p targetOrderSize, respectively.
72 USDSKEL_API
73 UsdSkelAnimMapper(const TfToken* sourceOrder, size_t sourceOrderSize,
74 const TfToken* targetOrder, size_t targetOrderSize);
75
76 /// Typed remapping of data in an arbitrary, stl-like container.
77 /// The \p source array provides a run of \p elementSize for each path in
78 /// the \\em sourceOrder. These elements are remapped and copied over the
79 /// \p target array.
80 /// Prior to remapping, the \p target array is resized to the size of the
81 /// \\em targetOrder (as given at mapper construction time) multiplied by
82 /// the \p elementSize. New element created in the array are initialized
83 /// to \p defaultValue, if provided.
84 template <typename Container>
85 bool Remap(const Container& source,
86 Container* target,
87 int elementSize=1,
88 const typename Container::value_type*
89 defaultValue=nullptr) const;
90
91 /// Type-erased remapping of data from \p source into \p target.
92 /// The \p source array provides a run of \p elementSize elements for each
93 /// path in the \\em sourceOrder. These elements are remapped and copied
94 /// over the \p target array.
95 /// Prior to remapping, the \p target array is resized to the size of the
96 /// \\em targetOrder (as given at mapper construction time) multiplied by
97 /// the \p elementSize. New elements created in the array are initialized
98 /// to \p defaultValue, if provided.
99 /// Remapping is supported for registered Sdf array value types only.
100 USDSKEL_API
101 bool Remap(const VtValue& source, VtValue* target,
102 int elementSize=1, const VtValue& defaultValue=VtValue()) const;
103
104 /// Convenience method for the common task of remapping transform arrays.
105 /// This performs the same operation as Remap(), but sets the matrix
106 /// identity as the default value.
107 template <typename Matrix4>
108 USDSKEL_API
109 bool RemapTransforms(const VtArray<Matrix4>& source,
110 VtArray<Matrix4>* target,
111 int elementSize=1) const;
112
113 /// Returns true if this is an identity map.
114 /// The source and target orders of an identity map are identical.
115 USDSKEL_API
116 bool IsIdentity() const;
117
118 /// Returns true if this is a sparse mapping.
119 /// A sparse mapping means that not all target values will be overridden
120 /// by source values, when mapped with Remap().
121 USDSKEL_API
122 bool IsSparse() const;
123
124 /// Returns true if this is a null mapping.
125 /// No source elements of a null map are mapped to the target.
126 USDSKEL_API
127 bool IsNull() const;
128
129 /// Get the size of the output array that this mapper expects to
130 /// map data into.
131 USDSKEL_API
size()132 size_t size() const { return _targetSize; }
133
134 bool operator==(const UsdSkelAnimMapper& o) const;
135
136 bool operator!=(const UsdSkelAnimMapper& o) const {
137 return !(*this == o);
138 }
139
140 private:
141
142 template <typename T>
143 bool _UntypedRemap(const VtValue& source, VtValue* target,
144 int elementSize, const VtValue& defaultValue) const;
145
146 template <typename T>
147 static void _ResizeContainer(VtArray<T>* array,
148 size_t size,
149 const T& defaultValue);
150
151 template <typename Container>
152 static void _ResizeContainer(
153 Container* container,
154 size_t size,
155 const typename Container::value_type& defaultValue,
156 typename std::enable_if<
157 !VtIsArray<Container>::value,
158 Container>::type* = 0)
159 { container->resize(size, defaultValue); }
160
161 USDSKEL_API
162 bool _IsOrdered() const;
163
164 /// Size of the output map.
165 size_t _targetSize;
166
167 /// For ordered mappings, an offset into the output array at which
168 /// to map the source data.
169 size_t _offset;
170
171 /// For unordered mappings, an index map, mapping from source
172 /// indices to target indices.
173 VtIntArray _indexMap;
174 int _flags;
175 };
176
177
178 template <typename T>
179 void
_ResizeContainer(VtArray<T> * array,size_t size,const T & defaultValue)180 UsdSkelAnimMapper::_ResizeContainer(VtArray<T>* array, size_t size,
181 const T& defaultValue)
182 {
183 // XXX: VtArray::resize() doesn't take an default value atm.
184 // We should fix this...
185 const size_t prevSize = array->size();
186 array->resize(size);
187 auto span = TfMakeSpan(*array);
188 for(size_t i = prevSize; i < size; ++i) {
189 span[i] = defaultValue;
190 }
191 }
192
193
194 template <typename Container>
195 bool
Remap(const Container & source,Container * target,int elementSize,const typename Container::value_type * defaultValue)196 UsdSkelAnimMapper::Remap(const Container& source,
197 Container* target,
198 int elementSize,
199 const typename Container::value_type* defaultValue) const
200 {
201 using _ValueType = typename Container::value_type;
202
203 if (!target) {
204 TF_CODING_ERROR("'target' is null");
205 return false;
206 }
207 if (elementSize <= 0) {
208 TF_WARN("Invalid elementSize [%d]: "
209 "size must be greater than zero.", elementSize);
210 return false;
211 }
212
213 const size_t targetArraySize = _targetSize*elementSize;
214
215 if (IsIdentity() && source.size() == targetArraySize) {
216 // Can make copy of the array.
217 *target = source;
218 return true;
219 }
220
221 // Resize the target array to the expected size.
222 _ResizeContainer(target, targetArraySize,
223 defaultValue ? *defaultValue : _ValueType());
224
225 if (IsNull()) {
226 return true;
227 } else if (_IsOrdered()) {
228
229 size_t copyCount =
230 std::min(source.size(), targetArraySize - _offset*elementSize);
231 std::copy(source.cdata(), source.cdata()+copyCount,
232 target->data() + _offset*elementSize);
233 } else {
234
235 const _ValueType* sourceData = source.cdata();
236
237 _ValueType* targetData = target->data();
238 size_t copyCount = std::min(source.size()/elementSize,
239 _indexMap.size());
240
241 const int* indexMap = _indexMap.data();
242
243 for (size_t i = 0; i < copyCount; ++i) {
244 int targetIdx = indexMap[i];
245 if (targetIdx >= 0 &&
246 static_cast<size_t>(targetIdx) < target->size()) {
247 TF_DEV_AXIOM(i*elementSize < source.size());
248 TF_DEV_AXIOM((i+1)*elementSize <= source.size());
249 TF_DEV_AXIOM(static_cast<size_t>((targetIdx+1)*elementSize)
250 <= target->size());
251 std::copy(sourceData + i*elementSize,
252 sourceData + (i+1)*elementSize,
253 targetData + targetIdx*elementSize);
254 }
255 }
256 }
257 return true;
258 }
259
260
261 PXR_NAMESPACE_CLOSE_SCOPE
262
263 #endif // PXR_USD_USD_SKEL_ANIM_MAPPER_H
264