a3f2c2ea3697a8f44ac309d960eba06a90bdf159
[blender.git] / intern / cycles / kernel / osl / osl_services.cpp
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 #include <string.h>
20
21 #include "mesh.h"
22 #include "object.h"
23 #include "scene.h"
24
25 #include "osl_services.h"
26 #include "osl_shader.h"
27
28 #include "util_foreach.h"
29 #include "util_string.h"
30
31 #include "kernel_compat_cpu.h"
32 #include "kernel_globals.h"
33 #include "kernel_object.h"
34 #include "kernel_triangle.h"
35
36 CCL_NAMESPACE_BEGIN
37
38 /* RenderServices implementation */
39
40 #define TO_MATRIX44(m) (*(OSL::Matrix44 *)&(m))
41
42 /* static ustrings */
43 ustring OSLRenderServices::u_distance("distance");
44 ustring OSLRenderServices::u_index("index");
45 ustring OSLRenderServices::u_camera("camera");
46 ustring OSLRenderServices::u_screen("screen");
47 ustring OSLRenderServices::u_raster("raster");
48 ustring OSLRenderServices::u_ndc("NDC");
49 ustring OSLRenderServices::u_empty;
50
51 OSLRenderServices::OSLRenderServices()
52 {
53         kernel_globals = NULL;
54 }
55
56 OSLRenderServices::~OSLRenderServices()
57 {
58 }
59
60 void OSLRenderServices::thread_init(KernelGlobals *kernel_globals_)
61 {
62         kernel_globals = kernel_globals_;
63 }
64
65 bool OSLRenderServices::get_matrix(OSL::Matrix44 &result, OSL::TransformationPtr xform, float time)
66 {
67         /* this is only used for shader and object space, we don't really have
68          * a concept of shader space, so we just use object space for both. */
69         if (xform) {
70                 KernelGlobals *kg = kernel_globals;
71                 const ShaderData *sd = (const ShaderData *)xform;
72                 int object = sd->object;
73
74                 if (object != ~0) {
75                         Transform tfm = object_fetch_transform(kg, object, time, OBJECT_TRANSFORM);
76                         tfm = transform_transpose(tfm);
77                         result = TO_MATRIX44(tfm);
78
79                         return true;
80                 }
81         }
82
83         return false;
84 }
85
86 bool OSLRenderServices::get_inverse_matrix(OSL::Matrix44 &result, OSL::TransformationPtr xform, float time)
87 {
88         /* this is only used for shader and object space, we don't really have
89          * a concept of shader space, so we just use object space for both. */
90         if (xform) {
91                 KernelGlobals *kg = kernel_globals;
92                 const ShaderData *sd = (const ShaderData *)xform;
93                 int object = sd->object;
94
95                 if (object != ~0) {
96                         Transform tfm = object_fetch_transform(kg, object, time, OBJECT_INVERSE_TRANSFORM);
97                         tfm = transform_transpose(tfm);
98                         result = TO_MATRIX44(tfm);
99
100                         return true;
101                 }
102         }
103
104         return false;
105 }
106
107 bool OSLRenderServices::get_matrix(OSL::Matrix44 &result, ustring from, float time)
108 {
109         KernelGlobals *kg = kernel_globals;
110
111         if (from == u_ndc) {
112                 Transform tfm = transform_transpose(kernel_data.cam.ndctoworld);
113                 result = TO_MATRIX44(tfm);
114                 return true;
115         }
116         else if (from == u_raster) {
117                 Transform tfm = transform_transpose(kernel_data.cam.rastertoworld);
118                 result = TO_MATRIX44(tfm);
119                 return true;
120         }
121         else if (from == u_screen) {
122                 Transform tfm = transform_transpose(kernel_data.cam.screentoworld);
123                 result = TO_MATRIX44(tfm);
124                 return true;
125         }
126         else if (from == u_camera) {
127                 Transform tfm = transform_transpose(kernel_data.cam.cameratoworld);
128                 result = TO_MATRIX44(tfm);
129                 return true;
130         }
131
132         return false;
133 }
134
135 bool OSLRenderServices::get_inverse_matrix(OSL::Matrix44 &result, ustring to, float time)
136 {
137         KernelGlobals *kg = kernel_globals;
138
139         if (to == u_ndc) {
140                 Transform tfm = transform_transpose(kernel_data.cam.worldtondc);
141                 result = TO_MATRIX44(tfm);
142                 return true;
143         }
144         else if (to == u_raster) {
145                 Transform tfm = transform_transpose(kernel_data.cam.worldtoraster);
146                 result = TO_MATRIX44(tfm);
147                 return true;
148         }
149         else if (to == u_screen) {
150                 Transform tfm = transform_transpose(kernel_data.cam.worldtoscreen);
151                 result = TO_MATRIX44(tfm);
152                 return true;
153         }
154         else if (to == u_camera) {
155                 Transform tfm = transform_transpose(kernel_data.cam.worldtocamera);
156                 result = TO_MATRIX44(tfm);
157                 return true;
158         }
159
160         return false;
161 }
162
163 bool OSLRenderServices::get_matrix(OSL::Matrix44 &result, OSL::TransformationPtr xform)
164 {
165         // XXX implementation
166         return true;
167 }
168
169 bool OSLRenderServices::get_matrix(OSL::Matrix44 &result, ustring from)
170 {
171         // XXX implementation
172         return true;
173 }
174
175 bool OSLRenderServices::get_array_attribute(void *renderstate, bool derivatives, 
176                                             ustring object, TypeDesc type, ustring name,
177                                             int index, void *val)
178 {
179         return false;
180 }
181
182 static bool get_mesh_attribute(KernelGlobals *kg, const ShaderData *sd,
183                                const OSLGlobals::Attribute& attr, bool derivatives, void *val)
184 {
185         if (attr.type == TypeDesc::TypeFloat) {
186                 float *fval = (float *)val;
187                 fval[0] = triangle_attribute_float(kg, sd, attr.elem, attr.offset,
188                                                    (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
189         }
190         else {
191                 /* todo: this won't work when float3 has w component */
192                 float3 *fval = (float3 *)val;
193                 fval[0] = triangle_attribute_float3(kg, sd, attr.elem, attr.offset,
194                                                     (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
195         }
196
197         return true;
198 }
199
200 static bool get_mesh_attribute_convert(KernelGlobals *kg, const ShaderData *sd,
201                                        const OSLGlobals::Attribute& attr, const TypeDesc& type, bool derivatives, void *val)
202 {
203         if (attr.type == TypeDesc::TypeFloat) {
204                 float tmp[3];
205                 float3 *fval = (float3 *)val;
206
207                 get_mesh_attribute(kg, sd, attr, derivatives, tmp);
208
209                 fval[0] = make_float3(tmp[0], tmp[0], tmp[0]);
210                 if (derivatives) {
211                         fval[1] = make_float3(tmp[1], tmp[1], tmp[1]);
212                         fval[2] = make_float3(tmp[2], tmp[2], tmp[2]);
213                 }
214
215                 return true;
216         }
217         else if (attr.type == TypeDesc::TypePoint || attr.type == TypeDesc::TypeVector ||
218                  attr.type == TypeDesc::TypeNormal || attr.type == TypeDesc::TypeColor)
219         {
220                 float3 tmp[3];
221                 float *fval = (float *)val;
222
223                 get_mesh_attribute(kg, sd, attr, derivatives, tmp);
224
225                 fval[0] = average(tmp[0]);
226                 if (derivatives) {
227                         fval[1] = average(tmp[1]);
228                         fval[2] = average(tmp[2]);
229                 }
230
231                 return true;
232         }
233         else
234                 return false;
235 }
236
237 static void get_object_attribute(const OSLGlobals::Attribute& attr, bool derivatives, void *val)
238 {
239         size_t datasize = attr.value.datasize();
240
241         memcpy(val, attr.value.data(), datasize);
242         if (derivatives)
243                 memset((char *)val + datasize, 0, datasize * 2);
244 }
245
246 bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustring object_name,
247                                       TypeDesc type, ustring name, void *val)
248 {
249         KernelGlobals *kg = kernel_globals;
250         const ShaderData *sd = (const ShaderData *)renderstate;
251         int object = sd->object;
252         int tri = sd->prim;
253
254         /* lookup of attribute on another object */
255         if (object_name != u_empty) {
256                 OSLGlobals::ObjectNameMap::iterator it = kg->osl.object_name_map.find(object_name);
257
258                 if (it == kg->osl.object_name_map.end())
259                         return false;
260
261                 object = it->second;
262                 tri = ~0;
263         }
264         else if (object == ~0) {
265                 /* no background attributes supported */
266                 return false;
267         }
268
269         /* find attribute on object */
270         OSLGlobals::AttributeMap& attribute_map = kg->osl.attribute_map[object];
271         OSLGlobals::AttributeMap::iterator it = attribute_map.find(name);
272
273         if (it == attribute_map.end())
274                 return false;
275
276         /* type mistmatch? */
277         const OSLGlobals::Attribute& attr = it->second;
278
279         if (attr.elem != ATTR_ELEMENT_VALUE) {
280                 /* triangle and vertex attributes */
281                 if (tri != ~0) {
282                         if (attr.type == type || (attr.type == TypeDesc::TypeColor &&
283                                                   (type == TypeDesc::TypePoint || type == TypeDesc::TypeVector || type == TypeDesc::TypeNormal)))
284                         {
285                                 return get_mesh_attribute(kg, sd, attr, derivatives, val);
286                         }
287                         else {
288                                 return get_mesh_attribute_convert(kg, sd, attr, type, derivatives, val);
289                         }
290                 }
291         }
292         else {
293                 /* object attribute */
294                 get_object_attribute(attr, derivatives, val);
295                 return true;
296         }
297
298         return false;
299 }
300
301 bool OSLRenderServices::get_userdata(bool derivatives, ustring name, TypeDesc type, 
302                                      void *renderstate, void *val)
303 {
304         return false; /* disabled by lockgeom */
305 }
306
307 bool OSLRenderServices::has_userdata(ustring name, TypeDesc type, void *renderstate)
308 {
309         return false; /* never called by OSL */
310 }
311
312 int OSLRenderServices::pointcloud_search(OSL::ShaderGlobals *sg, ustring filename, const OSL::Vec3 &center,
313                 float radius, int max_points, bool sort, size_t *out_indices, float *out_distances, int derivs_offset)
314 {
315     return 0;
316 }
317
318 int OSLRenderServices::pointcloud_get(ustring filename, size_t *indices, int count,
319                 ustring attr_name, TypeDesc attr_type, void *out_data)
320 {
321     return 0;
322 }
323
324 CCL_NAMESPACE_END