Merged changes in the trunk up to revision 53729.
[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_closures.h"
26 #include "osl_globals.h"
27 #include "osl_services.h"
28 #include "osl_shader.h"
29
30 #include "util_foreach.h"
31 #include "util_string.h"
32
33 #include "kernel_compat_cpu.h"
34 #include "kernel_globals.h"
35 #include "kernel_montecarlo.h"
36 #include "kernel_projection.h"
37 #include "kernel_differential.h"
38 #include "kernel_object.h"
39 #include "kernel_bvh.h"
40 #include "kernel_triangle.h"
41 #include "kernel_curve.h"
42 #include "kernel_primitive.h"
43 #include "kernel_projection.h"
44 #include "kernel_accumulate.h"
45 #include "kernel_shader.h"
46
47 CCL_NAMESPACE_BEGIN
48
49 /* RenderServices implementation */
50
51 #define COPY_MATRIX44(m1, m2) memcpy(m1, m2, sizeof(*m2))
52
53 /* static ustrings */
54 ustring OSLRenderServices::u_distance("distance");
55 ustring OSLRenderServices::u_index("index");
56 ustring OSLRenderServices::u_camera("camera");
57 ustring OSLRenderServices::u_screen("screen");
58 ustring OSLRenderServices::u_raster("raster");
59 ustring OSLRenderServices::u_ndc("NDC");
60 ustring OSLRenderServices::u_object_location("object:location");
61 ustring OSLRenderServices::u_object_index("object:index");
62 ustring OSLRenderServices::u_geom_dupli_generated("geom:dupli_generated");
63 ustring OSLRenderServices::u_geom_dupli_uv("geom:dupli_uv");
64 ustring OSLRenderServices::u_material_index("material:index");
65 ustring OSLRenderServices::u_object_random("object:random");
66 ustring OSLRenderServices::u_particle_index("particle:index");
67 ustring OSLRenderServices::u_particle_age("particle:age");
68 ustring OSLRenderServices::u_particle_lifetime("particle:lifetime");
69 ustring OSLRenderServices::u_particle_location("particle:location");
70 ustring OSLRenderServices::u_particle_rotation("particle:rotation");
71 ustring OSLRenderServices::u_particle_size("particle:size");
72 ustring OSLRenderServices::u_particle_velocity("particle:velocity");
73 ustring OSLRenderServices::u_particle_angular_velocity("particle:angular_velocity");
74 ustring OSLRenderServices::u_geom_numpolyvertices("geom:numpolyvertices");
75 ustring OSLRenderServices::u_geom_trianglevertices("geom:trianglevertices");
76 ustring OSLRenderServices::u_geom_polyvertices("geom:polyvertices");
77 ustring OSLRenderServices::u_geom_name("geom:name");
78 #ifdef __HAIR__
79 ustring OSLRenderServices::u_is_curve("geom:is_curve");
80 ustring OSLRenderServices::u_curve_thickness("geom:curve_thickness");
81 ustring OSLRenderServices::u_curve_tangent_normal("geom:curve_tangent_normal");
82 #endif
83 ustring OSLRenderServices::u_path_ray_length("path:ray_length");
84 ustring OSLRenderServices::u_trace("trace");
85 ustring OSLRenderServices::u_hit("hit");
86 ustring OSLRenderServices::u_hitdist("hitdist");
87 ustring OSLRenderServices::u_N("N");
88 ustring OSLRenderServices::u_Ng("Ng");
89 ustring OSLRenderServices::u_P("P");
90 ustring OSLRenderServices::u_I("I");
91 ustring OSLRenderServices::u_u("u");
92 ustring OSLRenderServices::u_v("v");
93 ustring OSLRenderServices::u_empty;
94
95 OSLRenderServices::OSLRenderServices()
96 {
97         kernel_globals = NULL;
98 }
99
100 OSLRenderServices::~OSLRenderServices()
101 {
102 }
103
104 void OSLRenderServices::thread_init(KernelGlobals *kernel_globals_)
105 {
106         kernel_globals = kernel_globals_;
107 }
108
109 bool OSLRenderServices::get_matrix(OSL::Matrix44 &result, OSL::TransformationPtr xform, float time)
110 {
111         /* this is only used for shader and object space, we don't really have
112          * a concept of shader space, so we just use object space for both. */
113         if (xform) {
114                 KernelGlobals *kg = kernel_globals;
115                 const ShaderData *sd = (const ShaderData *)xform;
116                 int object = sd->object;
117
118                 if (object != ~0) {
119 #ifdef __OBJECT_MOTION__
120                         Transform tfm;
121
122                         if(time == sd->time)
123                                 tfm = sd->ob_tfm;
124                         else
125                                 tfm = object_fetch_transform_motion_test(kg, object, time, NULL);
126 #else
127                         Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
128 #endif
129                         tfm = transform_transpose(tfm);
130                         COPY_MATRIX44(&result, &tfm);
131
132                         return true;
133                 }
134         }
135
136         return false;
137 }
138
139 bool OSLRenderServices::get_inverse_matrix(OSL::Matrix44 &result, OSL::TransformationPtr xform, float time)
140 {
141         /* this is only used for shader and object space, we don't really have
142          * a concept of shader space, so we just use object space for both. */
143         if (xform) {
144                 KernelGlobals *kg = kernel_globals;
145                 const ShaderData *sd = (const ShaderData *)xform;
146                 int object = sd->object;
147
148                 if (object != ~0) {
149 #ifdef __OBJECT_MOTION__
150                         Transform itfm;
151
152                         if(time == sd->time)
153                                 itfm = sd->ob_itfm;
154                         else
155                                 object_fetch_transform_motion_test(kg, object, time, &itfm);
156 #else
157                         Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
158 #endif
159                         itfm = transform_transpose(itfm);
160                         COPY_MATRIX44(&result, &itfm);
161
162                         return true;
163                 }
164         }
165
166         return false;
167 }
168
169 bool OSLRenderServices::get_matrix(OSL::Matrix44 &result, ustring from, float time)
170 {
171         KernelGlobals *kg = kernel_globals;
172
173         if (from == u_ndc) {
174                 Transform tfm = transform_transpose(transform_quick_inverse(kernel_data.cam.worldtondc));
175                 COPY_MATRIX44(&result, &tfm);
176                 return true;
177         }
178         else if (from == u_raster) {
179                 Transform tfm = transform_transpose(kernel_data.cam.rastertoworld);
180                 COPY_MATRIX44(&result, &tfm);
181                 return true;
182         }
183         else if (from == u_screen) {
184                 Transform tfm = transform_transpose(kernel_data.cam.screentoworld);
185                 COPY_MATRIX44(&result, &tfm);
186                 return true;
187         }
188         else if (from == u_camera) {
189                 Transform tfm = transform_transpose(kernel_data.cam.cameratoworld);
190                 COPY_MATRIX44(&result, &tfm);
191                 return true;
192         }
193
194         return false;
195 }
196
197 bool OSLRenderServices::get_inverse_matrix(OSL::Matrix44 &result, ustring to, float time)
198 {
199         KernelGlobals *kg = kernel_globals;
200
201         if (to == u_ndc) {
202                 Transform tfm = transform_transpose(kernel_data.cam.worldtondc);
203                 COPY_MATRIX44(&result, &tfm);
204                 return true;
205         }
206         else if (to == u_raster) {
207                 Transform tfm = transform_transpose(kernel_data.cam.worldtoraster);
208                 COPY_MATRIX44(&result, &tfm);
209                 return true;
210         }
211         else if (to == u_screen) {
212                 Transform tfm = transform_transpose(kernel_data.cam.worldtoscreen);
213                 COPY_MATRIX44(&result, &tfm);
214                 return true;
215         }
216         else if (to == u_camera) {
217                 Transform tfm = transform_transpose(kernel_data.cam.worldtocamera);
218                 COPY_MATRIX44(&result, &tfm);
219                 return true;
220         }
221
222         return false;
223 }
224
225 bool OSLRenderServices::get_matrix(OSL::Matrix44 &result, OSL::TransformationPtr xform)
226 {
227         /* this is only used for shader and object space, we don't really have
228          * a concept of shader space, so we just use object space for both. */
229         if (xform) {
230                 const ShaderData *sd = (const ShaderData *)xform;
231                 int object = sd->object;
232
233                 if (object != ~0) {
234 #ifdef __OBJECT_MOTION__
235                         Transform tfm = sd->ob_tfm;
236 #else
237                         KernelGlobals *kg = kernel_globals;
238                         Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
239 #endif
240                         tfm = transform_transpose(tfm);
241                         COPY_MATRIX44(&result, &tfm);
242
243                         return true;
244                 }
245         }
246
247         return false;
248 }
249
250 bool OSLRenderServices::get_inverse_matrix(OSL::Matrix44 &result, OSL::TransformationPtr xform)
251 {
252         /* this is only used for shader and object space, we don't really have
253          * a concept of shader space, so we just use object space for both. */
254         if (xform) {
255                 const ShaderData *sd = (const ShaderData *)xform;
256                 int object = sd->object;
257
258                 if (object != ~0) {
259 #ifdef __OBJECT_MOTION__
260                         Transform tfm = sd->ob_itfm;
261 #else
262                         KernelGlobals *kg = kernel_globals;
263                         Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
264 #endif
265                         tfm = transform_transpose(tfm);
266                         COPY_MATRIX44(&result, &tfm);
267
268                         return true;
269                 }
270         }
271
272         return false;
273 }
274
275 bool OSLRenderServices::get_matrix(OSL::Matrix44 &result, ustring from)
276 {
277         KernelGlobals *kg = kernel_globals;
278
279         if (from == u_ndc) {
280                 Transform tfm = transform_transpose(transform_quick_inverse(kernel_data.cam.worldtondc));
281                 COPY_MATRIX44(&result, &tfm);
282                 return true;
283         }
284         else if (from == u_raster) {
285                 Transform tfm = transform_transpose(kernel_data.cam.rastertoworld);
286                 COPY_MATRIX44(&result, &tfm);
287                 return true;
288         }
289         else if (from == u_screen) {
290                 Transform tfm = transform_transpose(kernel_data.cam.screentoworld);
291                 COPY_MATRIX44(&result, &tfm);
292                 return true;
293         }
294         else if (from == u_camera) {
295                 Transform tfm = transform_transpose(kernel_data.cam.cameratoworld);
296                 COPY_MATRIX44(&result, &tfm);
297                 return true;
298         }
299
300         return false;
301 }
302
303 bool OSLRenderServices::get_inverse_matrix(OSL::Matrix44 &result, ustring to)
304 {
305         KernelGlobals *kg = kernel_globals;
306         
307         if (to == u_ndc) {
308                 Transform tfm = transform_transpose(kernel_data.cam.worldtondc);
309                 COPY_MATRIX44(&result, &tfm);
310                 return true;
311         }
312         else if (to == u_raster) {
313                 Transform tfm = transform_transpose(kernel_data.cam.worldtoraster);
314                 COPY_MATRIX44(&result, &tfm);
315                 return true;
316         }
317         else if (to == u_screen) {
318                 Transform tfm = transform_transpose(kernel_data.cam.worldtoscreen);
319                 COPY_MATRIX44(&result, &tfm);
320                 return true;
321         }
322         else if (to == u_camera) {
323                 Transform tfm = transform_transpose(kernel_data.cam.worldtocamera);
324                 COPY_MATRIX44(&result, &tfm);
325                 return true;
326         }
327         
328         return false;
329 }
330
331 bool OSLRenderServices::get_array_attribute(void *renderstate, bool derivatives, 
332                                             ustring object, TypeDesc type, ustring name,
333                                             int index, void *val)
334 {
335         return false;
336 }
337
338 static bool set_attribute_float3(float3 f[3], TypeDesc type, bool derivatives, void *val)
339 {
340         if (type == TypeDesc::TypePoint || type == TypeDesc::TypeVector ||
341             type == TypeDesc::TypeNormal || type == TypeDesc::TypeColor)
342         {
343                 float *fval = (float *)val;
344
345                 fval[0] = f[0].x;
346                 fval[1] = f[0].y;
347                 fval[2] = f[0].z;
348
349                 if (derivatives) {
350                         fval[3] = f[1].x;
351                         fval[4] = f[1].y;
352                         fval[5] = f[1].z;
353
354                         fval[6] = f[2].x;
355                         fval[7] = f[2].y;
356                         fval[8] = f[2].z;
357                 }
358
359                 return true;
360         }
361         else if(type == TypeDesc::TypeFloat) {
362                 float *fval = (float *)val;
363                 fval[0] = average(f[0]);
364
365                 if (derivatives) {
366                         fval[1] = average(f[1]);
367                         fval[2] = average(f[2]);
368                 }
369
370                 return true;
371         }
372
373         return false;
374 }
375
376 static bool set_attribute_float3(float3 f, TypeDesc type, bool derivatives, void *val)
377 {
378         float3 fv[3];
379
380         fv[0] = f;
381         fv[1] = make_float3(0.0f, 0.0f, 0.0f);
382         fv[2] = make_float3(0.0f, 0.0f, 0.0f);
383
384         return set_attribute_float3(fv, type, derivatives, val);
385 }
386
387 static bool set_attribute_float(float f[3], TypeDesc type, bool derivatives, void *val)
388 {
389         if (type == TypeDesc::TypePoint || type == TypeDesc::TypeVector ||
390             type == TypeDesc::TypeNormal || type == TypeDesc::TypeColor)
391         {
392                 float *fval = (float *)val;
393                 fval[0] = f[0];
394                 fval[1] = f[1];
395                 fval[2] = f[2];
396
397                 if (derivatives) {
398                         fval[3] = f[1];
399                         fval[4] = f[1];
400                         fval[5] = f[1];
401
402                         fval[6] = f[2];
403                         fval[7] = f[2];
404                         fval[8] = f[2];
405                 }
406
407                 return true;
408         }
409         else if(type == TypeDesc::TypeFloat) {
410                 float *fval = (float *)val;
411                 fval[0] = f[0];
412
413                 if (derivatives) {
414                         fval[1] = f[1];
415                         fval[2] = f[2];
416                 }
417
418                 return true;
419         }
420
421         return false;
422 }
423
424 static bool set_attribute_float(float f, TypeDesc type, bool derivatives, void *val)
425 {
426         float fv[3];
427
428         fv[0] = f;
429         fv[1] = 0.0f;
430         fv[2] = 0.0f;
431
432         return set_attribute_float(fv, type, derivatives, val);
433 }
434
435 static bool set_attribute_int(int i, TypeDesc type, bool derivatives, void *val)
436 {
437         if(type.basetype == TypeDesc::INT && type.aggregate == TypeDesc::SCALAR && type.arraylen == 0) {
438                 int *ival = (int *)val;
439                 ival[0] = i;
440
441                 if (derivatives) {
442                         ival[1] = 0;
443                         ival[2] = 0;
444                 }
445
446                 return true;
447         }
448
449         return false;
450 }
451
452 static bool set_attribute_string(ustring str, TypeDesc type, bool derivatives, void *val)
453 {
454         if(type.basetype == TypeDesc::INT && type.aggregate == TypeDesc::SCALAR && type.arraylen == 0) {
455                 ustring *sval = (ustring *)val;
456                 sval[0] = str;
457
458                 if (derivatives) {
459                         sval[1] = OSLRenderServices::u_empty;
460                         sval[2] = OSLRenderServices::u_empty;
461                 }
462
463                 return true;
464         }
465
466         return false;
467 }
468
469 static bool set_attribute_float3_3(float3 P[3], TypeDesc type, bool derivatives, void *val)
470 {
471         if(type.vecsemantics == TypeDesc::POINT && type.arraylen >= 3) {
472                 float *fval = (float *)val;
473
474                 fval[0] = P[0].x;
475                 fval[1] = P[0].y;
476                 fval[2] = P[0].z;
477
478                 fval[3] = P[1].x;
479                 fval[4] = P[1].y;
480                 fval[5] = P[1].z;
481
482                 fval[6] = P[2].x;
483                 fval[7] = P[2].y;
484                 fval[8] = P[2].z;
485
486                 if(type.arraylen > 3)
487                         memset(fval + 3*3, 0, sizeof(float)*3*(type.arraylen - 3));
488                 if (derivatives)
489                         memset(fval + type.arraylen*3, 0, sizeof(float)*2*3*type.arraylen);
490
491                 return true;
492         }
493
494         return false;
495 }
496
497 static bool get_mesh_attribute(KernelGlobals *kg, const ShaderData *sd, const OSLGlobals::Attribute& attr,
498                                const TypeDesc& type, bool derivatives, void *val)
499 {
500         if (attr.type == TypeDesc::TypePoint || attr.type == TypeDesc::TypeVector ||
501             attr.type == TypeDesc::TypeNormal || attr.type == TypeDesc::TypeColor)
502         {
503                 float3 fval[3];
504                 fval[0] = primitive_attribute_float3(kg, sd, attr.elem, attr.offset,
505                                                      (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
506                 return set_attribute_float3(fval, type, derivatives, val);
507         }
508         else if (attr.type == TypeDesc::TypeFloat) {
509                 float fval[3];
510                 fval[0] = primitive_attribute_float(kg, sd, attr.elem, attr.offset,
511                                                     (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
512                 return set_attribute_float(fval, type, derivatives, val);
513         }
514         else {
515                 return false;
516         }
517 }
518
519 static void get_object_attribute(const OSLGlobals::Attribute& attr, bool derivatives, void *val)
520 {
521         size_t datasize = attr.value.datasize();
522
523         memcpy(val, attr.value.data(), datasize);
524         if (derivatives)
525                 memset((char *)val + datasize, 0, datasize * 2);
526 }
527
528 bool OSLRenderServices::get_object_standard_attribute(KernelGlobals *kg, ShaderData *sd, ustring name,
529                                                       TypeDesc type, bool derivatives, void *val)
530 {
531         /* todo: turn this into hash table? */
532
533         /* Object Attributes */
534         if (name == u_object_location) {
535                 float3 f = object_location(kg, sd);
536                 return set_attribute_float3(f, type, derivatives, val);
537         }
538         else if (name == u_object_index) {
539                 float f = object_pass_id(kg, sd->object);
540                 return set_attribute_float(f, type, derivatives, val);
541         }
542         else if (name == u_geom_dupli_generated) {
543                 float3 f = object_dupli_generated(kg, sd->object);
544                 return set_attribute_float3(f, type, derivatives, val);
545         }
546         else if (name == u_geom_dupli_uv) {
547                 float3 f = object_dupli_uv(kg, sd->object);
548                 return set_attribute_float3(f, type, derivatives, val);
549         }
550         else if (name == u_material_index) {
551                 float f = shader_pass_id(kg, sd);
552                 return set_attribute_float(f, type, derivatives, val);
553         }
554         else if (name == u_object_random) {
555                 float f = object_random_number(kg, sd->object);
556                 return set_attribute_float(f, type, derivatives, val);
557         }
558
559         /* Particle Attributes */
560         else if (name == u_particle_index) {
561                 uint particle_id = object_particle_id(kg, sd->object);
562                 float f = particle_index(kg, particle_id);
563                 return set_attribute_float(f, type, derivatives, val);
564         }
565         else if (name == u_particle_age) {
566                 uint particle_id = object_particle_id(kg, sd->object);
567                 float f = particle_age(kg, particle_id);
568                 return set_attribute_float(f, type, derivatives, val);
569         }
570         else if (name == u_particle_lifetime) {
571                 uint particle_id = object_particle_id(kg, sd->object);
572                 float f= particle_lifetime(kg, particle_id);
573                 return set_attribute_float(f, type, derivatives, val);
574         }
575         else if (name == u_particle_location) {
576                 uint particle_id = object_particle_id(kg, sd->object);
577                 float3 f = particle_location(kg, particle_id);
578                 return set_attribute_float3(f, type, derivatives, val);
579         }
580 #if 0   /* unsupported */
581         else if (name == u_particle_rotation) {
582                 uint particle_id = object_particle_id(kg, sd->object);
583                 float4 f = particle_rotation(kg, particle_id);
584                 return set_attribute_float4(f, type, derivatives, val);
585         }
586 #endif
587         else if (name == u_particle_size) {
588                 uint particle_id = object_particle_id(kg, sd->object);
589                 float f = particle_size(kg, particle_id);
590                 return set_attribute_float(f, type, derivatives, val);
591         }
592         else if (name == u_particle_velocity) {
593                 uint particle_id = object_particle_id(kg, sd->object);
594                 float3 f = particle_velocity(kg, particle_id);
595                 return set_attribute_float3(f, type, derivatives, val);
596         }
597         else if (name == u_particle_angular_velocity) {
598                 uint particle_id = object_particle_id(kg, sd->object);
599                 float3 f = particle_angular_velocity(kg, particle_id);
600                 return set_attribute_float3(f, type, derivatives, val);
601         }
602         
603         /* Geometry Attributes */
604         else if (name == u_geom_numpolyvertices) {
605                 return set_attribute_int(3, type, derivatives, val);
606         }
607         else if ((name == u_geom_trianglevertices || name == u_geom_polyvertices)
608 #ifdef __HAIR__
609                      && sd->segment == ~0) {
610 #else
611                 ) {
612 #endif
613                 float3 P[3];
614                 triangle_vertices(kg, sd->prim, P);
615
616                 if(!(sd->flag & SD_TRANSFORM_APPLIED)) {
617                         object_position_transform(kg, sd, &P[0]);
618                         object_position_transform(kg, sd, &P[1]);
619                         object_position_transform(kg, sd, &P[2]);
620                 }
621
622                 return set_attribute_float3_3(P, type, derivatives, val);
623         }
624         else if(name == u_geom_name) {
625                 ustring object_name = kg->osl->object_names[sd->object];
626                 return set_attribute_string(object_name, type, derivatives, val);
627         }
628         
629 #ifdef __HAIR__
630         /* Hair Attributes */
631         else if (name == u_is_curve) {
632                 float f = (sd->segment != ~0);
633                 return set_attribute_float(f, type, derivatives, val);
634         }
635         else if (name == u_curve_thickness) {
636                 float f = curve_thickness(kg, sd);
637                 return set_attribute_float(f, type, derivatives, val);
638         }
639         else if (name == u_curve_tangent_normal) {
640                 float3 f = curve_tangent_normal(kg, sd);
641                 return set_attribute_float3(f, type, derivatives, val);
642         }
643 #endif
644         else
645                 return false;
646 }
647
648 bool OSLRenderServices::get_background_attribute(KernelGlobals *kg, ShaderData *sd, ustring name,
649                                                  TypeDesc type, bool derivatives, void *val)
650 {
651         /* Ray Length */
652         if (name == u_path_ray_length) {
653                 float f = sd->ray_length;
654                 return set_attribute_float(f, type, derivatives, val);
655         }
656         
657         else
658                 return false;
659 }
660
661 bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustring object_name,
662                                       TypeDesc type, ustring name, void *val)
663 {
664         KernelGlobals *kg = kernel_globals;
665         ShaderData *sd = (ShaderData *)renderstate;
666         int object, prim, segment;
667
668         /* lookup of attribute on another object */
669         if (object_name != u_empty || sd == NULL) {
670                 OSLGlobals::ObjectNameMap::iterator it = kg->osl->object_name_map.find(object_name);
671
672                 if (it == kg->osl->object_name_map.end())
673                         return false;
674
675                 object = it->second;
676                 prim = ~0;
677                 segment = ~0;
678         }
679         else {
680                 object = sd->object;
681                 prim = sd->prim;
682 #ifdef __HAIR__
683                 segment = sd->segment;
684 #else
685                 segment = ~0;
686 #endif
687
688                 if (object == ~0)
689                         return get_background_attribute(kg, sd, name, type, derivatives, val);
690         }
691
692         /* find attribute on object */
693         object = object*ATTR_PRIM_TYPES + (segment != ~0);
694         OSLGlobals::AttributeMap& attribute_map = kg->osl->attribute_map[object];
695         OSLGlobals::AttributeMap::iterator it = attribute_map.find(name);
696
697         if (it != attribute_map.end()) {
698                 const OSLGlobals::Attribute& attr = it->second;
699
700                 if (attr.elem != ATTR_ELEMENT_VALUE) {
701                         /* triangle and vertex attributes */
702                         if (prim != ~0)
703                                 return get_mesh_attribute(kg, sd, attr, type, derivatives, val);
704                 }
705                 else {
706                         /* object attribute */
707                         get_object_attribute(attr, derivatives, val);
708                         return true;
709                 }
710         }
711         else {
712                 /* not found in attribute, check standard object info */
713                 bool is_std_object_attribute = get_object_standard_attribute(kg, sd, name, type, derivatives, val);
714
715                 if (is_std_object_attribute)
716                         return true;
717
718                 return get_background_attribute(kg, sd, name, type, derivatives, val);
719         }
720
721         return false;
722 }
723
724 bool OSLRenderServices::get_userdata(bool derivatives, ustring name, TypeDesc type, 
725                                      void *renderstate, void *val)
726 {
727         return false; /* disabled by lockgeom */
728 }
729
730 bool OSLRenderServices::has_userdata(ustring name, TypeDesc type, void *renderstate)
731 {
732         return false; /* never called by OSL */
733 }
734
735 bool OSLRenderServices::texture(ustring filename, TextureOpt &options,
736                                 OSL::ShaderGlobals *sg,
737                                 float s, float t, float dsdx, float dtdx,
738                                 float dsdy, float dtdy, float *result)
739 {
740         OSL::TextureSystem *ts = kernel_globals->osl->ts;
741         bool status = ts->texture(filename, options, s, t, dsdx, dtdx, dsdy, dtdy, result);
742
743         if(!status) {
744                 if(options.nchannels == 3 || options.nchannels == 4) {
745                         result[0] = 1.0f;
746                         result[1] = 0.0f;
747                         result[2] = 1.0f;
748
749                         if(options.nchannels == 4)
750                                 result[3] = 1.0f;
751                 }
752         }
753
754         return status;
755 }
756
757 bool OSLRenderServices::texture3d(ustring filename, TextureOpt &options,
758                                   OSL::ShaderGlobals *sg, const OSL::Vec3 &P,
759                                   const OSL::Vec3 &dPdx, const OSL::Vec3 &dPdy,
760                                   const OSL::Vec3 &dPdz, float *result)
761 {
762         OSL::TextureSystem *ts = kernel_globals->osl->ts;
763         bool status = ts->texture3d(filename, options, P, dPdx, dPdy, dPdz, result);
764
765         if(!status) {
766                 if(options.nchannels == 3 || options.nchannels == 4) {
767                         result[0] = 1.0f;
768                         result[1] = 0.0f;
769                         result[2] = 1.0f;
770
771                         if(options.nchannels == 4)
772                                 result[3] = 1.0f;
773                 }
774
775         }
776
777         return status;
778 }
779
780 bool OSLRenderServices::environment(ustring filename, TextureOpt &options,
781                                     OSL::ShaderGlobals *sg, const OSL::Vec3 &R,
782                                     const OSL::Vec3 &dRdx, const OSL::Vec3 &dRdy, float *result)
783 {
784         OSL::TextureSystem *ts = kernel_globals->osl->ts;
785         bool status = ts->environment(filename, options, R, dRdx, dRdy, result);
786
787         if(!status) {
788                 if(options.nchannels == 3 || options.nchannels == 4) {
789                         result[0] = 1.0f;
790                         result[1] = 0.0f;
791                         result[2] = 1.0f;
792
793                         if(options.nchannels == 4)
794                                 result[3] = 1.0f;
795                 }
796         }
797
798         return status;
799 }
800
801 bool OSLRenderServices::get_texture_info(ustring filename, int subimage,
802                                          ustring dataname,
803                                          TypeDesc datatype, void *data)
804 {
805         OSL::TextureSystem *ts = kernel_globals->osl->ts;
806         return ts->get_texture_info(filename, subimage, dataname, datatype, data);
807 }
808
809 int OSLRenderServices::pointcloud_search(OSL::ShaderGlobals *sg, ustring filename, const OSL::Vec3 &center,
810                                          float radius, int max_points, bool sort,
811                                          size_t *out_indices, float *out_distances, int derivs_offset)
812 {
813         return 0;
814 }
815
816 int OSLRenderServices::pointcloud_get(ustring filename, size_t *indices, int count,
817                                       ustring attr_name, TypeDesc attr_type, void *out_data)
818 {
819         return 0;
820 }
821
822 bool OSLRenderServices::trace(TraceOpt &options, OSL::ShaderGlobals *sg,
823         const OSL::Vec3 &P, const OSL::Vec3 &dPdx,
824         const OSL::Vec3 &dPdy, const OSL::Vec3 &R,
825         const OSL::Vec3 &dRdx, const OSL::Vec3 &dRdy)
826 {
827         /* todo: options.shader support, maybe options.traceset */
828         ShaderData *sd = (ShaderData *)(sg->renderstate);
829
830         /* setup ray */
831         Ray ray;
832
833         ray.P = TO_FLOAT3(P);
834         ray.D = TO_FLOAT3(R);
835         ray.t = (options.maxdist == 1.0e30)? FLT_MAX: options.maxdist - options.mindist;
836         ray.time = sd->time;
837
838         if(options.mindist == 0.0f) {
839                 /* avoid self-intersections */
840                 if(ray.P == sd->P) {
841                         bool transmit = (dot(sd->Ng, ray.D) < 0.0f);
842                         ray.P = ray_offset(sd->P, (transmit)? -sd->Ng: sd->Ng);
843                 }
844         }
845         else {
846                 /* offset for minimum distance */
847                 ray.P += options.mindist*ray.D;
848         }
849
850         /* ray differentials */
851         ray.dP.dx = TO_FLOAT3(dPdx);
852         ray.dP.dy = TO_FLOAT3(dPdy);
853         ray.dD.dx = TO_FLOAT3(dRdx);
854         ray.dD.dy = TO_FLOAT3(dRdy);
855
856         /* allocate trace data */
857         OSLTraceData *tracedata = (OSLTraceData*)sg->tracedata;
858         tracedata->ray = ray;
859         tracedata->setup = false;
860         tracedata->init = true;
861
862         /* raytrace */
863         return scene_intersect(kernel_globals, &ray, ~0, &tracedata->isect);
864 }
865
866
867 bool OSLRenderServices::getmessage(OSL::ShaderGlobals *sg, ustring source, ustring name,
868         TypeDesc type, void *val, bool derivatives)
869 {
870         OSLTraceData *tracedata = (OSLTraceData*)sg->tracedata;
871
872         if(source == u_trace && tracedata->init) {
873                 if(name == u_hit) {
874                         return set_attribute_int((tracedata->isect.prim != ~0), type, derivatives, val);
875                 }
876                 else if(tracedata->isect.prim != ~0) {
877                         if(name == u_hitdist) {
878                                 float f[3] = {tracedata->isect.t, 0.0f, 0.0f};
879                                 return set_attribute_float(f, type, derivatives, val);
880                         }
881                         else {
882                                 KernelGlobals *kg = kernel_globals;
883                                 ShaderData *sd = &tracedata->sd;
884
885                                 if(!tracedata->setup) {
886                                         /* lazy shader data setup */
887                                         shader_setup_from_ray(kg, sd, &tracedata->isect, &tracedata->ray);
888                                         tracedata->setup = true;
889                                 }
890
891                                 if(name == u_N) {
892                                         return set_attribute_float3(sd->N, type, derivatives, val);
893                                 }
894                                 else if(name == u_Ng) {
895                                         return set_attribute_float3(sd->Ng, type, derivatives, val);
896                                 }
897                                 else if(name == u_P) {
898                                         float3 f[3] = {sd->P, sd->dP.dx, sd->dP.dy};
899                                         return set_attribute_float3(f, type, derivatives, val);
900                                 }
901                                 else if(name == u_I) {
902                                         float3 f[3] = {sd->I, sd->dI.dx, sd->dI.dy};
903                                         return set_attribute_float3(f, type, derivatives, val);
904                                 }
905                                 else if(name == u_u) {
906                                         float f[3] = {sd->u, sd->du.dx, sd->du.dy};
907                                         return set_attribute_float(f, type, derivatives, val);
908                                 }
909                                 else if(name == u_v) {
910                                         float f[3] = {sd->v, sd->dv.dx, sd->dv.dy};
911                                         return set_attribute_float(f, type, derivatives, val);
912                                 }
913
914                                 return get_attribute(sd, derivatives, u_empty, type, name, val);
915                         }
916                 }
917         }
918
919         return false;
920 }
921
922 CCL_NAMESPACE_END