Merged changes in the trunk up to revision 42902.
[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(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_direction(const Transform *t, const float3 a)
50 {
51         float4 b = make_float4(a.x, a.y, a.z, 0.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 #ifndef __KERNEL_GPU__
58
59 __device_inline void print_transform(const char *label, const Transform& t)
60 {
61         print_float4(label, t.x);
62         print_float4(label, t.y);
63         print_float4(label, t.z);
64         print_float4(label, t.w);
65         printf("\n");
66 }
67
68 __device_inline Transform transform_transpose(const Transform a)
69 {
70         Transform t;
71
72         t.x.x = a.x.x; t.x.y = a.y.x; t.x.z = a.z.x; t.x.w = a.w.x;
73         t.y.x = a.x.y; t.y.y = a.y.y; t.y.z = a.z.y; t.y.w = a.w.y;
74         t.z.x = a.x.z; t.z.y = a.y.z; t.z.z = a.z.z; t.z.w = a.w.z;
75         t.w.x = a.x.w; t.w.y = a.y.w; t.w.z = a.z.w; t.w.w = a.w.w;
76
77         return t;
78 }
79
80 __device_inline Transform operator*(const Transform a, const Transform b)
81 {
82         Transform c = transform_transpose(b);
83         Transform t;
84
85         t.x = make_float4(dot(a.x, c.x), dot(a.x, c.y), dot(a.x, c.z), dot(a.x, c.w));
86         t.y = make_float4(dot(a.y, c.x), dot(a.y, c.y), dot(a.y, c.z), dot(a.y, c.w));
87         t.z = make_float4(dot(a.z, c.x), dot(a.z, c.y), dot(a.z, c.z), dot(a.z, c.w));
88         t.w = make_float4(dot(a.w, c.x), dot(a.w, c.y), dot(a.w, c.z), dot(a.w, c.w));
89
90         return t;
91 }
92
93 __device_inline Transform make_transform(float a, float b, float c, float d,
94                                                                         float e, float f, float g, float h,
95                                                                         float i, float j, float k, float l,
96                                                                         float m, float n, float o, float p)
97 {
98         Transform t;
99
100         t.x.x = a; t.x.y = b; t.x.z = c; t.x.w = d;
101         t.y.x = e; t.y.y = f; t.y.z = g; t.y.w = h;
102         t.z.x = i; t.z.y = j; t.z.z = k; t.z.w = l;
103         t.w.x = m; t.w.y = n; t.w.z = o; t.w.w = p;
104
105         return t;
106 }
107
108 __device_inline Transform transform_translate(float3 t)
109 {
110         return make_transform(
111                 1, 0, 0, t.x,
112                 0, 1, 0, t.y,
113                 0, 0, 1, t.z,
114                 0, 0, 0, 1);
115 }
116
117 __device_inline Transform transform_translate(float x, float y, float z)
118 {
119         return transform_translate(make_float3(x, y, z));
120 }
121
122 __device_inline Transform transform_scale(float3 s)
123 {
124         return make_transform(
125                 s.x, 0, 0, 0,
126                 0, s.y, 0, 0,
127                 0, 0, s.z, 0,
128                 0, 0, 0, 1);
129 }
130
131 __device_inline Transform transform_scale(float x, float y, float z)
132 {
133         return transform_scale(make_float3(x, y, z));
134 }
135
136 __device_inline Transform transform_perspective(float fov, float n, float f)
137 {
138         Transform persp = make_transform(
139                 1, 0, 0, 0,
140                 0, 1, 0, 0,
141                 0, 0, f / (f - n), -f*n / (f - n),
142                 0, 0, 1, 0);
143
144         float inv_angle = 1.0f/tanf(0.5f*fov);
145
146         Transform scale = transform_scale(inv_angle, inv_angle, 1);
147
148         return scale * persp;
149 }
150
151 __device_inline Transform transform_rotate(float angle, float3 axis)
152 {
153         float s = sinf(angle);
154         float c = cosf(angle);
155         float t = 1.f - c;
156
157         axis = normalize(axis);
158
159         return make_transform(
160                 axis.x*axis.x*t + c,
161                 axis.x*axis.y*t - s*axis.z,
162                 axis.x*axis.z*t + s*axis.y,
163                 0.0f,
164
165                 axis.y*axis.x*t + s*axis.z,
166                 axis.y*axis.y*t + c,
167                 axis.y*axis.z*t - s*axis.x,
168                 0.0f,
169
170                 axis.z*axis.x*t - s*axis.y,
171                 axis.z*axis.y*t + s*axis.x,
172                 axis.z*axis.z*t + c,
173                 0.0f,
174
175                 0.0f, 0.0f, 0.0f, 1.0f);
176 }
177
178 __device_inline Transform transform_euler(float3 euler)
179 {
180         return
181                 transform_rotate(euler.x, make_float3(1.0f, 0.0f, 0.0f)) *
182                 transform_rotate(euler.y, make_float3(0.0f, 1.0f, 0.0f)) *
183                 transform_rotate(euler.z, make_float3(0.0f, 0.0f, 1.0f));
184 }
185
186 __device_inline Transform transform_orthographic(float znear, float zfar)
187 {
188         return transform_scale(1.0f, 1.0f, 1.0f / (zfar-znear)) *
189                 transform_translate(0.0f, 0.0f, -znear);
190 }
191
192 __device_inline Transform transform_identity()
193 {
194         return transform_scale(1.0f, 1.0f, 1.0f);
195 }
196
197 __device_inline bool operator==(const Transform& A, const Transform& B)
198 {
199         return memcmp(&A, &B, sizeof(Transform)) == 0;
200 }
201
202 __device_inline bool operator!=(const Transform& A, const Transform& B)
203 {
204         return !(A == B);
205 }
206
207 __device_inline float3 transform_get_column(const Transform *t, int column)
208 {
209         return make_float3(t->x[column], t->y[column], t->z[column]);
210 }
211
212 __device_inline void transform_set_column(Transform *t, int column, float3 value)
213 {
214         t->x[column] = value.x;
215         t->y[column] = value.y;
216         t->z[column] = value.z;
217 }
218
219 Transform transform_inverse(const Transform& a);
220
221 __device_inline bool transform_uniform_scale(const Transform& tfm, float& scale)
222 {
223         /* the epsilon here is quite arbitrary, but this function is only used for
224            surface area and bump, where we except it to not be so sensitive */
225         Transform ttfm = transform_transpose(tfm);
226         float eps = 1e-7f; 
227         
228         float sx = len(float4_to_float3(tfm.x));
229         float sy = len(float4_to_float3(tfm.y));
230         float sz = len(float4_to_float3(tfm.z));
231         float stx = len(float4_to_float3(ttfm.x));
232         float sty = len(float4_to_float3(ttfm.y));
233         float stz = len(float4_to_float3(ttfm.z));
234         
235         if(fabsf(sx - sy) < eps && fabsf(sx - sz) < eps &&
236            fabsf(sx - stx) < eps && fabsf(sx - sty) < eps &&
237            fabsf(sx - stz) < eps) {
238                 scale = sx;
239                 return true;
240         }
241    
242    return false;
243 }
244
245 __device_inline bool transform_negative_scale(const Transform& tfm)
246 {
247         float3 c0 = transform_get_column(&tfm, 0);
248         float3 c1 = transform_get_column(&tfm, 1);
249         float3 c2 = transform_get_column(&tfm, 2);
250
251         return (dot(cross(c0, c1), c2) < 0.0f);
252 }
253
254 __device_inline Transform transform_clear_scale(const Transform& tfm)
255 {
256         Transform ntfm = tfm;
257
258         transform_set_column(&ntfm, 0, normalize(transform_get_column(&ntfm, 0)));
259         transform_set_column(&ntfm, 1, normalize(transform_get_column(&ntfm, 1)));
260         transform_set_column(&ntfm, 2, normalize(transform_get_column(&ntfm, 2)));
261
262         return ntfm;
263 }
264
265 #endif
266
267 CCL_NAMESPACE_END
268
269 #endif /* __UTIL_TRANSFORM_H__ */
270