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_IMAGING_HD_TIME_SAMPLE_ARRAY_H
25 #define PXR_IMAGING_HD_TIME_SAMPLE_ARRAY_H
26 
27 #include "pxr/pxr.h"
28 #include "pxr/imaging/hd/api.h"
29 #include "pxr/imaging/hd/version.h"
30 #include "pxr/base/vt/array.h"
31 #include "pxr/base/vt/value.h"
32 #include "pxr/base/gf/math.h"
33 #include "pxr/base/gf/quatf.h"
34 #include "pxr/base/tf/diagnostic.h"
35 #include "pxr/base/tf/smallVector.h"
36 
37 PXR_NAMESPACE_OPEN_SCOPE
38 
39 /// Resample two neighboring samples.
40 template <typename T>
HdResampleNeighbors(float alpha,const T & v0,const T & v1)41 inline T HdResampleNeighbors(float alpha, const T& v0, const T& v1)
42 {
43     return GfLerp(alpha, v0, v1);
44 }
45 
46 /// Specialization for HdQuatf: spherical linear interpolation.
47 HD_API
HdResampleNeighbors(float alpha,const GfQuatf & v0,const GfQuatf & v1)48 inline GfQuatf HdResampleNeighbors(float alpha,
49                                    const GfQuatf &v0,
50                                    const GfQuatf &v1)
51 {
52     return GfSlerp(double(alpha), v0, v1);
53 }
54 
55 /// Specialization for VtArray: component-wise resampling.
56 template <typename T>
HdResampleNeighbors(float alpha,const VtArray<T> & v0,const VtArray<T> & v1)57 inline VtArray<T> HdResampleNeighbors(float alpha,
58                                       const VtArray<T>& v0,
59                                       const VtArray<T>& v1)
60 {
61     VtArray<T> r(v0.size());
62     for (size_t i=0; i < r.size(); ++i) {
63         r[i] = HdResampleNeighbors(alpha, v0[i], v1[i]);
64     }
65     return r;
66 }
67 
68 /// Specialization for VtValue: interpolate the held values.
69 HD_API
70 VtValue HdResampleNeighbors(float alpha, const VtValue& v0, const VtValue& v1);
71 
72 /// Resample a function described by an ordered array of samples,
73 /// using a linear reconstruction filter evaluated at the given
74 /// parametric position u.  The function is considered constant
75 /// outside the supplied sample range.
76 template <typename T>
HdResampleRawTimeSamples(float u,size_t numSamples,const float * us,const T * vs)77 T HdResampleRawTimeSamples(
78     float u,
79     size_t numSamples,
80     const float *us,
81     const T *vs)
82 {
83     if (numSamples == 0) {
84         TF_CODING_ERROR("HdResampleRawTimeSamples: Zero samples provided");
85         return T();
86     }
87 
88     size_t i=0;
89     for (; i < numSamples; ++i) {
90         if (us[i] == u) {
91             // Fast path for exact parameter match.
92             return vs[i];
93         }
94         if (us[i] > u) {
95             break;
96         }
97     }
98     if (i == 0) {
99         // u is before the first sample.
100         return vs[0];
101     } else if (i == numSamples) {
102         // u is after the last sample.
103         return vs[numSamples-1];
104     } else if (us[i] == us[i-1]) {
105         // Neighboring samples have identical parameter.
106         // Arbitrarily choose a sample.
107         TF_WARN("HdResampleRawTimeSamples: overlapping samples at %f; "
108                 "using first sample", us[i]);
109         return vs[i-1];
110     } else {
111         // Linear blend of neighboring samples.
112         float alpha = (u-us[i-1]) / (us[i]-us[i-1]);
113         return HdResampleNeighbors(alpha, vs[i-1], vs[i]);
114     }
115 }
116 
117 /// Resample a function described by an ordered array of samples and sample
118 /// indices, using a linear reconstruction filter evaluated at the given
119 /// parametric position u.  The function is considered constant outside the
120 /// supplied sample range.
121 template <typename T>
HdResampleRawTimeSamples(float u,size_t numSamples,const float * us,const T * vs,const VtIntArray * is)122 std::pair<T, VtIntArray> HdResampleRawTimeSamples(
123     float u,
124     size_t numSamples,
125     const float *us,
126     const T *vs,
127     const VtIntArray *is)
128 {
129     if (numSamples == 0) {
130         TF_CODING_ERROR("HdResampleRawTimeSamples: Zero samples provided");
131         return std::pair<T, VtIntArray>(T(), VtIntArray(0));
132     }
133 
134     size_t i=0;
135     for (; i < numSamples; ++i) {
136         if (us[i] == u) {
137             // Fast path for exact parameter match.
138             return std::pair<T, VtIntArray>(vs[i], is[i]);
139         }
140         if (us[i] > u) {
141             break;
142         }
143     }
144     if (i == 0) {
145         // u is before the first sample.
146         return std::pair<T, VtIntArray>(vs[0], is[0]);
147     } else if (i == numSamples) {
148         // u is after the last sample.
149         return std::pair<T, VtIntArray>(vs[numSamples-1], is[numSamples-1]);
150     } else if (us[i] == us[i-1]) {
151         // Neighboring samples have identical parameter.
152         // Arbitrarily choose a sample.
153         TF_WARN("HdResampleRawTimeSamples: overlapping samples at %f; "
154                 "using first sample", us[i]);
155         return std::pair<T, VtIntArray>(vs[i-1], is[i-1]);
156     } else {
157         // Linear blend of neighboring samples for values
158         // Hold earlier value for indices
159         float alpha = (us[i]-u) / (us[i]-us[i-1]);
160         return std::pair<T, VtIntArray>(
161             HdResampleNeighbors(alpha, vs[i-1], vs[i]),
162             is[i-1]);
163     }
164 }
165 
166 /// An array of a value sampled over time, in struct-of-arrays layout.
167 /// This is provided as a convenience for time-sampling attributes.
168 /// This type has static capacity but dynamic size, providing
169 /// a limited ability to handle variable sampling without requiring
170 /// heap allocation.
171 template<typename TYPE, unsigned int CAPACITY>
172 struct HdTimeSampleArray
173 {
HdTimeSampleArrayHdTimeSampleArray174     HdTimeSampleArray() {
175         times.resize(CAPACITY);
176         values.resize(CAPACITY);
177         count = 0;
178     }
179 
HdTimeSampleArrayHdTimeSampleArray180     HdTimeSampleArray(const HdTimeSampleArray& rhs) {
181         times = rhs.times;
182         values = rhs.values;
183         count = rhs.count;
184     }
185 
186     HdTimeSampleArray& operator=(const HdTimeSampleArray& rhs) {
187         times = rhs.times;
188         values = rhs.values;
189         count = rhs.count;
190         return *this;
191     }
192 
193     /// Resize the internal buffers.
ResizeHdTimeSampleArray194     virtual void Resize(unsigned int newSize) {
195         times.resize(newSize);
196         values.resize(newSize);
197         count = newSize;
198     }
199 
200     /// Convience method for invoking HdResampleRawTimeSamples
201     /// on this HdTimeSampleArray.
ResampleHdTimeSampleArray202     TYPE Resample(float u) const {
203         return HdResampleRawTimeSamples(u, count, times.data(), values.data());
204     }
205 
206     /// Unbox an HdTimeSampleArray holding boxed VtValue<VtArray<T>>
207     /// samples into an array holding VtArray<T> samples.
208     ///
209     /// Similar to VtValue::Get(), this will issue a coding error if the
210     /// VtValue is not holding the expected type.
211     ///
212     /// \see VtValue::Get()
UnboxFromHdTimeSampleArray213     void UnboxFrom(HdTimeSampleArray<VtValue, CAPACITY> const& box) {
214         Resize(box.count);
215         times = box.times;
216         for (size_t i=0; i < box.count; ++i) {
217             if (box.values[i].GetArraySize() > 0) {
218                 values[i] = box.values[i].template Get<TYPE>();
219             } else {
220                 values[i] = TYPE();
221             }
222         }
223     }
224 
225     size_t count;
226     TfSmallVector<float, CAPACITY> times;
227     TfSmallVector<TYPE, CAPACITY> values;
228 };
229 
230 /// An array of a value and its indices sampled over time, in struct-of-arrays
231 /// layout.
232 template<typename TYPE, unsigned int CAPACITY>
233 struct HdIndexedTimeSampleArray : public HdTimeSampleArray<TYPE, CAPACITY>
234 {
HdIndexedTimeSampleArrayHdIndexedTimeSampleArray235     HdIndexedTimeSampleArray() : HdTimeSampleArray<TYPE, CAPACITY>() {
236         indices.resize(CAPACITY);
237     }
238 
HdIndexedTimeSampleArrayHdIndexedTimeSampleArray239     HdIndexedTimeSampleArray(const HdIndexedTimeSampleArray& rhs) :
240         HdTimeSampleArray<TYPE, CAPACITY>(rhs) {
241         indices = rhs.indices;
242     }
243 
244     HdIndexedTimeSampleArray&
245     operator=(const HdIndexedTimeSampleArray& rhs) {
246         this->times = rhs.times;
247         this->values = rhs.values;
248         this->count = rhs.count;
249         indices = rhs.indices;
250         return *this;
251     }
252 
253     /// Resize the internal buffers.
ResizeHdIndexedTimeSampleArray254     void Resize(unsigned int newSize) override {
255         HdTimeSampleArray<TYPE, CAPACITY>::Resize(newSize);
256         indices.resize(newSize);
257     }
258 
259     /// Convience method for invoking HdResampleRawTimeSamples
260     /// on this HdIndexedTimeSampleArray.
ResampleIndexedHdIndexedTimeSampleArray261     std::pair<TYPE, VtIntArray> ResampleIndexed(float u) const {
262         return HdResampleRawTimeSamples(u, this->count, this->times.data(),
263                                         this->values.data(), indices.data());
264     }
265 
266     /// Unbox an HdIndexedTimeSampleArray holding boxed VtValue<VtArray<T>>
267     /// samples into an array holding VtArray<T> samples.
268     ///
269     /// Similar to VtValue::Get(), this will issue a coding error if the
270     /// VtValue is not holding the expected type.
271     ///
272     /// \see VtValue::Get()
273     void
UnboxFromHdIndexedTimeSampleArray274     UnboxFrom(HdIndexedTimeSampleArray<VtValue, CAPACITY> const& box) {
275         Resize(box.count);
276         this->times = box.times;
277         indices = box.indices;
278         for (size_t i=0; i < box.count; ++i) {
279             if (box.values[i].GetArraySize() > 0) {
280                 this->values[i] = box.values[i].template Get<TYPE>();
281             } else {
282                 this->values[i] = TYPE();
283             }
284         }
285     }
286 
287     TfSmallVector<VtIntArray, CAPACITY> indices;
288 };
289 
290 PXR_NAMESPACE_CLOSE_SCOPE
291 
292 #endif // PXR_IMAGING_HD_TIME_SAMPLE_ARRAY_H
293