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