Cycles: add Transparent Depth output to Light Path node.
[blender-staging.git] / intern / cycles / kernel / osl / osl_services.cpp
1 /*
2  * Copyright 2011-2013 Blender Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License
15  */
16
17 #include <string.h>
18
19 #include "mesh.h"
20 #include "object.h"
21 #include "scene.h"
22
23 #include "osl_closures.h"
24 #include "osl_globals.h"
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_random.h"
34 #include "kernel_projection.h"
35 #include "kernel_differential.h"
36 #include "kernel_montecarlo.h"
37 #include "kernel_camera.h"
38
39 #include "geom/geom.h"
40
41 #include "kernel_projection.h"
42 #include "kernel_accumulate.h"
43 #include "kernel_shader.h"
44
45 #ifdef WITH_PTEX
46 #include <Ptexture.h>
47 #endif
48
49 CCL_NAMESPACE_BEGIN
50
51 /* RenderServices implementation */
52
53 #define COPY_MATRIX44(m1, m2) memcpy(m1, m2, sizeof(*m2))
54
55 /* static ustrings */
56 ustring OSLRenderServices::u_distance("distance");
57 ustring OSLRenderServices::u_index("index");
58 ustring OSLRenderServices::u_camera("camera");
59 ustring OSLRenderServices::u_screen("screen");
60 ustring OSLRenderServices::u_raster("raster");
61 ustring OSLRenderServices::u_ndc("NDC");
62 ustring OSLRenderServices::u_object_location("object:location");
63 ustring OSLRenderServices::u_object_index("object:index");
64 ustring OSLRenderServices::u_geom_dupli_generated("geom:dupli_generated");
65 ustring OSLRenderServices::u_geom_dupli_uv("geom:dupli_uv");
66 ustring OSLRenderServices::u_material_index("material:index");
67 ustring OSLRenderServices::u_object_random("object:random");
68 ustring OSLRenderServices::u_particle_index("particle:index");
69 ustring OSLRenderServices::u_particle_age("particle:age");
70 ustring OSLRenderServices::u_particle_lifetime("particle:lifetime");
71 ustring OSLRenderServices::u_particle_location("particle:location");
72 ustring OSLRenderServices::u_particle_rotation("particle:rotation");
73 ustring OSLRenderServices::u_particle_size("particle:size");
74 ustring OSLRenderServices::u_particle_velocity("particle:velocity");
75 ustring OSLRenderServices::u_particle_angular_velocity("particle:angular_velocity");
76 ustring OSLRenderServices::u_geom_numpolyvertices("geom:numpolyvertices");
77 ustring OSLRenderServices::u_geom_trianglevertices("geom:trianglevertices");
78 ustring OSLRenderServices::u_geom_polyvertices("geom:polyvertices");
79 ustring OSLRenderServices::u_geom_name("geom:name");
80 ustring OSLRenderServices::u_is_smooth("geom:is_smooth");
81 #ifdef __HAIR__
82 ustring OSLRenderServices::u_is_curve("geom:is_curve");
83 ustring OSLRenderServices::u_curve_thickness("geom:curve_thickness");
84 ustring OSLRenderServices::u_curve_tangent_normal("geom:curve_tangent_normal");
85 #endif
86 ustring OSLRenderServices::u_path_ray_length("path:ray_length");
87 ustring OSLRenderServices::u_path_ray_depth("path:ray_depth");
88 ustring OSLRenderServices::u_path_transparent_depth("path:transparent_depth");
89 ustring OSLRenderServices::u_trace("trace");
90 ustring OSLRenderServices::u_hit("hit");
91 ustring OSLRenderServices::u_hitdist("hitdist");
92 ustring OSLRenderServices::u_N("N");
93 ustring OSLRenderServices::u_Ng("Ng");
94 ustring OSLRenderServices::u_P("P");
95 ustring OSLRenderServices::u_I("I");
96 ustring OSLRenderServices::u_u("u");
97 ustring OSLRenderServices::u_v("v");
98 ustring OSLRenderServices::u_empty;
99
100 OSLRenderServices::OSLRenderServices()
101 {
102         kernel_globals = NULL;
103         osl_ts = NULL;
104
105 #ifdef WITH_PTEX
106         size_t maxmem = 16384 * 1024;
107         ptex_cache = PtexCache::create(0, maxmem);
108 #endif
109 }
110
111 OSLRenderServices::~OSLRenderServices()
112 {
113 #ifdef WITH_PTEX
114         ptex_cache->release();
115 #endif
116 }
117
118 void OSLRenderServices::thread_init(KernelGlobals *kernel_globals_, OSL::TextureSystem *osl_ts_)
119 {
120         kernel_globals = kernel_globals_;
121         osl_ts = osl_ts_;
122 }
123
124 bool OSLRenderServices::get_matrix(OSL::Matrix44 &result, OSL::TransformationPtr xform, float time)
125 {
126         /* this is only used for shader and object space, we don't really have
127          * a concept of shader space, so we just use object space for both. */
128         if (xform) {
129                 const ShaderData *sd = (const ShaderData *)xform;
130                 KernelGlobals *kg = sd->osl_globals;
131                 int object = sd->object;
132
133                 if (object != OBJECT_NONE) {
134 #ifdef __OBJECT_MOTION__
135                         Transform tfm;
136
137                         if(time == sd->time)
138                                 tfm = sd->ob_tfm;
139                         else
140                                 tfm = object_fetch_transform_motion_test(kg, object, time, NULL);
141 #else
142                         Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
143 #endif
144                         tfm = transform_transpose(tfm);
145                         COPY_MATRIX44(&result, &tfm);
146
147                         return true;
148                 }
149         }
150
151         return false;
152 }
153
154 bool OSLRenderServices::get_inverse_matrix(OSL::Matrix44 &result, OSL::TransformationPtr xform, float time)
155 {
156         /* this is only used for shader and object space, we don't really have
157          * a concept of shader space, so we just use object space for both. */
158         if (xform) {
159                 const ShaderData *sd = (const ShaderData *)xform;
160                 KernelGlobals *kg = sd->osl_globals;
161                 int object = sd->object;
162
163                 if (object != OBJECT_NONE) {
164 #ifdef __OBJECT_MOTION__
165                         Transform itfm;
166
167                         if(time == sd->time)
168                                 itfm = sd->ob_itfm;
169                         else
170                                 object_fetch_transform_motion_test(kg, object, time, &itfm);
171 #else
172                         Transform itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
173 #endif
174                         itfm = transform_transpose(itfm);
175                         COPY_MATRIX44(&result, &itfm);
176
177                         return true;
178                 }
179         }
180
181         return false;
182 }
183
184 bool OSLRenderServices::get_matrix(OSL::Matrix44 &result, ustring from, float time)
185 {
186         KernelGlobals *kg = kernel_globals;
187
188         if (from == u_ndc) {
189                 Transform tfm = transform_transpose(transform_quick_inverse(kernel_data.cam.worldtondc));
190                 COPY_MATRIX44(&result, &tfm);
191                 return true;
192         }
193         else if (from == u_raster) {
194                 Transform tfm = transform_transpose(kernel_data.cam.rastertoworld);
195                 COPY_MATRIX44(&result, &tfm);
196                 return true;
197         }
198         else if (from == u_screen) {
199                 Transform tfm = transform_transpose(kernel_data.cam.screentoworld);
200                 COPY_MATRIX44(&result, &tfm);
201                 return true;
202         }
203         else if (from == u_camera) {
204                 Transform tfm = transform_transpose(kernel_data.cam.cameratoworld);
205                 COPY_MATRIX44(&result, &tfm);
206                 return true;
207         }
208
209         return false;
210 }
211
212 bool OSLRenderServices::get_inverse_matrix(OSL::Matrix44 &result, ustring to, float time)
213 {
214         KernelGlobals *kg = kernel_globals;
215
216         if (to == u_ndc) {
217                 Transform tfm = transform_transpose(kernel_data.cam.worldtondc);
218                 COPY_MATRIX44(&result, &tfm);
219                 return true;
220         }
221         else if (to == u_raster) {
222                 Transform tfm = transform_transpose(kernel_data.cam.worldtoraster);
223                 COPY_MATRIX44(&result, &tfm);
224                 return true;
225         }
226         else if (to == u_screen) {
227                 Transform tfm = transform_transpose(kernel_data.cam.worldtoscreen);
228                 COPY_MATRIX44(&result, &tfm);
229                 return true;
230         }
231         else if (to == u_camera) {
232                 Transform tfm = transform_transpose(kernel_data.cam.worldtocamera);
233                 COPY_MATRIX44(&result, &tfm);
234                 return true;
235         }
236
237         return false;
238 }
239
240 bool OSLRenderServices::get_matrix(OSL::Matrix44 &result, OSL::TransformationPtr xform)
241 {
242         /* this is only used for shader and object space, we don't really have
243          * a concept of shader space, so we just use object space for both. */
244         if (xform) {
245                 const ShaderData *sd = (const ShaderData *)xform;
246                 int object = sd->object;
247
248                 if (object != OBJECT_NONE) {
249 #ifdef __OBJECT_MOTION__
250                         Transform tfm = sd->ob_tfm;
251 #else
252                         KernelGlobals *kg = sd->osl_globals;
253                         Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
254 #endif
255                         tfm = transform_transpose(tfm);
256                         COPY_MATRIX44(&result, &tfm);
257
258                         return true;
259                 }
260         }
261
262         return false;
263 }
264
265 bool OSLRenderServices::get_inverse_matrix(OSL::Matrix44 &result, OSL::TransformationPtr xform)
266 {
267         /* this is only used for shader and object space, we don't really have
268          * a concept of shader space, so we just use object space for both. */
269         if (xform) {
270                 const ShaderData *sd = (const ShaderData *)xform;
271                 int object = sd->object;
272
273                 if (object != OBJECT_NONE) {
274 #ifdef __OBJECT_MOTION__
275                         Transform tfm = sd->ob_itfm;
276 #else
277                         KernelGlobals *kg = sd->osl_globals;
278                         Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
279 #endif
280                         tfm = transform_transpose(tfm);
281                         COPY_MATRIX44(&result, &tfm);
282
283                         return true;
284                 }
285         }
286
287         return false;
288 }
289
290 bool OSLRenderServices::get_matrix(OSL::Matrix44 &result, ustring from)
291 {
292         KernelGlobals *kg = kernel_globals;
293
294         if (from == u_ndc) {
295                 Transform tfm = transform_transpose(transform_quick_inverse(kernel_data.cam.worldtondc));
296                 COPY_MATRIX44(&result, &tfm);
297                 return true;
298         }
299         else if (from == u_raster) {
300                 Transform tfm = transform_transpose(kernel_data.cam.rastertoworld);
301                 COPY_MATRIX44(&result, &tfm);
302                 return true;
303         }
304         else if (from == u_screen) {
305                 Transform tfm = transform_transpose(kernel_data.cam.screentoworld);
306                 COPY_MATRIX44(&result, &tfm);
307                 return true;
308         }
309         else if (from == u_camera) {
310                 Transform tfm = transform_transpose(kernel_data.cam.cameratoworld);
311                 COPY_MATRIX44(&result, &tfm);
312                 return true;
313         }
314
315         return false;
316 }
317
318 bool OSLRenderServices::get_inverse_matrix(OSL::Matrix44 &result, ustring to)
319 {
320         KernelGlobals *kg = kernel_globals;
321         
322         if (to == u_ndc) {
323                 Transform tfm = transform_transpose(kernel_data.cam.worldtondc);
324                 COPY_MATRIX44(&result, &tfm);
325                 return true;
326         }
327         else if (to == u_raster) {
328                 Transform tfm = transform_transpose(kernel_data.cam.worldtoraster);
329                 COPY_MATRIX44(&result, &tfm);
330                 return true;
331         }
332         else if (to == u_screen) {
333                 Transform tfm = transform_transpose(kernel_data.cam.worldtoscreen);
334                 COPY_MATRIX44(&result, &tfm);
335                 return true;
336         }
337         else if (to == u_camera) {
338                 Transform tfm = transform_transpose(kernel_data.cam.worldtocamera);
339                 COPY_MATRIX44(&result, &tfm);
340                 return true;
341         }
342         
343         return false;
344 }
345
346 bool OSLRenderServices::get_array_attribute(void *renderstate, bool derivatives, 
347                                             ustring object, TypeDesc type, ustring name,
348                                             int index, void *val)
349 {
350         return false;
351 }
352
353 static bool set_attribute_float3(float3 f[3], TypeDesc type, bool derivatives, void *val)
354 {
355         if (type == TypeDesc::TypePoint || type == TypeDesc::TypeVector ||
356             type == TypeDesc::TypeNormal || type == TypeDesc::TypeColor)
357         {
358                 float *fval = (float *)val;
359
360                 fval[0] = f[0].x;
361                 fval[1] = f[0].y;
362                 fval[2] = f[0].z;
363
364                 if (derivatives) {
365                         fval[3] = f[1].x;
366                         fval[4] = f[1].y;
367                         fval[5] = f[1].z;
368
369                         fval[6] = f[2].x;
370                         fval[7] = f[2].y;
371                         fval[8] = f[2].z;
372                 }
373
374                 return true;
375         }
376         else if(type == TypeDesc::TypeFloat) {
377                 float *fval = (float *)val;
378                 fval[0] = average(f[0]);
379
380                 if (derivatives) {
381                         fval[1] = average(f[1]);
382                         fval[2] = average(f[2]);
383                 }
384
385                 return true;
386         }
387
388         return false;
389 }
390
391 static bool set_attribute_float3(float3 f, TypeDesc type, bool derivatives, void *val)
392 {
393         float3 fv[3];
394
395         fv[0] = f;
396         fv[1] = make_float3(0.0f, 0.0f, 0.0f);
397         fv[2] = make_float3(0.0f, 0.0f, 0.0f);
398
399         return set_attribute_float3(fv, type, derivatives, val);
400 }
401
402 static bool set_attribute_float(float f[3], TypeDesc type, bool derivatives, void *val)
403 {
404         if (type == TypeDesc::TypePoint || type == TypeDesc::TypeVector ||
405             type == TypeDesc::TypeNormal || type == TypeDesc::TypeColor)
406         {
407                 float *fval = (float *)val;
408                 fval[0] = f[0];
409                 fval[1] = f[1];
410                 fval[2] = f[2];
411
412                 if (derivatives) {
413                         fval[3] = f[1];
414                         fval[4] = f[1];
415                         fval[5] = f[1];
416
417                         fval[6] = f[2];
418                         fval[7] = f[2];
419                         fval[8] = f[2];
420                 }
421
422                 return true;
423         }
424         else if(type == TypeDesc::TypeFloat) {
425                 float *fval = (float *)val;
426                 fval[0] = f[0];
427
428                 if (derivatives) {
429                         fval[1] = f[1];
430                         fval[2] = f[2];
431                 }
432
433                 return true;
434         }
435
436         return false;
437 }
438
439 static bool set_attribute_float(float f, TypeDesc type, bool derivatives, void *val)
440 {
441         float fv[3];
442
443         fv[0] = f;
444         fv[1] = 0.0f;
445         fv[2] = 0.0f;
446
447         return set_attribute_float(fv, type, derivatives, val);
448 }
449
450 static bool set_attribute_int(int i, TypeDesc type, bool derivatives, void *val)
451 {
452         if(type.basetype == TypeDesc::INT && type.aggregate == TypeDesc::SCALAR && type.arraylen == 0) {
453                 int *ival = (int *)val;
454                 ival[0] = i;
455
456                 if (derivatives) {
457                         ival[1] = 0;
458                         ival[2] = 0;
459                 }
460
461                 return true;
462         }
463
464         return false;
465 }
466
467 static bool set_attribute_string(ustring str, TypeDesc type, bool derivatives, void *val)
468 {
469         if(type.basetype == TypeDesc::INT && type.aggregate == TypeDesc::SCALAR && type.arraylen == 0) {
470                 ustring *sval = (ustring *)val;
471                 sval[0] = str;
472
473                 if (derivatives) {
474                         sval[1] = OSLRenderServices::u_empty;
475                         sval[2] = OSLRenderServices::u_empty;
476                 }
477
478                 return true;
479         }
480
481         return false;
482 }
483
484 static bool set_attribute_float3_3(float3 P[3], TypeDesc type, bool derivatives, void *val)
485 {
486         if(type.vecsemantics == TypeDesc::POINT && type.arraylen >= 3) {
487                 float *fval = (float *)val;
488
489                 fval[0] = P[0].x;
490                 fval[1] = P[0].y;
491                 fval[2] = P[0].z;
492
493                 fval[3] = P[1].x;
494                 fval[4] = P[1].y;
495                 fval[5] = P[1].z;
496
497                 fval[6] = P[2].x;
498                 fval[7] = P[2].y;
499                 fval[8] = P[2].z;
500
501                 if(type.arraylen > 3)
502                         memset(fval + 3*3, 0, sizeof(float)*3*(type.arraylen - 3));
503                 if (derivatives)
504                         memset(fval + type.arraylen*3, 0, sizeof(float)*2*3*type.arraylen);
505
506                 return true;
507         }
508
509         return false;
510 }
511
512 static bool set_attribute_matrix(const Transform& tfm, TypeDesc type, void *val)
513 {
514         if(type == TypeDesc::TypeMatrix) {
515                 Transform transpose = transform_transpose(tfm);
516                 memcpy(val, &transpose, sizeof(Transform));
517                 return true;
518         }
519
520         return false;
521 }
522
523 static bool get_mesh_element_attribute(KernelGlobals *kg, const ShaderData *sd, const OSLGlobals::Attribute& attr,
524                                const TypeDesc& type, bool derivatives, void *val)
525 {
526         if (attr.type == TypeDesc::TypePoint || attr.type == TypeDesc::TypeVector ||
527             attr.type == TypeDesc::TypeNormal || attr.type == TypeDesc::TypeColor) {
528                 float3 fval[3];
529                 fval[0] = primitive_attribute_float3(kg, sd, attr.elem, attr.offset,
530                                                      (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
531                 return set_attribute_float3(fval, type, derivatives, val);
532         }
533         else if (attr.type == TypeDesc::TypeFloat) {
534                 float fval[3];
535                 fval[0] = primitive_attribute_float(kg, sd, attr.elem, attr.offset,
536                                                     (derivatives) ? &fval[1] : NULL, (derivatives) ? &fval[2] : NULL);
537                 return set_attribute_float(fval, type, derivatives, val);
538         }
539         else {
540                 return false;
541         }
542 }
543
544 static bool get_mesh_attribute(KernelGlobals *kg, const ShaderData *sd, const OSLGlobals::Attribute& attr,
545                                const TypeDesc& type, bool derivatives, void *val)
546 {
547         if (attr.type == TypeDesc::TypeMatrix) {
548                 Transform tfm = primitive_attribute_matrix(kg, sd, attr.offset);
549                 return set_attribute_matrix(tfm, type, val);
550         }
551         else {
552                 return false;
553         }
554 }
555
556 static void get_object_attribute(const OSLGlobals::Attribute& attr, bool derivatives, void *val)
557 {
558         size_t datasize = attr.value.datasize();
559
560         memcpy(val, attr.value.data(), datasize);
561         if (derivatives)
562                 memset((char *)val + datasize, 0, datasize * 2);
563 }
564
565 bool OSLRenderServices::get_object_standard_attribute(KernelGlobals *kg, ShaderData *sd, ustring name,
566                                                       TypeDesc type, bool derivatives, void *val)
567 {
568         /* todo: turn this into hash table? */
569
570         /* Object Attributes */
571         if (name == u_object_location) {
572                 float3 f = object_location(kg, sd);
573                 return set_attribute_float3(f, type, derivatives, val);
574         }
575         else if (name == u_object_index) {
576                 float f = object_pass_id(kg, sd->object);
577                 return set_attribute_float(f, type, derivatives, val);
578         }
579         else if (name == u_geom_dupli_generated) {
580                 float3 f = object_dupli_generated(kg, sd->object);
581                 return set_attribute_float3(f, type, derivatives, val);
582         }
583         else if (name == u_geom_dupli_uv) {
584                 float3 f = object_dupli_uv(kg, sd->object);
585                 return set_attribute_float3(f, type, derivatives, val);
586         }
587         else if (name == u_material_index) {
588                 float f = shader_pass_id(kg, sd);
589                 return set_attribute_float(f, type, derivatives, val);
590         }
591         else if (name == u_object_random) {
592                 float f = object_random_number(kg, sd->object);
593                 return set_attribute_float(f, type, derivatives, val);
594         }
595
596         /* Particle Attributes */
597         else if (name == u_particle_index) {
598                 uint particle_id = object_particle_id(kg, sd->object);
599                 float f = particle_index(kg, particle_id);
600                 return set_attribute_float(f, type, derivatives, val);
601         }
602         else if (name == u_particle_age) {
603                 uint particle_id = object_particle_id(kg, sd->object);
604                 float f = particle_age(kg, particle_id);
605                 return set_attribute_float(f, type, derivatives, val);
606         }
607         else if (name == u_particle_lifetime) {
608                 uint particle_id = object_particle_id(kg, sd->object);
609                 float f= particle_lifetime(kg, particle_id);
610                 return set_attribute_float(f, type, derivatives, val);
611         }
612         else if (name == u_particle_location) {
613                 uint particle_id = object_particle_id(kg, sd->object);
614                 float3 f = particle_location(kg, particle_id);
615                 return set_attribute_float3(f, type, derivatives, val);
616         }
617 #if 0   /* unsupported */
618         else if (name == u_particle_rotation) {
619                 uint particle_id = object_particle_id(kg, sd->object);
620                 float4 f = particle_rotation(kg, particle_id);
621                 return set_attribute_float4(f, type, derivatives, val);
622         }
623 #endif
624         else if (name == u_particle_size) {
625                 uint particle_id = object_particle_id(kg, sd->object);
626                 float f = particle_size(kg, particle_id);
627                 return set_attribute_float(f, type, derivatives, val);
628         }
629         else if (name == u_particle_velocity) {
630                 uint particle_id = object_particle_id(kg, sd->object);
631                 float3 f = particle_velocity(kg, particle_id);
632                 return set_attribute_float3(f, type, derivatives, val);
633         }
634         else if (name == u_particle_angular_velocity) {
635                 uint particle_id = object_particle_id(kg, sd->object);
636                 float3 f = particle_angular_velocity(kg, particle_id);
637                 return set_attribute_float3(f, type, derivatives, val);
638         }
639         
640         /* Geometry Attributes */
641         else if (name == u_geom_numpolyvertices) {
642                 return set_attribute_int(3, type, derivatives, val);
643         }
644         else if ((name == u_geom_trianglevertices || name == u_geom_polyvertices)
645 #ifdef __HAIR__
646                      && sd->type & PRIMITIVE_ALL_TRIANGLE) {
647 #else
648                 ) {
649 #endif
650                 float3 P[3];
651
652                 if(sd->type & PRIMITIVE_TRIANGLE)
653                         triangle_vertices(kg, sd->prim, P);
654                 else
655                         motion_triangle_vertices(kg, sd->object, sd->prim, sd->time, P);
656
657                 if(!(sd->flag & SD_TRANSFORM_APPLIED)) {
658                         object_position_transform(kg, sd, &P[0]);
659                         object_position_transform(kg, sd, &P[1]);
660                         object_position_transform(kg, sd, &P[2]);
661                 }
662
663                 return set_attribute_float3_3(P, type, derivatives, val);
664         }
665         else if(name == u_geom_name) {
666                 ustring object_name = kg->osl->object_names[sd->object];
667                 return set_attribute_string(object_name, type, derivatives, val);
668         }
669         else if (name == u_is_smooth) {
670                 float f = ((sd->shader & SHADER_SMOOTH_NORMAL) != 0);
671                 return set_attribute_float(f, type, derivatives, val);
672         }
673 #ifdef __HAIR__
674         /* Hair Attributes */
675         else if (name == u_is_curve) {
676                 float f = (sd->type & PRIMITIVE_ALL_CURVE) != 0;
677                 return set_attribute_float(f, type, derivatives, val);
678         }
679         else if (name == u_curve_thickness) {
680                 float f = curve_thickness(kg, sd);
681                 return set_attribute_float(f, type, derivatives, val);
682         }
683         else if (name == u_curve_tangent_normal) {
684                 float3 f = curve_tangent_normal(kg, sd);
685                 return set_attribute_float3(f, type, derivatives, val);
686         }
687 #endif
688         else
689                 return false;
690 }
691
692 bool OSLRenderServices::get_background_attribute(KernelGlobals *kg, ShaderData *sd, ustring name,
693                                                  TypeDesc type, bool derivatives, void *val)
694 {
695         if (name == u_path_ray_length) {
696                 /* Ray Length */
697                 float f = sd->ray_length;
698                 return set_attribute_float(f, type, derivatives, val);
699         }
700         else if (name == u_path_ray_depth) {
701                 /* Ray Depth */
702                 int f = sd->ray_depth;
703                 return set_attribute_int(f, type, derivatives, val);
704         }
705         else if (name == u_path_transparent_depth) {
706                 /* Ray Depth */
707                 int f = sd->transparent_depth;
708                 return set_attribute_int(f, type, derivatives, val);
709         }
710         else if (name == u_ndc) {
711                 /* NDC coordinates with special exception for otho */
712                 OSLThreadData *tdata = kg->osl_tdata;
713                 OSL::ShaderGlobals *globals = &tdata->globals;
714                 float3 ndc[3];
715
716                 if((globals->raytype & PATH_RAY_CAMERA) && sd->object == OBJECT_NONE && kernel_data.cam.type == CAMERA_ORTHOGRAPHIC) {
717                         ndc[0] = camera_world_to_ndc(kg, sd, sd->ray_P);
718
719                         if(derivatives) {
720                                 ndc[1] = camera_world_to_ndc(kg, sd, sd->ray_P + sd->ray_dP.dx) - ndc[0];
721                                 ndc[2] = camera_world_to_ndc(kg, sd, sd->ray_P + sd->ray_dP.dy) - ndc[0];
722                         }
723                 }
724                 else {
725                         ndc[0] = camera_world_to_ndc(kg, sd, sd->P);
726
727                         if(derivatives) {
728                                 ndc[1] = camera_world_to_ndc(kg, sd, sd->P + sd->dP.dx) - ndc[0];
729                                 ndc[2] = camera_world_to_ndc(kg, sd, sd->P + sd->dP.dy) - ndc[0];
730                         }
731                 }
732
733                 return set_attribute_float3(ndc, type, derivatives, val);
734         }
735         else
736                 return false;
737 }
738
739 bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustring object_name,
740                                       TypeDesc type, ustring name, void *val)
741 {
742         ShaderData *sd = (ShaderData *)renderstate;
743         KernelGlobals *kg = sd->osl_globals;
744         bool is_curve;
745         int object, prim;
746
747         /* lookup of attribute on another object */
748         if (object_name != u_empty) {
749                 OSLGlobals::ObjectNameMap::iterator it = kg->osl->object_name_map.find(object_name);
750
751                 if (it == kg->osl->object_name_map.end())
752                         return false;
753
754                 object = it->second;
755                 prim = PRIM_NONE;
756                 is_curve = false;
757         }
758         else {
759                 object = sd->object;
760                 prim = sd->prim;
761                 is_curve = (sd->type & PRIMITIVE_ALL_CURVE) != 0;
762
763                 if (object == OBJECT_NONE)
764                         return get_background_attribute(kg, sd, name, type, derivatives, val);
765         }
766
767         /* find attribute on object */
768         object = object*ATTR_PRIM_TYPES + (is_curve == true);
769         OSLGlobals::AttributeMap& attribute_map = kg->osl->attribute_map[object];
770         OSLGlobals::AttributeMap::iterator it = attribute_map.find(name);
771
772         if (it != attribute_map.end()) {
773                 const OSLGlobals::Attribute& attr = it->second;
774
775                 if (attr.elem != ATTR_ELEMENT_OBJECT) {
776                         /* triangle and vertex attributes */
777                         if(!get_mesh_element_attribute(kg, sd, attr, type, derivatives, val))
778                                 return get_mesh_attribute(kg, sd, attr, type, derivatives, val);
779                 }
780                 else {
781                         /* object attribute */
782                         get_object_attribute(attr, derivatives, val);
783                         return true;
784                 }
785         }
786         else {
787                 /* not found in attribute, check standard object info */
788                 bool is_std_object_attribute = get_object_standard_attribute(kg, sd, name, type, derivatives, val);
789
790                 if (is_std_object_attribute)
791                         return true;
792
793                 return get_background_attribute(kg, sd, name, type, derivatives, val);
794         }
795
796         return false;
797 }
798
799 bool OSLRenderServices::get_userdata(bool derivatives, ustring name, TypeDesc type, 
800                                      void *renderstate, void *val)
801 {
802         return false; /* disabled by lockgeom */
803 }
804
805 bool OSLRenderServices::has_userdata(ustring name, TypeDesc type, void *renderstate)
806 {
807         return false; /* never called by OSL */
808 }
809
810 bool OSLRenderServices::texture(ustring filename, TextureOpt &options,
811                                 OSL::ShaderGlobals *sg,
812                                 float s, float t, float dsdx, float dtdx,
813                                 float dsdy, float dtdy, float *result)
814 {
815         OSL::TextureSystem *ts = osl_ts;
816         ShaderData *sd = (ShaderData *)(sg->renderstate);
817         KernelGlobals *kg = sd->osl_globals;
818
819 #ifdef WITH_PTEX
820         /* todo: this is just a quick hack, only works with particular files and options */
821         if(string_endswith(filename.string(), ".ptx")) {
822                 float2 uv;
823                 int faceid;
824
825                 if(!primitive_ptex(kg, sd, &uv, &faceid))
826                         return false;
827
828                 float u = uv.x;
829                 float v = uv.y;
830                 float dudx = 0.0f;
831                 float dvdx = 0.0f;
832                 float dudy = 0.0f;
833                 float dvdy = 0.0f;
834
835                 Ptex::String error;
836                 PtexPtr<PtexTexture> r(ptex_cache->get(filename.c_str(), error));
837
838                 if(!r) {
839                         //std::cerr << error.c_str() << std::endl;
840                         return false;
841                 }
842
843                 bool mipmaplerp = false;
844                 float sharpness = 1.0f;
845                 PtexFilter::Options opts(PtexFilter::f_bicubic, mipmaplerp, sharpness);
846                 PtexPtr<PtexFilter> f(PtexFilter::getFilter(r, opts));
847
848                 f->eval(result, options.firstchannel, options.nchannels, faceid, u, v, dudx, dvdx, dudy, dvdy);
849
850                 for(int c = r->numChannels(); c < options.nchannels; c++)
851                         result[c] = result[0];
852
853                 return true;
854         }
855 #endif
856
857         OSLThreadData *tdata = kg->osl_tdata;
858         OIIO::TextureSystem::Perthread *thread_info = tdata->oiio_thread_info;
859
860         OIIO::TextureSystem::TextureHandle *th = ts->get_texture_handle(filename, thread_info);
861
862         bool status = ts->texture(th, thread_info,
863                                   options, s, t, dsdx, dtdx, dsdy, dtdy, result);
864
865         if(!status) {
866                 if(options.nchannels == 3 || options.nchannels == 4) {
867                         result[0] = 1.0f;
868                         result[1] = 0.0f;
869                         result[2] = 1.0f;
870
871                         if(options.nchannels == 4)
872                                 result[3] = 1.0f;
873                 }
874         }
875
876         return status;
877 }
878
879 bool OSLRenderServices::texture3d(ustring filename, TextureOpt &options,
880                                   OSL::ShaderGlobals *sg, const OSL::Vec3 &P,
881                                   const OSL::Vec3 &dPdx, const OSL::Vec3 &dPdy,
882                                   const OSL::Vec3 &dPdz, float *result)
883 {
884         OSL::TextureSystem *ts = osl_ts;
885         ShaderData *sd = (ShaderData *)(sg->renderstate);
886         KernelGlobals *kg = sd->osl_globals;
887         OSLThreadData *tdata = kg->osl_tdata;
888         OIIO::TextureSystem::Perthread *thread_info = tdata->oiio_thread_info;
889
890         OIIO::TextureSystem::TextureHandle *th =  ts->get_texture_handle(filename, thread_info);
891
892         bool status = ts->texture3d(th, thread_info,
893                                     options, P, dPdx, dPdy, dPdz, result);
894
895         if(!status) {
896                 if(options.nchannels == 3 || options.nchannels == 4) {
897                         result[0] = 1.0f;
898                         result[1] = 0.0f;
899                         result[2] = 1.0f;
900
901                         if(options.nchannels == 4)
902                                 result[3] = 1.0f;
903                 }
904
905         }
906
907         return status;
908 }
909
910 bool OSLRenderServices::environment(ustring filename, TextureOpt &options,
911                                     OSL::ShaderGlobals *sg, const OSL::Vec3 &R,
912                                     const OSL::Vec3 &dRdx, const OSL::Vec3 &dRdy, float *result)
913 {
914         OSL::TextureSystem *ts = osl_ts;
915         ShaderData *sd = (ShaderData *)(sg->renderstate);
916         KernelGlobals *kg = sd->osl_globals;
917         OSLThreadData *tdata = kg->osl_tdata;
918         OIIO::TextureSystem::Perthread *thread_info = tdata->oiio_thread_info;
919
920         OIIO::TextureSystem::TextureHandle *th =  ts->get_texture_handle(filename, thread_info);
921         bool status = ts->environment(th, thread_info,
922                                       options, R, dRdx, dRdy, result);
923
924         if(!status) {
925                 if(options.nchannels == 3 || options.nchannels == 4) {
926                         result[0] = 1.0f;
927                         result[1] = 0.0f;
928                         result[2] = 1.0f;
929
930                         if(options.nchannels == 4)
931                                 result[3] = 1.0f;
932                 }
933         }
934
935         return status;
936 }
937
938 bool OSLRenderServices::get_texture_info(ustring filename, int subimage,
939                                          ustring dataname,
940                                          TypeDesc datatype, void *data)
941 {
942         OSL::TextureSystem *ts = osl_ts;
943         return ts->get_texture_info(filename, subimage, dataname, datatype, data);
944 }
945
946 int OSLRenderServices::pointcloud_search(OSL::ShaderGlobals *sg, ustring filename, const OSL::Vec3 &center,
947                                          float radius, int max_points, bool sort,
948                                          size_t *out_indices, float *out_distances, int derivs_offset)
949 {
950         return 0;
951 }
952
953 int OSLRenderServices::pointcloud_get(OSL::ShaderGlobals *sg, ustring filename, size_t *indices, int count,
954                                       ustring attr_name, TypeDesc attr_type, void *out_data)
955 {
956         return 0;
957 }
958
959 bool OSLRenderServices::pointcloud_write(OSL::ShaderGlobals *sg,
960                                          ustring filename, const OSL::Vec3 &pos,
961                                          int nattribs, const ustring *names,
962                                          const TypeDesc *types,
963                                          const void **data)
964 {
965         return false;
966 }
967
968 bool OSLRenderServices::trace(TraceOpt &options, OSL::ShaderGlobals *sg,
969         const OSL::Vec3 &P, const OSL::Vec3 &dPdx,
970         const OSL::Vec3 &dPdy, const OSL::Vec3 &R,
971         const OSL::Vec3 &dRdx, const OSL::Vec3 &dRdy)
972 {
973         /* todo: options.shader support, maybe options.traceset */
974         ShaderData *sd = (ShaderData *)(sg->renderstate);
975
976         /* setup ray */
977         Ray ray;
978
979         ray.P = TO_FLOAT3(P);
980         ray.D = TO_FLOAT3(R);
981         ray.t = (options.maxdist == 1.0e30)? FLT_MAX: options.maxdist - options.mindist;
982         ray.time = sd->time;
983
984         if(options.mindist == 0.0f) {
985                 /* avoid self-intersections */
986                 if(ray.P == sd->P) {
987                         bool transmit = (dot(sd->Ng, ray.D) < 0.0f);
988                         ray.P = ray_offset(sd->P, (transmit)? -sd->Ng: sd->Ng);
989                 }
990         }
991         else {
992                 /* offset for minimum distance */
993                 ray.P += options.mindist*ray.D;
994         }
995
996         /* ray differentials */
997         ray.dP.dx = TO_FLOAT3(dPdx);
998         ray.dP.dy = TO_FLOAT3(dPdy);
999         ray.dD.dx = TO_FLOAT3(dRdx);
1000         ray.dD.dy = TO_FLOAT3(dRdy);
1001
1002         /* allocate trace data */
1003         OSLTraceData *tracedata = (OSLTraceData*)sg->tracedata;
1004         tracedata->ray = ray;
1005         tracedata->setup = false;
1006         tracedata->init = true;
1007         tracedata->sd.osl_globals = sd->osl_globals;
1008
1009         /* raytrace */
1010 #ifdef __HAIR__
1011         return scene_intersect(sd->osl_globals, &ray, PATH_RAY_ALL_VISIBILITY, &tracedata->isect, NULL, 0.0f, 0.0f);
1012 #else
1013         return scene_intersect(sd->osl_globals, &ray, PATH_RAY_ALL_VISIBILITY, &tracedata->isect);
1014 #endif
1015 }
1016
1017
1018 bool OSLRenderServices::getmessage(OSL::ShaderGlobals *sg, ustring source, ustring name,
1019         TypeDesc type, void *val, bool derivatives)
1020 {
1021         OSLTraceData *tracedata = (OSLTraceData*)sg->tracedata;
1022
1023         if(source == u_trace && tracedata->init) {
1024                 if(name == u_hit) {
1025                         return set_attribute_int((tracedata->isect.prim != PRIM_NONE), type, derivatives, val);
1026                 }
1027                 else if(tracedata->isect.prim != PRIM_NONE) {
1028                         if(name == u_hitdist) {
1029                                 float f[3] = {tracedata->isect.t, 0.0f, 0.0f};
1030                                 return set_attribute_float(f, type, derivatives, val);
1031                         }
1032                         else {
1033                                 ShaderData *sd = &tracedata->sd;
1034                                 KernelGlobals *kg = sd->osl_globals;
1035
1036                                 if(!tracedata->setup) {
1037                                         /* lazy shader data setup */
1038                                         ShaderData *original_sd = (ShaderData *)(sg->renderstate);
1039                                         int bounce = original_sd->ray_depth + 1;
1040                                         int transparent_bounce = original_sd->transparent_depth;
1041
1042                                         shader_setup_from_ray(kg, sd, &tracedata->isect, &tracedata->ray, bounce, transparent_bounce);
1043                                         tracedata->setup = true;
1044                                 }
1045
1046                                 if(name == u_N) {
1047                                         return set_attribute_float3(sd->N, type, derivatives, val);
1048                                 }
1049                                 else if(name == u_Ng) {
1050                                         return set_attribute_float3(sd->Ng, type, derivatives, val);
1051                                 }
1052                                 else if(name == u_P) {
1053                                         float3 f[3] = {sd->P, sd->dP.dx, sd->dP.dy};
1054                                         return set_attribute_float3(f, type, derivatives, val);
1055                                 }
1056                                 else if(name == u_I) {
1057                                         float3 f[3] = {sd->I, sd->dI.dx, sd->dI.dy};
1058                                         return set_attribute_float3(f, type, derivatives, val);
1059                                 }
1060                                 else if(name == u_u) {
1061                                         float f[3] = {sd->u, sd->du.dx, sd->du.dy};
1062                                         return set_attribute_float(f, type, derivatives, val);
1063                                 }
1064                                 else if(name == u_v) {
1065                                         float f[3] = {sd->v, sd->dv.dx, sd->dv.dy};
1066                                         return set_attribute_float(f, type, derivatives, val);
1067                                 }
1068
1069                                 return get_attribute(sd, derivatives, u_empty, type, name, val);
1070                         }
1071                 }
1072         }
1073
1074         return false;
1075 }
1076
1077 CCL_NAMESPACE_END