add BLI_strcpy_rlen, replace strcat, which was used in misleading way.
[blender.git] / intern / cycles / kernel / kernel_primitive.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 __KERNEL_ATTRIBUTE_CL__
20 #define __KERNEL_ATTRIBUTE_CL__
21
22 CCL_NAMESPACE_BEGIN
23
24 /* attribute lookup */
25
26 __device_inline int find_attribute(KernelGlobals *kg, ShaderData *sd, uint id, AttributeElement *elem)
27 {
28         if(sd->object == ~0)
29                 return (int)ATTR_STD_NOT_FOUND;
30
31 #ifdef __OSL__
32         if (kg->osl) {
33                 return OSLShader::find_attribute(kg, sd, id, elem);
34         }
35         else
36 #endif
37         {
38                 /* for SVM, find attribute by unique id */
39                 uint attr_offset = sd->object*kernel_data.bvh.attributes_map_stride;
40 #ifdef __HAIR__
41                 attr_offset = (sd->segment == ~0)? attr_offset: attr_offset + ATTR_PRIM_CURVE;
42 #endif
43                 uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
44                 
45                 while(attr_map.x != id) {
46                         attr_offset += ATTR_PRIM_TYPES;
47                         attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
48                 }
49
50                 *elem = (AttributeElement)attr_map.y;
51                 
52                 /* return result */
53                 return (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z;
54         }
55 }
56
57 __device float primitive_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy)
58 {
59 #ifdef __HAIR__
60         if(sd->segment == ~0)
61 #endif
62                 return triangle_attribute_float(kg, sd, elem, offset, dx, dy);
63 #ifdef __HAIR__
64         else
65                 return curve_attribute_float(kg, sd, elem, offset, dx, dy);
66 #endif
67 }
68
69 __device float3 primitive_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy)
70 {
71 #ifdef __HAIR__
72         if(sd->segment == ~0)
73 #endif
74                 return triangle_attribute_float3(kg, sd, elem, offset, dx, dy);
75 #ifdef __HAIR__
76         else
77                 return curve_attribute_float3(kg, sd, elem, offset, dx, dy);
78 #endif
79 }
80
81 __device float3 primitive_uv(KernelGlobals *kg, ShaderData *sd)
82 {
83         AttributeElement elem_uv;
84         int offset_uv = find_attribute(kg, sd, ATTR_STD_UV, &elem_uv);
85
86         if(offset_uv == ATTR_STD_NOT_FOUND)
87                 return make_float3(0.0f, 0.0f, 0.0f);
88
89         float3 uv = primitive_attribute_float3(kg, sd, elem_uv, offset_uv, NULL, NULL);
90         uv.z = 1.0f;
91         return uv;
92 }
93
94 __device float3 primitive_tangent(KernelGlobals *kg, ShaderData *sd)
95 {
96 #ifdef __HAIR__
97         if(sd->segment != ~0)
98                 return normalize(sd->dPdu);
99 #endif
100
101         /* try to create spherical tangent from generated coordinates */
102         AttributeElement attr_elem;
103         int attr_offset = find_attribute(kg, sd, ATTR_STD_GENERATED, &attr_elem);
104
105         if(attr_offset != ATTR_STD_NOT_FOUND) {
106                 float3 data = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL);
107                 data = make_float3(-(data.y - 0.5f), (data.x - 0.5f), 0.0f);
108                 object_normal_transform(kg, sd, &data);
109                 return cross(sd->N, normalize(cross(data, sd->N)));
110         }
111         else {
112                 /* otherwise use surface derivatives */
113                 return normalize(sd->dPdu);
114         }
115 }
116
117 /* motion */
118
119 __device float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *sd)
120 {
121         float3 motion_pre = sd->P, motion_post = sd->P;
122
123         /* deformation motion */
124         AttributeElement elem_pre, elem_post;
125         int offset_pre = find_attribute(kg, sd, ATTR_STD_MOTION_PRE, &elem_pre);
126         int offset_post = find_attribute(kg, sd, ATTR_STD_MOTION_POST, &elem_post);
127
128         if(offset_pre != ATTR_STD_NOT_FOUND)
129                 motion_pre = primitive_attribute_float3(kg, sd, elem_pre, offset_pre, NULL, NULL);
130         if(offset_post != ATTR_STD_NOT_FOUND)
131                 motion_post = primitive_attribute_float3(kg, sd, elem_post, offset_post, NULL, NULL);
132
133         /* object motion. note that depending on the mesh having motion vectors, this
134          * transformation was set match the world/object space of motion_pre/post */
135         Transform tfm;
136         
137         tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_PRE);
138         motion_pre = transform_point(&tfm, motion_pre);
139
140         tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_POST);
141         motion_post = transform_point(&tfm, motion_post);
142
143         float3 P;
144
145         /* camera motion, for perspective/orthographic motion.pre/post will be a
146          * world-to-raster matrix, for panorama it's world-to-camera */
147         if (kernel_data.cam.type != CAMERA_PANORAMA) {
148                 tfm = kernel_data.cam.worldtoraster;
149                 P = transform_perspective(&tfm, sd->P);
150
151                 tfm = kernel_data.cam.motion.pre;
152                 motion_pre = transform_perspective(&tfm, motion_pre);
153
154                 tfm = kernel_data.cam.motion.post;
155                 motion_post = transform_perspective(&tfm, motion_post);
156         }
157         else {
158                 tfm = kernel_data.cam.worldtocamera;
159                 P = normalize(transform_point(&tfm, sd->P));
160                 P = float2_to_float3(direction_to_panorama(kg, P));
161                 P.x *= kernel_data.cam.width;
162                 P.y *= kernel_data.cam.height;
163
164                 tfm = kernel_data.cam.motion.pre;
165                 motion_pre = normalize(transform_point(&tfm, motion_pre));
166                 motion_pre = float2_to_float3(direction_to_panorama(kg, motion_pre));
167                 motion_pre.x *= kernel_data.cam.width;
168                 motion_pre.y *= kernel_data.cam.height;
169
170                 tfm = kernel_data.cam.motion.post;
171                 motion_post = normalize(transform_point(&tfm, motion_post));
172                 motion_post = float2_to_float3(direction_to_panorama(kg, motion_post));
173                 motion_post.x *= kernel_data.cam.width;
174                 motion_post.y *= kernel_data.cam.height;
175         }
176
177         motion_pre = motion_pre - P;
178         motion_post = P - motion_post;
179
180         return make_float4(motion_pre.x, motion_pre.y, motion_post.x, motion_post.y);
181 }
182
183 CCL_NAMESPACE_END
184
185 #endif /* __KERNEL_ATTRIBUTE_CL__ */