e73e5bc17a225cd9b38f7e288dfb7fd82277f509
[blender.git] / intern / cycles / util / util_math_float3.h
1 /*
2  * Copyright 2011-2017 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #ifndef __UTIL_MATH_FLOAT3_H__
18 #define __UTIL_MATH_FLOAT3_H__
19
20 #ifndef __UTIL_MATH_H__
21 #  error "Do not include this file directly, include util_types.h instead."
22 #endif
23
24 CCL_NAMESPACE_BEGIN
25
26 /*******************************************************************************
27  * Declaration.
28  */
29
30 #ifndef __KERNEL_OPENCL__
31 ccl_device_inline float3 operator-(const float3& a);
32 ccl_device_inline float3 operator*(const float3& a, const float3& b);
33 ccl_device_inline float3 operator*(const float3& a, const float f);
34 ccl_device_inline float3 operator*(const float f, const float3& a);
35 ccl_device_inline float3 operator/(const float f, const float3& a);
36 ccl_device_inline float3 operator/(const float3& a, const float f);
37 ccl_device_inline float3 operator/(const float3& a, const float3& b);
38 ccl_device_inline float3 operator+(const float3& a, const float3& b);
39 ccl_device_inline float3 operator-(const float3& a, const float3& b);
40 ccl_device_inline float3 operator+=(float3& a, const float3& b);
41 ccl_device_inline float3 operator-=(float3& a, const float3& b);
42 ccl_device_inline float3 operator*=(float3& a, const float3& b);
43 ccl_device_inline float3 operator*=(float3& a, float f);
44 ccl_device_inline float3 operator/=(float3& a, const float3& b);
45 ccl_device_inline float3 operator/=(float3& a, float f);
46
47 ccl_device_inline bool operator==(const float3& a, const float3& b);
48 ccl_device_inline bool operator!=(const float3& a, const float3& b);
49
50 ccl_device_inline float dot(const float3& a, const float3& b);
51 ccl_device_inline float dot_xy(const float3& a, const float3& b);
52 ccl_device_inline float3 cross(const float3& a, const float3& b);
53 ccl_device_inline float3 normalize(const float3& a);
54 ccl_device_inline float3 min(const float3& a, const float3& b);
55 ccl_device_inline float3 max(const float3& a, const float3& b);
56 ccl_device_inline float3 clamp(const float3& a, const float3& mn, const float3& mx);
57 ccl_device_inline float3 fabs(const float3& a);
58 ccl_device_inline float3 mix(const float3& a, const float3& b, float t);
59 ccl_device_inline float3 rcp(const float3& a);
60 #endif  /* !__KERNEL_OPENCL__ */
61
62 ccl_device_inline float max3(float3 a);
63 ccl_device_inline float len(const float3 a);
64 ccl_device_inline float len_squared(const float3 a);
65
66 ccl_device_inline float3 saturate3(float3 a);
67 ccl_device_inline float3 safe_normalize(const float3 a);
68 ccl_device_inline float3 normalize_len(const float3 a, float *t);;
69 ccl_device_inline float3 safe_normalize_len(const float3 a, float *t);
70 ccl_device_inline float3 interp(float3 a, float3 b, float t);
71
72 ccl_device_inline bool is_zero(const float3 a);
73 ccl_device_inline float reduce_add(const float3 a);
74 ccl_device_inline float average(const float3 a);
75 ccl_device_inline bool isequal_float3(const float3 a, const float3 b);
76
77 /*******************************************************************************
78  * Definition.
79  */
80
81 #ifndef __KERNEL_OPENCL__
82 ccl_device_inline float3 operator-(const float3& a)
83 {
84 #ifdef __KERNEL_SSE__
85         return float3(_mm_xor_ps(a.m128, _mm_castsi128_ps(_mm_set1_epi32(0x80000000))));
86 #else
87         return make_float3(-a.x, -a.y, -a.z);
88 #endif
89 }
90
91 ccl_device_inline float3 operator*(const float3& a, const float3& b)
92 {
93 #ifdef __KERNEL_SSE__
94         return float3(_mm_mul_ps(a.m128,b.m128));
95 #else
96         return make_float3(a.x*b.x, a.y*b.y, a.z*b.z);
97 #endif
98 }
99
100 ccl_device_inline float3 operator*(const float3& a, const float f)
101 {
102 #ifdef __KERNEL_SSE__
103         return float3(_mm_mul_ps(a.m128,_mm_set1_ps(f)));
104 #else
105         return make_float3(a.x*f, a.y*f, a.z*f);
106 #endif
107 }
108
109 ccl_device_inline float3 operator*(const float f, const float3& a)
110 {
111 #if defined(__KERNEL_SSE__)
112         return float3(_mm_mul_ps(_mm_set1_ps(f), a.m128));
113 #else
114         return make_float3(a.x*f, a.y*f, a.z*f);
115 #endif
116 }
117
118 ccl_device_inline float3 operator/(const float f, const float3& a)
119 {
120 #if defined(__KERNEL_SSE__)
121         return float3(_mm_div_ps(_mm_set1_ps(f), a.m128));
122 #else
123         return make_float3(f / a.x, f / a.y, f / a.z);
124 #endif
125 }
126
127 ccl_device_inline float3 operator/(const float3& a, const float f)
128 {
129         float invf = 1.0f/f;
130         return a * invf;
131 }
132
133 ccl_device_inline float3 operator/(const float3& a, const float3& b)
134 {
135 #if defined(__KERNEL_SSE__)
136         return float3(_mm_div_ps(a.m128, b.m128));
137 #else
138         return make_float3(a.x / b.x, a.y / b.y, a.z / b.z);
139 #endif
140 }
141
142 ccl_device_inline float3 operator+(const float3& a, const float3& b)
143 {
144 #ifdef __KERNEL_SSE__
145         return float3(_mm_add_ps(a.m128, b.m128));
146 #else
147         return make_float3(a.x + b.x, a.y + b.y, a.z + b.z);
148 #endif
149 }
150
151 ccl_device_inline float3 operator-(const float3& a, const float3& b)
152 {
153 #ifdef __KERNEL_SSE__
154         return float3(_mm_sub_ps(a.m128, b.m128));
155 #else
156         return make_float3(a.x - b.x, a.y - b.y, a.z - b.z);
157 #endif
158 }
159
160 ccl_device_inline float3 operator+=(float3& a, const float3& b)
161 {
162         return a = a + b;
163 }
164
165 ccl_device_inline float3 operator-=(float3& a, const float3& b)
166 {
167         return a = a - b;
168 }
169
170 ccl_device_inline float3 operator*=(float3& a, const float3& b)
171 {
172         return a = a * b;
173 }
174
175 ccl_device_inline float3 operator*=(float3& a, float f)
176 {
177         return a = a * f;
178 }
179
180 ccl_device_inline float3 operator/=(float3& a, const float3& b)
181 {
182         return a = a / b;
183 }
184
185 ccl_device_inline float3 operator/=(float3& a, float f)
186 {
187         float invf = 1.0f/f;
188         return a = a * invf;
189 }
190
191 ccl_device_inline bool operator==(const float3& a, const float3& b)
192 {
193 #ifdef __KERNEL_SSE__
194         return (_mm_movemask_ps(_mm_cmpeq_ps(a.m128, b.m128)) & 7) == 7;
195 #else
196         return (a.x == b.x && a.y == b.y && a.z == b.z);
197 #endif
198 }
199
200 ccl_device_inline bool operator!=(const float3& a, const float3& b)
201 {
202         return !(a == b);
203 }
204
205 ccl_device_inline float dot(const float3& a, const float3& b)
206 {
207 #if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__)
208         return _mm_cvtss_f32(_mm_dp_ps(a, b, 0x7F));
209 #else
210         return a.x*b.x + a.y*b.y + a.z*b.z;
211 #endif
212 }
213
214 ccl_device_inline float dot_xy(const float3& a, const float3& b)
215 {
216 #if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__)
217         return _mm_cvtss_f32(_mm_hadd_ps(_mm_mul_ps(a,b),b));
218 #else
219         return a.x*b.x + a.y*b.y;
220 #endif
221 }
222
223 ccl_device_inline float3 cross(const float3& a, const float3& b)
224 {
225         float3 r = make_float3(a.y*b.z - a.z*b.y, a.z*b.x - a.x*b.z, a.x*b.y - a.y*b.x);
226         return r;
227 }
228
229 ccl_device_inline float3 normalize(const float3& a)
230 {
231 #if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__)
232         __m128 norm = _mm_sqrt_ps(_mm_dp_ps(a.m128, a.m128, 0x7F));
233         return float3(_mm_div_ps(a.m128, norm));
234 #else
235         return a/len(a);
236 #endif
237 }
238
239 ccl_device_inline float3 min(const float3& a, const float3& b)
240 {
241 #ifdef __KERNEL_SSE__
242         return float3(_mm_min_ps(a.m128, b.m128));
243 #else
244         return make_float3(min(a.x, b.x), min(a.y, b.y), min(a.z, b.z));
245 #endif
246 }
247
248 ccl_device_inline float3 max(const float3& a, const float3& b)
249 {
250 #ifdef __KERNEL_SSE__
251         return float3(_mm_max_ps(a.m128, b.m128));
252 #else
253         return make_float3(max(a.x, b.x), max(a.y, b.y), max(a.z, b.z));
254 #endif
255 }
256
257 ccl_device_inline float3 clamp(const float3& a, const float3& mn, const float3& mx)
258 {
259         return min(max(a, mn), mx);
260 }
261
262 ccl_device_inline float3 fabs(const float3& a)
263 {
264 #ifdef __KERNEL_SSE__
265         __m128 mask = _mm_castsi128_ps(_mm_set1_epi32(0x7fffffff));
266         return float3(_mm_and_ps(a.m128, mask));
267 #else
268         return make_float3(fabsf(a.x), fabsf(a.y), fabsf(a.z));
269 #endif
270 }
271
272 ccl_device_inline float3 mix(const float3& a, const float3& b, float t)
273 {
274         return a + t*(b - a);
275 }
276
277 ccl_device_inline float3 rcp(const float3& a)
278 {
279 #ifdef __KERNEL_SSE__
280         /* Don't use _mm_rcp_ps due to poor precision. */
281         return float3(_mm_div_ps(_mm_set_ps1(1.0f), a.m128));
282 #else
283         return make_float3(1.0f/a.x, 1.0f/a.y, 1.0f/a.z);
284 #endif
285 }
286 #endif  /* !__KERNEL_OPENCL__ */
287
288 ccl_device_inline float max3(float3 a)
289 {
290         return max(max(a.x, a.y), a.z);
291 }
292
293 ccl_device_inline float len(const float3 a)
294 {
295 #if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__)
296         return _mm_cvtss_f32(_mm_sqrt_ss(_mm_dp_ps(a.m128, a.m128, 0x7F)));
297 #else
298         return sqrtf(dot(a, a));
299 #endif
300 }
301
302 ccl_device_inline float len_squared(const float3 a)
303 {
304         return dot(a, a);
305 }
306
307 ccl_device_inline float3 saturate3(float3 a)
308 {
309         return make_float3(saturate(a.x), saturate(a.y), saturate(a.z));
310 }
311
312 ccl_device_inline float3 normalize_len(const float3 a, float *t)
313 {
314         *t = len(a);
315         float x = 1.0f / *t;
316         return a*x;
317 }
318
319 ccl_device_inline float3 safe_normalize(const float3 a)
320 {
321         float t = len(a);
322         return (t != 0.0f)? a * (1.0f/t) : a;
323 }
324
325 ccl_device_inline float3 safe_normalize_len(const float3 a, float *t)
326 {
327         *t = len(a);
328         return (*t != 0.0f)? a/(*t): a;
329 }
330
331 ccl_device_inline float3 interp(float3 a, float3 b, float t)
332 {
333         return a + t*(b - a);
334 }
335
336 ccl_device_inline bool is_zero(const float3 a)
337 {
338 #ifdef __KERNEL_SSE__
339         return a == make_float3(0.0f);
340 #else
341         return (a.x == 0.0f && a.y == 0.0f && a.z == 0.0f);
342 #endif
343 }
344
345 ccl_device_inline float reduce_add(const float3 a)
346 {
347         return (a.x + a.y + a.z);
348 }
349
350 ccl_device_inline float average(const float3 a)
351 {
352         return reduce_add(a)*(1.0f/3.0f);
353 }
354
355 ccl_device_inline bool isequal_float3(const float3 a, const float3 b)
356 {
357 #ifdef __KERNEL_OPENCL__
358         return all(a == b);
359 #else
360         return a == b;
361 #endif
362 }
363
364 ccl_device_inline bool isfinite3_safe(float3 v)
365 {
366         return isfinite_safe(v.x) && isfinite_safe(v.y) && isfinite_safe(v.z);
367 }
368
369 ccl_device_inline float3 ensure_finite3(float3 v)
370 {
371         if(!isfinite_safe(v.x)) v.x = 0.0f;
372         if(!isfinite_safe(v.y)) v.y = 0.0f;
373         if(!isfinite_safe(v.z)) v.z = 0.0f;
374         return v;
375 }
376
377 CCL_NAMESPACE_END
378
379 #endif /* __UTIL_MATH_FLOAT3_H__ */