source: trunk/nv/interface/interpolate.hh @ 486

Last change on this file since 486 was 486, checked in by epyon, 9 years ago
  • mass update once again...
File size: 12.9 KB
RevLine 
[486]1// Copyright (C) 2015-2016 ChaosForge Ltd
2// http://chaosforge.org/
3//
4// This file is part of Nova libraries.
5// For conditions of distribution and use, see copying.txt file in root folder.
6
7// WARNING: this file is explicitly designed to fuck with your brain
8
9#ifndef NV_INTERFACE_INTERPOLATE_HH
10#define NV_INTERFACE_INTERPOLATE_HH
11
12#include <nv/common.hh>
13#include <nv/core/transform.hh>
14#include <nv/stl/math.hh>
15#include <nv/interface/data_descriptor.hh>
16
17namespace nv
18{
19
20        template < typename T >
21        struct no_interpolator
22        {
23                inline static T interpolate( float, const T& lhs, const T& ) { return lhs; }
24                inline static T interpolate( float, const T& , const T& v1, const T& , const T& ) { return v1; }
25        };
26
27        template < typename T >
28        struct linear_interpolator
29        {
30                inline static T interpolate( float f, const T& lhs, const T& rhs ) { return math::lerp( lhs, rhs, f ); }
31                inline static T interpolate( float f, const T& , const T& v1, const T& v2, const T& ) { return math::lerp( v1, v2, f ); }
32        };
33
34        template < typename T >
35        struct normalized_interpolator
36        {
37                inline static T interpolate( float f, const T& lhs, const T& rhs ) { return math::lerp( lhs, rhs, f ); }
38                inline static T interpolate( float f, const T& , const T& v1, const T& v2, const T& ) { return math::lerp( v1, v2, f ); }
39        };
40
41        template <>
42        struct normalized_interpolator< quat >
43        {
44                inline static quat interpolate( float f, const quat& lhs, const quat& rhs ) { return math::nlerp( lhs, rhs, f ); }
45                inline static quat interpolate( float f, const quat& , const quat& v1, const quat& v2, const quat& ) { return math::nlerp( v1, v2, f ); }
46        };
47
48        template <>
49        struct normalized_interpolator< transform >
50        {
51                inline static transform interpolate( float f, const transform& lhs, const transform& rhs ) { return transform( math::lerp( lhs.get_position(), rhs.get_position(), f ), math::nlerp( lhs.get_orientation(), rhs.get_orientation(), f ) ); }
52                inline static transform interpolate( float f, const transform& , const transform& v1, const transform& v2, const transform& ) { return transform( math::lerp( v1.get_position(), v2.get_position(), f ), math::nlerp( v1.get_orientation(), v2.get_orientation(), f ) ); }
53        };
54
55        template < typename T >
56        struct spherical_interpolator
57        {
58                inline static T interpolate( float f, const T& lhs, const T& rhs ) { return math::lerp( lhs, rhs, f ); }
59                inline static T interpolate( float f, const T& , const T& v1, const T& v2, const T& ) { return math::lerp( v1, v2, f ); }
60        };
61
62        template <>
63        struct spherical_interpolator< quat >
64        {
65                inline static quat interpolate( float f, const quat& lhs, const quat& rhs ) { return math::slerp( lhs, rhs, f ); }
66                inline static quat interpolate( float f, const quat& , const quat& v1, const quat& v2, const quat& ) { return math::slerp( v1, v2, f ); }
67        };
68
69        template <>
70        struct spherical_interpolator< transform >
71        {
72                inline static transform interpolate( float f, const transform& lhs, const transform& rhs ) { return transform( math::lerp( lhs.get_position(), rhs.get_position(), f ), math::slerp( lhs.get_orientation(), rhs.get_orientation(), f ) ); }
73                inline static transform interpolate( float f, const transform& , const transform& v1, const transform& v2, const transform& ) { return transform( math::lerp( v1.get_position(), v2.get_position(), f ), math::slerp( v1.get_orientation(), v2.get_orientation(), f ) ); }
74        };
75
76        struct quadratic_interpolator_base
77        {
78                float weights[4];
79
80                quadratic_interpolator_base( float value )
81                {
82                        float interp_squared = value*value;
83                        float interp_cubed = interp_squared*value;
84                        weights[0] = 0.5f * ( -interp_cubed + 2.0f * interp_squared - value );
85                        weights[1] = 0.5f * ( 3.0f * interp_cubed - 5.0f * interp_squared + 2.0f );
86                        weights[2] = 0.5f * ( -3.0f * interp_cubed + 4.0f * interp_squared + value );
87                        weights[3] = 0.5f * ( interp_cubed - interp_squared );
88                }
89        };
90
91        template < typename T >
92        struct quadratic_interpolator : public quadratic_interpolator_base
93        {
94                using quadratic_interpolator_base::quadratic_interpolator_base;
95                inline static T interpolate( float f, const T& lhs, const T& rhs ) { return math::lerp( lhs, rhs, f ); }
96                inline T interpolate( float, const T& v0, const T& v1, const T& v2, const T& v3 ) const
97                {
98                        return
99                                weights[0] * v0 +
100                                weights[1] * v1 +
101                                weights[2] * v2 +
102                                weights[3] * v3;
103                }
104        };
105
106        template <>
107        struct quadratic_interpolator< quat > : public quadratic_interpolator_base
108        {
109                using quadratic_interpolator_base::quadratic_interpolator_base;
110                inline static quat interpolate( float f, const quat& lhs, const quat& rhs ) { return math::lerp( lhs, rhs, f ); }
111                inline quat interpolate( float, const quat& v0, const quat& v1, const quat& v2, const quat& v3 ) const
112                {
113                        float a = dot( v1, v2 ) > 0.0f ? 1.0f : -1.0f;
114                        return normalize(
115                                weights[0] * v0 +
116                                weights[1] * ( a * v1 ) +
117                                weights[2] * v2 +
118                                weights[3] * v3
119                                );
120                }
121        };
122
123        template <>
124        struct quadratic_interpolator< transform > : public quadratic_interpolator_base
125        {
126                using quadratic_interpolator_base::quadratic_interpolator_base;
127                inline static transform interpolate( float f, const transform& lhs, const transform& rhs ) { return math::lerp( lhs, rhs, f ); }
128                inline transform interpolate( float, const transform& v0, const transform& v1, const transform& v2, const transform& v3 ) const
129                {
130                        float a = dot( v1.get_orientation(), v2.get_orientation() ) > 0.0f ? 1.0f : -1.0f;
131                        return transform(
132                                weights[0] * v0.get_position() +
133                                weights[1] * v1.get_position() +
134                                weights[2] * v2.get_position() +
135                                weights[3] * v3.get_position(),
136                                normalize(
137                                weights[0] * v0.get_orientation() +
138                                weights[1] * ( a * v1.get_orientation() ) +
139                                weights[2] * v2.get_orientation() +
140                                weights[3] * v3.get_orientation()
141                                ) );
142                }
143        };
144
145        template < typename T >
146        struct squad_interpolator
147        {
148                inline static T interpolate( float f, const T& lhs, const T& rhs ) { return math::slerp( lhs, rhs, f ); }
149                inline static T interpolate( float f, const T& v0, const T& v1, const T& v2, const T& v3 ) { return math::slerp( v1, v2, f ); }
150        };
151
152        template <>
153        struct squad_interpolator< quat >
154        {
155                inline static quat interpolate( float f, const quat& lhs, const quat& rhs ) { return math::slerp( lhs, rhs, f ); }
156                inline static quat interpolate( float f, const quat& v0, const quat& v1, const quat& v2, const quat& v3 )
157                {
158                        return normalize( math::squad(
159                                v1, v2,
160                                math::intermediate( v0, v1, v2 ),
161                                math::intermediate( v1, v2, v3 ),
162                                f ) );
163                }
164        };
165
166        template <>
167        struct squad_interpolator< transform >
168        {
169                inline static transform interpolate( float f, const transform& lhs, const transform& rhs ) { return spherical_interpolator<transform>::interpolate( f, lhs, rhs ); }
170                inline static transform interpolate( float f, const transform& v0, const transform& v1, const transform& v2, const transform& v3 )
171                {
172                        return transform(
173                                mix( v1.get_position(), v2.get_position(), f ),
174                                squad_interpolator< quat >::interpolate( f,
175                                        v0.get_orientation(),
176                                        v1.get_orientation(),
177                                        v2.get_orientation(),
178                                        v3.get_orientation()
179                                        ) );
180                }
181        };
182
183
184        enum class interpolation
185        {
186                NONE,
187                LINEAR,
188                NORMALIZED,
189                SPHERICAL,
190                QUADRATIC,
191                SQUADRATIC,
192        };
193
194        template < typename T, typename Interpolator, typename ...Args >
195        T interpolate( float f, const Interpolator& i, Args&&... args )
196        {
197                NV_UNUSED( i );
198                return i.interpolate( f, ::nv::forward<Args>( args )... );
199        }
200       
201        template < typename T, typename ...Args >
202        T interpolate( float f, interpolation i, Args&&... args )
203        {
204                switch ( i )
205                {
206                case interpolation::LINEAR        : return linear_interpolator<T>::interpolate( f, ::nv::forward<Args>( args )... );
207                case interpolation::NORMALIZED    : return normalized_interpolator<T>::interpolate( f, ::nv::forward<Args>( args )... );
208                case interpolation::SPHERICAL     : return spherical_interpolator<T>::interpolate( f, ::nv::forward<Args>( args )... );
209                case interpolation::QUADRATIC     : return quadratic_interpolator<T>::interpolate( f, ::nv::forward<Args>( args )... );
210                case interpolation::SQUADRATIC    : return squad_interpolator<T>::interpolate( f, ::nv::forward<Args>( args )... );
211                default: case interpolation::NONE : return no_interpolator<T>::interpolate( f, ::nv::forward<Args>( args )... );
212                }
213        }
214
215        template < typename T, typename ...Args >
216        void interpolate( T& result, float f, interpolation i, Args&&... args )
217        {
218                typedef typename T::value_type value_type;
219                switch ( i )
220                {
221                case interpolation::LINEAR        : interpolate_array( result, f, linear_interpolator<value_type>(), ::nv::forward<Args>( args )... ); break;
222                case interpolation::NORMALIZED    : interpolate_array( result, f, normalized_interpolator<value_type>(), ::nv::forward<Args>( args )... ); break;
223                case interpolation::SPHERICAL     : interpolate_array( result, f, spherical_interpolator<value_type>(), ::nv::forward<Args>( args )... ); break;
224                case interpolation::QUADRATIC     : interpolate_array( result, f, quadratic_interpolator<value_type>( f ), ::nv::forward<Args>( args )... ); break;
225                case interpolation::SQUADRATIC    : interpolate_array( result, f, squad_interpolator<value_type>(), ::nv::forward<Args>( args )... ); break;
226                default: case interpolation::NONE : interpolate_array( result, f, no_interpolator<value_type>(), ::nv::forward<Args>( args )... ); break;
227                }
228        }
229
230        template < typename T, typename Interpolator >
231        auto interpolate_extract( float f, const Interpolator& i, uint32 n, const T& a1, const T& a2 )
232                -> typename T::value_type
233        {
234                NV_UNUSED( i );
235                return i.interpolate( f, a1[n], a2[n] );
236        }
237
238        template < typename T, typename Interpolator >
239        auto interpolate_extract( float f, const Interpolator& i, uint32 n, const T& a0, const T& a1, const T& a2, const T& a3 )
240                -> typename T::value_type
241        {
242                NV_UNUSED( i );
243                return i.interpolate( f, a0[n], a1[n], a2[n], a3[n] );
244        }
245
246
247        template < typename T, typename Interpolator, typename ...Args >
248        void interpolate_array( T& result, float f, const Interpolator& in, Args&&... args )
249        {
250                uint32 size = result.size();
251                for ( uint32 n = 0; n < size; ++n )
252                {
253                        result[n] = interpolate_extract( f, in, n, ::nv::forward<Args>( args )... );
254                }
255        }
256
257        template < typename T, typename Interpolator, typename ...Args >
258        void interpolate_array( T& a, float f, const Interpolator& in, const array_view< bool >& mask, Args&&... args )
259        {
260                uint32 size = a.size();
261                for ( uint32 n = 0; n < size; ++n )
262                        if ( mask[ n ] )
263                        {
264                                a[n] = interpolate_extract( f, in, n, ::nv::forward<Args>( args )... );
265                        }
266        }
267
268        template < typename T, typename Interpolator, typename... Args >
269        void interpolate_array( T& result, float f, const Interpolator& in, float blend_factor, interpolation bi, Args&&... args )
270        {
271                typedef typename T::value_type value_type;
272                switch ( bi )
273                {
274                case interpolation::LINEAR        : interpolate_blend( result, f, in, blend_factor, linear_interpolator<value_type>(), ::nv::forward<Args>( args )... ); break;
275                case interpolation::NORMALIZED    : interpolate_blend( result, f, in, blend_factor, normalized_interpolator<value_type>(), ::nv::forward<Args>( args )... ); break;
276                case interpolation::SPHERICAL     : interpolate_blend( result, f, in, blend_factor, spherical_interpolator<value_type>(), ::nv::forward<Args>( args )... ); break;
277                case interpolation::QUADRATIC     : interpolate_blend( result, f, in, blend_factor, normalized_interpolator<value_type>(), ::nv::forward<Args>( args )... ); break;
278                case interpolation::SQUADRATIC    : interpolate_blend( result, f, in, blend_factor, spherical_interpolator<value_type>(), ::nv::forward<Args>( args )... ); break;
279                default: case interpolation::NONE : interpolate_blend( result, f, in, blend_factor, no_interpolator<value_type>(), ::nv::forward<Args>( args )... ); break;
280                }
281        }
282
283        template < typename T, typename Interpolator, typename BlendInterpolator, typename... Args >
284        void interpolate_blend( T& a, float f, const Interpolator& in, float blend_factor, const BlendInterpolator& bin, Args&&... args )
285        {
286                NV_UNUSED( bin );
287                typedef typename T::value_type value_type;
288                uint32 size = a.size();
289                for ( uint32 n = 0; n < size; ++n )
290                {
291                        value_type temp = interpolate_extract( f, in, n, ::nv::forward<Args>( args )... );
292                        a[n] = bin.interpolate( blend_factor, a[n], temp );
293                }
294        }
295
296        template < typename T, typename Interpolator, typename BlendInterpolator, typename... Args >
297        void interpolate_blend( T& a, float f, const Interpolator& in, float blend_factor, const BlendInterpolator& bin, const array_view< bool >& mask, Args&&... args )
298        {
299                NV_UNUSED( bin );
300                typedef typename T::value_type value_type;
301                uint32 size = a.size();
302                for ( uint32 n = 0; n < size; ++n )
303                        if ( mask[n] )
304                        {
305                                value_type temp = interpolate_extract( f, in, n, ::nv::forward<Args>( args )... );
306                                a[n] = bin.interpolate( blend_factor, a[n], temp );
307                        }
308        }
309
310
311
312}
313#endif // NV_INTERFACE_INTERPOLATE_HH
Note: See TracBrowser for help on using the repository browser.