Merge branch 'blender2.7'
[blender.git] / source / blender / blenlib / intern / math_geom_inline.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  *
19  * The Original Code is: some of this file.
20  *
21  * */
22
23 /** \file \ingroup bli
24  */
25
26 #ifndef __MATH_GEOM_INLINE_C__
27 #define __MATH_GEOM_INLINE_C__
28
29 #include "BLI_math.h"
30
31 #include <string.h>
32
33 /* A few small defines. Keep'em local! */
34 #define SMALL_NUMBER  1.e-8f
35
36 /********************************** Polygons *********************************/
37
38 MINLINE float cross_tri_v2(const float v1[2], const float v2[2], const float v3[2])
39 {
40         return (v1[0] - v2[0]) * (v2[1] - v3[1]) + (v1[1] - v2[1]) * (v3[0] - v2[0]);
41 }
42
43 MINLINE float area_tri_signed_v2(const float v1[2], const float v2[2], const float v3[2])
44 {
45         return 0.5f * ((v1[0] - v2[0]) * (v2[1] - v3[1]) + (v1[1] - v2[1]) * (v3[0] - v2[0]));
46 }
47
48 MINLINE float area_tri_v2(const float v1[2], const float v2[2], const float v3[2])
49 {
50         return fabsf(area_tri_signed_v2(v1, v2, v3));
51 }
52
53 MINLINE float area_squared_tri_v2(const float v1[2], const float v2[2], const float v3[2])
54 {
55         float area = area_tri_signed_v2(v1, v2, v3);
56         return area * area;
57 }
58
59 /****************************** Spherical Harmonics **************************/
60
61 MINLINE void zero_sh(float r[9])
62 {
63         memset(r, 0, sizeof(float) * 9);
64 }
65
66 MINLINE void copy_sh_sh(float r[9], const float a[9])
67 {
68         memcpy(r, a, sizeof(float) * 9);
69 }
70
71 MINLINE void mul_sh_fl(float r[9], const float f)
72 {
73         int i;
74
75         for (i = 0; i < 9; i++)
76                 r[i] *= f;
77 }
78
79 MINLINE void add_sh_shsh(float r[9], const float a[9], const float b[9])
80 {
81         int i;
82
83         for (i = 0; i < 9; i++)
84                 r[i] = a[i] + b[i];
85 }
86
87 MINLINE float dot_shsh(const float a[9], const float b[9])
88 {
89         float r = 0.0f;
90         int i;
91
92         for (i = 0; i < 9; i++)
93                 r += a[i] * b[i];
94
95         return r;
96 }
97
98 MINLINE float diffuse_shv3(float sh[9], const float v[3])
99 {
100         /* See formula (13) in:
101          * "An Efficient Representation for Irradiance Environment Maps" */
102         static const float c1 = 0.429043f, c2 = 0.511664f, c3 = 0.743125f;
103         static const float c4 = 0.886227f, c5 = 0.247708f;
104         float x, y, z, sum;
105
106         x = v[0];
107         y = v[1];
108         z = v[2];
109
110         sum = c1 * sh[8] * (x * x - y * y);
111         sum += c3 * sh[6] * z * z;
112         sum += c4 * sh[0];
113         sum += -c5 * sh[6];
114         sum += 2.0f * c1 * (sh[4] * x * y + sh[7] * x * z + sh[5] * y * z);
115         sum += 2.0f * c2 * (sh[3] * x + sh[1] * y + sh[2] * z);
116
117         return sum;
118 }
119
120 MINLINE void vec_fac_to_sh(float r[9], const float v[3], const float f)
121 {
122         /* See formula (3) in:
123          * "An Efficient Representation for Irradiance Environment Maps" */
124         float sh[9], x, y, z;
125
126         x = v[0];
127         y = v[1];
128         z = v[2];
129
130         sh[0] = 0.282095f;
131
132         sh[1] = 0.488603f * y;
133         sh[2] = 0.488603f * z;
134         sh[3] = 0.488603f * x;
135
136         sh[4] = 1.092548f * x * y;
137         sh[5] = 1.092548f * y * z;
138         sh[6] = 0.315392f * (3.0f * z * z - 1.0f);
139         sh[7] = 1.092548f * x * z;
140         sh[8] = 0.546274f * (x * x - y * y);
141
142         mul_sh_fl(sh, f);
143         copy_sh_sh(r, sh);
144 }
145
146 MINLINE float eval_shv3(float sh[9], const float v[3])
147 {
148         float tmp[9];
149
150         vec_fac_to_sh(tmp, v, 1.0f);
151         return dot_shsh(tmp, sh);
152 }
153
154 MINLINE void madd_sh_shfl(float r[9], const float sh[9], const float f)
155 {
156         float tmp[9];
157
158         copy_sh_sh(tmp, sh);
159         mul_sh_fl(tmp, f);
160         add_sh_shsh(r, r, tmp);
161 }
162
163 /* get the 2 dominant axis values, 0==X, 1==Y, 2==Z */
164 MINLINE void axis_dominant_v3(int *r_axis_a, int *r_axis_b, const float axis[3])
165 {
166         const float xn = fabsf(axis[0]);
167         const float yn = fabsf(axis[1]);
168         const float zn = fabsf(axis[2]);
169
170         if      (zn >= xn && zn >= yn) { *r_axis_a = 0; *r_axis_b = 1; }
171         else if (yn >= xn && yn >= zn) { *r_axis_a = 0; *r_axis_b = 2; }
172         else                           { *r_axis_a = 1; *r_axis_b = 2; }
173 }
174
175 /* same as axis_dominant_v3 but return the max value */
176 MINLINE float axis_dominant_v3_max(int *r_axis_a, int *r_axis_b, const float axis[3])
177 {
178         const float xn = fabsf(axis[0]);
179         const float yn = fabsf(axis[1]);
180         const float zn = fabsf(axis[2]);
181
182         if      (zn >= xn && zn >= yn) { *r_axis_a = 0; *r_axis_b = 1; return zn; }
183         else if (yn >= xn && yn >= zn) { *r_axis_a = 0; *r_axis_b = 2; return yn; }
184         else                           { *r_axis_a = 1; *r_axis_b = 2; return xn; }
185 }
186
187 /* get the single dominant axis value, 0==X, 1==Y, 2==Z */
188 MINLINE int axis_dominant_v3_single(const float vec[3])
189 {
190         const float x = fabsf(vec[0]);
191         const float y = fabsf(vec[1]);
192         const float z = fabsf(vec[2]);
193         return ((x > y) ?
194                ((x > z) ? 0 : 2) :
195                ((y > z) ? 1 : 2));
196 }
197
198 /* the dominant axis of an orthogonal vector */
199 MINLINE int axis_dominant_v3_ortho_single(const float vec[3])
200 {
201         const float x = fabsf(vec[0]);
202         const float y = fabsf(vec[1]);
203         const float z = fabsf(vec[2]);
204         return ((x < y) ?
205                ((x < z) ? 0 : 2) :
206                ((y < z) ? 1 : 2));
207 }
208
209 MINLINE int max_axis_v3(const float vec[3])
210 {
211         const float x = vec[0];
212         const float y = vec[1];
213         const float z = vec[2];
214         return ((x > y) ?
215                ((x > z) ? 0 : 2) :
216                ((y > z) ? 1 : 2));
217 }
218
219 MINLINE int min_axis_v3(const float vec[3])
220 {
221         const float x = vec[0];
222         const float y = vec[1];
223         const float z = vec[2];
224         return ((x < y) ?
225                ((x < z) ? 0 : 2) :
226                ((y < z) ? 1 : 2));
227 }
228
229 /**
230  * Simple method to find how many tri's we need when we already know the corner+poly count.
231  *
232  * \param poly_count: The number of ngon's/tris (1-2 sided faces will give incorrect results)
233  * \param corner_count: also known as loops in BMesh/DNA
234  */
235 MINLINE int poly_to_tri_count(const int poly_count, const int corner_count)
236 {
237         BLI_assert(!poly_count || corner_count > poly_count * 2);
238         return corner_count - (poly_count * 2);
239 }
240
241 MINLINE float plane_point_side_v3(const float plane[4], const float co[3])
242 {
243         return dot_v3v3(co, plane) + plane[3];
244 }
245
246 /* useful to calculate an even width shell, by taking the angle between 2 planes.
247  * The return value is a scale on the offset.
248  * no angle between planes is 1.0, as the angle between the 2 planes approaches 180d
249  * the distance gets very high, 180d would be inf, but this case isn't valid */
250 MINLINE float shell_angle_to_dist(const float angle)
251 {
252         return (UNLIKELY(angle < SMALL_NUMBER)) ? 1.0f : fabsf(1.0f / cosf(angle));
253 }
254 /**
255  * equivalent to ``shell_angle_to_dist(angle_normalized_v3v3(a, b))``
256  */
257 MINLINE float shell_v3v3_normalized_to_dist(const float a[3], const float b[3])
258 {
259         const float angle_cos = fabsf(dot_v3v3(a, b));
260         BLI_ASSERT_UNIT_V3(a);
261         BLI_ASSERT_UNIT_V3(b);
262         return (UNLIKELY(angle_cos < SMALL_NUMBER)) ? 1.0f : (1.0f / angle_cos);
263 }
264 /**
265  * equivalent to ``shell_angle_to_dist(angle_normalized_v2v2(a, b))``
266  */
267 MINLINE float shell_v2v2_normalized_to_dist(const float a[2], const float b[2])
268 {
269         const float angle_cos = fabsf(dot_v2v2(a, b));
270         BLI_ASSERT_UNIT_V2(a);
271         BLI_ASSERT_UNIT_V2(b);
272         return (UNLIKELY(angle_cos < SMALL_NUMBER)) ? 1.0f : (1.0f / angle_cos);
273 }
274
275 /**
276  * equivalent to ``shell_angle_to_dist(angle_normalized_v3v3(a, b) / 2)``
277  */
278 MINLINE float shell_v3v3_mid_normalized_to_dist(const float a[3], const float b[3])
279 {
280         float angle_cos;
281         float ab[3];
282         BLI_ASSERT_UNIT_V3(a);
283         BLI_ASSERT_UNIT_V3(b);
284         add_v3_v3v3(ab, a, b);
285         angle_cos = (normalize_v3(ab) != 0.0f) ? fabsf(dot_v3v3(a, ab)) : 0.0f;
286         return (UNLIKELY(angle_cos < SMALL_NUMBER)) ? 1.0f : (1.0f / angle_cos);
287 }
288
289 /**
290  * equivalent to ``shell_angle_to_dist(angle_normalized_v2v2(a, b) / 2)``
291  */
292 MINLINE float shell_v2v2_mid_normalized_to_dist(const float a[2], const float b[2])
293 {
294         float angle_cos;
295         float ab[2];
296         BLI_ASSERT_UNIT_V2(a);
297         BLI_ASSERT_UNIT_V2(b);
298         add_v2_v2v2(ab, a, b);
299         angle_cos = (normalize_v2(ab) != 0.0f) ? fabsf(dot_v2v2(a, ab)) : 0.0f;
300         return (UNLIKELY(angle_cos < SMALL_NUMBER)) ? 1.0f : (1.0f / angle_cos);
301 }
302
303 #undef SMALL_NUMBER
304
305 #endif /* __MATH_GEOM_INLINE_C__ */