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