Cycles code refactor: move geometry related kernel files into own directory.
[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 != ~0) {
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 != ~0) {
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 != ~0) {
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 != ~0) {
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->segment == ~0) {
647 #else
648                 ) {
649 #endif
650                 float3 P[3];
651                 triangle_vertices(kg, sd->prim, P);
652
653                 if(!(sd->flag & SD_TRANSFORM_APPLIED)) {
654                         object_position_transform(kg, sd, &P[0]);
655                         object_position_transform(kg, sd, &P[1]);
656                         object_position_transform(kg, sd, &P[2]);
657                 }
658
659                 return set_attribute_float3_3(P, type, derivatives, val);
660         }
661         else if(name == u_geom_name) {
662                 ustring object_name = kg->osl->object_names[sd->object];
663                 return set_attribute_string(object_name, type, derivatives, val);
664         }
665         else if (name == u_is_smooth) {
666                 float f = ((sd->shader & SHADER_SMOOTH_NORMAL) != 0);
667                 return set_attribute_float(f, type, derivatives, val);
668         }
669 #ifdef __HAIR__
670         /* Hair Attributes */
671         else if (name == u_is_curve) {
672                 float f = (sd->segment != ~0);
673                 return set_attribute_float(f, type, derivatives, val);
674         }
675         else if (name == u_curve_thickness) {
676                 float f = curve_thickness(kg, sd);
677                 return set_attribute_float(f, type, derivatives, val);
678         }
679         else if (name == u_curve_tangent_normal) {
680                 float3 f = curve_tangent_normal(kg, sd);
681                 return set_attribute_float3(f, type, derivatives, val);
682         }
683 #endif
684         else
685                 return false;
686 }
687
688 bool OSLRenderServices::get_background_attribute(KernelGlobals *kg, ShaderData *sd, ustring name,
689                                                  TypeDesc type, bool derivatives, void *val)
690 {
691         if (name == u_path_ray_length) {
692                 /* Ray Length */
693                 float f = sd->ray_length;
694                 return set_attribute_float(f, type, derivatives, val);
695         }
696         else if (name == u_path_ray_depth) {
697                 /* Ray Depth */
698                 int f = sd->ray_depth;
699                 return set_attribute_int(f, type, derivatives, val);
700         }
701         else if (name == u_ndc) {
702                 /* NDC coordinates with special exception for otho */
703                 OSLThreadData *tdata = kg->osl_tdata;
704                 OSL::ShaderGlobals *globals = &tdata->globals;
705                 float3 ndc[3];
706
707                 if((globals->raytype & PATH_RAY_CAMERA) && sd->object == ~0 && kernel_data.cam.type == CAMERA_ORTHOGRAPHIC) {
708                         ndc[0] = camera_world_to_ndc(kg, sd, sd->ray_P);
709
710                         if(derivatives) {
711                                 ndc[1] = camera_world_to_ndc(kg, sd, sd->ray_P + sd->ray_dP.dx) - ndc[0];
712                                 ndc[2] = camera_world_to_ndc(kg, sd, sd->ray_P + sd->ray_dP.dy) - ndc[0];
713                         }
714                 }
715                 else {
716                         ndc[0] = camera_world_to_ndc(kg, sd, sd->P);
717
718                         if(derivatives) {
719                                 ndc[1] = camera_world_to_ndc(kg, sd, sd->P + sd->dP.dx) - ndc[0];
720                                 ndc[2] = camera_world_to_ndc(kg, sd, sd->P + sd->dP.dy) - ndc[0];
721                         }
722                 }
723
724                 return set_attribute_float3(ndc, type, derivatives, val);
725         }
726         else
727                 return false;
728 }
729
730 bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustring object_name,
731                                       TypeDesc type, ustring name, void *val)
732 {
733         ShaderData *sd = (ShaderData *)renderstate;
734         KernelGlobals *kg = sd->osl_globals;
735         int object, prim, segment;
736
737         /* lookup of attribute on another object */
738         if (object_name != u_empty) {
739                 OSLGlobals::ObjectNameMap::iterator it = kg->osl->object_name_map.find(object_name);
740
741                 if (it == kg->osl->object_name_map.end())
742                         return false;
743
744                 object = it->second;
745                 prim = ~0;
746                 segment = ~0;
747         }
748         else {
749                 object = sd->object;
750                 prim = sd->prim;
751 #ifdef __HAIR__
752                 segment = sd->segment;
753 #else
754                 segment = ~0;
755 #endif
756
757                 if (object == ~0)
758                         return get_background_attribute(kg, sd, name, type, derivatives, val);
759         }
760
761         /* find attribute on object */
762         object = object*ATTR_PRIM_TYPES + (segment != ~0);
763         OSLGlobals::AttributeMap& attribute_map = kg->osl->attribute_map[object];
764         OSLGlobals::AttributeMap::iterator it = attribute_map.find(name);
765
766         if (it != attribute_map.end()) {
767                 const OSLGlobals::Attribute& attr = it->second;
768
769                 if (attr.elem != ATTR_ELEMENT_OBJECT) {
770                         /* triangle and vertex attributes */
771                         if (prim != ~0)
772                                 return get_mesh_element_attribute(kg, sd, attr, type, derivatives, val);
773                         else
774                                 return get_mesh_attribute(kg, sd, attr, type, derivatives, val);
775                 }
776                 else {
777                         /* object attribute */
778                         get_object_attribute(attr, derivatives, val);
779                         return true;
780                 }
781         }
782         else {
783                 /* not found in attribute, check standard object info */
784                 bool is_std_object_attribute = get_object_standard_attribute(kg, sd, name, type, derivatives, val);
785
786                 if (is_std_object_attribute)
787                         return true;
788
789                 return get_background_attribute(kg, sd, name, type, derivatives, val);
790         }
791
792         return false;
793 }
794
795 bool OSLRenderServices::get_userdata(bool derivatives, ustring name, TypeDesc type, 
796                                      void *renderstate, void *val)
797 {
798         return false; /* disabled by lockgeom */
799 }
800
801 bool OSLRenderServices::has_userdata(ustring name, TypeDesc type, void *renderstate)
802 {
803         return false; /* never called by OSL */
804 }
805
806 bool OSLRenderServices::texture(ustring filename, TextureOpt &options,
807                                 OSL::ShaderGlobals *sg,
808                                 float s, float t, float dsdx, float dtdx,
809                                 float dsdy, float dtdy, float *result)
810 {
811         OSL::TextureSystem *ts = osl_ts;
812         ShaderData *sd = (ShaderData *)(sg->renderstate);
813         KernelGlobals *kg = sd->osl_globals;
814
815 #ifdef WITH_PTEX
816         /* todo: this is just a quick hack, only works with particular files and options */
817         if(string_endswith(filename.string(), ".ptx")) {
818                 float2 uv;
819                 int faceid;
820
821                 if(!primitive_ptex(kg, sd, &uv, &faceid))
822                         return false;
823
824                 float u = uv.x;
825                 float v = uv.y;
826                 float dudx = 0.0f;
827                 float dvdx = 0.0f;
828                 float dudy = 0.0f;
829                 float dvdy = 0.0f;
830
831                 Ptex::String error;
832                 PtexPtr<PtexTexture> r(ptex_cache->get(filename.c_str(), error));
833
834                 if(!r) {
835                         //std::cerr << error.c_str() << std::endl;
836                         return false;
837                 }
838
839                 bool mipmaplerp = false;
840                 float sharpness = 1.0f;
841                 PtexFilter::Options opts(PtexFilter::f_bicubic, mipmaplerp, sharpness);
842                 PtexPtr<PtexFilter> f(PtexFilter::getFilter(r, opts));
843
844                 f->eval(result, options.firstchannel, options.nchannels, faceid, u, v, dudx, dvdx, dudy, dvdy);
845
846                 for(int c = r->numChannels(); c < options.nchannels; c++)
847                         result[c] = result[0];
848
849                 return true;
850         }
851 #endif
852
853         OSLThreadData *tdata = kg->osl_tdata;
854         OIIO::TextureSystem::Perthread *thread_info = tdata->oiio_thread_info;
855
856         OIIO::TextureSystem::TextureHandle *th = ts->get_texture_handle(filename, thread_info);
857
858         bool status = ts->texture(th, thread_info,
859                                   options, s, t, dsdx, dtdx, dsdy, dtdy, result);
860
861         if(!status) {
862                 if(options.nchannels == 3 || options.nchannels == 4) {
863                         result[0] = 1.0f;
864                         result[1] = 0.0f;
865                         result[2] = 1.0f;
866
867                         if(options.nchannels == 4)
868                                 result[3] = 1.0f;
869                 }
870         }
871
872         return status;
873 }
874
875 bool OSLRenderServices::texture3d(ustring filename, TextureOpt &options,
876                                   OSL::ShaderGlobals *sg, const OSL::Vec3 &P,
877                                   const OSL::Vec3 &dPdx, const OSL::Vec3 &dPdy,
878                                   const OSL::Vec3 &dPdz, float *result)
879 {
880         OSL::TextureSystem *ts = osl_ts;
881         ShaderData *sd = (ShaderData *)(sg->renderstate);
882         KernelGlobals *kg = sd->osl_globals;
883         OSLThreadData *tdata = kg->osl_tdata;
884         OIIO::TextureSystem::Perthread *thread_info = tdata->oiio_thread_info;
885
886         OIIO::TextureSystem::TextureHandle *th =  ts->get_texture_handle(filename, thread_info);
887
888         bool status = ts->texture3d(th, thread_info,
889                                     options, P, dPdx, dPdy, dPdz, result);
890
891         if(!status) {
892                 if(options.nchannels == 3 || options.nchannels == 4) {
893                         result[0] = 1.0f;
894                         result[1] = 0.0f;
895                         result[2] = 1.0f;
896
897                         if(options.nchannels == 4)
898                                 result[3] = 1.0f;
899                 }
900
901         }
902
903         return status;
904 }
905
906 bool OSLRenderServices::environment(ustring filename, TextureOpt &options,
907                                     OSL::ShaderGlobals *sg, const OSL::Vec3 &R,
908                                     const OSL::Vec3 &dRdx, const OSL::Vec3 &dRdy, float *result)
909 {
910         OSL::TextureSystem *ts = osl_ts;
911         ShaderData *sd = (ShaderData *)(sg->renderstate);
912         KernelGlobals *kg = sd->osl_globals;
913         OSLThreadData *tdata = kg->osl_tdata;
914         OIIO::TextureSystem::Perthread *thread_info = tdata->oiio_thread_info;
915
916         OIIO::TextureSystem::TextureHandle *th =  ts->get_texture_handle(filename, thread_info);
917         bool status = ts->environment(th, thread_info,
918                                       options, R, dRdx, dRdy, result);
919
920         if(!status) {
921                 if(options.nchannels == 3 || options.nchannels == 4) {
922                         result[0] = 1.0f;
923                         result[1] = 0.0f;
924                         result[2] = 1.0f;
925
926                         if(options.nchannels == 4)
927                                 result[3] = 1.0f;
928                 }
929         }
930
931         return status;
932 }
933
934 bool OSLRenderServices::get_texture_info(ustring filename, int subimage,
935                                          ustring dataname,
936                                          TypeDesc datatype, void *data)
937 {
938         OSL::TextureSystem *ts = osl_ts;
939         return ts->get_texture_info(filename, subimage, dataname, datatype, data);
940 }
941
942 int OSLRenderServices::pointcloud_search(OSL::ShaderGlobals *sg, ustring filename, const OSL::Vec3 &center,
943                                          float radius, int max_points, bool sort,
944                                          size_t *out_indices, float *out_distances, int derivs_offset)
945 {
946         return 0;
947 }
948
949 int OSLRenderServices::pointcloud_get(OSL::ShaderGlobals *sg, ustring filename, size_t *indices, int count,
950                                       ustring attr_name, TypeDesc attr_type, void *out_data)
951 {
952         return 0;
953 }
954
955 bool OSLRenderServices::pointcloud_write(OSL::ShaderGlobals *sg,
956                                          ustring filename, const OSL::Vec3 &pos,
957                                          int nattribs, const ustring *names,
958                                          const TypeDesc *types,
959                                          const void **data)
960 {
961         return false;
962 }
963
964 bool OSLRenderServices::trace(TraceOpt &options, OSL::ShaderGlobals *sg,
965         const OSL::Vec3 &P, const OSL::Vec3 &dPdx,
966         const OSL::Vec3 &dPdy, const OSL::Vec3 &R,
967         const OSL::Vec3 &dRdx, const OSL::Vec3 &dRdy)
968 {
969         /* todo: options.shader support, maybe options.traceset */
970         ShaderData *sd = (ShaderData *)(sg->renderstate);
971
972         /* setup ray */
973         Ray ray;
974
975         ray.P = TO_FLOAT3(P);
976         ray.D = TO_FLOAT3(R);
977         ray.t = (options.maxdist == 1.0e30)? FLT_MAX: options.maxdist - options.mindist;
978         ray.time = sd->time;
979
980         if(options.mindist == 0.0f) {
981                 /* avoid self-intersections */
982                 if(ray.P == sd->P) {
983                         bool transmit = (dot(sd->Ng, ray.D) < 0.0f);
984                         ray.P = ray_offset(sd->P, (transmit)? -sd->Ng: sd->Ng);
985                 }
986         }
987         else {
988                 /* offset for minimum distance */
989                 ray.P += options.mindist*ray.D;
990         }
991
992         /* ray differentials */
993         ray.dP.dx = TO_FLOAT3(dPdx);
994         ray.dP.dy = TO_FLOAT3(dPdy);
995         ray.dD.dx = TO_FLOAT3(dRdx);
996         ray.dD.dy = TO_FLOAT3(dRdy);
997
998         /* allocate trace data */
999         OSLTraceData *tracedata = (OSLTraceData*)sg->tracedata;
1000         tracedata->ray = ray;
1001         tracedata->setup = false;
1002         tracedata->init = true;
1003         tracedata->sd.osl_globals = sd->osl_globals;
1004
1005         /* raytrace */
1006 #ifdef __HAIR__
1007         return scene_intersect(sd->osl_globals, &ray, ~0, &tracedata->isect, NULL, 0.0f, 0.0f);
1008 #else
1009         return scene_intersect(sd->osl_globals, &ray, ~0, &tracedata->isect);
1010 #endif
1011 }
1012
1013
1014 bool OSLRenderServices::getmessage(OSL::ShaderGlobals *sg, ustring source, ustring name,
1015         TypeDesc type, void *val, bool derivatives)
1016 {
1017         OSLTraceData *tracedata = (OSLTraceData*)sg->tracedata;
1018
1019         if(source == u_trace && tracedata->init) {
1020                 if(name == u_hit) {
1021                         return set_attribute_int((tracedata->isect.prim != ~0), type, derivatives, val);
1022                 }
1023                 else if(tracedata->isect.prim != ~0) {
1024                         if(name == u_hitdist) {
1025                                 float f[3] = {tracedata->isect.t, 0.0f, 0.0f};
1026                                 return set_attribute_float(f, type, derivatives, val);
1027                         }
1028                         else {
1029                                 ShaderData *sd = &tracedata->sd;
1030                                 KernelGlobals *kg = sd->osl_globals;
1031
1032                                 if(!tracedata->setup) {
1033                                         /* lazy shader data setup */
1034                                         ShaderData *original_sd = (ShaderData *)(sg->renderstate);
1035                                         int bounce = original_sd->ray_depth + 1;
1036
1037                                         shader_setup_from_ray(kg, sd, &tracedata->isect, &tracedata->ray, bounce);
1038                                         tracedata->setup = true;
1039                                 }
1040
1041                                 if(name == u_N) {
1042                                         return set_attribute_float3(sd->N, type, derivatives, val);
1043                                 }
1044                                 else if(name == u_Ng) {
1045                                         return set_attribute_float3(sd->Ng, type, derivatives, val);
1046                                 }
1047                                 else if(name == u_P) {
1048                                         float3 f[3] = {sd->P, sd->dP.dx, sd->dP.dy};
1049                                         return set_attribute_float3(f, type, derivatives, val);
1050                                 }
1051                                 else if(name == u_I) {
1052                                         float3 f[3] = {sd->I, sd->dI.dx, sd->dI.dy};
1053                                         return set_attribute_float3(f, type, derivatives, val);
1054                                 }
1055                                 else if(name == u_u) {
1056                                         float f[3] = {sd->u, sd->du.dx, sd->du.dy};
1057                                         return set_attribute_float(f, type, derivatives, val);
1058                                 }
1059                                 else if(name == u_v) {
1060                                         float f[3] = {sd->v, sd->dv.dx, sd->dv.dy};
1061                                         return set_attribute_float(f, type, derivatives, val);
1062                                 }
1063
1064                                 return get_attribute(sd, derivatives, u_empty, type, name, val);
1065                         }
1066                 }
1067         }
1068
1069         return false;
1070 }
1071
1072 CCL_NAMESPACE_END