Merged changes in the trunk up to revision 45820.
[blender-staging.git] / intern / cycles / util / util_transform.h
1 /*
2  * Copyright 2011, Blender Foundation.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18
19 #ifndef __UTIL_TRANSFORM_H__
20 #define __UTIL_TRANSFORM_H__
21
22 #ifndef __KERNEL_GPU__
23 #include <string.h>
24 #endif
25
26 #include "util_math.h"
27 #include "util_types.h"
28
29 CCL_NAMESPACE_BEGIN
30
31 typedef struct Transform {
32         float4 x, y, z, w; /* rows */
33
34 #ifndef __KERNEL_GPU__
35         float4 operator[](int i) const { return *(&x + i); }
36         float4& operator[](int i) { return *(&x + i); }
37 #endif
38 } Transform;
39
40 __device_inline float3 transform_perspective(const Transform *t, const float3 a)
41 {
42         float4 b = make_float4(a.x, a.y, a.z, 1.0f);
43         float3 c = make_float3(dot(t->x, b), dot(t->y, b), dot(t->z, b));
44         float w = dot(t->w, b);
45
46         return (w != 0.0f)? c/w: make_float3(0.0f, 0.0f, 0.0f);
47 }
48
49 __device_inline float3 transform_point(const Transform *t, const float3 a)
50 {
51         float4 b = make_float4(a.x, a.y, a.z, 1.0f);
52         float3 c = make_float3(dot(t->x, b), dot(t->y, b), dot(t->z, b));
53
54         return c;
55 }
56
57 __device_inline float3 transform_direction(const Transform *t, const float3 a)
58 {
59         float4 b = make_float4(a.x, a.y, a.z, 0.0f);
60         float3 c = make_float3(dot(t->x, b), dot(t->y, b), dot(t->z, b));
61
62         return c;
63 }
64
65 #ifndef __KERNEL_GPU__
66
67 __device_inline void print_transform(const char *label, const Transform& t)
68 {
69         print_float4(label, t.x);
70         print_float4(label, t.y);
71         print_float4(label, t.z);
72         print_float4(label, t.w);
73         printf("\n");
74 }
75
76 __device_inline Transform transform_transpose(const Transform a)
77 {
78         Transform t;
79
80         t.x.x = a.x.x; t.x.y = a.y.x; t.x.z = a.z.x; t.x.w = a.w.x;
81         t.y.x = a.x.y; t.y.y = a.y.y; t.y.z = a.z.y; t.y.w = a.w.y;
82         t.z.x = a.x.z; t.z.y = a.y.z; t.z.z = a.z.z; t.z.w = a.w.z;
83         t.w.x = a.x.w; t.w.y = a.y.w; t.w.z = a.z.w; t.w.w = a.w.w;
84
85         return t;
86 }
87
88 __device_inline Transform operator*(const Transform a, const Transform b)
89 {
90         Transform c = transform_transpose(b);
91         Transform t;
92
93         t.x = make_float4(dot(a.x, c.x), dot(a.x, c.y), dot(a.x, c.z), dot(a.x, c.w));
94         t.y = make_float4(dot(a.y, c.x), dot(a.y, c.y), dot(a.y, c.z), dot(a.y, c.w));
95         t.z = make_float4(dot(a.z, c.x), dot(a.z, c.y), dot(a.z, c.z), dot(a.z, c.w));
96         t.w = make_float4(dot(a.w, c.x), dot(a.w, c.y), dot(a.w, c.z), dot(a.w, c.w));
97
98         return t;
99 }
100
101 __device_inline Transform make_transform(float a, float b, float c, float d,
102                                                                         float e, float f, float g, float h,
103                                                                         float i, float j, float k, float l,
104                                                                         float m, float n, float o, float p)
105 {
106         Transform t;
107
108         t.x.x = a; t.x.y = b; t.x.z = c; t.x.w = d;
109         t.y.x = e; t.y.y = f; t.y.z = g; t.y.w = h;
110         t.z.x = i; t.z.y = j; t.z.z = k; t.z.w = l;
111         t.w.x = m; t.w.y = n; t.w.z = o; t.w.w = p;
112
113         return t;
114 }
115
116 __device_inline Transform transform_translate(float3 t)
117 {
118         return make_transform(
119                 1, 0, 0, t.x,
120                 0, 1, 0, t.y,
121                 0, 0, 1, t.z,
122                 0, 0, 0, 1);
123 }
124
125 __device_inline Transform transform_translate(float x, float y, float z)
126 {
127         return transform_translate(make_float3(x, y, z));
128 }
129
130 __device_inline Transform transform_scale(float3 s)
131 {
132         return make_transform(
133                 s.x, 0, 0, 0,
134                 0, s.y, 0, 0,
135                 0, 0, s.z, 0,
136                 0, 0, 0, 1);
137 }
138
139 __device_inline Transform transform_scale(float x, float y, float z)
140 {
141         return transform_scale(make_float3(x, y, z));
142 }
143
144 __device_inline Transform transform_perspective(float fov, float n, float f)
145 {
146         Transform persp = make_transform(
147                 1, 0, 0, 0,
148                 0, 1, 0, 0,
149                 0, 0, f / (f - n), -f*n / (f - n),
150                 0, 0, 1, 0);
151
152         float inv_angle = 1.0f/tanf(0.5f*fov);
153
154         Transform scale = transform_scale(inv_angle, inv_angle, 1);
155
156         return scale * persp;
157 }
158
159 __device_inline Transform transform_rotate(float angle, float3 axis)
160 {
161         float s = sinf(angle);
162         float c = cosf(angle);
163         float t = 1.f - c;
164
165         axis = normalize(axis);
166
167         return make_transform(
168                 axis.x*axis.x*t + c,
169                 axis.x*axis.y*t - s*axis.z,
170                 axis.x*axis.z*t + s*axis.y,
171                 0.0f,
172
173                 axis.y*axis.x*t + s*axis.z,
174                 axis.y*axis.y*t + c,
175                 axis.y*axis.z*t - s*axis.x,
176                 0.0f,
177
178                 axis.z*axis.x*t - s*axis.y,
179                 axis.z*axis.y*t + s*axis.x,
180                 axis.z*axis.z*t + c,
181                 0.0f,
182
183                 0.0f, 0.0f, 0.0f, 1.0f);
184 }
185
186 __device_inline Transform transform_euler(float3 euler)
187 {
188         return
189                 transform_rotate(euler.x, make_float3(1.0f, 0.0f, 0.0f)) *
190                 transform_rotate(euler.y, make_float3(0.0f, 1.0f, 0.0f)) *
191                 transform_rotate(euler.z, make_float3(0.0f, 0.0f, 1.0f));
192 }
193
194 __device_inline Transform transform_orthographic(float znear, float zfar)
195 {
196         return transform_scale(1.0f, 1.0f, 1.0f / (zfar-znear)) *
197                 transform_translate(0.0f, 0.0f, -znear);
198 }
199
200 __device_inline Transform transform_identity()
201 {
202         return transform_scale(1.0f, 1.0f, 1.0f);
203 }
204
205 __device_inline bool operator==(const Transform& A, const Transform& B)
206 {
207         return memcmp(&A, &B, sizeof(Transform)) == 0;
208 }
209
210 __device_inline bool operator!=(const Transform& A, const Transform& B)
211 {
212         return !(A == B);
213 }
214
215 __device_inline float3 transform_get_column(const Transform *t, int column)
216 {
217         return make_float3(t->x[column], t->y[column], t->z[column]);
218 }
219
220 __device_inline void transform_set_column(Transform *t, int column, float3 value)
221 {
222         t->x[column] = value.x;
223         t->y[column] = value.y;
224         t->z[column] = value.z;
225 }
226
227 Transform transform_inverse(const Transform& a);
228
229 __device_inline bool transform_uniform_scale(const Transform& tfm, float& scale)
230 {
231         /* the epsilon here is quite arbitrary, but this function is only used for
232            surface area and bump, where we except it to not be so sensitive */
233         Transform ttfm = transform_transpose(tfm);
234         float eps = 1e-7f; 
235         
236         float sx = len(float4_to_float3(tfm.x));
237         float sy = len(float4_to_float3(tfm.y));
238         float sz = len(float4_to_float3(tfm.z));
239         float stx = len(float4_to_float3(ttfm.x));
240         float sty = len(float4_to_float3(ttfm.y));
241         float stz = len(float4_to_float3(ttfm.z));
242         
243         if(fabsf(sx - sy) < eps && fabsf(sx - sz) < eps &&
244            fabsf(sx - stx) < eps && fabsf(sx - sty) < eps &&
245            fabsf(sx - stz) < eps) {
246                 scale = sx;
247                 return true;
248         }
249    
250    return false;
251 }
252
253 __device_inline bool transform_negative_scale(const Transform& tfm)
254 {
255         float3 c0 = transform_get_column(&tfm, 0);
256         float3 c1 = transform_get_column(&tfm, 1);
257         float3 c2 = transform_get_column(&tfm, 2);
258
259         return (dot(cross(c0, c1), c2) < 0.0f);
260 }
261
262 __device_inline Transform transform_clear_scale(const Transform& tfm)
263 {
264         Transform ntfm = tfm;
265
266         transform_set_column(&ntfm, 0, normalize(transform_get_column(&ntfm, 0)));
267         transform_set_column(&ntfm, 1, normalize(transform_get_column(&ntfm, 1)));
268         transform_set_column(&ntfm, 2, normalize(transform_get_column(&ntfm, 2)));
269
270         return ntfm;
271 }
272
273 #endif
274
275 CCL_NAMESPACE_END
276
277 #endif /* __UTIL_TRANSFORM_H__ */
278