Added Object Info node implementation for OSL. This uses an additional attribute...
[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 void set_attribute_float3(float3 f[3], TypeDesc type, bool derivatives, void *val)
183 {
184         if (type == TypeDesc::TypePoint || type == TypeDesc::TypeVector ||
185                 type == TypeDesc::TypeNormal || type == TypeDesc::TypeColor) {
186                 float3 *fval = (float3 *)val;
187                 fval[0] = f[0];
188                 if (derivatives) {
189                         fval[1] = f[1];
190                         fval[2] = f[2];
191                 }
192         }
193         else {
194                 float *fval = (float *)val;
195                 fval[0] = average(f[0]);
196                 if (derivatives) {
197                         fval[1] = average(f[1]);
198                         fval[2] = average(f[2]);
199                 }
200         }
201 }
202
203 static void set_attribute_float(float f[3], TypeDesc type, bool derivatives, void *val)
204 {
205         if (type == TypeDesc::TypePoint || type == TypeDesc::TypeVector ||
206                 type == TypeDesc::TypeNormal || type == TypeDesc::TypeColor) {
207                 float3 *fval = (float3 *)val;
208                 fval[0] = make_float3(f[0], f[0], f[0]);
209                 if (derivatives) {
210                         fval[1] = make_float3(f[1], f[2], f[1]);
211                         fval[2] = make_float3(f[2], f[2], f[2]);
212                 }
213         }
214         else {
215                 float *fval = (float *)val;
216                 fval[0] = f[0];
217                 if (derivatives) {
218                         fval[1] = f[1];
219                         fval[2] = f[2];
220                 }
221         }
222 }
223
224 static bool get_mesh_attribute(KernelGlobals *kg, const ShaderData *sd, const OSLGlobals::Attribute& attr,
225                                const TypeDesc& type, bool derivatives, void *val)
226 {
227         if (attr.type == TypeDesc::TypeFloat) {
228                 float fval[3];
229                 fval[0] = triangle_attribute_float(kg, sd, attr.elem, attr.offset,
230                                                    (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
231                 set_attribute_float(fval, type, derivatives, val);
232                 return true;
233         }
234         else if (attr.type == TypeDesc::TypePoint || attr.type == TypeDesc::TypeVector ||
235                  attr.type == TypeDesc::TypeNormal || attr.type == TypeDesc::TypeColor) {
236                 /* todo: this won't work when float3 has w component */
237                 float3 fval[3];
238                 fval[0] = triangle_attribute_float3(kg, sd, attr.elem, attr.offset,
239                                                     (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
240                 set_attribute_float3(fval, type, derivatives, val);
241                 return true;
242         }
243         else
244                 return false;
245 }
246
247 static void get_object_attribute(const OSLGlobals::Attribute& attr, bool derivatives, void *val)
248 {
249         size_t datasize = attr.value.datasize();
250
251         memcpy(val, attr.value.data(), datasize);
252         if (derivatives)
253                 memset((char *)val + datasize, 0, datasize * 2);
254 }
255
256 static bool get_object_standard_attribute(KernelGlobals *kg, ShaderData *sd, ustring name,
257                                           TypeDesc type, bool derivatives, void *val)
258 {
259         if (name == "std::object_location") {
260                 float3 loc[3];
261                 loc[0] = object_location(kg, sd);
262                 loc[1] = loc[2] = make_float3(0.0, 0.0, 0.0);   /* derivates set to 0 */
263                 set_attribute_float3(loc, type, derivatives, val);
264                 return true;
265         }
266         else if (name == "std::object_index") {
267                 float loc[3];
268                 loc[0] = object_pass_id(kg, sd->object);
269                 loc[1] = loc[2] = 0.0;  /* derivates set to 0 */
270                 set_attribute_float(loc, type, derivatives, val);
271                 return true;
272         }
273         else if (name == "std::material_index") {
274                 float loc[3];
275                 loc[0] = shader_pass_id(kg, sd);
276                 loc[1] = loc[2] = 0.0;  /* derivates set to 0 */
277                 set_attribute_float(loc, type, derivatives, val);
278                 return true;
279         }
280         else if (name == "std::object_random") {
281                 float loc[3];
282                 loc[0] = object_random_number(kg, sd->object);
283                 loc[1] = loc[2] = 0.0;  /* derivates set to 0 */
284                 set_attribute_float(loc, type, derivatives, val);
285                 return true;
286         }
287         else
288                 return false;
289 }
290
291 bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustring object_name,
292                                       TypeDesc type, ustring name, void *val)
293 {
294         KernelGlobals *kg = kernel_globals;
295         ShaderData *sd = (ShaderData *)renderstate;
296         int object = sd->object;
297         int tri = sd->prim;
298
299         /* lookup of attribute on another object */
300         if (object_name != u_empty) {
301                 OSLGlobals::ObjectNameMap::iterator it = kg->osl.object_name_map.find(object_name);
302
303                 if (it == kg->osl.object_name_map.end())
304                         return false;
305
306                 object = it->second;
307                 tri = ~0;
308         }
309         else if (object == ~0) {
310                 /* no background attributes supported */
311                 return false;
312         }
313
314         /* find attribute on object */
315         OSLGlobals::AttributeMap& attribute_map = kg->osl.attribute_map[object];
316         OSLGlobals::AttributeMap::iterator it = attribute_map.find(name);
317
318         if (it != attribute_map.end()) {
319                 const OSLGlobals::Attribute& attr = it->second;
320                 
321                 if (attr.elem != ATTR_ELEMENT_VALUE) {
322                         /* triangle and vertex attributes */
323                         if (tri != ~0)
324                                 return get_mesh_attribute(kg, sd, attr, type, derivatives, val);
325                 }
326                 else {
327                         /* object attribute */
328                         get_object_attribute(attr, derivatives, val);
329                         return true;
330                 }
331         }
332         else {
333                 /* not found in attribute, check standard object info */
334                 return get_object_standard_attribute(kg, sd, name, type, derivatives, val);
335         }
336
337         return false;
338 }
339
340 bool OSLRenderServices::get_userdata(bool derivatives, ustring name, TypeDesc type, 
341                                      void *renderstate, void *val)
342 {
343         return false; /* disabled by lockgeom */
344 }
345
346 bool OSLRenderServices::has_userdata(ustring name, TypeDesc type, void *renderstate)
347 {
348         return false; /* never called by OSL */
349 }
350
351 int OSLRenderServices::pointcloud_search(OSL::ShaderGlobals *sg, ustring filename, const OSL::Vec3 &center,
352                 float radius, int max_points, bool sort, size_t *out_indices, float *out_distances, int derivs_offset)
353 {
354     return 0;
355 }
356
357 int OSLRenderServices::pointcloud_get(ustring filename, size_t *indices, int count,
358                 ustring attr_name, TypeDesc attr_type, void *out_data)
359 {
360     return 0;
361 }
362
363 CCL_NAMESPACE_END