Cycles code refactor: replace magic ~0 values in the code with defines.
[blender.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
35 #include "geom/geom_bvh.h"
36
37 #include "kernel_montecarlo.h"
38 #include "kernel_projection.h"
39 #include "kernel_differential.h"
40 #include "kernel_primitive.h"
41 #include "kernel_projection.h"
42 #include "kernel_accumulate.h"
43 #include "kernel_camera.h"
44 #include "kernel_shader.h"
45
46 #ifdef WITH_PTEX
47 #include <Ptexture.h>
48 #endif
49
50 CCL_NAMESPACE_BEGIN
51
52 /* RenderServices implementation */
53
54 #define COPY_MATRIX44(m1, m2) memcpy(m1, m2, sizeof(*m2))
55
56 /* static ustrings */
57 ustring OSLRenderServices::u_distance("distance");
58 ustring OSLRenderServices::u_index("index");
59 ustring OSLRenderServices::u_camera("camera");
60 ustring OSLRenderServices::u_screen("screen");
61 ustring OSLRenderServices::u_raster("raster");
62 ustring OSLRenderServices::u_ndc("NDC");
63 ustring OSLRenderServices::u_object_location("object:location");
64 ustring OSLRenderServices::u_object_index("object:index");
65 ustring OSLRenderServices::u_geom_dupli_generated("geom:dupli_generated");
66 ustring OSLRenderServices::u_geom_dupli_uv("geom:dupli_uv");
67 ustring OSLRenderServices::u_material_index("material:index");
68 ustring OSLRenderServices::u_object_random("object:random");
69 ustring OSLRenderServices::u_particle_index("particle:index");
70 ustring OSLRenderServices::u_particle_age("particle:age");
71 ustring OSLRenderServices::u_particle_lifetime("particle:lifetime");
72 ustring OSLRenderServices::u_particle_location("particle:location");
73 ustring OSLRenderServices::u_particle_rotation("particle:rotation");
74 ustring OSLRenderServices::u_particle_size("particle:size");
75 ustring OSLRenderServices::u_particle_velocity("particle:velocity");
76 ustring OSLRenderServices::u_particle_angular_velocity("particle:angular_velocity");
77 ustring OSLRenderServices::u_geom_numpolyvertices("geom:numpolyvertices");
78 ustring OSLRenderServices::u_geom_trianglevertices("geom:trianglevertices");
79 ustring OSLRenderServices::u_geom_polyvertices("geom:polyvertices");
80 ustring OSLRenderServices::u_geom_name("geom:name");
81 ustring OSLRenderServices::u_is_smooth("geom:is_smooth");
82 #ifdef __HAIR__
83 ustring OSLRenderServices::u_is_curve("geom:is_curve");
84 ustring OSLRenderServices::u_curve_thickness("geom:curve_thickness");
85 ustring OSLRenderServices::u_curve_tangent_normal("geom:curve_tangent_normal");
86 #endif
87 ustring OSLRenderServices::u_path_ray_length("path:ray_length");
88 ustring OSLRenderServices::u_path_ray_depth("path:ray_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_ndc) {
706                 /* NDC coordinates with special exception for otho */
707                 OSLThreadData *tdata = kg->osl_tdata;
708                 OSL::ShaderGlobals *globals = &tdata->globals;
709                 float3 ndc[3];
710
711                 if((globals->raytype & PATH_RAY_CAMERA) && sd->object == OBJECT_NONE && kernel_data.cam.type == CAMERA_ORTHOGRAPHIC) {
712                         ndc[0] = camera_world_to_ndc(kg, sd, sd->ray_P);
713
714                         if(derivatives) {
715                                 ndc[1] = camera_world_to_ndc(kg, sd, sd->ray_P + sd->ray_dP.dx) - ndc[0];
716                                 ndc[2] = camera_world_to_ndc(kg, sd, sd->ray_P + sd->ray_dP.dy) - ndc[0];
717                         }
718                 }
719                 else {
720                         ndc[0] = camera_world_to_ndc(kg, sd, sd->P);
721
722                         if(derivatives) {
723                                 ndc[1] = camera_world_to_ndc(kg, sd, sd->P + sd->dP.dx) - ndc[0];
724                                 ndc[2] = camera_world_to_ndc(kg, sd, sd->P + sd->dP.dy) - ndc[0];
725                         }
726                 }
727
728                 return set_attribute_float3(ndc, type, derivatives, val);
729         }
730         else
731                 return false;
732 }
733
734 bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustring object_name,
735                                       TypeDesc type, ustring name, void *val)
736 {
737         ShaderData *sd = (ShaderData *)renderstate;
738         KernelGlobals *kg = sd->osl_globals;
739         bool is_curve;
740         int object, prim;
741
742         /* lookup of attribute on another object */
743         if (object_name != u_empty) {
744                 OSLGlobals::ObjectNameMap::iterator it = kg->osl->object_name_map.find(object_name);
745
746                 if (it == kg->osl->object_name_map.end())
747                         return false;
748
749                 object = it->second;
750                 prim = PRIM_NONE;
751                 is_curve = false;
752         }
753         else {
754                 object = sd->object;
755                 prim = sd->prim;
756                 is_curve = (sd->type & PRIMITIVE_ALL_CURVE) != 0;
757
758                 if (object == OBJECT_NONE)
759                         return get_background_attribute(kg, sd, name, type, derivatives, val);
760         }
761
762         /* find attribute on object */
763         object = object*ATTR_PRIM_TYPES + (is_curve == true);
764         OSLGlobals::AttributeMap& attribute_map = kg->osl->attribute_map[object];
765         OSLGlobals::AttributeMap::iterator it = attribute_map.find(name);
766
767         if (it != attribute_map.end()) {
768                 const OSLGlobals::Attribute& attr = it->second;
769
770                 if (attr.elem != ATTR_ELEMENT_OBJECT) {
771                         /* triangle and vertex attributes */
772                         if (prim != PRIM_NONE)
773                                 return get_mesh_element_attribute(kg, sd, attr, type, derivatives, val);
774                         else
775                                 return get_mesh_attribute(kg, sd, attr, type, derivatives, val);
776                 }
777                 else {
778                         /* object attribute */
779                         get_object_attribute(attr, derivatives, val);
780                         return true;
781                 }
782         }
783         else {
784                 /* not found in attribute, check standard object info */
785                 bool is_std_object_attribute = get_object_standard_attribute(kg, sd, name, type, derivatives, val);
786
787                 if (is_std_object_attribute)
788                         return true;
789
790                 return get_background_attribute(kg, sd, name, type, derivatives, val);
791         }
792
793         return false;
794 }
795
796 bool OSLRenderServices::get_userdata(bool derivatives, ustring name, TypeDesc type, 
797                                      void *renderstate, void *val)
798 {
799         return false; /* disabled by lockgeom */
800 }
801
802 bool OSLRenderServices::has_userdata(ustring name, TypeDesc type, void *renderstate)
803 {
804         return false; /* never called by OSL */
805 }
806
807 bool OSLRenderServices::texture(ustring filename, TextureOpt &options,
808                                 OSL::ShaderGlobals *sg,
809                                 float s, float t, float dsdx, float dtdx,
810                                 float dsdy, float dtdy, float *result)
811 {
812         OSL::TextureSystem *ts = osl_ts;
813         ShaderData *sd = (ShaderData *)(sg->renderstate);
814         KernelGlobals *kg = sd->osl_globals;
815
816 #ifdef WITH_PTEX
817         /* todo: this is just a quick hack, only works with particular files and options */
818         if(string_endswith(filename.string(), ".ptx")) {
819                 float2 uv;
820                 int faceid;
821
822                 if(!primitive_ptex(kg, sd, &uv, &faceid))
823                         return false;
824
825                 float u = uv.x;
826                 float v = uv.y;
827                 float dudx = 0.0f;
828                 float dvdx = 0.0f;
829                 float dudy = 0.0f;
830                 float dvdy = 0.0f;
831
832                 Ptex::String error;
833                 PtexPtr<PtexTexture> r(ptex_cache->get(filename.c_str(), error));
834
835                 if(!r) {
836                         //std::cerr << error.c_str() << std::endl;
837                         return false;
838                 }
839
840                 bool mipmaplerp = false;
841                 float sharpness = 1.0f;
842                 PtexFilter::Options opts(PtexFilter::f_bicubic, mipmaplerp, sharpness);
843                 PtexPtr<PtexFilter> f(PtexFilter::getFilter(r, opts));
844
845                 f->eval(result, options.firstchannel, options.nchannels, faceid, u, v, dudx, dvdx, dudy, dvdy);
846
847                 for(int c = r->numChannels(); c < options.nchannels; c++)
848                         result[c] = result[0];
849
850                 return true;
851         }
852 #endif
853
854         OSLThreadData *tdata = kg->osl_tdata;
855         OIIO::TextureSystem::Perthread *thread_info = tdata->oiio_thread_info;
856
857         OIIO::TextureSystem::TextureHandle *th = ts->get_texture_handle(filename, thread_info);
858
859         bool status = ts->texture(th, thread_info,
860                                   options, s, t, dsdx, dtdx, dsdy, dtdy, result);
861
862         if(!status) {
863                 if(options.nchannels == 3 || options.nchannels == 4) {
864                         result[0] = 1.0f;
865                         result[1] = 0.0f;
866                         result[2] = 1.0f;
867
868                         if(options.nchannels == 4)
869                                 result[3] = 1.0f;
870                 }
871         }
872
873         return status;
874 }
875
876 bool OSLRenderServices::texture3d(ustring filename, TextureOpt &options,
877                                   OSL::ShaderGlobals *sg, const OSL::Vec3 &P,
878                                   const OSL::Vec3 &dPdx, const OSL::Vec3 &dPdy,
879                                   const OSL::Vec3 &dPdz, float *result)
880 {
881         OSL::TextureSystem *ts = osl_ts;
882         ShaderData *sd = (ShaderData *)(sg->renderstate);
883         KernelGlobals *kg = sd->osl_globals;
884         OSLThreadData *tdata = kg->osl_tdata;
885         OIIO::TextureSystem::Perthread *thread_info = tdata->oiio_thread_info;
886
887         OIIO::TextureSystem::TextureHandle *th =  ts->get_texture_handle(filename, thread_info);
888
889         bool status = ts->texture3d(th, thread_info,
890                                     options, P, dPdx, dPdy, dPdz, result);
891
892         if(!status) {
893                 if(options.nchannels == 3 || options.nchannels == 4) {
894                         result[0] = 1.0f;
895                         result[1] = 0.0f;
896                         result[2] = 1.0f;
897
898                         if(options.nchannels == 4)
899                                 result[3] = 1.0f;
900                 }
901
902         }
903
904         return status;
905 }
906
907 bool OSLRenderServices::environment(ustring filename, TextureOpt &options,
908                                     OSL::ShaderGlobals *sg, const OSL::Vec3 &R,
909                                     const OSL::Vec3 &dRdx, const OSL::Vec3 &dRdy, float *result)
910 {
911         OSL::TextureSystem *ts = osl_ts;
912         ShaderData *sd = (ShaderData *)(sg->renderstate);
913         KernelGlobals *kg = sd->osl_globals;
914         OSLThreadData *tdata = kg->osl_tdata;
915         OIIO::TextureSystem::Perthread *thread_info = tdata->oiio_thread_info;
916
917         OIIO::TextureSystem::TextureHandle *th =  ts->get_texture_handle(filename, thread_info);
918         bool status = ts->environment(th, thread_info,
919                                       options, R, dRdx, dRdy, result);
920
921         if(!status) {
922                 if(options.nchannels == 3 || options.nchannels == 4) {
923                         result[0] = 1.0f;
924                         result[1] = 0.0f;
925                         result[2] = 1.0f;
926
927                         if(options.nchannels == 4)
928                                 result[3] = 1.0f;
929                 }
930         }
931
932         return status;
933 }
934
935 bool OSLRenderServices::get_texture_info(ustring filename, int subimage,
936                                          ustring dataname,
937                                          TypeDesc datatype, void *data)
938 {
939         OSL::TextureSystem *ts = osl_ts;
940         return ts->get_texture_info(filename, subimage, dataname, datatype, data);
941 }
942
943 int OSLRenderServices::pointcloud_search(OSL::ShaderGlobals *sg, ustring filename, const OSL::Vec3 &center,
944                                          float radius, int max_points, bool sort,
945                                          size_t *out_indices, float *out_distances, int derivs_offset)
946 {
947         return 0;
948 }
949
950 int OSLRenderServices::pointcloud_get(OSL::ShaderGlobals *sg, ustring filename, size_t *indices, int count,
951                                       ustring attr_name, TypeDesc attr_type, void *out_data)
952 {
953         return 0;
954 }
955
956 bool OSLRenderServices::pointcloud_write(OSL::ShaderGlobals *sg,
957                                          ustring filename, const OSL::Vec3 &pos,
958                                          int nattribs, const ustring *names,
959                                          const TypeDesc *types,
960                                          const void **data)
961 {
962         return false;
963 }
964
965 bool OSLRenderServices::trace(TraceOpt &options, OSL::ShaderGlobals *sg,
966         const OSL::Vec3 &P, const OSL::Vec3 &dPdx,
967         const OSL::Vec3 &dPdy, const OSL::Vec3 &R,
968         const OSL::Vec3 &dRdx, const OSL::Vec3 &dRdy)
969 {
970         /* todo: options.shader support, maybe options.traceset */
971         ShaderData *sd = (ShaderData *)(sg->renderstate);
972
973         /* setup ray */
974         Ray ray;
975
976         ray.P = TO_FLOAT3(P);
977         ray.D = TO_FLOAT3(R);
978         ray.t = (options.maxdist == 1.0e30)? FLT_MAX: options.maxdist - options.mindist;
979         ray.time = sd->time;
980
981         if(options.mindist == 0.0f) {
982                 /* avoid self-intersections */
983                 if(ray.P == sd->P) {
984                         bool transmit = (dot(sd->Ng, ray.D) < 0.0f);
985                         ray.P = ray_offset(sd->P, (transmit)? -sd->Ng: sd->Ng);
986                 }
987         }
988         else {
989                 /* offset for minimum distance */
990                 ray.P += options.mindist*ray.D;
991         }
992
993         /* ray differentials */
994         ray.dP.dx = TO_FLOAT3(dPdx);
995         ray.dP.dy = TO_FLOAT3(dPdy);
996         ray.dD.dx = TO_FLOAT3(dRdx);
997         ray.dD.dy = TO_FLOAT3(dRdy);
998
999         /* allocate trace data */
1000         OSLTraceData *tracedata = (OSLTraceData*)sg->tracedata;
1001         tracedata->ray = ray;
1002         tracedata->setup = false;
1003         tracedata->init = true;
1004         tracedata->sd.osl_globals = sd->osl_globals;
1005
1006         /* raytrace */
1007 #ifdef __HAIR__
1008         return scene_intersect(sd->osl_globals, &ray, PATH_RAY_ALL_VISIBILITY, &tracedata->isect, NULL, 0.0f, 0.0f);
1009 #else
1010         return scene_intersect(sd->osl_globals, &ray, PATH_RAY_ALL_VISIBILITY, &tracedata->isect);
1011 #endif
1012 }
1013
1014
1015 bool OSLRenderServices::getmessage(OSL::ShaderGlobals *sg, ustring source, ustring name,
1016         TypeDesc type, void *val, bool derivatives)
1017 {
1018         OSLTraceData *tracedata = (OSLTraceData*)sg->tracedata;
1019
1020         if(source == u_trace && tracedata->init) {
1021                 if(name == u_hit) {
1022                         return set_attribute_int((tracedata->isect.prim != PRIM_NONE), type, derivatives, val);
1023                 }
1024                 else if(tracedata->isect.prim != PRIM_NONE) {
1025                         if(name == u_hitdist) {
1026                                 float f[3] = {tracedata->isect.t, 0.0f, 0.0f};
1027                                 return set_attribute_float(f, type, derivatives, val);
1028                         }
1029                         else {
1030                                 ShaderData *sd = &tracedata->sd;
1031                                 KernelGlobals *kg = sd->osl_globals;
1032
1033                                 if(!tracedata->setup) {
1034                                         /* lazy shader data setup */
1035                                         ShaderData *original_sd = (ShaderData *)(sg->renderstate);
1036                                         int bounce = original_sd->ray_depth + 1;
1037
1038                                         shader_setup_from_ray(kg, sd, &tracedata->isect, &tracedata->ray, bounce);
1039                                         tracedata->setup = true;
1040                                 }
1041
1042                                 if(name == u_N) {
1043                                         return set_attribute_float3(sd->N, type, derivatives, val);
1044                                 }
1045                                 else if(name == u_Ng) {
1046                                         return set_attribute_float3(sd->Ng, type, derivatives, val);
1047                                 }
1048                                 else if(name == u_P) {
1049                                         float3 f[3] = {sd->P, sd->dP.dx, sd->dP.dy};
1050                                         return set_attribute_float3(f, type, derivatives, val);
1051                                 }
1052                                 else if(name == u_I) {
1053                                         float3 f[3] = {sd->I, sd->dI.dx, sd->dI.dy};
1054                                         return set_attribute_float3(f, type, derivatives, val);
1055                                 }
1056                                 else if(name == u_u) {
1057                                         float f[3] = {sd->u, sd->du.dx, sd->du.dy};
1058                                         return set_attribute_float(f, type, derivatives, val);
1059                                 }
1060                                 else if(name == u_v) {
1061                                         float f[3] = {sd->v, sd->dv.dx, sd->dv.dy};
1062                                         return set_attribute_float(f, type, derivatives, val);
1063                                 }
1064
1065                                 return get_attribute(sd, derivatives, u_empty, type, name, val);
1066                         }
1067                 }
1068         }
1069
1070         return false;
1071 }
1072
1073 CCL_NAMESPACE_END