Blender V2.61 - r43446

util_transform.h

Go to the documentation of this file.
00001 /*
00002  * Copyright 2011, Blender Foundation.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  */
00018 
00019 #ifndef __UTIL_TRANSFORM_H__
00020 #define __UTIL_TRANSFORM_H__
00021 
00022 #ifndef __KERNEL_GPU__
00023 #include <string.h>
00024 #endif
00025 
00026 #include "util_math.h"
00027 #include "util_types.h"
00028 
00029 CCL_NAMESPACE_BEGIN
00030 
00031 typedef struct Transform {
00032     float4 x, y, z, w; /* rows */
00033 
00034 #ifndef __KERNEL_GPU__
00035     float4 operator[](int i) const { return *(&x + i); }
00036     float4& operator[](int i) { return *(&x + i); }
00037 #endif
00038 } Transform;
00039 
00040 __device_inline float3 transform(const Transform *t, const float3 a)
00041 {
00042     float4 b = make_float4(a.x, a.y, a.z, 1.0f);
00043     float3 c = make_float3(dot(t->x, b), dot(t->y, b), dot(t->z, b));
00044     float w = dot(t->w, b);
00045 
00046     return (w != 0.0f)? c/w: make_float3(0.0f, 0.0f, 0.0f);
00047 }
00048 
00049 __device_inline float3 transform_direction(const Transform *t, const float3 a)
00050 {
00051     float4 b = make_float4(a.x, a.y, a.z, 0.0f);
00052     float3 c = make_float3(dot(t->x, b), dot(t->y, b), dot(t->z, b));
00053 
00054     return c;
00055 }
00056 
00057 #ifndef __KERNEL_GPU__
00058 
00059 __device_inline void print_transform(const char *label, const Transform& t)
00060 {
00061     print_float4(label, t.x);
00062     print_float4(label, t.y);
00063     print_float4(label, t.z);
00064     print_float4(label, t.w);
00065     printf("\n");
00066 }
00067 
00068 __device_inline Transform transform_transpose(const Transform a)
00069 {
00070     Transform t;
00071 
00072     t.x.x = a.x.x; t.x.y = a.y.x; t.x.z = a.z.x; t.x.w = a.w.x;
00073     t.y.x = a.x.y; t.y.y = a.y.y; t.y.z = a.z.y; t.y.w = a.w.y;
00074     t.z.x = a.x.z; t.z.y = a.y.z; t.z.z = a.z.z; t.z.w = a.w.z;
00075     t.w.x = a.x.w; t.w.y = a.y.w; t.w.z = a.z.w; t.w.w = a.w.w;
00076 
00077     return t;
00078 }
00079 
00080 __device_inline Transform operator*(const Transform a, const Transform b)
00081 {
00082     Transform c = transform_transpose(b);
00083     Transform t;
00084 
00085     t.x = make_float4(dot(a.x, c.x), dot(a.x, c.y), dot(a.x, c.z), dot(a.x, c.w));
00086     t.y = make_float4(dot(a.y, c.x), dot(a.y, c.y), dot(a.y, c.z), dot(a.y, c.w));
00087     t.z = make_float4(dot(a.z, c.x), dot(a.z, c.y), dot(a.z, c.z), dot(a.z, c.w));
00088     t.w = make_float4(dot(a.w, c.x), dot(a.w, c.y), dot(a.w, c.z), dot(a.w, c.w));
00089 
00090     return t;
00091 }
00092 
00093 __device_inline Transform make_transform(float a, float b, float c, float d,
00094                                     float e, float f, float g, float h,
00095                                     float i, float j, float k, float l,
00096                                     float m, float n, float o, float p)
00097 {
00098     Transform t;
00099 
00100     t.x.x = a; t.x.y = b; t.x.z = c; t.x.w = d;
00101     t.y.x = e; t.y.y = f; t.y.z = g; t.y.w = h;
00102     t.z.x = i; t.z.y = j; t.z.z = k; t.z.w = l;
00103     t.w.x = m; t.w.y = n; t.w.z = o; t.w.w = p;
00104 
00105     return t;
00106 }
00107 
00108 __device_inline Transform transform_translate(float3 t)
00109 {
00110     return make_transform(
00111         1, 0, 0, t.x,
00112         0, 1, 0, t.y,
00113         0, 0, 1, t.z,
00114         0, 0, 0, 1);
00115 }
00116 
00117 __device_inline Transform transform_translate(float x, float y, float z)
00118 {
00119     return transform_translate(make_float3(x, y, z));
00120 }
00121 
00122 __device_inline Transform transform_scale(float3 s)
00123 {
00124     return make_transform(
00125         s.x, 0, 0, 0,
00126         0, s.y, 0, 0,
00127         0, 0, s.z, 0,
00128         0, 0, 0, 1);
00129 }
00130 
00131 __device_inline Transform transform_scale(float x, float y, float z)
00132 {
00133     return transform_scale(make_float3(x, y, z));
00134 }
00135 
00136 __device_inline Transform transform_perspective(float fov, float n, float f)
00137 {
00138     Transform persp = make_transform(
00139         1, 0, 0, 0,
00140         0, 1, 0, 0,
00141         0, 0, f / (f - n), -f*n / (f - n),
00142         0, 0, 1, 0);
00143 
00144     float inv_angle = 1.0f/tanf(0.5f*fov);
00145 
00146     Transform scale = transform_scale(inv_angle, inv_angle, 1);
00147 
00148     return scale * persp;
00149 }
00150 
00151 __device_inline Transform transform_rotate(float angle, float3 axis)
00152 {
00153     float s = sinf(angle);
00154     float c = cosf(angle);
00155     float t = 1.f - c;
00156 
00157     axis = normalize(axis);
00158 
00159     return make_transform(
00160         axis.x*axis.x*t + c,
00161         axis.x*axis.y*t - s*axis.z,
00162         axis.x*axis.z*t + s*axis.y,
00163         0.0f,
00164 
00165         axis.y*axis.x*t + s*axis.z,
00166         axis.y*axis.y*t + c,
00167         axis.y*axis.z*t - s*axis.x,
00168         0.0f,
00169 
00170         axis.z*axis.x*t - s*axis.y,
00171         axis.z*axis.y*t + s*axis.x,
00172         axis.z*axis.z*t + c,
00173         0.0f,
00174 
00175         0.0f, 0.0f, 0.0f, 1.0f);
00176 }
00177 
00178 __device_inline Transform transform_euler(float3 euler)
00179 {
00180     return
00181         transform_rotate(euler.x, make_float3(1.0f, 0.0f, 0.0f)) *
00182         transform_rotate(euler.y, make_float3(0.0f, 1.0f, 0.0f)) *
00183         transform_rotate(euler.z, make_float3(0.0f, 0.0f, 1.0f));
00184 }
00185 
00186 __device_inline Transform transform_orthographic(float znear, float zfar)
00187 {
00188     return transform_scale(1.0f, 1.0f, 1.0f / (zfar-znear)) *
00189         transform_translate(0.0f, 0.0f, -znear);
00190 }
00191 
00192 __device_inline Transform transform_identity()
00193 {
00194     return transform_scale(1.0f, 1.0f, 1.0f);
00195 }
00196 
00197 __device_inline bool operator==(const Transform& A, const Transform& B)
00198 {
00199     return memcmp(&A, &B, sizeof(Transform)) == 0;
00200 }
00201 
00202 __device_inline bool operator!=(const Transform& A, const Transform& B)
00203 {
00204     return !(A == B);
00205 }
00206 
00207 __device_inline float3 transform_get_column(const Transform *t, int column)
00208 {
00209     return make_float3(t->x[column], t->y[column], t->z[column]);
00210 }
00211 
00212 __device_inline void transform_set_column(Transform *t, int column, float3 value)
00213 {
00214     t->x[column] = value.x;
00215     t->y[column] = value.y;
00216     t->z[column] = value.z;
00217 }
00218 
00219 Transform transform_inverse(const Transform& a);
00220 
00221 __device_inline bool transform_uniform_scale(const Transform& tfm, float& scale)
00222 {
00223     /* the epsilon here is quite arbitrary, but this function is only used for
00224        surface area and bump, where we except it to not be so sensitive */
00225     Transform ttfm = transform_transpose(tfm);
00226     float eps = 1e-7f; 
00227     
00228     float sx = len(float4_to_float3(tfm.x));
00229     float sy = len(float4_to_float3(tfm.y));
00230     float sz = len(float4_to_float3(tfm.z));
00231     float stx = len(float4_to_float3(ttfm.x));
00232     float sty = len(float4_to_float3(ttfm.y));
00233     float stz = len(float4_to_float3(ttfm.z));
00234     
00235     if(fabsf(sx - sy) < eps && fabsf(sx - sz) < eps &&
00236        fabsf(sx - stx) < eps && fabsf(sx - sty) < eps &&
00237        fabsf(sx - stz) < eps) {
00238         scale = sx;
00239         return true;
00240     }
00241    
00242    return false;
00243 }
00244 
00245 __device_inline bool transform_negative_scale(const Transform& tfm)
00246 {
00247     float3 c0 = transform_get_column(&tfm, 0);
00248     float3 c1 = transform_get_column(&tfm, 1);
00249     float3 c2 = transform_get_column(&tfm, 2);
00250 
00251     return (dot(cross(c0, c1), c2) < 0.0f);
00252 }
00253 
00254 __device_inline Transform transform_clear_scale(const Transform& tfm)
00255 {
00256     Transform ntfm = tfm;
00257 
00258     transform_set_column(&ntfm, 0, normalize(transform_get_column(&ntfm, 0)));
00259     transform_set_column(&ntfm, 1, normalize(transform_get_column(&ntfm, 1)));
00260     transform_set_column(&ntfm, 2, normalize(transform_get_column(&ntfm, 2)));
00261 
00262     return ntfm;
00263 }
00264 
00265 #endif
00266 
00267 CCL_NAMESPACE_END
00268 
00269 #endif /* __UTIL_TRANSFORM_H__ */
00270