Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'intern/cycles/kernel')
-rw-r--r--intern/cycles/kernel/CMakeLists.txt104
-rw-r--r--intern/cycles/kernel/kernel.cl105
-rw-r--r--intern/cycles/kernel/kernel.cpp300
-rw-r--r--intern/cycles/kernel/kernel.cu53
-rw-r--r--intern/cycles/kernel/kernel.h47
-rw-r--r--intern/cycles/kernel/kernel_bvh.h361
-rw-r--r--intern/cycles/kernel/kernel_camera.h132
-rw-r--r--intern/cycles/kernel/kernel_compat_cpu.h162
-rw-r--r--intern/cycles/kernel/kernel_compat_cuda.h65
-rw-r--r--intern/cycles/kernel/kernel_compat_opencl.h50
-rw-r--r--intern/cycles/kernel/kernel_differential.h90
-rw-r--r--intern/cycles/kernel/kernel_displace.h35
-rw-r--r--intern/cycles/kernel/kernel_emission.h118
-rw-r--r--intern/cycles/kernel/kernel_film.h68
-rw-r--r--intern/cycles/kernel/kernel_globals.h208
-rw-r--r--intern/cycles/kernel/kernel_light.h145
-rw-r--r--intern/cycles/kernel/kernel_math.h27
-rw-r--r--intern/cycles/kernel/kernel_mbvh.h394
-rw-r--r--intern/cycles/kernel/kernel_montecarlo.h196
-rw-r--r--intern/cycles/kernel/kernel_object.h68
-rw-r--r--intern/cycles/kernel/kernel_path.h263
-rw-r--r--intern/cycles/kernel/kernel_qbvh.h413
-rw-r--r--intern/cycles/kernel/kernel_random.h175
-rw-r--r--intern/cycles/kernel/kernel_shader.h460
-rw-r--r--intern/cycles/kernel/kernel_triangle.h183
-rw-r--r--intern/cycles/kernel/kernel_types.h374
-rw-r--r--intern/cycles/kernel/osl/CMakeLists.txt33
-rw-r--r--intern/cycles/kernel/osl/background.cpp100
-rw-r--r--intern/cycles/kernel/osl/bsdf_ashikhmin_velvet.cpp175
-rw-r--r--intern/cycles/kernel/osl/bsdf_diffuse.cpp181
-rw-r--r--intern/cycles/kernel/osl/bsdf_microfacet.cpp533
-rw-r--r--intern/cycles/kernel/osl/bsdf_reflection.cpp108
-rw-r--r--intern/cycles/kernel/osl/bsdf_refraction.cpp120
-rw-r--r--intern/cycles/kernel/osl/bsdf_transparent.cpp97
-rw-r--r--intern/cycles/kernel/osl/bsdf_ward.cpp222
-rw-r--r--intern/cycles/kernel/osl/bsdf_westin.cpp239
-rw-r--r--intern/cycles/kernel/osl/bssrdf.cpp105
-rw-r--r--intern/cycles/kernel/osl/debug.cpp80
-rw-r--r--intern/cycles/kernel/osl/emissive.cpp107
-rw-r--r--intern/cycles/kernel/osl/nodes/CMakeLists.txt69
-rw-r--r--intern/cycles/kernel/osl/nodes/node_add_closure.osl28
-rw-r--r--intern/cycles/kernel/osl/nodes/node_attribute.osl43
-rw-r--r--intern/cycles/kernel/osl/nodes/node_background.osl28
-rw-r--r--intern/cycles/kernel/osl/nodes/node_blend_texture.osl78
-rw-r--r--intern/cycles/kernel/osl/nodes/node_bump.osl46
-rw-r--r--intern/cycles/kernel/osl/nodes/node_clouds_texture.osl42
-rw-r--r--intern/cycles/kernel/osl/nodes/node_convert_from_color.osl33
-rw-r--r--intern/cycles/kernel/osl/nodes/node_convert_from_float.osl33
-rw-r--r--intern/cycles/kernel/osl/nodes/node_convert_from_normal.osl33
-rw-r--r--intern/cycles/kernel/osl/nodes/node_convert_from_point.osl33
-rw-r--r--intern/cycles/kernel/osl/nodes/node_convert_from_vector.osl33
-rw-r--r--intern/cycles/kernel/osl/nodes/node_diffuse_bsdf.osl28
-rw-r--r--intern/cycles/kernel/osl/nodes/node_distorted_noise_texture.osl46
-rw-r--r--intern/cycles/kernel/osl/nodes/node_emission.osl32
-rw-r--r--intern/cycles/kernel/osl/nodes/node_environment_texture.osl28
-rw-r--r--intern/cycles/kernel/osl/nodes/node_fresnel.h21
-rw-r--r--intern/cycles/kernel/osl/nodes/node_fresnel.osl30
-rw-r--r--intern/cycles/kernel/osl/nodes/node_geometry.osl50
-rw-r--r--intern/cycles/kernel/osl/nodes/node_glass_bsdf.osl41
-rw-r--r--intern/cycles/kernel/osl/nodes/node_glossy_bsdf.osl45
-rw-r--r--intern/cycles/kernel/osl/nodes/node_image_texture.osl28
-rw-r--r--intern/cycles/kernel/osl/nodes/node_light_path.osl36
-rw-r--r--intern/cycles/kernel/osl/nodes/node_magic_texture.osl103
-rw-r--r--intern/cycles/kernel/osl/nodes/node_mapping.osl28
-rw-r--r--intern/cycles/kernel/osl/nodes/node_marble_texture.osl58
-rw-r--r--intern/cycles/kernel/osl/nodes/node_math.osl84
-rw-r--r--intern/cycles/kernel/osl/nodes/node_mix.osl388
-rw-r--r--intern/cycles/kernel/osl/nodes/node_mix_closure.osl30
-rw-r--r--intern/cycles/kernel/osl/nodes/node_musgrave_texture.osl218
-rw-r--r--intern/cycles/kernel/osl/nodes/node_noise_texture.osl36
-rw-r--r--intern/cycles/kernel/osl/nodes/node_output_displacement.osl25
-rw-r--r--intern/cycles/kernel/osl/nodes/node_output_surface.osl25
-rw-r--r--intern/cycles/kernel/osl/nodes/node_output_volume.osl25
-rw-r--r--intern/cycles/kernel/osl/nodes/node_sky_texture.osl162
-rw-r--r--intern/cycles/kernel/osl/nodes/node_stucci_texture.osl49
-rw-r--r--intern/cycles/kernel/osl/nodes/node_texture.h251
-rw-r--r--intern/cycles/kernel/osl/nodes/node_texture_coordinate.osl66
-rw-r--r--intern/cycles/kernel/osl/nodes/node_translucent_bsdf.osl28
-rw-r--r--intern/cycles/kernel/osl/nodes/node_transparent_bsdf.osl28
-rw-r--r--intern/cycles/kernel/osl/nodes/node_value.osl33
-rw-r--r--intern/cycles/kernel/osl/nodes/node_vector_math.osl53
-rw-r--r--intern/cycles/kernel/osl/nodes/node_velvet_bsdf.osl40
-rw-r--r--intern/cycles/kernel/osl/nodes/node_voronoi_texture.osl82
-rw-r--r--intern/cycles/kernel/osl/nodes/node_ward_bsdf.osl30
-rw-r--r--intern/cycles/kernel/osl/nodes/node_wood_texture.osl63
-rw-r--r--intern/cycles/kernel/osl/nodes/stdosl.h471
-rw-r--r--intern/cycles/kernel/osl/osl_closures.cpp93
-rw-r--r--intern/cycles/kernel/osl/osl_closures.h114
-rw-r--r--intern/cycles/kernel/osl/osl_globals.h74
-rw-r--r--intern/cycles/kernel/osl/osl_services.cpp424
-rw-r--r--intern/cycles/kernel/osl/osl_services.h111
-rw-r--r--intern/cycles/kernel/osl/osl_shader.cpp559
-rw-r--r--intern/cycles/kernel/osl/osl_shader.h87
-rw-r--r--intern/cycles/kernel/osl/vol_subsurface.cpp135
-rw-r--r--intern/cycles/kernel/svm/bsdf.h135
-rw-r--r--intern/cycles/kernel/svm/bsdf_ashikhmin_velvet.h154
-rw-r--r--intern/cycles/kernel/svm/bsdf_diffuse.h166
-rw-r--r--intern/cycles/kernel/svm/bsdf_microfacet.h493
-rw-r--r--intern/cycles/kernel/svm/bsdf_reflection.h95
-rw-r--r--intern/cycles/kernel/svm/bsdf_refraction.h103
-rw-r--r--intern/cycles/kernel/svm/bsdf_transparent.h78
-rw-r--r--intern/cycles/kernel/svm/bsdf_ward.h202
-rw-r--r--intern/cycles/kernel/svm/bsdf_westin.h212
-rw-r--r--intern/cycles/kernel/svm/emissive.h83
-rw-r--r--intern/cycles/kernel/svm/svm.h271
-rw-r--r--intern/cycles/kernel/svm/svm_attribute.h154
-rw-r--r--intern/cycles/kernel/svm/svm_blend.h79
-rw-r--r--intern/cycles/kernel/svm/svm_bsdf.h228
-rw-r--r--intern/cycles/kernel/svm/svm_closure.h208
-rw-r--r--intern/cycles/kernel/svm/svm_clouds.h55
-rw-r--r--intern/cycles/kernel/svm/svm_convert.h48
-rw-r--r--intern/cycles/kernel/svm/svm_displace.h51
-rw-r--r--intern/cycles/kernel/svm/svm_distorted_noise.h58
-rw-r--r--intern/cycles/kernel/svm/svm_fresnel.h34
-rw-r--r--intern/cycles/kernel/svm/svm_geometry.h78
-rw-r--r--intern/cycles/kernel/svm/svm_image.h162
-rw-r--r--intern/cycles/kernel/svm/svm_light_path.h41
-rw-r--r--intern/cycles/kernel/svm/svm_magic.h108
-rw-r--r--intern/cycles/kernel/svm/svm_mapping.h38
-rw-r--r--intern/cycles/kernel/svm/svm_marble.h67
-rw-r--r--intern/cycles/kernel/svm/svm_math.h181
-rw-r--r--intern/cycles/kernel/svm/svm_mix.h387
-rw-r--r--intern/cycles/kernel/svm/svm_musgrave.h237
-rw-r--r--intern/cycles/kernel/svm/svm_noise.h230
-rw-r--r--intern/cycles/kernel/svm/svm_noisetex.h48
-rw-r--r--intern/cycles/kernel/svm/svm_sky.h92
-rw-r--r--intern/cycles/kernel/svm/svm_stucci.h63
-rw-r--r--intern/cycles/kernel/svm/svm_tex_coord.h170
-rw-r--r--intern/cycles/kernel/svm/svm_texture.h240
-rw-r--r--intern/cycles/kernel/svm/svm_types.h286
-rw-r--r--intern/cycles/kernel/svm/svm_value.h38
-rw-r--r--intern/cycles/kernel/svm/svm_voronoi.h105
-rw-r--r--intern/cycles/kernel/svm/svm_wood.h69
-rw-r--r--intern/cycles/kernel/svm/volume.h43
134 files changed, 17143 insertions, 0 deletions
diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt
new file mode 100644
index 00000000000..30b618eb1ad
--- /dev/null
+++ b/intern/cycles/kernel/CMakeLists.txt
@@ -0,0 +1,104 @@
+
+SET(sources
+ kernel.cpp
+ kernel.cl
+ kernel.cu)
+
+SET(headers
+ kernel.h
+ kernel_bvh.h
+ kernel_camera.h
+ kernel_compat_cpu.h
+ kernel_compat_cuda.h
+ kernel_compat_opencl.h
+ kernel_differential.h
+ kernel_displace.h
+ kernel_emission.h
+ kernel_film.h
+ kernel_globals.h
+ kernel_light.h
+ kernel_math.h
+ kernel_mbvh.h
+ kernel_montecarlo.h
+ kernel_object.h
+ kernel_path.h
+ kernel_qbvh.h
+ kernel_random.h
+ kernel_shader.h
+ kernel_triangle.h
+ kernel_types.h
+ svm/bsdf.h
+ svm/bsdf_ashikhmin_velvet.h
+ svm/bsdf_diffuse.h
+ svm/bsdf_microfacet.h
+ svm/bsdf_reflection.h
+ svm/bsdf_refraction.h
+ svm/bsdf_transparent.h
+ svm/bsdf_ward.h
+ svm/bsdf_westin.h
+ svm/emissive.h
+ svm/svm.h
+ svm/svm_attribute.h
+ svm/svm_blend.h
+ svm/svm_bsdf.h
+ svm/svm_closure.h
+ svm/svm_clouds.h
+ svm/svm_convert.h
+ svm/svm_displace.h
+ svm/svm_distorted_noise.h
+ svm/svm_fresnel.h
+ svm/svm_geometry.h
+ svm/svm_image.h
+ svm/svm_light_path.h
+ svm/svm_magic.h
+ svm/svm_mapping.h
+ svm/svm_marble.h
+ svm/svm_math.h
+ svm/svm_mix.h
+ svm/svm_musgrave.h
+ svm/svm_noise.h
+ svm/svm_noisetex.h
+ svm/svm_sky.h
+ svm/svm_stucci.h
+ svm/svm_tex_coord.h
+ svm/svm_texture.h
+ svm/svm_types.h
+ svm/svm_value.h
+ svm/svm_voronoi.h
+ svm/svm_wood.h
+ svm/volume.h
+ )
+
+# CUDA module
+
+IF(WITH_CUDA)
+ SET(cuda_sources kernel.cu ${headers})
+ SET(cuda_cubins)
+
+ FOREACH(arch ${CUDA_ARCH})
+ SET(cuda_cubin kernel_${arch}.cubin)
+
+ ADD_CUSTOM_COMMAND(
+ OUTPUT ${cuda_cubin}
+ COMMAND ${CUDA_NVCC} -arch=${arch} -m64 --cubin ${CMAKE_CURRENT_SOURCE_DIR}/kernel.cu --use_fast_math -o ${CMAKE_CURRENT_BINARY_DIR}/${cuda_cubin} --ptxas-options="-v" --maxrregcount=${CUDA_MAXREG} --opencc-options -OPT:Olimit=0 -I${CMAKE_CURRENT_SOURCE_DIR}/../util -I${CMAKE_CURRENT_SOURCE_DIR}/svm -DCCL_NAMESPACE_BEGIN= -DCCL_NAMESPACE_END=
+ DEPENDS ${cuda_sources})
+
+ INSTALL(FILES ${CMAKE_CURRENT_BINARY_DIR}/${cuda_cubin} DESTINATION ${INSTALL_PATH}/cycles/lib)
+ LIST(APPEND cuda_cubins ${cuda_cubin})
+ ENDFOREACH()
+
+ ADD_CUSTOM_TARGET(kernel_cuda ALL DEPENDS ${cuda_cubins})
+ENDIF(WITH_CUDA)
+
+# OSL module
+
+IF(WITH_OSL)
+ ADD_SUBDIRECTORY(osl)
+ENDIF(WITH_OSL)
+
+# CPU module
+
+INCLUDE_DIRECTORIES(. ../util osl svm)
+
+ADD_LIBRARY(kernel ${sources} ${headers})
+
diff --git a/intern/cycles/kernel/kernel.cl b/intern/cycles/kernel/kernel.cl
new file mode 100644
index 00000000000..a22db5fe040
--- /dev/null
+++ b/intern/cycles/kernel/kernel.cl
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/* OpenCL kernel entry points - unfinished */
+
+#include "kernel_compat_opencl.h"
+#include "kernel_math.h"
+#include "kernel_types.h"
+#include "kernel_globals.h"
+
+typedef struct KernelGlobals {
+ __constant KernelData *data;
+
+ __global float *__response_curve_R;
+ int __response_curve_R_width;
+
+ __global float *__response_curve_G;
+ int __response_curve_G_width;
+
+ __global float *__response_curve_B;
+ int __response_curve_B_width;
+} KernelGlobals;
+
+#include "kernel_film.h"
+//#include "kernel_path.h"
+//#include "kernel_displace.h"
+
+__kernel void kernel_ocl_path_trace(__constant KernelData *data, __global float4 *buffer, __global uint *rng_state, int pass, int sx, int sy, int sw, int sh)
+{
+ KernelGlobals kglobals, *kg = &kglobals;
+ kg->data = data;
+
+ int x = get_global_id(0);
+ int y = get_global_id(1);
+ int w = kernel_data.cam.width;
+
+ if(x < sx + sw && y < sy + sh) {
+ if(pass == 0) {
+ buffer[x + w*y].x = 0.5f;
+ buffer[x + w*y].y = 0.5f;
+ buffer[x + w*y].z = 0.5f;
+ }
+ else {
+ buffer[x + w*y].x += 0.5f;
+ buffer[x + w*y].y += 0.5f;
+ buffer[x + w*y].z += 0.5f;
+ }
+
+ //= make_float3(1.0f, 0.9f, 0.0f);
+ //kernel_path_trace(buffer, rng_state, pass, x, y);
+ }
+}
+
+__kernel void kernel_ocl_tonemap(
+ __constant KernelData *data,
+ __global uchar4 *rgba,
+ __global float4 *buffer,
+ __global float *__response_curve_R,
+ int __response_curve_R_width,
+ __global float *__response_curve_G,
+ int __response_curve_G_width,
+ __global float *__response_curve_B,
+ int __response_curve_B_width,
+ int pass, int resolution,
+ int sx, int sy, int sw, int sh)
+{
+ KernelGlobals kglobals, *kg = &kglobals;
+
+ kg->data = data;
+ kg->__response_curve_R = __response_curve_R;
+ kg->__response_curve_R_width = __response_curve_R_width;
+ kg->__response_curve_G = __response_curve_G;
+ kg->__response_curve_G_width = __response_curve_G_width;
+ kg->__response_curve_B = __response_curve_B;
+ kg->__response_curve_B_width = __response_curve_B_width;
+
+ int x = sx + get_global_id(0);
+ int y = sy + get_global_id(1);
+
+ if(x < sx + sw && y < sy + sh)
+ kernel_film_tonemap(kg, rgba, buffer, pass, resolution, x, y);
+}
+
+__kernel void kernel_ocl_displace(__global uint4 *input, __global float3 *offset, int sx)
+{
+ int x = sx + get_global_id(0);
+
+ kernel_displace(input, offset, x);
+}
+
diff --git a/intern/cycles/kernel/kernel.cpp b/intern/cycles/kernel/kernel.cpp
new file mode 100644
index 00000000000..656e90eb526
--- /dev/null
+++ b/intern/cycles/kernel/kernel.cpp
@@ -0,0 +1,300 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/* CPU kernel entry points */
+
+#include "kernel.h"
+#include "kernel_compat_cpu.h"
+#include "kernel_math.h"
+#include "kernel_types.h"
+#include "kernel_globals.h"
+#include "kernel_film.h"
+#include "kernel_path.h"
+#include "kernel_displace.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Globals */
+
+KernelGlobals *kernel_globals_create()
+{
+ KernelGlobals *kg = new KernelGlobals();
+#ifdef WITH_OSL
+ kg->osl.use = false;
+#endif
+ return kg;
+}
+
+void kernel_globals_free(KernelGlobals *kg)
+{
+ delete kg;
+}
+
+/* OSL */
+
+#ifdef WITH_OSL
+
+void *kernel_osl_memory(KernelGlobals *kg)
+{
+ return (void*)&kg->osl;
+}
+
+bool kernel_osl_use(KernelGlobals *kg)
+{
+ return kg->osl.use;
+}
+
+#endif
+
+/* Memory Copy */
+
+void kernel_const_copy(KernelGlobals *kg, const char *name, void *host, size_t size)
+{
+ if(strcmp(name, "__data") == 0)
+ memcpy(&kg->__data, host, size);
+ else
+ assert(0);
+}
+
+void kernel_tex_copy(KernelGlobals *kg, const char *name, device_ptr mem, size_t width, size_t height)
+{
+ if(strcmp(name, "__bvh_nodes") == 0) {
+ kg->__bvh_nodes.data = (float4*)mem;
+ kg->__bvh_nodes.width = width;
+ }
+ else if(strcmp(name, "__objects") == 0) {
+ kg->__objects.data = (float4*)mem;
+ kg->__objects.width = width;
+ }
+ else if(strcmp(name, "__tri_normal") == 0) {
+ kg->__tri_normal.data = (float4*)mem;
+ kg->__tri_normal.width = width;
+ }
+ else if(strcmp(name, "__tri_woop") == 0) {
+ kg->__tri_woop.data = (float4*)mem;
+ kg->__tri_woop.width = width;
+ }
+ else if(strcmp(name, "__prim_index") == 0) {
+ kg->__prim_index.data = (uint*)mem;
+ kg->__prim_index.width = width;
+ }
+ else if(strcmp(name, "__prim_object") == 0) {
+ kg->__prim_object.data = (uint*)mem;
+ kg->__prim_object.width = width;
+ }
+ else if(strcmp(name, "__object_node") == 0) {
+ kg->__object_node.data = (uint*)mem;
+ kg->__object_node.width = width;
+ }
+ else if(strcmp(name, "__tri_vnormal") == 0) {
+ kg->__tri_vnormal.data = (float4*)mem;
+ kg->__tri_vnormal.width = width;
+ }
+ else if(strcmp(name, "__tri_vindex") == 0) {
+ kg->__tri_vindex.data = (float4*)mem;
+ kg->__tri_vindex.width = width;
+ }
+ else if(strcmp(name, "__tri_verts") == 0) {
+ kg->__tri_verts.data = (float4*)mem;
+ kg->__tri_verts.width = width;
+ }
+ else if(strcmp(name, "__light_distribution") == 0) {
+ kg->__light_distribution.data = (float4*)mem;
+ kg->__light_distribution.width = width;
+ }
+ else if(strcmp(name, "__light_point") == 0) {
+ kg->__light_point.data = (float4*)mem;
+ kg->__light_point.width = width;
+ }
+ else if(strcmp(name, "__svm_nodes") == 0) {
+ kg->__svm_nodes.data = (uint4*)mem;
+ kg->__svm_nodes.width = width;
+ }
+ else if(strcmp(name, "__filter_table") == 0) {
+ kg->__filter_table.data = (float*)mem;
+ kg->__filter_table.width = width;
+ }
+ else if(strcmp(name, "__response_curve_R") == 0) {
+ kg->__response_curve_R.data = (float*)mem;
+ kg->__response_curve_R.width = width;
+ }
+ else if(strcmp(name, "__response_curve_B") == 0) {
+ kg->__response_curve_B.data = (float*)mem;
+ kg->__response_curve_B.width = width;
+ }
+ else if(strcmp(name, "__response_curve_G") == 0) {
+ kg->__response_curve_G.data = (float*)mem;
+ kg->__response_curve_G.width = width;
+ }
+ else if(strcmp(name, "__sobol_directions") == 0) {
+ kg->__sobol_directions.data = (uint*)mem;
+ kg->__sobol_directions.width = width;
+ }
+ else if(strcmp(name, "__attributes_map") == 0) {
+ kg->__attributes_map.data = (uint4*)mem;
+ kg->__attributes_map.width = width;
+ }
+ else if(strcmp(name, "__attributes_float") == 0) {
+ kg->__attributes_float.data = (float*)mem;
+ kg->__attributes_float.width = width;
+ }
+ else if(strcmp(name, "__attributes_float3") == 0) {
+ kg->__attributes_float3.data = (float4*)mem;
+ kg->__attributes_float3.width = width;
+ }
+ else if(strstr(name, "__tex_image")) {
+ texture_image_uchar4 *tex = NULL;
+ int id = atoi(name + strlen("__tex_image_"));
+
+ switch(id) {
+ case 0: tex = &kg->__tex_image_000; break;
+ case 1: tex = &kg->__tex_image_001; break;
+ case 2: tex = &kg->__tex_image_002; break;
+ case 3: tex = &kg->__tex_image_003; break;
+ case 4: tex = &kg->__tex_image_004; break;
+ case 5: tex = &kg->__tex_image_005; break;
+ case 6: tex = &kg->__tex_image_006; break;
+ case 7: tex = &kg->__tex_image_007; break;
+ case 8: tex = &kg->__tex_image_008; break;
+ case 9: tex = &kg->__tex_image_009; break;
+ case 10: tex = &kg->__tex_image_010; break;
+ case 11: tex = &kg->__tex_image_011; break;
+ case 12: tex = &kg->__tex_image_012; break;
+ case 13: tex = &kg->__tex_image_013; break;
+ case 14: tex = &kg->__tex_image_014; break;
+ case 15: tex = &kg->__tex_image_015; break;
+ case 16: tex = &kg->__tex_image_016; break;
+ case 17: tex = &kg->__tex_image_017; break;
+ case 18: tex = &kg->__tex_image_018; break;
+ case 19: tex = &kg->__tex_image_019; break;
+ case 20: tex = &kg->__tex_image_020; break;
+ case 21: tex = &kg->__tex_image_021; break;
+ case 22: tex = &kg->__tex_image_022; break;
+ case 23: tex = &kg->__tex_image_023; break;
+ case 24: tex = &kg->__tex_image_024; break;
+ case 25: tex = &kg->__tex_image_025; break;
+ case 26: tex = &kg->__tex_image_026; break;
+ case 27: tex = &kg->__tex_image_027; break;
+ case 28: tex = &kg->__tex_image_028; break;
+ case 29: tex = &kg->__tex_image_029; break;
+ case 30: tex = &kg->__tex_image_030; break;
+ case 31: tex = &kg->__tex_image_031; break;
+ case 32: tex = &kg->__tex_image_032; break;
+ case 33: tex = &kg->__tex_image_033; break;
+ case 34: tex = &kg->__tex_image_034; break;
+ case 35: tex = &kg->__tex_image_035; break;
+ case 36: tex = &kg->__tex_image_036; break;
+ case 37: tex = &kg->__tex_image_037; break;
+ case 38: tex = &kg->__tex_image_038; break;
+ case 39: tex = &kg->__tex_image_039; break;
+ case 40: tex = &kg->__tex_image_040; break;
+ case 41: tex = &kg->__tex_image_041; break;
+ case 42: tex = &kg->__tex_image_042; break;
+ case 43: tex = &kg->__tex_image_043; break;
+ case 44: tex = &kg->__tex_image_044; break;
+ case 45: tex = &kg->__tex_image_045; break;
+ case 46: tex = &kg->__tex_image_046; break;
+ case 47: tex = &kg->__tex_image_047; break;
+ case 48: tex = &kg->__tex_image_048; break;
+ case 49: tex = &kg->__tex_image_049; break;
+ case 50: tex = &kg->__tex_image_050; break;
+ case 51: tex = &kg->__tex_image_051; break;
+ case 52: tex = &kg->__tex_image_052; break;
+ case 53: tex = &kg->__tex_image_053; break;
+ case 54: tex = &kg->__tex_image_054; break;
+ case 55: tex = &kg->__tex_image_055; break;
+ case 56: tex = &kg->__tex_image_056; break;
+ case 57: tex = &kg->__tex_image_057; break;
+ case 58: tex = &kg->__tex_image_058; break;
+ case 59: tex = &kg->__tex_image_059; break;
+ case 60: tex = &kg->__tex_image_060; break;
+ case 61: tex = &kg->__tex_image_061; break;
+ case 62: tex = &kg->__tex_image_062; break;
+ case 63: tex = &kg->__tex_image_063; break;
+ case 64: tex = &kg->__tex_image_064; break;
+ case 65: tex = &kg->__tex_image_065; break;
+ case 66: tex = &kg->__tex_image_066; break;
+ case 67: tex = &kg->__tex_image_067; break;
+ case 68: tex = &kg->__tex_image_068; break;
+ case 69: tex = &kg->__tex_image_069; break;
+ case 70: tex = &kg->__tex_image_070; break;
+ case 71: tex = &kg->__tex_image_071; break;
+ case 72: tex = &kg->__tex_image_072; break;
+ case 73: tex = &kg->__tex_image_073; break;
+ case 74: tex = &kg->__tex_image_074; break;
+ case 75: tex = &kg->__tex_image_075; break;
+ case 76: tex = &kg->__tex_image_076; break;
+ case 77: tex = &kg->__tex_image_077; break;
+ case 78: tex = &kg->__tex_image_078; break;
+ case 79: tex = &kg->__tex_image_079; break;
+ case 80: tex = &kg->__tex_image_080; break;
+ case 81: tex = &kg->__tex_image_081; break;
+ case 82: tex = &kg->__tex_image_082; break;
+ case 83: tex = &kg->__tex_image_083; break;
+ case 84: tex = &kg->__tex_image_084; break;
+ case 85: tex = &kg->__tex_image_085; break;
+ case 86: tex = &kg->__tex_image_086; break;
+ case 87: tex = &kg->__tex_image_087; break;
+ case 88: tex = &kg->__tex_image_088; break;
+ case 89: tex = &kg->__tex_image_089; break;
+ case 90: tex = &kg->__tex_image_090; break;
+ case 91: tex = &kg->__tex_image_091; break;
+ case 92: tex = &kg->__tex_image_092; break;
+ case 93: tex = &kg->__tex_image_093; break;
+ case 94: tex = &kg->__tex_image_094; break;
+ case 95: tex = &kg->__tex_image_095; break;
+ case 96: tex = &kg->__tex_image_096; break;
+ case 97: tex = &kg->__tex_image_097; break;
+ case 98: tex = &kg->__tex_image_098; break;
+ case 99: tex = &kg->__tex_image_099; break;
+ default: break;
+ }
+
+ if(tex) {
+ tex->data = (uchar4*)mem;
+ tex->width = width;
+ tex->height = height;
+ }
+ }
+ else
+ assert(0);
+}
+
+/* Path Tracing */
+
+void kernel_cpu_path_trace(KernelGlobals *kg, float4 *buffer, unsigned int *rng_state, int pass, int x, int y)
+{
+ kernel_path_trace(kg, buffer, rng_state, pass, x, y);
+}
+
+/* Tonemapping */
+
+void kernel_cpu_tonemap(KernelGlobals *kg, uchar4 *rgba, float4 *buffer, int pass, int resolution, int x, int y)
+{
+ kernel_film_tonemap(kg, rgba, buffer, pass, resolution, x, y);
+}
+
+/* Displacement */
+
+void kernel_cpu_displace(KernelGlobals *kg, uint4 *input, float3 *offset, int i)
+{
+ kernel_displace(kg, input, offset, i);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/kernel.cu b/intern/cycles/kernel/kernel.cu
new file mode 100644
index 00000000000..5e5b445ac2c
--- /dev/null
+++ b/intern/cycles/kernel/kernel.cu
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/* CUDA kernel entry points */
+
+#include "kernel_compat_cuda.h"
+#include "kernel_math.h"
+#include "kernel_types.h"
+#include "kernel_globals.h"
+#include "kernel_film.h"
+#include "kernel_path.h"
+#include "kernel_displace.h"
+
+extern "C" __global__ void kernel_cuda_path_trace(float4 *buffer, uint *rng_state, int pass, int sx, int sy, int sw, int sh)
+{
+ int x = sx + blockDim.x*blockIdx.x + threadIdx.x;
+ int y = sy + blockDim.y*blockIdx.y + threadIdx.y;
+
+ if(x < sx + sw && y < sy + sh)
+ kernel_path_trace(NULL, buffer, rng_state, pass, x, y);
+}
+
+extern "C" __global__ void kernel_cuda_tonemap(uchar4 *rgba, float4 *buffer, int pass, int resolution, int sx, int sy, int sw, int sh)
+{
+ int x = sx + blockDim.x*blockIdx.x + threadIdx.x;
+ int y = sy + blockDim.y*blockIdx.y + threadIdx.y;
+
+ if(x < sx + sw && y < sy + sh)
+ kernel_film_tonemap(NULL, rgba, buffer, pass, resolution, x, y);
+}
+
+extern "C" __global__ void kernel_cuda_displace(uint4 *input, float3 *offset, int sx)
+{
+ int x = sx + blockDim.x*blockIdx.x + threadIdx.x;
+
+ kernel_displace(NULL, input, offset, x);
+}
+
diff --git a/intern/cycles/kernel/kernel.h b/intern/cycles/kernel/kernel.h
new file mode 100644
index 00000000000..2bab585c6e6
--- /dev/null
+++ b/intern/cycles/kernel/kernel.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __KERNEL_H__
+#define __KERNEL_H__
+
+/* CPU Kernel Interfae */
+
+#include "util_types.h"
+
+CCL_NAMESPACE_BEGIN
+
+struct KernelGlobals;
+
+KernelGlobals *kernel_globals_create();
+void kernel_globals_free(KernelGlobals *kg);
+
+void *kernel_osl_memory(KernelGlobals *kg);
+bool kernel_osl_use(KernelGlobals *kg);
+
+void kernel_const_copy(KernelGlobals *kg, const char *name, void *host, size_t size);
+void kernel_tex_copy(KernelGlobals *kg, const char *name, device_ptr mem, size_t width, size_t height);
+
+void kernel_cpu_path_trace(KernelGlobals *kg, float4 *buffer, unsigned int *rng_state, int pass, int x, int y);
+void kernel_cpu_tonemap(KernelGlobals *kg, uchar4 *rgba, float4 *buffer, int pass, int resolution, int x, int y);
+
+void kernel_cpu_displace(KernelGlobals *kg, uint4 *input, float3 *offset, int i);
+
+CCL_NAMESPACE_END
+
+#endif /* __KERNEL_H__ */
+
diff --git a/intern/cycles/kernel/kernel_bvh.h b/intern/cycles/kernel/kernel_bvh.h
new file mode 100644
index 00000000000..4dea540e31c
--- /dev/null
+++ b/intern/cycles/kernel/kernel_bvh.h
@@ -0,0 +1,361 @@
+/*
+ * Adapted from code Copyright 2009-2010 NVIDIA Corporation
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/*
+ * "Persistent while-while kernel" used in:
+ *
+ * "Understanding the Efficiency of Ray Traversal on GPUs",
+ * Timo Aila and Samuli Laine,
+ * Proc. High-Performance Graphics 2009
+ */
+
+/* bottom-most stack entry, indicating the end of traversal */
+
+#define ENTRYPOINT_SENTINEL 0x76543210
+/* 64 object BVH + 64 mesh BVH + 64 object node splitting */
+#define BVH_STACK_SIZE 192
+#define BVH_NODE_SIZE 4
+#define TRI_NODE_SIZE 3
+
+__device_inline float3 bvh_inverse_direction(float3 dir)
+{
+ /* avoid divide by zero (ooeps = exp2f(-80.0f)) */
+ float ooeps = 0.00000000000000000000000082718061255302767487140869206996285356581211090087890625f;
+ float3 idir;
+
+ idir.x = 1.0f/((fabsf(dir.x) > ooeps)? dir.x: copysignf(ooeps, dir.x));
+ idir.y = 1.0f/((fabsf(dir.y) > ooeps)? dir.y: copysignf(ooeps, dir.y));
+ idir.z = 1.0f/((fabsf(dir.z) > ooeps)? dir.z: copysignf(ooeps, dir.z));
+
+ return idir;
+}
+
+__device_inline void bvh_instance_push(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *idir, float *t, const float tmax)
+{
+ Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
+
+ *P = transform(&tfm, ray->P);
+
+ float3 dir = transform_direction(&tfm, ray->D);
+
+ float len;
+ dir = normalize_len(dir, &len);
+
+ *idir = bvh_inverse_direction(dir);
+
+ if(*t != FLT_MAX)
+ *t *= len;
+}
+
+__device_inline void bvh_instance_pop(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *idir, float *t, const float tmax)
+{
+ Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
+
+ if(*t != FLT_MAX)
+ *t *= len(transform_direction(&tfm, 1.0f/(*idir)));
+
+ *P = ray->P;
+ *idir = bvh_inverse_direction(ray->D);
+}
+
+/* intersect two bounding boxes */
+__device_inline void bvh_node_intersect(KernelGlobals *kg,
+ bool *traverseChild0, bool *traverseChild1,
+ bool *closestChild1, int *nodeAddr0, int *nodeAddr1,
+ float3 P, float3 idir, float t, int nodeAddr)
+{
+ /* fetch node data */
+ float4 n0xy = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+0);
+ float4 n1xy = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+1);
+ float4 nz = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+2);
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*BVH_NODE_SIZE+3);
+
+ /* intersect ray against child nodes */
+ float3 ood = P * idir;
+ float c0lox = n0xy.x * idir.x - ood.x;
+ float c0hix = n0xy.y * idir.x - ood.x;
+ float c0loy = n0xy.z * idir.y - ood.y;
+ float c0hiy = n0xy.w * idir.y - ood.y;
+ float c0loz = nz.x * idir.z - ood.z;
+ float c0hiz = nz.y * idir.z - ood.z;
+ float c1loz = nz.z * idir.z - ood.z;
+ float c1hiz = nz.w * idir.z - ood.z;
+
+ float c0min_x = min(c0lox, c0hix);
+ float c0min_y = min(c0loy, c0hiy);
+ float c0min_z = min(c0loz, c0hiz);
+
+ float c0min = max4(c0min_x, c0min_y, c0min_z, 0.0f);
+ float c0max = min4(max(c0lox, c0hix), max(c0loy, c0hiy), max(c0loz, c0hiz), t);
+ float c1lox = n1xy.x * idir.x - ood.x;
+ float c1hix = n1xy.y * idir.x - ood.x;
+ float c1loy = n1xy.z * idir.y - ood.y;
+ float c1hiy = n1xy.w * idir.y - ood.y;
+ float c1min = max4(min(c1lox, c1hix), min(c1loy, c1hiy), min(c1loz, c1hiz), 0.0f);
+ float c1max = min4(max(c1lox, c1hix), max(c1loy, c1hiy), max(c1loz, c1hiz), t);
+
+ /* decide which nodes to traverse next */
+ *traverseChild0 = (c0max >= c0min);
+ *traverseChild1 = (c1max >= c1min);
+
+ *nodeAddr0 = __float_as_int(cnodes.x);
+ *nodeAddr1 = __float_as_int(cnodes.y);
+
+ *closestChild1 = (c1min < c0min);
+}
+
+/* Sven Woop's algorithm */
+__device_inline void bvh_triangle_intersect(KernelGlobals *kg, Intersection *isect, float3 P, float3 idir, int object, int triAddr)
+{
+ /* compute and check intersection t-value */
+ float4 v00 = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+0);
+ float4 v11 = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+1);
+ float3 dir = 1.0f/idir;
+
+ float Oz = v00.w - P.x*v00.x - P.y*v00.y - P.z*v00.z;
+ float invDz = 1.0f/(dir.x*v00.x + dir.y*v00.y + dir.z*v00.z);
+ float t = Oz * invDz;
+
+ if(t > 0.0f && t < isect->t) {
+ /* compute and check barycentric u */
+ float Ox = v11.w + P.x*v11.x + P.y*v11.y + P.z*v11.z;
+ float Dx = dir.x*v11.x + dir.y*v11.y + dir.z*v11.z;
+ float u = Ox + t*Dx;
+
+ if(u >= 0.0f) {
+ /* compute and check barycentric v */
+ float4 v22 = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+2);
+ float Oy = v22.w + P.x*v22.x + P.y*v22.y + P.z*v22.z;
+ float Dy = dir.x*v22.x + dir.y*v22.y + dir.z*v22.z;
+ float v = Oy + t*Dy;
+
+ if(v >= 0.0f && u + v <= 1.0f) {
+ /* record intersection */
+ isect->prim = triAddr;
+ isect->object = object;
+ isect->u = u;
+ isect->v = v;
+ isect->t = t;
+ }
+ }
+ }
+}
+
+__device_inline bool scene_intersect(KernelGlobals *kg, const Ray *ray, const bool isshadowray, Intersection *isect)
+{
+ /* traversal stack in CUDA thread-local memory */
+ int traversalStack[BVH_STACK_SIZE];
+ traversalStack[0] = ENTRYPOINT_SENTINEL;
+
+ /* traversal variables in registers */
+ int stackPtr = 0;
+ int nodeAddr = kernel_data.bvh.root;
+
+ /* ray parameters in registers */
+ const float tmax = ray->t;
+ float3 P = ray->P;
+ float3 idir = bvh_inverse_direction(ray->D);
+ int object = ~0;
+
+ isect->t = tmax;
+ isect->object = ~0;
+ isect->prim = ~0;
+ isect->u = 0.0f;
+ isect->v = 0.0f;
+
+ /* traversal loop */
+ do {
+ do
+ {
+ /* traverse internal nodes */
+ while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL)
+ {
+ bool traverseChild0, traverseChild1, closestChild1;
+ int nodeAddrChild1;
+
+ bvh_node_intersect(kg, &traverseChild0, &traverseChild1,
+ &closestChild1, &nodeAddr, &nodeAddrChild1,
+ P, idir, isect->t, nodeAddr);
+
+ if(traverseChild0 != traverseChild1) {
+ /* one child was intersected */
+ if(traverseChild1) {
+ nodeAddr = nodeAddrChild1;
+ }
+ }
+ else {
+ if(!traverseChild0) {
+ /* neither child was intersected */
+ nodeAddr = traversalStack[stackPtr];
+ --stackPtr;
+ }
+ else {
+ /* both children were intersected, push the farther one */
+ if(closestChild1) {
+ int tmp = nodeAddr;
+ nodeAddr = nodeAddrChild1;
+ nodeAddrChild1 = tmp;
+ }
+
+ ++stackPtr;
+ traversalStack[stackPtr] = nodeAddrChild1;
+ }
+ }
+ }
+
+ /* if node is leaf, fetch triangle list */
+ if(nodeAddr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_nodes, (-nodeAddr-1)*BVH_NODE_SIZE+(BVH_NODE_SIZE-1));
+ int primAddr = __float_as_int(leaf.x);
+
+#ifdef __INSTANCING__
+ if(primAddr >= 0) {
+#endif
+ int primAddr2 = __float_as_int(leaf.y);
+
+ /* pop */
+ nodeAddr = traversalStack[stackPtr];
+ --stackPtr;
+
+ /* triangle intersection */
+ while(primAddr < primAddr2) {
+ /* intersect ray against triangle */
+ bvh_triangle_intersect(kg, isect, P, idir, object, primAddr);
+
+ /* shadow ray early termination */
+ if(isshadowray && isect->prim != ~0)
+ return true;
+
+ primAddr++;
+ }
+#ifdef __INSTANCING__
+ }
+ else {
+ /* instance push */
+ object = kernel_tex_fetch(__prim_object, -primAddr-1);
+
+ bvh_instance_push(kg, object, ray, &P, &idir, &isect->t, tmax);
+
+ ++stackPtr;
+ traversalStack[stackPtr] = ENTRYPOINT_SENTINEL;
+
+ nodeAddr = kernel_tex_fetch(__object_node, object);
+ }
+#endif
+ }
+ } while(nodeAddr != ENTRYPOINT_SENTINEL);
+
+#ifdef __INSTANCING__
+ if(stackPtr >= 0) {
+ kernel_assert(object != ~0);
+
+ /* instance pop */
+ bvh_instance_pop(kg, object, ray, &P, &idir, &isect->t, tmax);
+ object = ~0;
+ nodeAddr = traversalStack[stackPtr];
+ --stackPtr;
+ }
+#endif
+ } while(nodeAddr != ENTRYPOINT_SENTINEL);
+
+ return (isect->prim != ~0);
+}
+
+__device_inline float3 ray_offset(float3 P, float3 Ng)
+{
+#ifdef __INTERSECTION_REFINE__
+ const float epsilon_f = 1e-5f;
+ const int epsilon_i = 32;
+
+ float3 res;
+
+ /* x component */
+ if(fabsf(P.x) < epsilon_f) {
+ res.x = P.x + Ng.x*epsilon_f;
+ }
+ else {
+ uint ix = __float_as_uint(P.x);
+ ix += ((ix ^ __float_as_uint(Ng.x)) >> 31)? -epsilon_i: epsilon_i;
+ res.x = __uint_as_float(ix);
+ }
+
+ /* y component */
+ if(fabsf(P.y) < epsilon_f) {
+ res.y = P.y + Ng.y*epsilon_f;
+ }
+ else {
+ uint iy = __float_as_uint(P.y);
+ iy += ((iy ^ __float_as_uint(Ng.y)) >> 31)? -epsilon_i: epsilon_i;
+ res.y = __uint_as_float(iy);
+ }
+
+ /* z component */
+ if(fabsf(P.z) < epsilon_f) {
+ res.z = P.z + Ng.z*epsilon_f;
+ }
+ else {
+ uint iz = __float_as_uint(P.z);
+ iz += ((iz ^ __float_as_uint(Ng.z)) >> 31)? -epsilon_i: epsilon_i;
+ res.z = __uint_as_float(iz);
+ }
+
+ return res;
+#else
+ const float epsilon_f = 1e-4f;
+ return P + epsilon_f*Ng;
+#endif
+}
+
+__device_inline float3 bvh_triangle_refine(KernelGlobals *kg, const Intersection *isect, const Ray *ray)
+{
+ float3 P = ray->P;
+ float3 D = ray->D;
+ float t = isect->t;
+
+#ifdef __INTERSECTION_REFINE__
+ if(isect->object != ~0) {
+ Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_INVERSE_TRANSFORM);
+
+ P = transform(&tfm, P);
+ D = transform_direction(&tfm, D*t);
+ D = normalize_len(D, &t);
+ }
+
+ P = P + D*t;
+
+ float4 v00 = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+0);
+ float Oz = v00.w - P.x*v00.x - P.y*v00.y - P.z*v00.z;
+ float invDz = 1.0f/(D.x*v00.x + D.y*v00.y + D.z*v00.z);
+ float rt = Oz * invDz;
+
+ P = P + D*rt;
+
+ if(isect->object != ~0) {
+ Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_TRANSFORM);
+ P = transform(&tfm, P);
+ }
+
+ return P;
+#else
+ return P + D*t;
+#endif
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/kernel_camera.h b/intern/cycles/kernel/kernel_camera.h
new file mode 100644
index 00000000000..1f93394e078
--- /dev/null
+++ b/intern/cycles/kernel/kernel_camera.h
@@ -0,0 +1,132 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Perspective Camera */
+
+__device void camera_sample_perspective(KernelGlobals *kg, float raster_x, float raster_y, float lens_u, float lens_v, Ray *ray)
+{
+ /* create ray form raster position */
+ Transform rastertocamera = kernel_data.cam.rastertocamera;
+ float3 Pcamera = transform(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
+
+ ray->P = make_float3(0.0f, 0.0f, 0.0f);
+ ray->D = Pcamera;
+
+ /* modify ray for depth of field */
+ float lensradius = kernel_data.cam.lensradius;
+
+ if(lensradius > 0.0f) {
+ /* sample point on lens */
+ float2 lensuv;
+
+ lensuv = concentric_sample_disk(lens_u, lens_v);
+ lensuv *= lensradius;
+
+ /* compute point on plane of focus */
+ float ft = kernel_data.cam.focaldistance/ray->D.z;
+ float3 Pfocus = ray->P + ray->D*ft;
+
+ /* update ray for effect of lens */
+ ray->P = make_float3(lensuv.x, lensuv.y, 0.0f);
+ ray->D = normalize(Pfocus - ray->P);
+ }
+
+ /* transform ray from camera to world */
+ Transform cameratoworld = kernel_data.cam.cameratoworld;
+
+ ray->P = transform(&cameratoworld, ray->P);
+ ray->D = transform_direction(&cameratoworld, ray->D);
+ ray->D = normalize(ray->D);
+
+#ifdef __RAY_DIFFERENTIALS__
+ /* ray differential */
+ float3 Ddiff = transform_direction(&cameratoworld, Pcamera);
+
+ ray->dP.dx = make_float3(0.0f, 0.0f, 0.0f);
+ ray->dP.dy = make_float3(0.0f, 0.0f, 0.0f);
+
+ ray->dD.dx = normalize(Ddiff + kernel_data.cam.dx) - normalize(Ddiff);
+ ray->dD.dy = normalize(Ddiff + kernel_data.cam.dy) - normalize(Ddiff);
+#endif
+
+#ifdef __CAMERA_CLIPPING__
+ /* clipping */
+ ray->P += kernel_data.cam.nearclip*ray->D;
+ ray->t = kernel_data.cam.cliplength;
+#else
+ ray->t = FLT_MAX;
+#endif
+}
+
+/* Orthographic Camera */
+
+__device void camera_sample_orthographic(KernelGlobals *kg, float raster_x, float raster_y, Ray *ray)
+{
+ /* create ray form raster position */
+ Transform rastertocamera = kernel_data.cam.rastertocamera;
+ float3 Pcamera = transform(&rastertocamera, make_float3(raster_x, raster_y, 0.0f));
+
+ ray->P = Pcamera;
+ ray->D = make_float3(0.0f, 0.0f, 1.0f);
+
+ /* transform ray from camera to world */
+ Transform cameratoworld = kernel_data.cam.cameratoworld;
+
+ ray->P = transform(&cameratoworld, ray->P);
+ ray->D = transform_direction(&cameratoworld, ray->D);
+ ray->D = normalize(ray->D);
+
+#ifdef __RAY_DIFFERENTIALS__
+ /* ray differential */
+ ray->dP.dx = kernel_data.cam.dx;
+ ray->dP.dy = kernel_data.cam.dy;
+
+ ray->dD.dx = make_float3(0.0f, 0.0f, 0.0f);
+ ray->dD.dy = make_float3(0.0f, 0.0f, 0.0f);
+#endif
+
+#ifdef __CAMERA_CLIPPING__
+ /* clipping */
+ ray->t = kernel_data.cam.cliplength;
+#else
+ ray->t = FLT_MAX;
+#endif
+}
+
+/* Common */
+
+__device void camera_sample(KernelGlobals *kg, int x, int y, float filter_u, float filter_v, float lens_u, float lens_v, Ray *ray)
+{
+ /* pixel filter */
+ float raster_x = x + kernel_tex_interp(__filter_table, filter_u);
+ float raster_y = y + kernel_tex_interp(__filter_table, filter_v);
+
+ /* motion blur */
+ //ray->time = lerp(time_t, kernel_data.cam.shutter_open, kernel_data.cam.shutter_close);
+
+ /* sample */
+ if(kernel_data.cam.ortho)
+ camera_sample_orthographic(kg, raster_x, raster_y, ray);
+ else
+ camera_sample_perspective(kg, raster_x, raster_y, lens_u, lens_v, ray);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/kernel_compat_cpu.h b/intern/cycles/kernel/kernel_compat_cpu.h
new file mode 100644
index 00000000000..cee0710492f
--- /dev/null
+++ b/intern/cycles/kernel/kernel_compat_cpu.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __KERNEL_COMPAT_CPU_H__
+#define __KERNEL_COMPAT_CPU_H__
+
+#define __KERNEL_CPU__
+
+#include "util_debug.h"
+#include "util_math.h"
+#include "util_types.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Assertions inside the kernel only work for the CPU device, so we wrap it in
+ a macro which is empty for other devices */
+
+#define kernel_assert(cond) assert(cond)
+
+/* Texture types to be compatible with CUDA textures. These are really just
+ simple arrays and after inlining fetch hopefully revert to being a simple
+ pointer lookup. */
+
+template<typename T> struct texture {
+ T fetch(int index)
+ {
+ kernel_assert(index >= 0 && index < width);
+ return data[index];
+ }
+
+ __m128 fetch_m128(int index)
+ {
+ kernel_assert(index >= 0 && index < width);
+ return ((__m128*)data)[index];
+ }
+
+ __m128i fetch_m128i(int index)
+ {
+ kernel_assert(index >= 0 && index < width);
+ return ((__m128i*)data)[index];
+ }
+
+ float interp(float x)
+ {
+ x = clamp(x, 0.0f, 1.0f)*width;
+
+ int index = min((int)x, width-1);
+ int nindex = min(index+1, width-1);
+ float t = x - index;
+
+ return (1.0f - t)*data[index] + t*data[nindex];
+ }
+
+ T *data;
+ int width;
+};
+
+template<typename T> struct texture_image {
+ float4 read(float4 r)
+ {
+ return r;
+ }
+
+ float4 read(uchar4 r)
+ {
+ float f = 1.0f/255.0f;
+ return make_float4(r.x*f, r.y*f, r.z*f, r.w*f);
+ }
+
+ int wrap_periodic(int x, int width)
+ {
+ x %= width;
+ if(x < 0)
+ x += width;
+ return x;
+ }
+
+ int wrap_clamp(int x, int width)
+ {
+ return clamp(x, 0, width-1);
+ }
+
+ float frac(float x, int *ix)
+ {
+ int i = (int)x - ((x < 0.0f)? 1: 0);
+ *ix = i;
+ return x - (float)i;
+ }
+
+ float4 interp(float x, float y, bool periodic = true)
+ {
+ if(!data)
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+
+ int ix, iy, nix, niy;
+ float tx = frac(x*width, &ix);
+ float ty = frac(y*height, &iy);
+
+ if(periodic) {
+ ix = wrap_periodic(ix, width);
+ iy = wrap_periodic(iy, height);
+
+ nix = wrap_periodic(ix+1, width);
+ niy = wrap_periodic(iy+1, height);
+ }
+ else {
+ ix = wrap_clamp(ix, width);
+ iy = wrap_clamp(iy, height);
+
+ nix = wrap_clamp(ix+1, width);
+ niy = wrap_clamp(iy+1, height);
+ }
+
+ float4 r = (1.0f - ty)*(1.0f - tx)*read(data[ix + iy*width]);
+ r += (1.0f - ty)*tx*read(data[nix + iy*width]);
+ r += ty*(1.0f - tx)*read(data[ix + niy*width]);
+ r += ty*tx*read(data[nix + niy*width]);
+
+ return r;
+ }
+
+ T *data;
+ int width, height;
+};
+
+typedef texture<float4> texture_float4;
+typedef texture<float> texture_float;
+typedef texture<uint> texture_uint;
+typedef texture<int> texture_int;
+typedef texture<uint4> texture_uint4;
+typedef texture_image<float4> texture_image_float4;
+typedef texture_image<uchar4> texture_image_uchar4;
+
+/* Macros to handle different memory storage on different devices */
+
+#define kernel_tex_fetch(tex, index) (kg->tex.fetch(index))
+#define kernel_tex_fetch_m128(tex, index) (kg->tex.fetch_m128(index))
+#define kernel_tex_fetch_m128i(tex, index) (kg->tex.fetch_m128i(index))
+#define kernel_tex_interp(tex, t) (kg->tex.interp(t))
+#define kernel_tex_image_interp(tex, x, y) (kg->tex.interp(x, y))
+
+#define kernel_data (kg->__data)
+
+CCL_NAMESPACE_END
+
+#endif /* __KERNEL_COMPAT_CPU_H__ */
+
diff --git a/intern/cycles/kernel/kernel_compat_cuda.h b/intern/cycles/kernel/kernel_compat_cuda.h
new file mode 100644
index 00000000000..99c1df1fb1a
--- /dev/null
+++ b/intern/cycles/kernel/kernel_compat_cuda.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __KERNEL_COMPAT_CUDA_H__
+#define __KERNEL_COMPAT_CUDA_H__
+
+#define __KERNEL_GPU__
+#define __KERNEL_CUDA__
+
+#include <cuda.h>
+#include <float.h>
+
+#include "util_types.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Qualifier wrappers for different names on different devices */
+
+#define __device __device__ __inline__
+#define __device_inline __device__ __inline__
+#define __global
+#define __shared __shared__
+#define __constant __constant__
+
+/* No assert supported for CUDA */
+
+#define kernel_assert(cond)
+
+/* Textures */
+
+typedef texture<float4, 1> texture_float4;
+typedef texture<float, 1> texture_float;
+typedef texture<uint, 1> texture_uint;
+typedef texture<int, 1> texture_int;
+typedef texture<uint4, 1> texture_uint4;
+typedef texture<float4, 2> texture_image_float4;
+typedef texture<uchar4, 2, cudaReadModeNormalizedFloat> texture_image_uchar4;
+
+/* Macros to handle different memory storage on different devices */
+
+#define kernel_tex_fetch(t, index) tex1Dfetch(t, index)
+#define kernel_tex_interp(t, x) tex1D(t, x)
+#define kernel_tex_image_interp(t, x, y) tex2D(t, x, y)
+
+#define kernel_data __data
+
+CCL_NAMESPACE_END
+
+#endif /* __KERNEL_COMPAT_CUDA_H__ */
+
diff --git a/intern/cycles/kernel/kernel_compat_opencl.h b/intern/cycles/kernel/kernel_compat_opencl.h
new file mode 100644
index 00000000000..16ddca5305b
--- /dev/null
+++ b/intern/cycles/kernel/kernel_compat_opencl.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __KERNEL_COMPAT_OPENCL_H__
+#define __KERNEL_COMPAT_OPENCL_H__
+
+#define __KERNEL_GPU__
+#define __KERNEL_OPENCL__
+
+#include "util_types.h"
+
+CCL_NAMESPACE_BEGIN
+
+#define __device
+#define __device_inline
+
+__device float kernel_tex_interp_(__global float *data, int width, float x)
+{
+ x = clamp(x, 0.0f, 1.0f)*width;
+
+ int index = min((int)x, width-1);
+ int nindex = min(index+1, width-1);
+ float t = x - index;
+
+ return (1.0f - t)*data[index] + t*data[nindex];
+}
+
+#define kernel_data (*kg->data)
+#define kernel_tex_interp(t, x) \
+ kernel_tex_interp_(kg->t, kg->t##_width, x);
+
+CCL_NAMESPACE_END
+
+#endif /* __KERNEL_COMPAT_OPENCL_H__ */
+
diff --git a/intern/cycles/kernel/kernel_differential.h b/intern/cycles/kernel/kernel_differential.h
new file mode 100644
index 00000000000..4e2b1ea7d13
--- /dev/null
+++ b/intern/cycles/kernel/kernel_differential.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* See "Tracing Ray Differentials", Homan Igehy, 1999. */
+
+__device void differential_transfer(differential3 *dP_, const differential3 dP, float3 D, const differential3 dD, float3 Ng, float t)
+{
+ /* ray differential transfer through homogenous medium, to
+ * compute dPdx/dy at a shading point from the incoming ray */
+
+ float3 tmp = D/dot(D, Ng);
+ float3 tmpx = dP.dx + t*dD.dx;
+ float3 tmpy = dP.dy + t*dD.dy;
+
+ dP_->dx = tmpx - dot(tmpx, Ng)*tmp;
+ dP_->dy = tmpy - dot(tmpy, Ng)*tmp;
+}
+
+__device void differential_incoming(differential3 *dI, const differential3 dD)
+{
+ /* compute dIdx/dy at a shading point, we just need to negate the
+ * differential of the ray direction */
+
+ dI->dx = -dD.dx;
+ dI->dy = -dD.dy;
+}
+
+__device void differential_dudv(differential *du, differential *dv, float3 dPdu, float3 dPdv, differential3 dP, float3 Ng)
+{
+ /* now we have dPdx/dy from the ray differential transfer, and dPdu/dv
+ * from the primitive, we can compute dudx/dy and dvdx/dy. these are
+ * mainly used for differentials of arbitrary mesh attributes. */
+
+ /* find most stable axis to project to 2D */
+ float xn= fabsf(Ng.x);
+ float yn= fabsf(Ng.y);
+ float zn= fabsf(Ng.z);
+
+ if(zn < xn || zn < yn) {
+ if(yn < xn || yn < zn) {
+ dPdu.x = dPdu.y;
+ dPdv.x = dPdv.y;
+ dP.dx.x = dP.dx.y;
+ dP.dy.x = dP.dy.y;
+ }
+
+ dPdu.y = dPdu.z;
+ dPdv.y = dPdv.z;
+ dP.dx.y = dP.dx.z;
+ dP.dy.y = dP.dy.z;
+ }
+
+ /* using Cramer's rule, we solve for dudx and dvdx in a 2x2 linear system,
+ * and the same for dudy and dvdy. the denominator is the same for both
+ * solutions, so we compute it only once.
+ *
+ * dP.dx = dPdu * dudx + dPdv * dvdx;
+ * dP.dy = dPdu * dudy + dPdv * dvdy; */
+
+ float det = (dPdu.x*dPdv.y - dPdv.x*dPdu.y);
+
+ if(det != 0.0f)
+ det = 1.0f/det;
+
+ du->dx = (dP.dx.x*dPdv.y - dP.dx.y*dPdv.x)*det;
+ dv->dx = (dP.dx.y*dPdu.x - dP.dx.x*dPdu.y)*det;
+
+ du->dy = (dP.dy.x*dPdv.y - dP.dy.y*dPdv.x)*det;
+ dv->dy = (dP.dy.y*dPdu.x - dP.dy.x*dPdu.y)*det;
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/kernel_displace.h b/intern/cycles/kernel/kernel_displace.h
new file mode 100644
index 00000000000..ef6c3810a75
--- /dev/null
+++ b/intern/cycles/kernel/kernel_displace.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+__device void kernel_displace(KernelGlobals *kg, uint4 *input, float3 *offset, int i)
+{
+ /* setup shader data */
+ ShaderData sd;
+ uint4 in = input[i];
+ shader_setup_from_displace(kg, &sd, in.x, in.y, __int_as_float(in.z), __int_as_float(in.w));
+
+ /* evaluate */
+ float3 P = sd.P;
+ shader_eval_displacement(kg, &sd);
+ offset[i] = sd.P - P;
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/kernel_emission.h b/intern/cycles/kernel/kernel_emission.h
new file mode 100644
index 00000000000..6b6033e9ebd
--- /dev/null
+++ b/intern/cycles/kernel/kernel_emission.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Direction Emission */
+
+__device float3 direct_emissive_eval(KernelGlobals *kg, float rando,
+ LightSample *ls, float u, float v, float3 I)
+{
+ /* setup shading at emitter */
+ ShaderData sd;
+
+ shader_setup_from_sample(kg, &sd, ls->P, ls->Ng, I, ls->shader, ls->object, ls->prim, u, v);
+ ls->Ng = sd.Ng;
+
+ /* no path flag, we're evaluating this for all closures. that's weak but
+ we'd have to do multiple evaluations otherwise */
+ shader_eval_surface(kg, &sd, rando, 0);
+
+ float3 eval;
+
+ /* evaluate emissive closure */
+ if(sd.flag & SD_EMISSION)
+ eval = shader_emissive_eval(kg, &sd);
+ else
+ eval = make_float3(0.0f, 0.0f, 0.0f);
+
+ shader_release(kg, &sd);
+
+ return eval;
+}
+
+__device bool direct_emission(KernelGlobals *kg, ShaderData *sd, float randt, float rando,
+ float randu, float randv, Ray *ray, float3 *eval)
+{
+ /* sample a position on a light */
+ LightSample ls;
+
+ light_sample(kg, randt, randu, randv, sd->P, &ls);
+
+ /* compute incoming direction and distance */
+ float t;
+ float3 omega_in = normalize_len(ls.P - sd->P, &t);
+
+ /* compute pdf */
+ float pdf = light_pdf(kg, &ls, -omega_in, t);
+
+ /* evaluate closure */
+ *eval = direct_emissive_eval(kg, rando, &ls, randu, randv, -omega_in);
+
+ if(is_zero(*eval) || pdf == 0.0f)
+ return false;
+
+ /* evaluate BSDF at shading point */
+ float bsdf_pdf;
+ float3 bsdf_eval = shader_bsdf_eval(kg, sd, omega_in, &bsdf_pdf);
+
+ *eval *= bsdf_eval/pdf;
+
+ if(is_zero(*eval))
+ return false;
+
+ if(ls.prim != ~0) {
+ /* multiple importance sampling */
+ float mis_weight = power_heuristic(pdf, bsdf_pdf);
+ *eval *= mis_weight;
+ }
+ else {
+ /* ensure point light works in Watts, this should be handled
+ * elsewhere but for now together with the diffuse emission
+ * closure it works out to the right value */
+ *eval *= 0.25f;
+ }
+
+ /* setup ray */
+ ray->P = ray_offset(sd->P, sd->Ng);
+ ray->D = ray_offset(ls.P, ls.Ng) - ray->P;
+ ray->D = normalize_len(ray->D, &ray->t);
+
+ return true;
+}
+
+/* Indirect Emission */
+
+__device float3 indirect_emission(KernelGlobals *kg, ShaderData *sd, float t, int path_flag, float bsdf_pdf)
+{
+ /* evaluate emissive closure */
+ float3 L = shader_emissive_eval(kg, sd);
+
+ if(!(path_flag & PATH_RAY_SINGULAR)) {
+ /* multiple importance sampling */
+ float pdf = triangle_light_pdf(kg, sd->Ng, sd->I, t);
+ float mis_weight = power_heuristic(bsdf_pdf, pdf);
+
+ return L*mis_weight;
+ }
+
+ return L;
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/kernel_film.h b/intern/cycles/kernel/kernel_film.h
new file mode 100644
index 00000000000..04ea889f4c0
--- /dev/null
+++ b/intern/cycles/kernel/kernel_film.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+__device float4 film_map(KernelGlobals *kg, float4 irradiance, int pass)
+{
+ float scale = kernel_data.film.exposure*(1.0f/(pass+1));
+ float4 result = irradiance*scale;
+
+ if(kernel_data.film.use_response_curve) {
+ /* camera response curve */
+ result.x = kernel_tex_interp(__response_curve_R, result.x);
+ result.y = kernel_tex_interp(__response_curve_G, result.y);
+ result.z = kernel_tex_interp(__response_curve_B, result.z);
+ }
+ else {
+ /* conversion to srgb */
+ result.x = color_scene_linear_to_srgb(result.x);
+ result.y = color_scene_linear_to_srgb(result.y);
+ result.z = color_scene_linear_to_srgb(result.z);
+ }
+
+ return result;
+}
+
+__device uchar4 film_float_to_byte(float4 color)
+{
+ uchar4 result;
+
+ /* simple float to byte conversion */
+ result.x = clamp(color.x*255.0f, 0.0f, 255.0f);
+ result.y = clamp(color.y*255.0f, 0.0f, 255.0f);
+ result.z = clamp(color.z*255.0f, 0.0f, 255.0f);
+ result.w = 255;
+
+ return result;
+}
+
+__device void kernel_film_tonemap(KernelGlobals *kg, __global uchar4 *rgba, __global float4 *buffer, int pass, int resolution, int x, int y)
+{
+ int w = kernel_data.cam.width;
+ int index = x + y*w;
+ float4 irradiance = buffer[index];
+
+ float4 float_result = film_map(kg, irradiance, pass);
+ uchar4 byte_result = film_float_to_byte(float_result);
+
+ rgba[index] = byte_result;
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/kernel_globals.h b/intern/cycles/kernel/kernel_globals.h
new file mode 100644
index 00000000000..4c4f35bb508
--- /dev/null
+++ b/intern/cycles/kernel/kernel_globals.h
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/* Constant Globals */
+
+#ifdef __KERNEL_CPU__
+
+#ifdef WITH_OSL
+#include "osl_globals.h"
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+/* On the CPU, we pass along the struct KernelGlobals to nearly everywhere in
+ the kernel, to access constant data. These are all stored as "textures", but
+ these are really just standard arrays. We can't use actually globals because
+ multiple renders may be running inside the same process. */
+typedef struct KernelGlobals {
+
+#else
+
+/* On the GPU, constant memory textures must be globals, so we can't put them
+ into a struct. As a result we don't actually use this struct and use actual
+ globals and simply pass along a NULL pointer everywhere, which we hope gets
+ optimized out. */
+#ifdef __KERNEL_CUDA__
+typedef struct KernelGlobals {} KernelGlobals;
+#endif
+
+#endif
+
+/* globals */
+__constant KernelData __data;
+
+#ifndef __KERNEL_OPENCL__
+
+/* bvh */
+texture_float4 __bvh_nodes;
+texture_float4 __tri_woop;
+texture_uint __prim_index;
+texture_uint __prim_object;
+texture_uint __object_node;
+
+/* objects */
+texture_float4 __objects;
+
+/* triangles */
+texture_float4 __tri_normal;
+texture_float4 __tri_vnormal;
+texture_float4 __tri_vindex;
+texture_float4 __tri_verts;
+
+/* attributes */
+texture_uint4 __attributes_map;
+texture_float __attributes_float;
+texture_float4 __attributes_float3;
+
+/* lights */
+texture_float4 __light_distribution;
+texture_float4 __light_point;
+
+/* shaders */
+texture_uint4 __svm_nodes;
+
+/* camera/film */
+texture_float __filter_table;
+texture_float __response_curve_R;
+texture_float __response_curve_G;
+texture_float __response_curve_B;
+
+/* sobol */
+texture_uint __sobol_directions;
+
+/* image */
+texture_image_uchar4 __tex_image_000;
+texture_image_uchar4 __tex_image_001;
+texture_image_uchar4 __tex_image_002;
+texture_image_uchar4 __tex_image_003;
+texture_image_uchar4 __tex_image_004;
+texture_image_uchar4 __tex_image_005;
+texture_image_uchar4 __tex_image_006;
+texture_image_uchar4 __tex_image_007;
+texture_image_uchar4 __tex_image_008;
+texture_image_uchar4 __tex_image_009;
+texture_image_uchar4 __tex_image_010;
+texture_image_uchar4 __tex_image_011;
+texture_image_uchar4 __tex_image_012;
+texture_image_uchar4 __tex_image_013;
+texture_image_uchar4 __tex_image_014;
+texture_image_uchar4 __tex_image_015;
+texture_image_uchar4 __tex_image_016;
+texture_image_uchar4 __tex_image_017;
+texture_image_uchar4 __tex_image_018;
+texture_image_uchar4 __tex_image_019;
+texture_image_uchar4 __tex_image_020;
+texture_image_uchar4 __tex_image_021;
+texture_image_uchar4 __tex_image_022;
+texture_image_uchar4 __tex_image_023;
+texture_image_uchar4 __tex_image_024;
+texture_image_uchar4 __tex_image_025;
+texture_image_uchar4 __tex_image_026;
+texture_image_uchar4 __tex_image_027;
+texture_image_uchar4 __tex_image_028;
+texture_image_uchar4 __tex_image_029;
+texture_image_uchar4 __tex_image_030;
+texture_image_uchar4 __tex_image_031;
+texture_image_uchar4 __tex_image_032;
+texture_image_uchar4 __tex_image_033;
+texture_image_uchar4 __tex_image_034;
+texture_image_uchar4 __tex_image_035;
+texture_image_uchar4 __tex_image_036;
+texture_image_uchar4 __tex_image_037;
+texture_image_uchar4 __tex_image_038;
+texture_image_uchar4 __tex_image_039;
+texture_image_uchar4 __tex_image_040;
+texture_image_uchar4 __tex_image_041;
+texture_image_uchar4 __tex_image_042;
+texture_image_uchar4 __tex_image_043;
+texture_image_uchar4 __tex_image_044;
+texture_image_uchar4 __tex_image_045;
+texture_image_uchar4 __tex_image_046;
+texture_image_uchar4 __tex_image_047;
+texture_image_uchar4 __tex_image_048;
+texture_image_uchar4 __tex_image_049;
+texture_image_uchar4 __tex_image_050;
+texture_image_uchar4 __tex_image_051;
+texture_image_uchar4 __tex_image_052;
+texture_image_uchar4 __tex_image_053;
+texture_image_uchar4 __tex_image_054;
+texture_image_uchar4 __tex_image_055;
+texture_image_uchar4 __tex_image_056;
+texture_image_uchar4 __tex_image_057;
+texture_image_uchar4 __tex_image_058;
+texture_image_uchar4 __tex_image_059;
+texture_image_uchar4 __tex_image_060;
+texture_image_uchar4 __tex_image_061;
+texture_image_uchar4 __tex_image_062;
+texture_image_uchar4 __tex_image_063;
+texture_image_uchar4 __tex_image_064;
+texture_image_uchar4 __tex_image_065;
+texture_image_uchar4 __tex_image_066;
+texture_image_uchar4 __tex_image_067;
+texture_image_uchar4 __tex_image_068;
+texture_image_uchar4 __tex_image_069;
+texture_image_uchar4 __tex_image_070;
+texture_image_uchar4 __tex_image_071;
+texture_image_uchar4 __tex_image_072;
+texture_image_uchar4 __tex_image_073;
+texture_image_uchar4 __tex_image_074;
+texture_image_uchar4 __tex_image_075;
+texture_image_uchar4 __tex_image_076;
+texture_image_uchar4 __tex_image_077;
+texture_image_uchar4 __tex_image_078;
+texture_image_uchar4 __tex_image_079;
+texture_image_uchar4 __tex_image_080;
+texture_image_uchar4 __tex_image_081;
+texture_image_uchar4 __tex_image_082;
+texture_image_uchar4 __tex_image_083;
+texture_image_uchar4 __tex_image_084;
+texture_image_uchar4 __tex_image_085;
+texture_image_uchar4 __tex_image_086;
+texture_image_uchar4 __tex_image_087;
+texture_image_uchar4 __tex_image_088;
+texture_image_uchar4 __tex_image_089;
+texture_image_uchar4 __tex_image_090;
+texture_image_uchar4 __tex_image_091;
+texture_image_uchar4 __tex_image_092;
+texture_image_uchar4 __tex_image_093;
+texture_image_uchar4 __tex_image_094;
+texture_image_uchar4 __tex_image_095;
+texture_image_uchar4 __tex_image_096;
+texture_image_uchar4 __tex_image_097;
+texture_image_uchar4 __tex_image_098;
+texture_image_uchar4 __tex_image_099;
+
+#endif
+
+#ifdef __KERNEL_CPU__
+
+#ifdef WITH_OSL
+
+/* On the CPU, we also have the OSL globals here. Most data structures are shared
+ with SVM, the difference is in the shaders and object/mesh attributes. */
+
+OSLGlobals osl;
+
+#endif
+
+} KernelGlobals;
+#endif
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/kernel_light.h b/intern/cycles/kernel/kernel_light.h
new file mode 100644
index 00000000000..537f7ea00f0
--- /dev/null
+++ b/intern/cycles/kernel/kernel_light.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+struct LightSample {
+ float3 P;
+ float3 Ng;
+ int object;
+ int prim;
+ int shader;
+ float weight;
+};
+
+/* Point Light */
+
+__device void point_light_sample(KernelGlobals *kg, int point,
+ float randu, float randv, float3 P, LightSample *ls)
+{
+ float4 f = kernel_tex_fetch(__light_point, point);
+
+ ls->P = make_float3(f.x, f.y, f.z);
+ ls->Ng = normalize(ls->P - P);
+ ls->shader = __float_as_int(f.w);
+ ls->object = ~0;
+ ls->prim = ~0;
+}
+
+__device float point_light_pdf(KernelGlobals *kg, float t)
+{
+ return t*t*kernel_data.integrator.pdf_lights;
+}
+
+/* Triangle Light */
+
+__device void triangle_light_sample(KernelGlobals *kg, int prim, int object,
+ float randu, float randv, LightSample *ls)
+{
+ /* triangle, so get position, normal, shader */
+ ls->P = triangle_sample_MT(kg, prim, randu, randv);
+ ls->Ng = triangle_normal_MT(kg, prim, &ls->shader);
+ ls->object = object;
+ ls->prim = prim;
+
+#ifdef __INSTANCING__
+ /* instance transform */
+ if(ls->object >= 0) {
+ object_position_transform(kg, ls->object, &ls->P);
+ object_normal_transform(kg, ls->object, &ls->Ng);
+ }
+#endif
+}
+
+__device float triangle_light_pdf(KernelGlobals *kg,
+ const float3 Ng, const float3 I, float t)
+{
+ float cos_pi = fabsf(dot(Ng, I));
+
+ if(cos_pi == 0.0f)
+ return 0.0f;
+
+ return (t*t*kernel_data.integrator.pdf_triangles)/cos_pi;
+}
+
+/* Light Distribution */
+
+__device int light_distribution_sample(KernelGlobals *kg, float randt)
+{
+ /* this is basically std::upper_bound as used by pbrt, to find a point light or
+ triangle to emit from, proportional to area. a good improvement would be to
+ also sample proportional to power, though it's not so well defined with
+ OSL shaders. */
+ int first = 0;
+ int len = kernel_data.integrator.num_distribution + 1;
+
+ while(len > 0) {
+ int half_len = len >> 1;
+ int middle = first + half_len;
+
+ if(randt < kernel_tex_fetch(__light_distribution, middle).x) {
+ len = half_len;
+ }
+ else {
+ first = middle + 1;
+ len = len - half_len - 1;
+ }
+ }
+
+ first = max(0, first-1);
+ kernel_assert(first >= 0 && first < kernel_data.integrator.num_distribution);
+
+ return first;
+}
+
+/* Generic Light */
+
+__device void light_sample(KernelGlobals *kg, float randt, float randu, float randv, float3 P, LightSample *ls)
+{
+ /* sample index */
+ int index = light_distribution_sample(kg, randt);
+
+ /* fetch light data */
+ float4 l = kernel_tex_fetch(__light_distribution, index);
+ int prim = __float_as_int(l.y);
+ ls->weight = l.z;
+
+ if(prim >= 0) {
+ int object = __float_as_int(l.w);
+ triangle_light_sample(kg, prim, object, randu, randv, ls);
+ }
+ else {
+ int point = -prim-1;
+ point_light_sample(kg, point, randu, randv, P, ls);
+ }
+}
+
+__device float light_pdf(KernelGlobals *kg, LightSample *ls, float3 I, float t)
+{
+ float pdf;
+
+ if(ls->prim != ~0)
+ pdf = triangle_light_pdf(kg, ls->Ng, I, t);
+ else
+ pdf = point_light_pdf(kg, t);
+
+ return pdf;
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/kernel_math.h b/intern/cycles/kernel/kernel_math.h
new file mode 100644
index 00000000000..165535077da
--- /dev/null
+++ b/intern/cycles/kernel/kernel_math.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __KERNEL_MATH_H__
+#define __KERNEL_MATH_H__
+
+#include "util_color.h"
+#include "util_math.h"
+#include "util_transform.h"
+
+#endif /* __KERNEL_MATH_H__ */
+
diff --git a/intern/cycles/kernel/kernel_mbvh.h b/intern/cycles/kernel/kernel_mbvh.h
new file mode 100644
index 00000000000..3995e782abd
--- /dev/null
+++ b/intern/cycles/kernel/kernel_mbvh.h
@@ -0,0 +1,394 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+#define MBVH_OBJECT_SENTINEL 0x76543210
+#define MBVH_NODE_SIZE 8
+#define MBVH_STACK_SIZE 1024
+#define MBVH_RAY_STACK_SIZE 10000
+
+typedef struct MBVHTask {
+ int node;
+ int index;
+ int num;
+ int object;
+} MBVHTask;
+
+typedef struct MVBHRay {
+ float3 P;
+ float u;
+ float3 idir;
+ float v;
+ float t;
+ int index;
+ int object;
+
+ float3 origP;
+ float3 origD;
+ float tmax;
+} MBVHRay;
+
+__device float3 mbvh_inverse_direction(float3 dir)
+{
+ // Avoid divide by zero (ooeps = exp2f(-80.0f))
+ float ooeps = 0.00000000000000000000000082718061255302767487140869206996285356581211090087890625f;
+ float3 idir;
+
+ idir.x = 1.0f / (fabsf(dir.x) > ooeps ? dir.x : copysignf(ooeps, dir.x));
+ idir.y = 1.0f / (fabsf(dir.y) > ooeps ? dir.y : copysignf(ooeps, dir.y));
+ idir.z = 1.0f / (fabsf(dir.z) > ooeps ? dir.z : copysignf(ooeps, dir.z));
+
+ return idir;
+}
+
+__device void mbvh_instance_push(KernelGlobals *kg, int object, MBVHRay *ray)
+{
+ Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
+
+ ray->P = transform(&tfm, ray->origP);
+
+ float3 dir = ray->origD;
+
+ if(ray->t != ray->tmax) dir *= ray->t;
+
+ dir = transform_direction(&tfm, dir);
+ ray->idir = mbvh_inverse_direction(normalize(dir));
+
+ if(ray->t != ray->tmax) ray->t = len(dir);
+}
+
+__device void mbvh_instance_pop(KernelGlobals *kg, int object, MBVHRay *ray)
+{
+ Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
+
+ if(ray->t != ray->tmax)
+ ray->t = len(transform_direction(&tfm, (1.0f/(ray->idir)) * (ray->t)));
+
+ ray->P = ray->origP;
+ ray->idir = mbvh_inverse_direction(ray->origD);
+}
+
+/* Sven Woop's algorithm */
+__device void mbvh_triangle_intersect(KernelGlobals *kg, MBVHRay *ray, int object, int triAddr)
+{
+ float3 P = ray->P;
+ float3 idir = ray->idir;
+
+ /* compute and check intersection t-value */
+ float4 v00 = kernel_tex_fetch(__tri_woop, triAddr*MBVH_NODE_SIZE+0);
+ float4 v11 = kernel_tex_fetch(__tri_woop, triAddr*MBVH_NODE_SIZE+1);
+ float3 dir = 1.0f/idir;
+
+ float Oz = v00.w - P.x*v00.x - P.y*v00.y - P.z*v00.z;
+ float invDz = 1.0f/(dir.x*v00.x + dir.y*v00.y + dir.z*v00.z);
+ float t = Oz * invDz;
+
+ if(t > 0.0f && t < ray->t) {
+ /* compute and check barycentric u */
+ float Ox = v11.w + P.x*v11.x + P.y*v11.y + P.z*v11.z;
+ float Dx = dir.x*v11.x + dir.y*v11.y + dir.z*v11.z;
+ float u = Ox + t*Dx;
+
+ if(u >= 0.0f) {
+ /* compute and check barycentric v */
+ float4 v22 = kernel_tex_fetch(__tri_woop, triAddr*MBVH_NODE_SIZE+2);
+ float Oy = v22.w + P.x*v22.x + P.y*v22.y + P.z*v22.z;
+ float Dy = dir.x*v22.x + dir.y*v22.y + dir.z*v22.z;
+ float v = Oy + t*Dy;
+
+ if(v >= 0.0f && u + v <= 1.0f) {
+ /* record intersection */
+ ray->index = triAddr;
+ ray->object = object;
+ ray->u = u;
+ ray->v = v;
+ ray->t = t;
+ }
+ }
+ }
+}
+
+__device void mbvh_node_intersect(KernelGlobals *kg, __m128 *traverseChild,
+ __m128 *tHit, float3 P, float3 idir, float t, int nodeAddr)
+{
+ /* X axis */
+ const __m128 bminx = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*MBVH_NODE_SIZE+0);
+ const __m128 t0x = _mm_mul_ps(_mm_sub_ps(bminx, _mm_set_ps1(P.x)), _mm_set_ps1(idir.x));
+ const __m128 bmaxx = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*MBVH_NODE_SIZE+1);
+ const __m128 t1x = _mm_mul_ps(_mm_sub_ps(bmaxx, _mm_set_ps1(P.x)), _mm_set_ps1(idir.x));
+
+ __m128 tmin = _mm_max_ps(_mm_min_ps(t0x, t1x), _mm_setzero_ps());
+ __m128 tmax = _mm_min_ps(_mm_max_ps(t0x, t1x), _mm_set_ps1(t));
+
+ /* Y axis */
+ const __m128 bminy = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*MBVH_NODE_SIZE+2);
+ const __m128 t0y = _mm_mul_ps(_mm_sub_ps(bminy, _mm_set_ps1(P.y)), _mm_set_ps1(idir.y));
+ const __m128 bmaxy = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*MBVH_NODE_SIZE+3);
+ const __m128 t1y = _mm_mul_ps(_mm_sub_ps(bmaxy, _mm_set_ps1(P.y)), _mm_set_ps1(idir.y));
+
+ tmin = _mm_max_ps(_mm_min_ps(t0y, t1y), tmin);
+ tmax = _mm_min_ps(_mm_max_ps(t0y, t1y), tmax);
+
+ /* Z axis */
+ const __m128 bminz = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*MBVH_NODE_SIZE+4);
+ const __m128 t0z = _mm_mul_ps(_mm_sub_ps(bminz, _mm_set_ps1(P.z)), _mm_set_ps1(idir.z));
+ const __m128 bmaxz = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*MBVH_NODE_SIZE+5);
+ const __m128 t1z = _mm_mul_ps(_mm_sub_ps(bmaxz, _mm_set_ps1(P.z)), _mm_set_ps1(idir.z));
+
+ tmin = _mm_max_ps(_mm_min_ps(t0z, t1z), tmin);
+ tmax = _mm_min_ps(_mm_max_ps(t0z, t1z), tmax);
+
+ /* compare and get mask */
+ *traverseChild = _mm_cmple_ps(tmin, tmax);
+
+ /* get distance XXX probably wrong */
+ *tHit = tmin;
+}
+
+static void mbvh_sort_by_length(int id[4], float len[4])
+{
+ for(int i = 1; i < 4; i++) {
+ int j = i - 1;
+
+ while(j >= 0 && len[j] > len[j+1]) {
+ swap(len[j], len[j+1]);
+ swap(id[j], id[j+1]);
+ j--;
+ }
+ }
+}
+
+__device void scene_intersect(KernelGlobals *kg, MBVHRay *rays, int numrays)
+{
+ /* traversal stacks */
+ MBVHTask task_stack[MBVH_STACK_SIZE];
+ int active_ray_stacks[4][MBVH_RAY_STACK_SIZE];
+ int num_task, num_active[4] = {0, 0, 0, 0};
+ __m128i one_mm = _mm_set1_epi32(1);
+
+ /* push root node task on stack */
+ task_stack[0].node = kernel_data.bvh.root;
+ task_stack[0].index = 0;
+ task_stack[0].num = numrays;
+ task_stack[0].object = ~0;
+ num_task = 1;
+
+ /* push all rays in first SIMD lane */
+ for(int i = 0; i < numrays; i++)
+ active_ray_stacks[0][i] = i;
+ num_active[0] = numrays;
+
+ while(num_task >= 1) {
+ /* pop task */
+ MBVHTask task = task_stack[--num_task];
+
+ if(task.node == MBVH_OBJECT_SENTINEL) {
+ /* instance pop */
+
+ /* pop rays from stack */
+ num_active[task.index] -= task.num;
+ int ray_offset = num_active[task.index];
+
+ /* transform rays */
+ for(int i = 0; i < task.num; i++) {
+ MBVHRay *ray = &rays[active_ray_stacks[task.index][ray_offset + i]];
+ mbvh_instance_pop(kg, task.object, ray);
+ }
+ }
+ else if(task.node >= 0) {
+ /* inner node? */
+
+ /* pop rays from stack*/
+ num_active[task.index] -= task.num;
+ int ray_offset = num_active[task.index];
+
+ /* initialze simd values */
+ __m128i num_active_mm = _mm_load_si128((__m128i*)num_active);
+ __m128 len_mm = _mm_set_ps1(0.0f);
+
+ for(int i = 0; i < task.num; i++) {
+ int rayid = active_ray_stacks[task.index][ray_offset + i];
+ MVBHRay *ray = rays + rayid;
+
+ /* intersect 4 QBVH node children */
+ __m128 result;
+ __m128 thit;
+
+ mbvh_node_intersect(kg, &result, &thit, ray->P, ray->idir, ray->t, task.node);
+
+ /* update length for sorting */
+ len_mm = _mm_add_ps(len_mm, _mm_and_ps(thit, result));
+
+ /* push rays on stack */
+ for(int j = 0; j < 4; j++)
+ active_ray_stacks[j][num_active[j]] = rayid;
+
+ /* update num active */
+ __m128i resulti = _mm_and_si128(*((__m128i*)&result), one_mm);
+ num_active_mm = _mm_add_epi32(resulti, num_active_mm);
+ _mm_store_si128((__m128i*)num_active, num_active_mm);
+ }
+
+ if(num_active[0] || num_active[1] || num_active[2] || num_active[3]) {
+ /* load child node addresses */
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, task.node);
+ int child[4] = {
+ __float_as_int(cnodes.x),
+ __float_as_int(cnodes.y),
+ __float_as_int(cnodes.z),
+ __float_as_int(cnodes.w)};
+
+ /* sort nodes by average intersection distance */
+ int ids[4] = {0, 1, 2, 3};
+ float len[4];
+
+ _mm_store_ps(len, len_mm);
+ mbvh_sort_by_length(ids, len);
+
+ /* push new tasks on stack */
+ for(int j = 0; j < 4; j++) {
+ if(num_active[j]) {
+ int id = ids[j];
+
+ task_stack[num_task].node = child[id];
+ task_stack[num_task].index = id;
+ task_stack[num_task].num = num_active[id];
+ task_stack[num_task].object = task.object;
+ num_task++;
+ }
+ }
+ }
+ }
+ else {
+ /* fetch leaf node data */
+ float4 leaf = kernel_tex_fetch(__bvh_nodes, (-task.node-1)*MBVH_NODE_SIZE+(MBVH_NODE_SIZE-2));
+ int triAddr = __float_as_int(leaf.x);
+ int triAddr2 = __float_as_int(leaf.y);
+
+ /* pop rays from stack*/
+ num_active[task.index] -= task.num;
+ int ray_offset = num_active[task.index];
+
+ /* triangles */
+ if(triAddr >= 0) {
+ int i, numq = (task.num >> 2) << 2;
+
+ /* SIMD ray leaf intersection */
+ for(i = 0; i < numq; i += 4) {
+ MBVHRay *ray4[4] = {
+ &rays[active_ray_stacks[task.index][ray_offset + i + 0]],
+ &rays[active_ray_stacks[task.index][ray_offset + i + 1]],
+ &rays[active_ray_stacks[task.index][ray_offset + i + 2]],
+ &rays[active_ray_stacks[task.index][ray_offset + i + 3]]};
+
+ /* load SoA */
+
+ while(triAddr < triAddr2) {
+ mbvh_triangle_intersect(ray4[0], task.object, task.node);
+ mbvh_triangle_intersect(ray4[1], task.object, task.node);
+ mbvh_triangle_intersect(ray4[2], task.object, task.node);
+ mbvh_triangle_intersect(ray4[3], task.object, task.node);
+ triAddr++;
+
+ /* some shadow ray optim could be done by setting t=0 */
+ }
+
+ /* store AoS */
+ }
+
+ /* mono ray leaf intersection */
+ for(; i < task.num; i++) {
+ MBVHRay *ray = &rays[active_ray_stacks[task.index][ray_offset + i]];
+
+ while(triAddr < triAddr2) {
+ mbvh_triangle_intersect(kg, ray, task.object, task.node);
+ triAddr++;
+ }
+ }
+ }
+ else {
+ /* instance push */
+ int object = -triAddr-1;
+ int node = triAddr;
+
+ /* push instance pop task */
+ task_stack[num_task].node = MBVH_OBJECT_SENTINEL;
+ task_stack[num_task].index = task.index;
+ task_stack[num_task].num = task.num;
+ task_stack[num_task].object = object;
+ num_task++;
+
+ num_active[task.index] += task.num;
+
+ /* push node task */
+ task_stack[num_task].node = node;
+ task_stack[num_task].index = task.index;
+ task_stack[num_task].num = task.num;
+ task_stack[num_task].object = object;
+ num_task++;
+
+ for(int i = 0; i < task.num; i++) {
+ int rayid = active_ray_stacks[task.index][ray_offset + i];
+
+ /* push on stack for last task */
+ active_ray_stacks[task.index][num_active[task.index]] = rayid;
+ num_active[task.index]++;
+
+ /* transform ray */
+ MBVHRay *ray = &rays[rayid];
+ mbvh_instance_push(kg, object, ray);
+ }
+ }
+ }
+ }
+}
+
+__device void mbvh_set_ray(MBVHRay *rays, int i, Ray *ray, float tmax)
+{
+ MBVHRay *mray = &rays[i];
+
+ /* ray parameters in registers */
+ mray->P = ray->P;
+ mray->idir = mbvh_inverse_direction(ray->D);
+ mray->t = tmax;
+}
+
+__device bool mbvh_get_intersection(MVBHRay *rays, int i, Intersection *isect, float tmax)
+{
+ MBVHRay *mray = &rays[i];
+
+ if(mray->t == tmax)
+ return false;
+
+ isect->t = mray->t;
+ isect->u = mray->u;
+ isect->v = mray->v;
+ isect->index = mray->index;
+ isect->object = mray->object;
+
+ return true;
+}
+
+__device bool mbvh_get_shadow(MBVHRay *rays, int i, float tmax)
+{
+ return (rays[i].t == tmax);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/kernel_montecarlo.h b/intern/cycles/kernel/kernel_montecarlo.h
new file mode 100644
index 00000000000..6f3a3dd3421
--- /dev/null
+++ b/intern/cycles/kernel/kernel_montecarlo.h
@@ -0,0 +1,196 @@
+/*
+ * Parts adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __KERNEL_MONTECARLO_CL__
+#define __KERNEL_MONTECARLO_CL__
+
+CCL_NAMESPACE_BEGIN
+
+/// Given values x and y on [0,1], convert them in place to values on
+/// [-1,1] uniformly distributed over a unit sphere. This code is
+/// derived from Peter Shirley, "Realistic Ray Tracing", p. 103.
+__device void to_unit_disk(float *x, float *y)
+{
+ float r, phi;
+ float a = 2.0f * (*x) - 1.0f;
+ float b = 2.0f * (*y) - 1.0f;
+ if(a > -b) {
+ if(a > b) {
+ r = a;
+ phi = M_PI_4_F *(b/a);
+ } else {
+ r = b;
+ phi = M_PI_4_F *(2.0f - a/b);
+ }
+ } else {
+ if(a < b) {
+ r = -a;
+ phi = M_PI_4_F *(4.0f + b/a);
+ } else {
+ r = -b;
+ if(b != 0.0f)
+ phi = M_PI_4_F *(6.0f - a/b);
+ else
+ phi = 0.0f;
+ }
+ }
+ *x = r * cosf(phi);
+ *y = r * sinf(phi);
+}
+
+__device_inline void make_orthonormals(const float3 N, float3 *a, float3 *b)
+{
+ if(N.x != N.y || N.x != N.z)
+ *a = make_float3(N.z-N.y, N.x-N.z, N.y-N.x); //(1,1,1)x N
+ else
+ *a = make_float3(N.z-N.y, N.x+N.z, -N.y-N.x); //(-1,1,1)x N
+
+ *a = normalize(*a);
+ *b = cross(N, *a);
+}
+
+__device void make_orthonormals_tangent(const float3 N, const float3 T, float3 *a, float3 *b)
+{
+ *b = cross(N, T);
+ *a = cross(*b, N);
+}
+
+__device_inline void sample_cos_hemisphere(const float3 N,
+ float randu, float randv, float3 *omega_in, float *pdf)
+{
+ // Default closure BSDF implementation: uniformly sample
+ // cosine-weighted hemisphere above the point.
+ to_unit_disk(&randu, &randv);
+ float costheta = sqrtf(max(1.0f - randu * randu - randv * randv, 0.0f));
+ float3 T, B;
+ make_orthonormals(N, &T, &B);
+ *omega_in = randu * T + randv * B + costheta * N;
+ *pdf = costheta *M_1_PI_F;
+}
+
+__device_inline void sample_uniform_hemisphere(const float3 N,
+ float randu, float randv,
+ float3 *omega_in, float *pdf)
+{
+ float z = randu;
+ float r = sqrtf(max(0.f, 1.f - z*z));
+ float phi = 2.f * M_PI_F * randv;
+ float x = r * cosf(phi);
+ float y = r * sinf(phi);
+
+ float3 T, B;
+ make_orthonormals (N, &T, &B);
+ *omega_in = x * T + y * B + z * N;
+ *pdf = 0.5f * M_1_PI_F;
+}
+
+__device float3 sample_uniform_sphere(float u1, float u2)
+{
+ float z = 1.0f - 2.0f*u1;
+ float r = sqrtf(fmaxf(0.0f, 1.0f - z*z));
+ float phi = 2.0f*M_PI_F*u2;
+ float x = r*cosf(phi);
+ float y = r*sinf(phi);
+
+ return make_float3(x, y, z);
+}
+
+__device float power_heuristic(float a, float b)
+{
+ return (a*a)/(a*a + b*b);
+}
+
+__device float2 concentric_sample_disk(float u1, float u2)
+{
+ float r, theta;
+ // Map uniform random numbers to $[-1,1]^2$
+ float sx = 2 * u1 - 1;
+ float sy = 2 * u2 - 1;
+
+ // Map square to $(r,\theta)$
+
+ // Handle degeneracy at the origin
+ if(sx == 0.0f && sy == 0.0f) {
+ return make_float2(0.0f, 0.0f);
+ }
+ if(sx >= -sy) {
+ if(sx > sy) {
+ // Handle first region of disk
+ r = sx;
+ if(sy > 0.0f) theta = sy/r;
+ else theta = 8.0f + sy/r;
+ }
+ else {
+ // Handle second region of disk
+ r = sy;
+ theta = 2.0f - sx/r;
+ }
+ }
+ else {
+ if(sx <= sy) {
+ // Handle third region of disk
+ r = -sx;
+ theta = 4.0f - sy/r;
+ }
+ else {
+ // Handle fourth region of disk
+ r = -sy;
+ theta = 6.0f + sx/r;
+ }
+ }
+
+ theta *= M_PI_4_F;
+ return make_float2(r * cosf(theta), r * sinf(theta));
+}
+
+/* Spherical coordinates <-> Cartesion direction */
+
+__device float2 direction_to_spherical(float3 dir)
+{
+ float theta = acosf(dir.z);
+ float phi = atan2f(dir.x, dir.y);
+
+ return make_float2(theta, phi);
+}
+
+__device float3 spherical_to_direction(float theta, float phi)
+{
+ return make_float3(
+ sinf(theta)*cosf(phi),
+ sinf(theta)*sinf(phi),
+ cosf(theta));
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __KERNEL_MONTECARLO_CL__ */
+
diff --git a/intern/cycles/kernel/kernel_object.h b/intern/cycles/kernel/kernel_object.h
new file mode 100644
index 00000000000..b4c42d3bacc
--- /dev/null
+++ b/intern/cycles/kernel/kernel_object.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+enum ObjectTransform {
+ OBJECT_TRANSFORM = 0,
+ OBJECT_INVERSE_TRANSFORM = 4,
+ OBJECT_NORMAL_TRANSFORM = 8,
+ OBJECT_PROPERTIES = 12
+};
+
+__device_inline Transform object_fetch_transform(KernelGlobals *kg, int object, enum ObjectTransform type)
+{
+ Transform tfm;
+
+ int offset = object*OBJECT_SIZE + (int)type;
+
+ tfm.x = kernel_tex_fetch(__objects, offset + 0);
+ tfm.y = kernel_tex_fetch(__objects, offset + 1);
+ tfm.z = kernel_tex_fetch(__objects, offset + 2);
+ tfm.w = kernel_tex_fetch(__objects, offset + 3);
+
+ return tfm;
+}
+
+__device_inline void object_position_transform(KernelGlobals *kg, int object, float3 *P)
+{
+ Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
+ *P = transform(&tfm, *P);
+}
+
+__device_inline void object_normal_transform(KernelGlobals *kg, int object, float3 *N)
+{
+ Transform tfm = object_fetch_transform(kg, object, OBJECT_NORMAL_TRANSFORM);
+ *N = normalize(transform_direction(&tfm, *N));
+}
+
+__device_inline void object_dir_transform(KernelGlobals *kg, int object, float3 *D)
+{
+ Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
+ *D = transform_direction(&tfm, *D);
+}
+
+__device_inline float object_surface_area(KernelGlobals *kg, int object)
+{
+ int offset = object*OBJECT_SIZE + OBJECT_PROPERTIES;
+ float4 f = kernel_tex_fetch(__objects, offset);
+ return f.x;
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/kernel_path.h b/intern/cycles/kernel/kernel_path.h
new file mode 100644
index 00000000000..15c7e67f101
--- /dev/null
+++ b/intern/cycles/kernel/kernel_path.h
@@ -0,0 +1,263 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "kernel_differential.h"
+#include "kernel_montecarlo.h"
+#include "kernel_triangle.h"
+#include "kernel_object.h"
+#ifdef __QBVH__
+#include "kernel_qbvh.h"
+#else
+#include "kernel_bvh.h"
+#endif
+#include "kernel_camera.h"
+#include "kernel_shader.h"
+#include "kernel_light.h"
+#include "kernel_emission.h"
+#include "kernel_random.h"
+
+CCL_NAMESPACE_BEGIN
+
+#ifdef __MODIFY_TP__
+__device float3 path_terminate_modified_throughput(KernelGlobals *kg, __global float3 *buffer, int x, int y, int pass)
+{
+ /* modify throughput to influence path termination probability, to avoid
+ darker regions receiving fewer samples than lighter regions. also RGB
+ are weighted differently. proper validation still remains to be done. */
+ const float3 weights = make_float3(1.0f, 1.33f, 0.66f);
+ const float3 one = make_float3(1.0f, 1.0f, 1.0f);
+ const int minpass = 5;
+ const float minL = 0.1f;
+
+ if(pass >= minpass) {
+ float3 L = buffer[x + y*kernel_data.cam.width];
+ float3 Lmin = make_float3(minL, minL, minL);
+ float correct = (float)(pass+1)/(float)pass;
+
+ L = film_map(L*correct, pass);
+
+ return weights/clamp(L, Lmin, one);
+ }
+
+ return weights;
+}
+#endif
+
+__device float path_terminate_probability(KernelGlobals *kg, int bounce, const float3 throughput)
+{
+ if(bounce >= kernel_data.integrator.maxbounce)
+ return 0.0f;
+ else if(bounce <= kernel_data.integrator.minbounce)
+ return 1.0f;
+
+ return average(throughput);
+}
+
+__device int path_flag_from_label(int path_flag, int label)
+{
+ /* reflect/transmit */
+ if(label & LABEL_REFLECT) {
+ path_flag |= PATH_RAY_REFLECT;
+ path_flag &= ~PATH_RAY_TRANSMIT;
+ }
+ else {
+ kernel_assert(label & LABEL_TRANSMIT);
+
+ path_flag |= PATH_RAY_TRANSMIT;
+ path_flag &= ~PATH_RAY_REFLECT;
+ }
+
+ /* diffuse/glossy/singular */
+ if(label & LABEL_DIFFUSE) {
+ path_flag |= PATH_RAY_DIFFUSE;
+ path_flag &= ~(PATH_RAY_GLOSSY|PATH_RAY_SINGULAR);
+ }
+ else if(label & LABEL_GLOSSY) {
+ path_flag |= PATH_RAY_GLOSSY;
+ path_flag &= ~(PATH_RAY_DIFFUSE|PATH_RAY_SINGULAR);
+ }
+ else {
+ kernel_assert(label & (LABEL_SINGULAR|LABEL_STRAIGHT));
+
+ path_flag |= PATH_RAY_SINGULAR;
+ path_flag &= ~(PATH_RAY_DIFFUSE|PATH_RAY_GLOSSY);
+ }
+
+ /* ray through transparent is still camera ray */
+ if(!(label & LABEL_STRAIGHT))
+ path_flag &= ~PATH_RAY_CAMERA;
+
+ return path_flag;
+}
+
+__device float3 kernel_path_integrate(KernelGlobals *kg, RNG *rng, int pass, Ray ray, float3 throughput)
+{
+ /* initialize */
+ float3 L = make_float3(0.0f, 0.0f, 0.0f);
+
+#ifdef __EMISSION__
+ float ray_pdf = 0.0f;
+#endif
+ int path_flag = PATH_RAY_CAMERA|PATH_RAY_SINGULAR;
+ int rng_offset = PRNG_BASE_NUM;
+
+ /* path iteration */
+ for(int bounce = 0; ; bounce++, rng_offset += PRNG_BOUNCE_NUM) {
+ /* intersect scene */
+ Intersection isect;
+
+ if(!scene_intersect(kg, &ray, false, &isect)) {
+ /* eval background shader if nothing hit */
+#ifdef __BACKGROUND__
+ ShaderData sd;
+ shader_setup_from_background(kg, &sd, &ray);
+ L += throughput*shader_eval_background(kg, &sd, path_flag);
+ shader_release(kg, &sd);
+#else
+ L += throughputmake_float3(0.8f, 0.8f, 0.8f);
+#endif
+ break;
+ }
+
+ /* setup shading */
+ ShaderData sd;
+ shader_setup_from_ray(kg, &sd, &isect, &ray);
+ float rbsdf = path_rng(kg, rng, pass, rng_offset + PRNG_BSDF);
+ shader_eval_surface(kg, &sd, rbsdf, path_flag);
+
+#ifdef __EMISSION__
+ /* emission */
+ if(kernel_data.integrator.use_emission) {
+ if(sd.flag & SD_EMISSION)
+ L += throughput*indirect_emission(kg, &sd, isect.t, path_flag, ray_pdf);
+
+ /* sample illumination from lights to find path contribution */
+ if((sd.flag & SD_BSDF_HAS_EVAL) &&
+ bounce != kernel_data.integrator.maxbounce) {
+ float light_t = path_rng(kg, rng, pass, rng_offset + PRNG_LIGHT);
+ float light_o = path_rng(kg, rng, pass, rng_offset + PRNG_LIGHT_F);
+ float light_u = path_rng(kg, rng, pass, rng_offset + PRNG_LIGHT_U);
+ float light_v = path_rng(kg, rng, pass, rng_offset + PRNG_LIGHT_V);
+
+ Ray light_ray;
+ float3 light_L;
+
+ if(direct_emission(kg, &sd, light_t, light_o, light_u, light_v, &light_ray, &light_L)) {
+ /* trace shadow ray */
+ if(!scene_intersect(kg, &light_ray, true, &isect))
+ L += throughput*light_L;
+ }
+ }
+ }
+#endif
+
+ /* sample BSDF */
+ float bsdf_pdf;
+ float3 bsdf_eval;
+ float3 bsdf_omega_in;
+ differential3 bsdf_domega_in;
+ float bsdf_u = path_rng(kg, rng, pass, rng_offset + PRNG_BSDF_U);
+ float bsdf_v = path_rng(kg, rng, pass, rng_offset + PRNG_BSDF_V);
+ int label;
+
+ label = shader_bsdf_sample(kg, &sd, bsdf_u, bsdf_v, &bsdf_eval,
+ &bsdf_omega_in, &bsdf_domega_in, &bsdf_pdf);
+
+ shader_release(kg, &sd);
+
+ if(bsdf_pdf == 0.0f || is_zero(bsdf_eval))
+ break;
+
+ /* modify throughput */
+ throughput *= bsdf_eval/bsdf_pdf;
+
+ /* set labels */
+#ifdef __EMISSION__
+ ray_pdf = bsdf_pdf;
+#endif
+
+ path_flag = path_flag_from_label(path_flag, label);
+
+ /* path termination */
+ float probability = path_terminate_probability(kg, bounce, throughput);
+ float terminate = path_rng(kg, rng, pass, rng_offset + PRNG_TERMINATE);
+
+ if(terminate >= probability)
+ break;
+
+ throughput /= probability;
+
+ /* setup ray */
+ ray.P = ray_offset(sd.P, (label & LABEL_TRANSMIT)? -sd.Ng: sd.Ng);
+ ray.D = bsdf_omega_in;
+ ray.t = FLT_MAX;
+#ifdef __RAY_DIFFERENTIALS__
+ ray.dP = sd.dP;
+ ray.dD = bsdf_domega_in;
+#endif
+ }
+
+ return L;
+}
+
+__device void kernel_path_trace(KernelGlobals *kg, __global float4 *buffer, __global uint *rng_state, int pass, int x, int y)
+{
+ /* initialize random numbers */
+ RNG rng;
+
+ float filter_u;
+ float filter_v;
+
+ path_rng_init(kg, rng_state, pass, &rng, x, y, &filter_u, &filter_v);
+
+ /* sample camera ray */
+ Ray ray;
+
+ float lens_u = path_rng(kg, &rng, pass, PRNG_LENS_U);
+ float lens_v = path_rng(kg, &rng, pass, PRNG_LENS_V);
+
+ camera_sample(kg, x, y, filter_u, filter_v, lens_u, lens_v, &ray);
+
+ /* integrate */
+#ifdef __MODIFY_TP__
+ float3 throughput = path_terminate_modified_throughput(kg, buffer, x, y, pass);
+ float3 L = kernel_path_integrate(kg, &rng, pass, ray, throughput)/throughput;
+#else
+ float3 throughput = make_float3(1.0f, 1.0f, 1.0f);
+ float3 L = kernel_path_integrate(kg, &rng, pass, ray, throughput);
+#endif
+
+ /* accumulate result in output buffer */
+ int index = x + y*kernel_data.cam.width;
+
+ float4 result;
+ result.x = L.x;
+ result.y = L.y;
+ result.z = L.z;
+ result.w = 1.0f;
+
+ if(pass == 0)
+ buffer[index] = result;
+ else
+ buffer[index] += result;
+
+ path_rng_end(kg, rng_state, rng, x, y);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/kernel_qbvh.h b/intern/cycles/kernel/kernel_qbvh.h
new file mode 100644
index 00000000000..96e68d797dd
--- /dev/null
+++ b/intern/cycles/kernel/kernel_qbvh.h
@@ -0,0 +1,413 @@
+/*
+ * Adapted from code Copyright 2009-2010 NVIDIA Corporation
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/*
+ * "Persistent while-while kernel" used in:
+ *
+ * "Understanding the Efficiency of Ray Traversal on GPUs",
+ * Timo Aila and Samuli Laine,
+ * Proc. High-Performance Graphics 2009
+ */
+
+/* bottom-most stack entry, indicating the end of traversal */
+
+#define ENTRYPOINT_SENTINEL 0x76543210
+/* 64 object BVH + 64 mesh BVH + 64 object node splitting */
+#define QBVH_STACK_SIZE 192
+#define QBVH_NODE_SIZE 8
+#define TRI_NODE_SIZE 3
+
+__device_inline float3 qbvh_inverse_direction(float3 dir)
+{
+ // Avoid divide by zero (ooeps = exp2f(-80.0f))
+ float ooeps = 0.00000000000000000000000082718061255302767487140869206996285356581211090087890625f;
+ float3 idir;
+
+ idir.x = 1.0f/((fabsf(dir.x) > ooeps)? dir.x: copysignf(ooeps, dir.x));
+ idir.y = 1.0f/((fabsf(dir.y) > ooeps)? dir.y: copysignf(ooeps, dir.y));
+ idir.z = 1.0f/((fabsf(dir.z) > ooeps)? dir.z: copysignf(ooeps, dir.z));
+
+ return idir;
+}
+
+__device_inline void qbvh_instance_push(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *idir, float *t, const float tmax)
+{
+ Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
+
+ *P = transform(&tfm, ray->P);
+
+ float3 dir = transform_direction(&tfm, ray->D);
+
+ float len;
+ dir = normalize_len(dir, &len);
+
+ *idir = qbvh_inverse_direction(dir);
+
+ if(*t != FLT_MAX)
+ *t *= len;
+}
+
+__device_inline void qbvh_instance_pop(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *idir, float *t, const float tmax)
+{
+ Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
+
+ if(*t != FLT_MAX)
+ *t *= len(transform_direction(&tfm, 1.0f/(*idir)));
+
+ *P = ray->P;
+ *idir = qbvh_inverse_direction(ray->D);
+}
+
+#ifdef __KERNEL_CPU__
+
+__device_inline void qbvh_node_intersect(KernelGlobals *kg, int *traverseChild,
+ int nodeAddrChild[4], float3 P, float3 idir, float t, int nodeAddr)
+{
+ /* X axis */
+ const __m128 bminx = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+0);
+ const __m128 t0x = _mm_mul_ps(_mm_sub_ps(bminx, _mm_set_ps1(P.x)), _mm_set_ps1(idir.x));
+ const __m128 bmaxx = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+1);
+ const __m128 t1x = _mm_mul_ps(_mm_sub_ps(bmaxx, _mm_set_ps1(P.x)), _mm_set_ps1(idir.x));
+
+ __m128 tmin = _mm_max_ps(_mm_min_ps(t0x, t1x), _mm_setzero_ps());
+ __m128 tmax = _mm_min_ps(_mm_max_ps(t0x, t1x), _mm_set_ps1(t));
+
+ /* Y axis */
+ const __m128 bminy = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+2);
+ const __m128 t0y = _mm_mul_ps(_mm_sub_ps(bminy, _mm_set_ps1(P.y)), _mm_set_ps1(idir.y));
+ const __m128 bmaxy = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+3);
+ const __m128 t1y = _mm_mul_ps(_mm_sub_ps(bmaxy, _mm_set_ps1(P.y)), _mm_set_ps1(idir.y));
+
+ tmin = _mm_max_ps(_mm_min_ps(t0y, t1y), tmin);
+ tmax = _mm_min_ps(_mm_max_ps(t0y, t1y), tmax);
+
+ /* Z axis */
+ const __m128 bminz = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+4);
+ const __m128 t0z = _mm_mul_ps(_mm_sub_ps(bminz, _mm_set_ps1(P.z)), _mm_set_ps1(idir.z));
+ const __m128 bmaxz = kernel_tex_fetch_m128(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+5);
+ const __m128 t1z = _mm_mul_ps(_mm_sub_ps(bmaxz, _mm_set_ps1(P.z)), _mm_set_ps1(idir.z));
+
+ tmin = _mm_max_ps(_mm_min_ps(t0z, t1z), tmin);
+ tmax = _mm_min_ps(_mm_max_ps(t0z, t1z), tmax);
+
+ /* compare and get mask */
+ *traverseChild = _mm_movemask_ps(_mm_cmple_ps(tmin, tmax));
+
+ /* get node addresses */
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+6);
+
+ nodeAddrChild[0] = __float_as_int(cnodes.x);
+ nodeAddrChild[1] = __float_as_int(cnodes.y);
+ nodeAddrChild[2] = __float_as_int(cnodes.z);
+ nodeAddrChild[3] = __float_as_int(cnodes.w);
+}
+
+#else
+
+__device_inline bool qbvh_bb_intersect(float3 bmin, float3 bmax, float3 P, float3 idir, float t)
+{
+ float t0x = (bmin.x - P.x)*idir.x;
+ float t1x = (bmax.x - P.x)*idir.x;
+ float t0y = (bmin.y - P.y)*idir.y;
+ float t1y = (bmax.y - P.y)*idir.y;
+ float t0z = (bmin.z - P.z)*idir.z;
+ float t1z = (bmax.z - P.z)*idir.z;
+
+ float minx = min(t0x, t1x);
+ float maxx = max(t0x, t1x);
+ float miny = min(t0y, t1y);
+ float maxy = max(t0y, t1y);
+ float minz = min(t0z, t1z);
+ float maxz = max(t0z, t1z);
+
+ float tmin = max4(0.0f, minx, miny, minz);
+ float tmax = min4(t, maxx, maxy, maxz);
+
+ return (tmin <= tmax);
+}
+
+/* intersect four bounding boxes */
+__device_inline void qbvh_node_intersect(KernelGlobals *kg, int *traverseChild,
+ int nodeAddrChild[4], float3 P, float3 idir, float t, int nodeAddr)
+{
+ /* fetch node data */
+ float4 minx = kernel_tex_fetch(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+0);
+ float4 miny = kernel_tex_fetch(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+2);
+ float4 minz = kernel_tex_fetch(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+4);
+ float4 maxx = kernel_tex_fetch(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+1);
+ float4 maxy = kernel_tex_fetch(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+3);
+ float4 maxz = kernel_tex_fetch(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+5);
+
+ /* intersect bounding boxes */
+ bool traverseChild0 = qbvh_bb_intersect(make_float3(minx.x, miny.x, minz.x), make_float3(maxx.x, maxy.x, maxz.x), P, idir, t);
+ bool traverseChild1 = qbvh_bb_intersect(make_float3(minx.y, miny.y, minz.y), make_float3(maxx.y, maxy.y, maxz.y), P, idir, t);
+ bool traverseChild2 = qbvh_bb_intersect(make_float3(minx.z, miny.z, minz.z), make_float3(maxx.z, maxy.z, maxz.z), P, idir, t);
+ bool traverseChild3 = qbvh_bb_intersect(make_float3(minx.w, miny.w, minz.w), make_float3(maxx.w, maxy.w, maxz.w), P, idir, t);
+
+ *traverseChild = 0;
+ if(traverseChild0) *traverseChild |= 1;
+ if(traverseChild1) *traverseChild |= 2;
+ if(traverseChild2) *traverseChild |= 4;
+ if(traverseChild3) *traverseChild |= 8;
+
+ /* get node addresses */
+ float4 cnodes = kernel_tex_fetch(__bvh_nodes, nodeAddr*QBVH_NODE_SIZE+6);
+
+ nodeAddrChild[0] = __float_as_int(cnodes.x);
+ nodeAddrChild[1] = __float_as_int(cnodes.y);
+ nodeAddrChild[2] = __float_as_int(cnodes.z);
+ nodeAddrChild[3] = __float_as_int(cnodes.w);
+}
+
+#endif
+
+/* Sven Woop's algorithm */
+__device_inline void qbvh_triangle_intersect(KernelGlobals *kg, Intersection *isect, float3 P, float3 idir, int object, int triAddr)
+{
+ /* compute and check intersection t-value */
+ float4 v00 = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+0);
+ float4 v11 = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+1);
+ float3 dir = 1.0f/idir;
+
+ float Oz = v00.w - P.x*v00.x - P.y*v00.y - P.z*v00.z;
+ float invDz = 1.0f/(dir.x*v00.x + dir.y*v00.y + dir.z*v00.z);
+ float t = Oz * invDz;
+
+ if(t > 0.0f && t < isect->t) {
+ /* compute and check barycentric u */
+ float Ox = v11.w + P.x*v11.x + P.y*v11.y + P.z*v11.z;
+ float Dx = dir.x*v11.x + dir.y*v11.y + dir.z*v11.z;
+ float u = Ox + t*Dx;
+
+ if(u >= 0.0f) {
+ /* compute and check barycentric v */
+ float4 v22 = kernel_tex_fetch(__tri_woop, triAddr*TRI_NODE_SIZE+2);
+ float Oy = v22.w + P.x*v22.x + P.y*v22.y + P.z*v22.z;
+ float Dy = dir.x*v22.x + dir.y*v22.y + dir.z*v22.z;
+ float v = Oy + t*Dy;
+
+ if(v >= 0.0f && u + v <= 1.0f) {
+ /* record intersection */
+ isect->prim = triAddr;
+ isect->object = object;
+ isect->u = u;
+ isect->v = v;
+ isect->t = t;
+ }
+ }
+ }
+}
+
+__device_inline bool scene_intersect(KernelGlobals *kg, const Ray *ray, const bool isshadowray, Intersection *isect)
+{
+ /* traversal stack in CUDA thread-local memory */
+ int traversalStack[QBVH_STACK_SIZE];
+ traversalStack[0] = ENTRYPOINT_SENTINEL;
+
+ /* traversal variables in registers */
+ int stackPtr = 0;
+ int nodeAddr = kernel_data.bvh.root;
+
+ /* ray parameters in registers */
+ const float tmax = ray->t;
+ float3 P = ray->P;
+ float3 idir = qbvh_inverse_direction(ray->D);
+ int object = ~0;
+
+ isect->t = tmax;
+ isect->object = ~0;
+ isect->prim = ~0;
+ isect->u = 0.0f;
+ isect->v = 0.0f;
+
+ /* traversal loop */
+ do {
+ do
+ {
+ /* traverse internal nodes */
+ while(nodeAddr >= 0 && nodeAddr != ENTRYPOINT_SENTINEL)
+ {
+ int traverseChild, nodeAddrChild[4];
+
+ qbvh_node_intersect(kg, &traverseChild, nodeAddrChild,
+ P, idir, isect->t, nodeAddr);
+
+ if(traverseChild & 1) {
+ ++stackPtr;
+ traversalStack[stackPtr] = nodeAddrChild[0];
+ }
+
+ if(traverseChild & 2) {
+ ++stackPtr;
+ traversalStack[stackPtr] = nodeAddrChild[1];
+ }
+ if(traverseChild & 4) {
+ ++stackPtr;
+ traversalStack[stackPtr] = nodeAddrChild[2];
+ }
+
+ if(traverseChild & 8) {
+ ++stackPtr;
+ traversalStack[stackPtr] = nodeAddrChild[3];
+ }
+
+ nodeAddr = traversalStack[stackPtr];
+ --stackPtr;
+ }
+
+ /* if node is leaf, fetch triangle list */
+ if(nodeAddr < 0) {
+ float4 leaf = kernel_tex_fetch(__bvh_nodes, (-nodeAddr-1)*QBVH_NODE_SIZE+(QBVH_NODE_SIZE-2));
+ int primAddr = __float_as_int(leaf.x);
+
+#ifdef __INSTANCING__
+ if(primAddr >= 0) {
+#endif
+ int primAddr2 = __float_as_int(leaf.y);
+
+ /* pop */
+ nodeAddr = traversalStack[stackPtr];
+ --stackPtr;
+
+ /* triangle intersection */
+ while(primAddr < primAddr2) {
+ /* intersect ray against triangle */
+ qbvh_triangle_intersect(kg, isect, P, idir, object, primAddr);
+
+ /* shadow ray early termination */
+ if(isshadowray && isect->prim != ~0)
+ return true;
+
+ primAddr++;
+ }
+#ifdef __INSTANCING__
+ }
+ else {
+ /* instance push */
+ object = kernel_tex_fetch(__prim_object, -primAddr-1);
+
+ qbvh_instance_push(kg, object, ray, &P, &idir, &isect->t, tmax);
+
+ ++stackPtr;
+ traversalStack[stackPtr] = ENTRYPOINT_SENTINEL;
+
+ nodeAddr = kernel_tex_fetch(__object_node, object);
+ }
+#endif
+ }
+ } while(nodeAddr != ENTRYPOINT_SENTINEL);
+
+#ifdef __INSTANCING__
+ if(stackPtr >= 0) {
+ kernel_assert(object != ~0);
+
+ /* instance pop */
+ qbvh_instance_pop(kg, object, ray, &P, &idir, &isect->t, tmax);
+ object = ~0;
+ nodeAddr = traversalStack[stackPtr];
+ --stackPtr;
+ }
+#endif
+ } while(nodeAddr != ENTRYPOINT_SENTINEL);
+
+ return (isect->prim != ~0);
+}
+
+__device_inline float3 ray_offset(float3 P, float3 Ng)
+{
+#ifdef __INTERSECTION_REFINE__
+ const float epsilon_f = 1e-5f;
+ const int epsilon_i = 32;
+
+ float3 res;
+
+ /* x component */
+ if(fabsf(P.x) < epsilon_f) {
+ res.x = P.x + Ng.x*epsilon_f;
+ }
+ else {
+ uint ix = __float_as_uint(P.x);
+ ix += ((ix ^ __float_as_uint(Ng.x)) >> 31)? -epsilon_i: epsilon_i;
+ res.x = __uint_as_float(ix);
+ }
+
+ /* y component */
+ if(fabsf(P.y) < epsilon_f) {
+ res.y = P.y + Ng.y*epsilon_f;
+ }
+ else {
+ uint iy = __float_as_uint(P.y);
+ iy += ((iy ^ __float_as_uint(Ng.y)) >> 31)? -epsilon_i: epsilon_i;
+ res.y = __uint_as_float(iy);
+ }
+
+ /* z component */
+ if(fabsf(P.z) < epsilon_f) {
+ res.z = P.z + Ng.z*epsilon_f;
+ }
+ else {
+ uint iz = __float_as_uint(P.z);
+ iz += ((iz ^ __float_as_uint(Ng.z)) >> 31)? -epsilon_i: epsilon_i;
+ res.z = __uint_as_float(iz);
+ }
+
+ return res;
+#else
+ const float epsilon_f = 1e-4f;
+ return P + epsilon_f*Ng;
+#endif
+}
+
+__device_inline float3 bvh_triangle_refine(KernelGlobals *kg, const Intersection *isect, const Ray *ray)
+{
+ float3 P = ray->P;
+ float3 D = ray->D;
+ float t = isect->t;
+
+#ifdef __INTERSECTION_REFINE__
+ if(isect->object != ~0) {
+ Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_INVERSE_TRANSFORM);
+
+ P = transform(&tfm, P);
+ D = transform_direction(&tfm, D*t);
+ D = normalize_len(D, &t);
+ }
+
+ P = P + D*t;
+
+ float4 v00 = kernel_tex_fetch(__tri_woop, isect->prim*TRI_NODE_SIZE+0);
+ float Oz = v00.w - P.x*v00.x - P.y*v00.y - P.z*v00.z;
+ float invDz = 1.0f/(D.x*v00.x + D.y*v00.y + D.z*v00.z);
+ float rt = Oz * invDz;
+
+ P = P + D*rt;
+
+ if(isect->object != ~0) {
+ Transform tfm = object_fetch_transform(kg, isect->object, OBJECT_TRANSFORM);
+ P = transform(&tfm, P);
+ }
+
+ return P;
+#else
+ return P + D*t;
+#endif
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/kernel_random.h b/intern/cycles/kernel/kernel_random.h
new file mode 100644
index 00000000000..6c2daafb061
--- /dev/null
+++ b/intern/cycles/kernel/kernel_random.h
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+typedef uint RNG;
+
+#ifdef __SOBOL__
+
+/* High Dimensional Sobol */
+
+/* van der corput radical inverse */
+__device uint van_der_corput(uint bits)
+{
+ bits = (bits << 16) | (bits >> 16);
+ bits = ((bits & 0x00ff00ff) << 8) | ((bits & 0xff00ff00) >> 8);
+ bits = ((bits & 0x0f0f0f0f) << 4) | ((bits & 0xf0f0f0f0) >> 4);
+ bits = ((bits & 0x33333333) << 2) | ((bits & 0xcccccccc) >> 2);
+ bits = ((bits & 0x55555555) << 1) | ((bits & 0xaaaaaaaa) >> 1);
+ return bits;
+}
+
+/* sobol radical inverse */
+__device uint sobol(uint i)
+{
+ uint r = 0;
+
+ for(uint v = 1U << 31; i; i >>= 1, v ^= v >> 1)
+ if(i & 1)
+ r ^= v;
+
+ return r;
+}
+
+/* inverse of sobol radical inverse */
+__device uint sobol_inverse(uint i)
+{
+ const uint msb = 1U << 31;
+ uint r = 0;
+
+ for(uint v = 1; i; i <<= 1, v ^= v << 1)
+ if(i & msb)
+ r ^= v;
+
+ return r;
+}
+
+/* multidimensional sobol with generator matrices
+ dimension 0 and 1 are equal to van_der_corput() and sobol() respectively */
+__device uint sobol_dimension(KernelGlobals *kg, int index, int dimension)
+{
+ uint result = 0;
+ uint i = index;
+
+ for(uint j = 0; i; i >>= 1, j++)
+ if(i & 1)
+ result ^= kernel_tex_fetch(__sobol_directions, 32*dimension + j);
+
+ return result;
+}
+
+/* lookup index and x/y coordinate, assumes m is a power of two */
+__device uint sobol_lookup(const uint m, const uint frame, const uint ex, const uint ey, uint *x, uint *y)
+{
+ /* shift is constant per frame */
+ const uint shift = frame << (m << 1);
+ const uint sobol_shift = sobol(shift);
+ /* van der Corput is its own inverse */
+ const uint lower = van_der_corput(ex << (32 - m));
+ /* need to compensate for ey difference and shift */
+ const uint sobol_lower = sobol(lower);
+ const uint mask = ~-(1 << m) << (32 - m); /* only m upper bits */
+ const uint delta = ((ey << (32 - m)) ^ sobol_lower ^ sobol_shift) & mask;
+ /* only use m upper bits for the index (m is a power of two) */
+ const uint sobol_result = delta | (delta >> m);
+ const uint upper = sobol_inverse(sobol_result);
+ const uint index = shift | upper | lower;
+ *x = van_der_corput(index);
+ *y = sobol_shift ^ sobol_result ^ sobol_lower;
+ return index;
+}
+
+__device_inline float path_rng(KernelGlobals *kg, RNG *rng, int pass, int dimension)
+{
+#ifdef __SOBOL_FULL_SCREEN__
+ uint result = sobol_dimension(kg, *rng, dimension);
+ float r = (float)result * (1.0f/(float)0xFFFFFFFF);
+ return r;
+#else
+ /* compute sobol sequence value using direction vectors */
+ uint result = sobol_dimension(kg, pass, dimension);
+ float r = (float)result * (1.0f/(float)0xFFFFFFFF);
+
+ /* Cranly-Patterson rotation using rng seed */
+ float shift;
+
+ if(dimension & 1)
+ shift = (*rng >> 16)/((float)0xFFFF);
+ else
+ shift = (*rng & 0xFFFF)/((float)0xFFFF);
+
+ return r + shift - floor(r + shift);
+#endif
+}
+
+__device_inline void path_rng_init(KernelGlobals *kg, __global uint *rng_state, int pass, RNG *rng, int x, int y, float *fx, float *fy)
+{
+#ifdef __SOBOL_FULL_SCREEN__
+ uint px, py;
+ uint bits = 16; /* limits us to 65536x65536 and 65536 samples */
+ uint size = 1 << bits;
+ uint frame = pass;
+
+ *rng = sobol_lookup(bits, frame, x, y, &px, &py);
+
+ *fx = size * (float)px * (1.0f/(float)0xFFFFFFFF) - x;
+ *fy = size * (float)py * (1.0f/(float)0xFFFFFFFF) - y;
+#else
+ *rng = rng_state[x + y*kernel_data.cam.width];
+
+ *fx = path_rng(kg, rng, pass, PRNG_FILTER_U);
+ *fy = path_rng(kg, rng, pass, PRNG_FILTER_V);
+#endif
+}
+
+__device void path_rng_end(KernelGlobals *kg, __global uint *rng_state, RNG rng, int x, int y)
+{
+ /* nothing to do */
+}
+
+#else
+
+/* Linear Congruential Generator */
+
+__device float path_rng(KernelGlobals *kg, RNG *rng, int pass, int dimension)
+{
+ /* implicit mod 2^32 */
+ *rng = (1103515245*(*rng) + 12345);
+ return (float)*rng * (1.0f/(float)0xFFFFFFFF);
+}
+
+__device void path_rng_init(KernelGlobals *kg, __global uint *rng_state, int pass, RNG *rng, int x, int y, float *fx, float *fy)
+{
+ /* load state */
+ *rng = rng_state[x + y*kernel_data.cam.width];
+
+ *fx = path_rng(kg, rng, pass, PRNG_FILTER_U);
+ *fy = path_rng(kg, rng, pass, PRNG_FILTER_V);
+}
+
+__device void path_rng_end(KernelGlobals *kg, __global uint *rng_state, RNG rng, int x, int y)
+{
+ /* store state for next pass */
+ rng_state[x + y*kernel_data.cam.width] = rng;
+}
+
+#endif
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/kernel_shader.h b/intern/cycles/kernel/kernel_shader.h
new file mode 100644
index 00000000000..f1abbda7ae5
--- /dev/null
+++ b/intern/cycles/kernel/kernel_shader.h
@@ -0,0 +1,460 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/*
+ * ShaderData, used in four steps:
+ *
+ * Setup from incoming ray, sampled position and background.
+ * Execute for surface, volume or displacement.
+ * Evaluate one or more closures.
+ * Release.
+ *
+ */
+
+#include "svm/bsdf.h"
+#include "svm/emissive.h"
+#include "svm/volume.h"
+#include "svm/svm_bsdf.h"
+#include "svm/svm.h"
+
+#ifdef WITH_OSL
+#include "osl_shader.h"
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+/* ShaderData setup from incoming ray */
+
+__device_inline void shader_setup_from_ray(KernelGlobals *kg, ShaderData *sd,
+ const Intersection *isect, const Ray *ray)
+{
+ /* fetch triangle data */
+ int prim = kernel_tex_fetch(__prim_index, isect->prim);
+ float4 Ns = kernel_tex_fetch(__tri_normal, prim);
+ float3 Ng = make_float3(Ns.x, Ns.y, Ns.z);
+ int shader = __float_as_int(Ns.w);
+
+ /* vectors */
+ sd->P = bvh_triangle_refine(kg, isect, ray);
+ sd->Ng = Ng;
+ sd->N = Ng;
+ sd->I = -ray->D;
+ sd->shader = shader;
+ sd->flag = 0;
+
+ /* triangle */
+#ifdef __INSTANCING__
+ sd->object = isect->object;
+#endif
+ sd->prim = prim;
+#ifdef __UV__
+ sd->u = isect->u;
+ sd->v = isect->v;
+#endif
+
+ /* smooth normal */
+ if(sd->shader < 0) {
+ sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v);
+ sd->shader = -sd->shader;
+ }
+
+#ifdef __DPDU__
+ /* dPdu/dPdv */
+ triangle_dPdudv(kg, &sd->dPdu, &sd->dPdv, sd->prim);
+#endif
+
+#ifdef __INSTANCING__
+ if(sd->object != ~0) {
+ /* instance transform */
+ object_normal_transform(kg, sd->object, &sd->N);
+ object_normal_transform(kg, sd->object, &sd->Ng);
+#ifdef __DPDU__
+ object_dir_transform(kg, sd->object, &sd->dPdu);
+ object_dir_transform(kg, sd->object, &sd->dPdv);
+#endif
+ }
+ else {
+ /* non-instanced object index */
+ sd->object = kernel_tex_fetch(__prim_object, isect->prim);
+ }
+#endif
+
+ /* backfacing test */
+ bool backfacing = (dot(sd->Ng, sd->I) < 0.0f);
+
+ if(backfacing) {
+ sd->flag = SD_BACKFACING;
+ sd->Ng = -sd->Ng;
+ sd->N = -sd->N;
+#ifdef __DPDU__
+ sd->dPdu = -sd->dPdu;
+ sd->dPdv = -sd->dPdv;
+#endif
+ }
+
+#ifdef __RAY_DIFFERENTIALS__
+ /* differentials */
+ differential_transfer(&sd->dP, ray->dP, ray->D, ray->dD, sd->Ng, isect->t);
+ differential_incoming(&sd->dI, ray->dD);
+ differential_dudv(&sd->du, &sd->dv, sd->dPdu, sd->dPdv, sd->dP, sd->Ng);
+#endif
+}
+
+/* ShaderData setup from position sampled on mesh */
+
+__device void shader_setup_from_sample(KernelGlobals *kg, ShaderData *sd,
+ const float3 P, const float3 Ng, const float3 I,
+ int shader, int object, int prim, float u, float v)
+{
+ /* vectors */
+ sd->P = P;
+ sd->N = Ng;
+ sd->Ng = Ng;
+ sd->I = I;
+ sd->shader = shader;
+ sd->flag = 0;
+
+ /* primitive */
+#ifdef __INSTANCING__
+ sd->object = object;
+#endif
+ sd->prim = prim;
+#ifdef __UV__
+ sd->u = u;
+ sd->v = v;
+#endif
+
+ /* detect instancing, for non-instanced the object index is -object-1 */
+ bool instanced = false;
+
+ if(sd->prim != ~0) {
+ if(sd->object >= 0)
+ instanced = true;
+ else
+ sd->object = -sd->object-1;
+ }
+
+ /* smooth normal */
+ if(sd->shader < 0) {
+ sd->N = triangle_smooth_normal(kg, sd->prim, sd->u, sd->v);
+ sd->shader = -sd->shader;
+
+#ifdef __INSTANCING__
+ if(instanced)
+ object_normal_transform(kg, sd->object, &sd->N);
+#endif
+ }
+
+#ifdef __DPDU__
+ /* dPdu/dPdv */
+ if(sd->prim == ~0) {
+ sd->dPdu = make_float3(0.0f, 0.0f, 0.0f);
+ sd->dPdv = make_float3(0.0f, 0.0f, 0.0f);
+ }
+ else {
+ triangle_dPdudv(kg, &sd->dPdu, &sd->dPdv, sd->prim);
+
+#ifdef __INSTANCING__
+ if(instanced) {
+ object_dir_transform(kg, sd->object, &sd->dPdu);
+ object_dir_transform(kg, sd->object, &sd->dPdv);
+ }
+#endif
+ }
+#endif
+
+ /* backfacing test */
+ if(sd->prim != ~0) {
+ bool backfacing = (dot(sd->Ng, sd->I) < 0.0f);
+
+ if(backfacing) {
+ sd->flag = SD_BACKFACING;
+ sd->Ng = -sd->Ng;
+ sd->N = -sd->N;
+#ifdef __DPDU__
+ sd->dPdu = -sd->dPdu;
+ sd->dPdv = -sd->dPdv;
+#endif
+ }
+ }
+
+#ifdef __RAY_DIFFERENTIALS__
+ /* no ray differentials here yet */
+ sd->dP.dx = make_float3(0.0f, 0.0f, 0.0f);
+ sd->dP.dy = make_float3(0.0f, 0.0f, 0.0f);
+ sd->dI.dx = make_float3(0.0f, 0.0f, 0.0f);
+ sd->dI.dy = make_float3(0.0f, 0.0f, 0.0f);
+ sd->du.dx = 0.0f;
+ sd->du.dy = 0.0f;
+ sd->dv.dx = 0.0f;
+ sd->dv.dy = 0.0f;
+#endif
+}
+
+/* ShaderData setup for displacement */
+
+__device void shader_setup_from_displace(KernelGlobals *kg, ShaderData *sd,
+ int object, int prim, float u, float v)
+{
+ float3 P, Ng, I = make_float3(0.0f, 0.0f, 0.0f);
+ int shader;
+
+ P = triangle_point_MT(kg, prim, u, v);
+ Ng = triangle_normal_MT(kg, prim, &shader);
+
+ /* force smooth shading for displacement */
+ if(shader >= 0)
+ shader = -shader;
+
+ /* watch out: no instance transform currently */
+
+ shader_setup_from_sample(kg, sd, P, Ng, I, shader, object, prim, u, v);
+}
+
+/* ShaderData setup from ray into background */
+
+__device_inline void shader_setup_from_background(KernelGlobals *kg, ShaderData *sd, const Ray *ray)
+{
+ /* vectors */
+ sd->P = ray->D;
+ sd->N = -sd->P;
+ sd->Ng = -sd->P;
+ sd->I = -sd->P;
+ sd->shader = kernel_data.background.shader;
+ sd->flag = 0;
+
+#ifdef __INSTANCING__
+ sd->object = ~0;
+#endif
+ sd->prim = ~0;
+#ifdef __UV__
+ sd->u = 0.0f;
+ sd->v = 0.0f;
+#endif
+
+#ifdef __DPDU__
+ /* dPdu/dPdv */
+ sd->dPdu = make_float3(0.0f, 0.0f, 0.0f);
+ sd->dPdv = make_float3(0.0f, 0.0f, 0.0f);
+#endif
+
+#ifdef __RAY_DIFFERENTIALS__
+ /* differentials */
+ sd->dP = ray->dD;
+ differential_incoming(&sd->dI, sd->dP);
+ sd->du.dx = 0.0f;
+ sd->du.dy = 0.0f;
+ sd->dv.dx = 0.0f;
+ sd->dv.dy = 0.0f;
+#endif
+}
+
+/* BSDF */
+
+__device int shader_bsdf_sample(KernelGlobals *kg, const ShaderData *sd,
+ float randu, float randv, float3 *eval,
+ float3 *omega_in, differential3 *domega_in, float *pdf)
+{
+ int label;
+
+ *pdf = 0.0f;
+
+#ifdef WITH_OSL
+ if(kg->osl.use)
+ label = OSLShader::bsdf_sample(sd, randu, randv, *eval, *omega_in, *domega_in, *pdf);
+ else
+#endif
+ label = svm_bsdf_sample(sd, randu, randv, eval, omega_in, domega_in, pdf);
+
+ return label;
+}
+
+__device float3 shader_bsdf_eval(KernelGlobals *kg, const ShaderData *sd,
+ const float3 omega_in, float *pdf)
+{
+ float3 eval;
+
+ *pdf = 0.0f;
+
+#ifdef WITH_OSL
+ if(kg->osl.use)
+ eval = OSLShader::bsdf_eval(sd, omega_in, *pdf);
+ else
+#endif
+ eval = svm_bsdf_eval(sd, omega_in, pdf);
+
+ return eval;
+}
+
+__device void shader_bsdf_blur(KernelGlobals *kg, ShaderData *sd, float roughness)
+{
+#ifdef WITH_OSL
+ if(!kg->osl.use)
+#endif
+ svm_bsdf_blur(sd, roughness);
+}
+
+/* Emission */
+
+__device float3 shader_emissive_eval(KernelGlobals *kg, ShaderData *sd)
+{
+#ifdef WITH_OSL
+ if(kg->osl.use) {
+ return OSLShader::emissive_eval(sd);
+ }
+ else
+#endif
+ {
+ return svm_emissive_eval(sd);
+ }
+}
+
+__device void shader_emissive_sample(KernelGlobals *kg, ShaderData *sd,
+ float randu, float randv, float3 *eval, float3 *I, float *pdf)
+{
+#ifdef WITH_OSL
+ if(kg->osl.use) {
+ OSLShader::emissive_sample(sd, randu, randv, eval, I, pdf);
+ }
+ else
+#endif
+ {
+ svm_emissive_sample(sd, randu, randv, eval, I, pdf);
+ }
+}
+
+/* Surface Evaluation */
+
+__device void shader_eval_surface(KernelGlobals *kg, ShaderData *sd,
+ float randb, int path_flag)
+{
+#ifdef WITH_OSL
+ if(kg->osl.use) {
+ OSLShader::eval_surface(kg, sd, randb, path_flag);
+ }
+ else
+#endif
+ {
+#ifdef __SVM__
+ svm_eval_nodes(kg, sd, SHADER_TYPE_SURFACE, randb, path_flag);
+#else
+ sd->svm_closure = CLOSURE_BSDF_DIFFUSE_ID;
+ sd->svm_closure_weight = make_float3(0.8f, 0.8f, 0.8f);
+#endif
+
+#ifdef __CAUSTICS_TRICKS__
+ /* caustic tricks */
+ if((path_flag & PATH_RAY_DIFFUSE) && (sd->flag & SD_BSDF_GLOSSY)) {
+ if(kernel_data.integrator.no_caustics) {
+ sd->flag &= ~(SD_BSDF_GLOSSY|SD_BSDF_HAS_EVAL|SD_EMISSION);
+ sd->svm_closure = NBUILTIN_CLOSURES;
+ sd->svm_closure_weight = make_float3(0.0f, 0.0f, 0.0f);
+ }
+ else if(kernel_data.integrator.blur_caustics > 0.0f)
+ shader_bsdf_blur(kg, sd, kernel_data.integrator.blur_caustics);
+ }
+#endif
+ }
+}
+
+/* Background Evaluation */
+
+__device float3 shader_eval_background(KernelGlobals *kg, ShaderData *sd, int path_flag)
+{
+#ifdef WITH_OSL
+ if(kg->osl.use) {
+ return OSLShader::eval_background(kg, sd, path_flag);
+ }
+ else
+#endif
+ {
+#ifdef __SVM__
+ svm_eval_nodes(kg, sd, SHADER_TYPE_SURFACE, 0.0f, path_flag);
+#else
+ sd->svm_closure_weight = make_float3(0.8f, 0.8f, 0.8f);
+#endif
+
+ return sd->svm_closure_weight;
+ }
+}
+
+/* Volume */
+
+__device float3 shader_volume_eval_phase(KernelGlobals *kg, ShaderData *sd,
+ float3 omega_in, float3 omega_out)
+{
+#ifdef WITH_OSL
+ if(kg->osl.use) {
+ OSLShader::volume_eval_phase(sd, omega_in, omega_out);
+ }
+ else
+#endif
+ {
+ return volume_eval_phase(sd, omega_in, omega_out);
+ }
+}
+
+/* Volume Evaluation */
+
+__device void shader_eval_volume(KernelGlobals *kg, ShaderData *sd,
+ float randb, int path_flag)
+{
+#ifdef WITH_OSL
+ if(kg->osl.use) {
+ OSLShader::eval_volume(kg, sd, randb, path_flag);
+ }
+ else
+#endif
+ {
+#ifdef __SVM__
+ svm_eval_nodes(kg, sd, SHADER_TYPE_VOLUME, randb, path_flag);
+#endif
+ }
+}
+
+/* Displacement Evaluation */
+
+__device void shader_eval_displacement(KernelGlobals *kg, ShaderData *sd)
+{
+ /* this will modify sd->P */
+
+#ifdef WITH_OSL
+ if(kg->osl.use) {
+ OSLShader::eval_displacement(kg, sd);
+ }
+ else
+#endif
+ {
+#ifdef __SVM__
+ svm_eval_nodes(kg, sd, SHADER_TYPE_DISPLACEMENT, 0.0f, 0);
+#endif
+ }
+}
+
+/* Free ShaderData */
+
+__device void shader_release(KernelGlobals *kg, ShaderData *sd)
+{
+#ifdef WITH_OSL
+ if(kg->osl.use)
+ OSLShader::release(kg, sd);
+#endif
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/kernel_triangle.h b/intern/cycles/kernel/kernel_triangle.h
new file mode 100644
index 00000000000..64cbb2dcb61
--- /dev/null
+++ b/intern/cycles/kernel/kernel_triangle.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Point on triangle for Moller-Trumbore triangles */
+__device_inline float3 triangle_point_MT(KernelGlobals *kg, int tri_index, float u, float v)
+{
+ /* load triangle vertices */
+ float3 tri_vindex = as_float3(kernel_tex_fetch(__tri_vindex, tri_index));
+
+ float3 v0 = as_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x)));
+ float3 v1 = as_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y)));
+ float3 v2 = as_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z)));
+
+ /* compute point */
+ float t = 1.0f - u - v;
+ return (u*v0 + v*v1 + t*v2);
+}
+
+/* Sample point on triangle */
+__device_inline float3 triangle_sample_MT(KernelGlobals *kg, int tri_index, float randu, float randv)
+{
+ /* compute point */
+ randu = sqrtf(randu);
+
+ float u = 1.0f - randu;
+ float v = randv*randu;
+
+ return triangle_point_MT(kg, tri_index, u, v);
+}
+
+/* Normal for Moller-Trumbore triangles */
+__device_inline float3 triangle_normal_MT(KernelGlobals *kg, int tri_index, int *shader)
+{
+#if 0
+ /* load triangle vertices */
+ float3 tri_vindex = as_float3(kernel_tex_fetch(__tri_vindex, tri_index));
+
+ float3 v0 = as_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x)));
+ float3 v1 = as_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y)));
+ float3 v2 = as_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z)));
+
+ /* compute normal */
+ return normalize(cross(v2 - v0, v1 - v0));
+#else
+ float4 Nm = kernel_tex_fetch(__tri_normal, tri_index);
+ *shader = __float_as_int(Nm.w);
+ return make_float3(Nm.x, Nm.y, Nm.z);
+#endif
+}
+
+__device_inline float3 triangle_smooth_normal(KernelGlobals *kg, int tri_index, float u, float v)
+{
+ /* load triangle vertices */
+ float3 tri_vindex = as_float3(kernel_tex_fetch(__tri_vindex, tri_index));
+
+ float3 n0 = as_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.x)));
+ float3 n1 = as_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.y)));
+ float3 n2 = as_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.z)));
+
+ return normalize((1.0f - u - v)*n2 + u*n0 + v*n1);
+}
+
+__device_inline void triangle_dPdudv(KernelGlobals *kg, float3 *dPdu, float3 *dPdv, int tri)
+{
+ /* fetch triangle vertex coordinates */
+ float3 tri_vindex = as_float3(kernel_tex_fetch(__tri_vindex, tri));
+
+ float3 p0 = as_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x)));
+ float3 p1 = as_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y)));
+ float3 p2 = as_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z)));
+
+ /* compute derivatives of P w.r.t. uv */
+ *dPdu = (p0 - p2);
+ *dPdv = (p1 - p2);
+}
+
+/* attributes */
+
+__device float triangle_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy)
+{
+ if(elem == ATTR_ELEMENT_FACE) {
+ if(dx) *dx = 0.0f;
+ if(dy) *dy = 0.0f;
+
+ return kernel_tex_fetch(__attributes_float, offset + sd->prim);
+ }
+ else if(elem == ATTR_ELEMENT_VERTEX) {
+ float3 tri_vindex = as_float3(kernel_tex_fetch(__tri_vindex, sd->prim));
+
+ float f0 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.x));
+ float f1 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.y));
+ float f2 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.z));
+
+#ifdef __RAY_DIFFERENTIALS__
+ if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2;
+ if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2;
+#endif
+
+ return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2;
+ }
+ else if(elem == ATTR_ELEMENT_CORNER) {
+ int tri = offset + sd->prim;
+ float f0 = kernel_tex_fetch(__attributes_float, tri*3 + 0);
+ float f1 = kernel_tex_fetch(__attributes_float, tri*3 + 1);
+ float f2 = kernel_tex_fetch(__attributes_float, tri*3 + 2);
+
+#ifdef __RAY_DIFFERENTIALS__
+ if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2;
+ if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2;
+#endif
+
+ return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2;
+ }
+ else {
+ if(dx) *dx = 0.0f;
+ if(dy) *dy = 0.0f;
+
+ return 0.0f;
+ }
+}
+
+__device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy)
+{
+ if(elem == ATTR_ELEMENT_FACE) {
+ if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
+ if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
+
+ return as_float3(kernel_tex_fetch(__attributes_float3, offset + sd->prim));
+ }
+ else if(elem == ATTR_ELEMENT_VERTEX) {
+ float3 tri_vindex = as_float3(kernel_tex_fetch(__tri_vindex, sd->prim));
+
+ float3 f0 = as_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.x)));
+ float3 f1 = as_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.y)));
+ float3 f2 = as_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.z)));
+
+#ifdef __RAY_DIFFERENTIALS__
+ if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2;
+ if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2;
+#endif
+
+ return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2;
+ }
+ else if(elem == ATTR_ELEMENT_CORNER) {
+ int tri = offset + sd->prim;
+ float3 f0 = as_float3(kernel_tex_fetch(__attributes_float3, tri*3 + 0));
+ float3 f1 = as_float3(kernel_tex_fetch(__attributes_float3, tri*3 + 1));
+ float3 f2 = as_float3(kernel_tex_fetch(__attributes_float3, tri*3 + 2));
+
+#ifdef __RAY_DIFFERENTIALS__
+ if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2;
+ if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2;
+#endif
+
+ return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2;
+ }
+ else {
+ if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
+ if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
+
+ return make_float3(0.0f, 0.0f, 0.0f);
+ }
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/kernel_types.h b/intern/cycles/kernel/kernel_types.h
new file mode 100644
index 00000000000..8e378d2871b
--- /dev/null
+++ b/intern/cycles/kernel/kernel_types.h
@@ -0,0 +1,374 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __KERNEL_TYPES_H__
+#define __KERNEL_TYPES_H__
+
+#include "kernel_math.h"
+
+#ifndef __KERNEL_OPENCL__
+
+#include "svm_types.h"
+
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+#define OBJECT_SIZE 16
+
+#define __INSTANCING__
+#define __DPDU__
+#define __UV__
+#define __BACKGROUND__
+#define __EMISSION__
+#define __CAUSTICS_TRICKS__
+#define __SVM__
+#define __SOBOL__
+#define __TEXTURES__
+#define __RAY_DIFFERENTIALS__
+#define __CAMERA_CLIPPING__
+#define __INTERSECTION_REFINE__
+//#define __SOBOL_FULL_SCREEN__
+//#define __MODIFY_TP__
+//#define __QBVH__
+
+/* Path Tracing */
+
+enum PathTraceDimension {
+ PRNG_FILTER_U = 0,
+ PRNG_FILTER_V = 1,
+ PRNG_LENS_U = 2,
+ PRNG_LENS_V = 3,
+ PRNG_BASE_NUM = 4,
+
+ PRNG_BSDF_U = 0,
+ PRNG_BSDF_V = 1,
+ PRNG_BSDF = 2,
+ PRNG_LIGHT = 3,
+ PRNG_LIGHT_U = 4,
+ PRNG_LIGHT_V = 5,
+ PRNG_LIGHT_F = 6,
+ PRNG_TERMINATE = 7,
+ PRNG_BOUNCE_NUM = 8
+};
+
+/* these flag values correspond exactly to OSL defaults, so be careful not to
+ * change this, or if you do, set the "raytypes" shading system attribute with
+ * your own new ray types and bitflag values */
+enum PathRayFlag {
+ PATH_RAY_CAMERA = 1,
+ PATH_RAY_SHADOW = 2,
+ PATH_RAY_REFLECT = 4,
+ PATH_RAY_TRANSMIT = 8,
+ PATH_RAY_DIFFUSE = 16,
+ PATH_RAY_GLOSSY = 32,
+ PATH_RAY_SINGULAR = 64
+};
+
+/* Bidirectional Path Tracing */
+
+enum BidirTraceDimension {
+ BRNG_FILTER_U = 0,
+ BRNG_FILTER_V = 1,
+ BRNG_LENS_U = 2,
+ BRNG_LENS_V = 3,
+ BRNG_LIGHT_U = 4,
+ BRNG_LIGHT_V = 5,
+ BRNG_LIGHT = 6,
+ BRNG_LIGHT_F = 7,
+ BRNG_EMISSIVE_U = 8,
+ BRNG_EMISSIVE_V = 9,
+ BRNG_BASE_NUM = 10,
+
+ BRNG_BSDF_U = 0,
+ BRNG_BSDF_V = 1,
+ BRNG_BSDF = 2,
+ BRNG_TERMINATE = 3,
+ BRNG_BOUNCE_NUM = 4
+};
+
+/* Closure Label */
+
+typedef enum ClosureLabel {
+ LABEL_NONE = 0,
+ LABEL_CAMERA = 1,
+ LABEL_LIGHT = 2,
+ LABEL_BACKGROUND = 4,
+ LABEL_TRANSMIT = 8,
+ LABEL_REFLECT = 16,
+ LABEL_VOLUME = 32,
+ LABEL_OBJECT = 64,
+ LABEL_DIFFUSE = 128,
+ LABEL_GLOSSY = 256,
+ LABEL_SINGULAR = 512,
+ LABEL_STRAIGHT = 1024,
+ LABEL_STOP = 2048
+} ClosureLabel;
+
+/* Ray Type */
+
+typedef enum RayType {
+ RayTypeCamera = 1,
+ RayTypeShadow = 2,
+ RayTypeReflection = 4,
+ RayTypeRefraction = 8,
+ RayTypeDiffuse = 16,
+ RayTypeGlossy = 32
+} RayType;
+
+/* Differential */
+
+typedef struct differential3 {
+ float3 dx;
+ float3 dy;
+} differential3;
+
+typedef struct differential {
+ float dx;
+ float dy;
+} differential;
+
+/* Ray */
+
+typedef struct Ray {
+ float3 P;
+ float3 D;
+ float t;
+
+#ifdef __RAY_DIFFERENTIALS__
+ differential3 dP;
+ differential3 dD;
+#endif
+} Ray;
+
+/* Intersection */
+
+typedef struct Intersection {
+ float t, u, v;
+ int prim;
+ int object;
+} Intersection;
+
+/* Attributes */
+
+typedef enum AttributeElement {
+ ATTR_ELEMENT_FACE,
+ ATTR_ELEMENT_VERTEX,
+ ATTR_ELEMENT_CORNER,
+ ATTR_ELEMENT_VALUE,
+ ATTR_ELEMENT_NONE
+} AttributeElement;
+
+/* OSL data */
+
+#if !defined(__KERNEL_GPU__) && defined(WITH_OSL)
+
+#define MAX_OSL_CLOSURE 8
+
+struct FlatClosure {
+ void *prim;
+ float3 weight;
+ float sample_weight;
+};
+
+#endif
+
+/* Shader Data
+ *
+ * Main shader state at a point on the surface or in a volume. All coordinates
+ * are in world space. */
+
+enum ShaderDataFlag {
+ SD_BACKFACING = 1, /* backside of surface? */
+ SD_EMISSION = 2, /* have emissive closure? */
+ SD_BSDF_HAS_EVAL = 4, /* have non-singular bsdf closure? */
+ SD_BSDF_GLOSSY = 8 /* have glossy bsdf */
+};
+
+typedef struct ShaderData {
+ /* position */
+ float3 P;
+ /* smooth normal for shading */
+ float3 N;
+ /* true geometric normal */
+ float3 Ng;
+ /* view/incoming direction */
+ float3 I;
+ /* shader id */
+ int shader;
+ /* booleans describing shader, see ShaderDataFlag */
+ int flag;
+
+ /* primitive id if there is one, ~0 otherwise */
+ int prim;
+ /* parametric coordinates
+ * - barycentric weights for triangles
+ * - latlong coordinates for background */
+ float u, v;
+ /* object id if there is one, ~0 otherwise */
+ int object;
+
+#ifdef __RAY_DIFFERENTIALS__
+ /* differential of P. these are orthogonal to Ng, not N */
+ differential3 dP;
+ /* differential of I */
+ differential3 dI;
+ /* differential of u, v */
+ differential du;
+ differential dv;
+#endif
+#ifdef __DPDU__
+ /* differential of P w.r.t. parametric coordinates. note that dPdu is
+ * not readily suitable as a tangent for shading on triangles. */
+ float3 dPdu, dPdv;
+#endif
+
+ /* SVM closure data. we always sample a single closure, to get fixed
+ * memory usage, svm_closure_data contains closure parameters. */
+#ifndef __KERNEL_OPENCL__
+ ClosureType svm_closure;
+#endif
+ float3 svm_closure_weight;
+ float svm_closure_data[3]; /* CUDA gives compile error if out of bounds */
+
+#if !defined(__KERNEL_GPU__) && defined(WITH_OSL)
+ /* OSL closure data and context. we store all closures flattened into
+ * lists per type, different from SVM. */
+ struct {
+ FlatClosure bsdf[MAX_OSL_CLOSURE];
+ FlatClosure emissive[MAX_OSL_CLOSURE];
+ FlatClosure volume[MAX_OSL_CLOSURE];
+
+ int num_bsdf;
+ int num_emissive;
+ int num_volume;
+
+ float bsdf_sample_sum;
+ float emissive_sample_sum;
+ float volume_sample_sum;
+
+ float randb;
+ } osl_closure;
+
+ void *osl_ctx;
+#endif
+} ShaderData;
+
+/* Constrant Kernel Data */
+
+typedef struct KernelCamera {
+ /* type */
+ int ortho;
+ int pad;
+
+ /* size */
+ int width, height;
+
+ /* matrices */
+ Transform cameratoworld;
+ Transform rastertocamera;
+
+ /* depth of field */
+ float lensradius;
+ float focaldistance;
+
+ /* motion blur */
+ float shutteropen;
+ float shutterclose;
+
+ /* differentials */
+ float3 dx, dy;
+
+ /* clipping */
+ float nearclip;
+ float cliplength;
+
+ /* more matrices */
+ Transform screentoworld;
+ Transform rastertoworld;
+ Transform ndctoworld;
+ Transform worldtoscreen;
+ Transform worldtoraster;
+ Transform worldtondc;
+ Transform worldtocamera;
+} KernelCamera;
+
+typedef struct KernelFilm {
+ float exposure;
+ int use_response_curve;
+ int pad1, pad2;
+} KernelFilm;
+
+typedef struct KernelBackground {
+ /* only shader index */
+ int shader;
+ int pad1, pad2, pad3;
+} KernelBackground;
+
+typedef struct KernelSunSky {
+ /* sun direction in spherical and cartesian */
+ float theta, phi;
+ float3 dir;
+ float pad;
+
+ /* perez function parameters */
+ float zenith_Y, zenith_x, zenith_y;
+ float perez_Y[5], perez_x[5], perez_y[5];
+} KernelSunSky;
+
+typedef struct KernelIntegrator {
+ /* emission */
+ int use_emission;
+ int num_triangles;
+ int num_distribution;
+ int num_lights;
+ float pdf_triangles;
+ float pdf_lights;
+
+ /* path tracing */
+ int minbounce;
+ int maxbounce;
+
+ /* caustics */
+ int no_caustics;
+ float blur_caustics;
+
+ /* padding */
+ int pad;
+} KernelIntegrator;
+
+typedef struct KernelBVH {
+ /* root node */
+ int root;
+ int attributes_map_stride;
+ int pad1, pad2;
+} KernelBVH;
+
+typedef struct KernelData {
+ KernelCamera cam;
+ KernelFilm film;
+ KernelBackground background;
+ KernelSunSky sunsky;
+ KernelIntegrator integrator;
+ KernelBVH bvh;
+} KernelData;
+
+CCL_NAMESPACE_END
+
+#endif /* __KERNEL_TYPES_H__ */
+
diff --git a/intern/cycles/kernel/osl/CMakeLists.txt b/intern/cycles/kernel/osl/CMakeLists.txt
new file mode 100644
index 00000000000..3ca3fa4cd6b
--- /dev/null
+++ b/intern/cycles/kernel/osl/CMakeLists.txt
@@ -0,0 +1,33 @@
+
+INCLUDE_DIRECTORIES(. ../ ../svm ../../render ../../util ../../device)
+
+SET(sources
+ background.cpp
+ bsdf_ashikhmin_velvet.cpp
+ bsdf_diffuse.cpp
+ bsdf_microfacet.cpp
+ bsdf_reflection.cpp
+ bsdf_refraction.cpp
+ bsdf_transparent.cpp
+ bsdf_ward.cpp
+ bsdf_westin.cpp
+ bssrdf.cpp
+ debug.cpp
+ emissive.cpp
+ osl_closures.cpp
+ osl_services.cpp
+ osl_shader.cpp
+ vol_subsurface.cpp)
+
+SET(headers
+ osl_closures.h
+ osl_globals.h
+ osl_services.h
+ osl_shader.h)
+
+SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${RTTI_DISABLE_FLAGS}")
+
+ADD_LIBRARY(kernel_osl ${sources} ${headers})
+
+ADD_SUBDIRECTORY(nodes)
+
diff --git a/intern/cycles/kernel/osl/background.cpp b/intern/cycles/kernel/osl/background.cpp
new file mode 100644
index 00000000000..c35119ae9cf
--- /dev/null
+++ b/intern/cycles/kernel/osl/background.cpp
@@ -0,0 +1,100 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <OpenImageIO/fmath.h>
+
+#include <OSL/genclosure.h>
+
+#include "osl_closures.h"
+
+CCL_NAMESPACE_BEGIN
+
+using namespace OSL;
+
+/// Generic background closure
+///
+/// We only have a background closure for the shaders
+/// to return a color in background shaders. No methods,
+/// only the weight is taking into account
+///
+class GenericBackgroundClosure : public BackgroundClosure {
+public:
+ GenericBackgroundClosure() { }
+
+ void setup() {};
+
+ size_t memsize () const { return sizeof(*this); }
+
+ const char *name () const { return "background"; }
+
+ void print_on (std::ostream &out) const {
+ out << name() << " ()";
+ }
+
+};
+
+
+/// Holdout closure
+///
+/// This will be used by the shader to mark the
+/// amount of holdout for the current shading
+/// point. No parameters, only the weight will be
+/// used
+///
+class HoldoutClosure : ClosurePrimitive {
+public:
+ HoldoutClosure () : ClosurePrimitive (Holdout) { }
+
+ void setup() {};
+
+ size_t memsize () const { return sizeof(*this); }
+
+ const char *name () const { return "holdout"; }
+
+ void print_on (std::ostream &out) const {
+ out << name() << " ()";
+ }
+};
+
+ClosureParam closure_background_params[] = {
+ CLOSURE_STRING_KEYPARAM("label"),
+ CLOSURE_FINISH_PARAM(GenericBackgroundClosure) };
+
+CLOSURE_PREPARE(closure_background_prepare, GenericBackgroundClosure)
+
+ClosureParam closure_holdout_params[] = {
+ CLOSURE_FINISH_PARAM(HoldoutClosure) };
+
+CLOSURE_PREPARE(closure_holdout_prepare, HoldoutClosure)
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/osl/bsdf_ashikhmin_velvet.cpp b/intern/cycles/kernel/osl/bsdf_ashikhmin_velvet.cpp
new file mode 100644
index 00000000000..a38c5b55cf5
--- /dev/null
+++ b/intern/cycles/kernel/osl/bsdf_ashikhmin_velvet.cpp
@@ -0,0 +1,175 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <OpenImageIO/fmath.h>
+
+#include <OSL/genclosure.h>
+
+#include "osl_closures.h"
+
+CCL_NAMESPACE_BEGIN
+
+using namespace OSL;
+
+class AshikhminVelvetClosure : public BSDFClosure {
+public:
+ Vec3 m_N;
+ float m_sigma;
+ float m_invsigma2;
+
+ AshikhminVelvetClosure() : BSDFClosure(Labels::DIFFUSE) { }
+
+ void setup()
+ {
+ m_sigma = std::max(m_sigma, 0.01f);
+ m_invsigma2 = 1.0f/(m_sigma * m_sigma);
+ }
+
+ bool mergeable (const ClosurePrimitive *other) const {
+ const AshikhminVelvetClosure *comp = (const AshikhminVelvetClosure *)other;
+ return m_N == comp->m_N && m_sigma == comp->m_sigma &&
+ BSDFClosure::mergeable(other);
+ }
+
+ size_t memsize () const { return sizeof(*this); }
+
+ const char *name () const { return "ashikhmin_velvet"; }
+
+ void print_on (std::ostream &out) const
+ {
+ out << name() << " (";
+ out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), ";
+ out << m_sigma;
+ out << ")";
+ }
+
+ float albedo (const Vec3 &omega_out) const
+ {
+ return 1.0f;
+ }
+
+ Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
+ {
+ float cosNO = m_N.dot(omega_out);
+ float cosNI = m_N.dot(omega_in);
+ if (cosNO > 0 && cosNI > 0) {
+ Vec3 H = omega_in + omega_out;
+ H.normalize();
+
+ float cosNH = m_N.dot(H);
+ float cosHO = fabsf(omega_out.dot(H));
+
+ float cosNHdivHO = cosNH / cosHO;
+ cosNHdivHO = std::max(cosNHdivHO, 0.00001f);
+
+ float fac1 = 2 * fabsf(cosNHdivHO * cosNO);
+ float fac2 = 2 * fabsf(cosNHdivHO * cosNI);
+
+ float sinNH2 = 1 - cosNH * cosNH;
+ float sinNH4 = sinNH2 * sinNH2;
+ float cotangent2 = (cosNH * cosNH) / sinNH2;
+
+ float D = expf(-cotangent2 * m_invsigma2) * m_invsigma2 * float(M_1_PI) / sinNH4;
+ float G = std::min(1.0f, std::min(fac1, fac2)); // TODO: derive G from D analytically
+
+ float out = 0.25f * (D * G) / cosNO;
+
+ pdf = 0.5f * (float) M_1_PI;
+ return Color3 (out, out, out);
+ }
+ return Color3 (0, 0, 0);
+ }
+
+ Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
+ {
+ return Color3 (0, 0, 0);
+ }
+
+ ustring sample (const Vec3 &Ng,
+ const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
+ float randu, float randv,
+ Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
+ float &pdf, Color3 &eval) const
+ {
+ // we are viewing the surface from above - send a ray out with uniform
+ // distribution over the hemisphere
+ sample_uniform_hemisphere (m_N, omega_out, randu, randv, omega_in, pdf);
+ if (Ng.dot(omega_in) > 0) {
+ Vec3 H = omega_in + omega_out;
+ H.normalize();
+
+ float cosNI = m_N.dot(omega_in);
+ float cosNO = m_N.dot(omega_out);
+ float cosNH = m_N.dot(H);
+ float cosHO = fabsf(omega_out.dot(H));
+
+ float cosNHdivHO = cosNH / cosHO;
+ cosNHdivHO = std::max(cosNHdivHO, 0.00001f);
+
+ float fac1 = 2 * fabsf(cosNHdivHO * cosNO);
+ float fac2 = 2 * fabsf(cosNHdivHO * cosNI);
+
+ float sinNH2 = 1 - cosNH * cosNH;
+ float sinNH4 = sinNH2 * sinNH2;
+ float cotangent2 = (cosNH * cosNH) / sinNH2;
+
+ float D = expf(-cotangent2 * m_invsigma2) * m_invsigma2 * float(M_1_PI) / sinNH4;
+ float G = std::min(1.0f, std::min(fac1, fac2)); // TODO: derive G from D analytically
+
+ float power = 0.25f * (D * G) / cosNO;
+
+ eval.setValue(power, power, power);
+
+ // TODO: find a better approximation for the retroreflective bounce
+ domega_in_dx = (2 * m_N.dot(domega_out_dx)) * m_N - domega_out_dx;
+ domega_in_dy = (2 * m_N.dot(domega_out_dy)) * m_N - domega_out_dy;
+ domega_in_dx *= 125;
+ domega_in_dy *= 125;
+ } else
+ pdf = 0;
+ return Labels::REFLECT;
+ }
+
+};
+
+
+
+ClosureParam bsdf_ashikhmin_velvet_params[] = {
+ CLOSURE_VECTOR_PARAM(AshikhminVelvetClosure, m_N),
+ CLOSURE_FLOAT_PARAM (AshikhminVelvetClosure, m_sigma),
+ CLOSURE_STRING_KEYPARAM("label"),
+ CLOSURE_FINISH_PARAM(AshikhminVelvetClosure) };
+
+CLOSURE_PREPARE(bsdf_ashikhmin_velvet_prepare, AshikhminVelvetClosure)
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/osl/bsdf_diffuse.cpp b/intern/cycles/kernel/osl/bsdf_diffuse.cpp
new file mode 100644
index 00000000000..0d4b3fa471f
--- /dev/null
+++ b/intern/cycles/kernel/osl/bsdf_diffuse.cpp
@@ -0,0 +1,181 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <OpenImageIO/fmath.h>
+
+#include <OSL/genclosure.h>
+
+#include "osl_closures.h"
+
+CCL_NAMESPACE_BEGIN
+
+using namespace OSL;
+
+class DiffuseClosure : public BSDFClosure {
+public:
+ Vec3 m_N;
+
+ DiffuseClosure() : BSDFClosure(Labels::DIFFUSE) { }
+
+ void setup() {};
+
+ bool mergeable (const ClosurePrimitive *other) const {
+ const DiffuseClosure *comp = (const DiffuseClosure *)other;
+ return m_N == comp->m_N && BSDFClosure::mergeable(other);
+ }
+
+ size_t memsize () const { return sizeof(*this); }
+
+ const char *name () const { return "diffuse"; }
+
+ void print_on (std::ostream &out) const
+ {
+ out << name() << " ((" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "))";
+ }
+
+ float albedo (const Vec3 &omega_out) const
+ {
+ return 1.0f;
+ }
+
+ Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
+ {
+ float cos_pi = std::max(m_N.dot(omega_in),0.0f) * (float) M_1_PI;
+ pdf = cos_pi;
+ return Color3 (cos_pi, cos_pi, cos_pi);
+ }
+
+ Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
+ {
+ return Color3 (0, 0, 0);
+ }
+
+ ustring sample (const Vec3 &Ng,
+ const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
+ float randu, float randv,
+ Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
+ float &pdf, Color3 &eval) const
+ {
+ // we are viewing the surface from the right side - send a ray out with cosine
+ // distribution over the hemisphere
+ sample_cos_hemisphere (m_N, omega_out, randu, randv, omega_in, pdf);
+ if (Ng.dot(omega_in) > 0) {
+ eval.setValue(pdf, pdf, pdf);
+ // TODO: find a better approximation for the diffuse bounce
+ domega_in_dx = (2 * m_N.dot(domega_out_dx)) * m_N - domega_out_dx;
+ domega_in_dy = (2 * m_N.dot(domega_out_dy)) * m_N - domega_out_dy;
+ domega_in_dx *= 125;
+ domega_in_dy *= 125;
+ } else
+ pdf = 0;
+ return Labels::REFLECT;
+ }
+};
+
+
+
+class TranslucentClosure : public BSDFClosure {
+public:
+ Vec3 m_N;
+
+ TranslucentClosure() : BSDFClosure(Labels::DIFFUSE, Back) { }
+
+ void setup() {};
+
+ bool mergeable (const ClosurePrimitive *other) const {
+ const TranslucentClosure *comp = (const TranslucentClosure *)other;
+ return m_N == comp->m_N && BSDFClosure::mergeable(other);
+ }
+
+ size_t memsize () const { return sizeof(*this); }
+
+ const char *name () const { return "translucent"; }
+
+ void print_on (std::ostream &out) const
+ {
+ out << name() << " ((" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "))";
+ }
+
+ Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
+ {
+ return Color3 (0, 0, 0);
+ }
+
+ float albedo (const Vec3 &omega_out) const
+ {
+ return 1.0f;
+ }
+
+ Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
+ {
+ float cos_pi = std::max(-m_N.dot(omega_in), 0.0f) * (float) M_1_PI;
+ pdf = cos_pi;
+ return Color3 (cos_pi, cos_pi, cos_pi);
+ }
+
+ ustring sample (const Vec3 &Ng,
+ const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
+ float randu, float randv,
+ Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
+ float &pdf, Color3 &eval) const
+ {
+ // we are viewing the surface from the right side - send a ray out with cosine
+ // distribution over the hemisphere
+ sample_cos_hemisphere (-m_N, omega_out, randu, randv, omega_in, pdf);
+ if (Ng.dot(omega_in) < 0) {
+ eval.setValue(pdf, pdf, pdf);
+ // TODO: find a better approximation for the diffuse bounce
+ domega_in_dx = (2 * m_N.dot(domega_out_dx)) * m_N - domega_out_dx;
+ domega_in_dy = (2 * m_N.dot(domega_out_dy)) * m_N - domega_out_dy;
+ domega_in_dx *= -125;
+ domega_in_dy *= -125;
+ } else
+ pdf = 0;
+ return Labels::TRANSMIT;
+ }
+};
+
+ClosureParam bsdf_diffuse_params[] = {
+ CLOSURE_VECTOR_PARAM (DiffuseClosure, m_N),
+ CLOSURE_STRING_KEYPARAM("label"),
+ CLOSURE_FINISH_PARAM (DiffuseClosure) };
+
+ClosureParam bsdf_translucent_params[] = {
+ CLOSURE_VECTOR_PARAM (TranslucentClosure, m_N),
+ CLOSURE_STRING_KEYPARAM("label"),
+ CLOSURE_FINISH_PARAM (TranslucentClosure) };
+
+CLOSURE_PREPARE(bsdf_diffuse_prepare, DiffuseClosure)
+CLOSURE_PREPARE(bsdf_translucent_prepare, TranslucentClosure)
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/osl/bsdf_microfacet.cpp b/intern/cycles/kernel/osl/bsdf_microfacet.cpp
new file mode 100644
index 00000000000..d87268da81e
--- /dev/null
+++ b/intern/cycles/kernel/osl/bsdf_microfacet.cpp
@@ -0,0 +1,533 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <OpenImageIO/fmath.h>
+
+#include <OSL/genclosure.h>
+
+#include "osl_closures.h"
+
+#include "util_math.h"
+
+using namespace OSL;
+
+CCL_NAMESPACE_BEGIN
+
+// TODO: fresnel_dielectric is only used for derivatives, could be optimized
+
+// TODO: refactor these two classes so they share everything by the microfacet
+// distribution terms
+
+// microfacet model with GGX facet distribution
+// see http://www.graphics.cornell.edu/~bjw/microfacetbsdf.pdf
+template <int Refractive = 0>
+class MicrofacetGGXClosure : public BSDFClosure {
+public:
+ Vec3 m_N;
+ float m_ag; // width parameter (roughness)
+ float m_eta; // index of refraction (for fresnel term)
+ MicrofacetGGXClosure() : BSDFClosure(Labels::GLOSSY, Refractive ? Back : Front) { m_eta = 1.0f; }
+
+ void setup()
+ {
+ m_ag = clamp(m_ag, 1e-5f, 1.0f);
+ }
+
+ bool mergeable (const ClosurePrimitive *other) const {
+ const MicrofacetGGXClosure *comp = (const MicrofacetGGXClosure *)other;
+ return m_N == comp->m_N && m_ag == comp->m_ag &&
+ m_eta == comp->m_eta && BSDFClosure::mergeable(other);
+ }
+
+ size_t memsize () const { return sizeof(*this); }
+
+ const char *name () const {
+ return Refractive ? "microfacet_ggx_refraction" : "microfacet_ggx";
+ }
+
+ void print_on (std::ostream &out) const {
+ out << name() << " (";
+ out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), ";
+ out << m_ag << ", ";
+ out << m_eta;
+ out << ")";
+ }
+
+ float albedo (const Vec3 &omega_out) const
+ {
+ return 1.0f;
+ }
+
+ Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
+ {
+ if (Refractive == 1) return Color3 (0, 0, 0);
+ float cosNO = m_N.dot(omega_out);
+ float cosNI = m_N.dot(omega_in);
+ if (cosNI > 0 && cosNO > 0) {
+ // get half vector
+ Vec3 Hr = omega_in + omega_out;
+ Hr.normalize();
+ // eq. 20: (F*G*D)/(4*in*on)
+ // eq. 33: first we calculate D(m) with m=Hr:
+ float alpha2 = m_ag * m_ag;
+ float cosThetaM = m_N.dot(Hr);
+ float cosThetaM2 = cosThetaM * cosThetaM;
+ float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2;
+ float cosThetaM4 = cosThetaM2 * cosThetaM2;
+ float D = alpha2 / ((float) M_PI * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2));
+ // eq. 34: now calculate G1(i,m) and G1(o,m)
+ float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO)));
+ float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI)));
+ float G = G1o * G1i;
+ float out = (G * D) * 0.25f / cosNO;
+ // eq. 24
+ float pm = D * cosThetaM;
+ // convert into pdf of the sampled direction
+ // eq. 38 - but see also:
+ // eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf
+ pdf = pm * 0.25f / Hr.dot(omega_out);
+ return Color3 (out, out, out);
+ }
+ return Color3 (0, 0, 0);
+ }
+
+ Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
+ {
+ if (Refractive == 0) return Color3 (0, 0, 0);
+ float cosNO = m_N.dot(omega_out);
+ float cosNI = m_N.dot(omega_in);
+ if (cosNO <= 0 || cosNI >= 0)
+ return Color3 (0, 0, 0); // vectors on same side -- not possible
+ // compute half-vector of the refraction (eq. 16)
+ Vec3 ht = -(m_eta * omega_in + omega_out);
+ Vec3 Ht = ht; Ht.normalize();
+ float cosHO = Ht.dot(omega_out);
+
+ float cosHI = Ht.dot(omega_in);
+ // eq. 33: first we calculate D(m) with m=Ht:
+ float alpha2 = m_ag * m_ag;
+ float cosThetaM = m_N.dot(Ht);
+ float cosThetaM2 = cosThetaM * cosThetaM;
+ float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2;
+ float cosThetaM4 = cosThetaM2 * cosThetaM2;
+ float D = alpha2 / ((float) M_PI * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2));
+ // eq. 34: now calculate G1(i,m) and G1(o,m)
+ float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO)));
+ float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI)));
+ float G = G1o * G1i;
+ // probability
+ float invHt2 = 1 / ht.dot(ht);
+ pdf = D * fabsf(cosThetaM) * (fabsf(cosHI) * (m_eta * m_eta)) * invHt2;
+ float out = (fabsf(cosHI * cosHO) * (m_eta * m_eta) * (G * D) * invHt2) / cosNO;
+ return Color3 (out, out, out);
+ }
+
+ ustring sample (const Vec3 &Ng,
+ const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
+ float randu, float randv,
+ Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
+ float &pdf, Color3 &eval) const
+ {
+ float cosNO = m_N.dot(omega_out);
+ if (cosNO > 0) {
+ Vec3 X, Y, Z = m_N;
+ make_orthonormals(Z, X, Y);
+ // generate a random microfacet normal m
+ // eq. 35,36:
+ // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2)
+ // and sin(atan(x)) == x/sqrt(1+x^2)
+ float alpha2 = m_ag * m_ag;
+ float tanThetaM2 = alpha2 * randu / (1 - randu);
+ float cosThetaM = 1 / sqrtf(1 + tanThetaM2);
+ float sinThetaM = cosThetaM * sqrtf(tanThetaM2);
+ float phiM = 2 * float(M_PI) * randv;
+ Vec3 m = (cosf(phiM) * sinThetaM) * X +
+ (sinf(phiM) * sinThetaM) * Y +
+ cosThetaM * Z;
+ if (Refractive == 0) {
+ float cosMO = m.dot(omega_out);
+ if (cosMO > 0) {
+ // eq. 39 - compute actual reflected direction
+ omega_in = 2 * cosMO * m - omega_out;
+ if (Ng.dot(omega_in) > 0) {
+ // microfacet normal is visible to this ray
+ // eq. 33
+ float cosThetaM2 = cosThetaM * cosThetaM;
+ float cosThetaM4 = cosThetaM2 * cosThetaM2;
+ float D = alpha2 / (float(M_PI) * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2));
+ // eq. 24
+ float pm = D * cosThetaM;
+ // convert into pdf of the sampled direction
+ // eq. 38 - but see also:
+ // eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf
+ pdf = pm * 0.25f / cosMO;
+ // eval BRDF*cosNI
+ float cosNI = m_N.dot(omega_in);
+ // eq. 34: now calculate G1(i,m) and G1(o,m)
+ float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO)));
+ float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI)));
+ float G = G1o * G1i;
+ // eq. 20: (F*G*D)/(4*in*on)
+ float out = (G * D) * 0.25f / cosNO;
+ eval.setValue(out, out, out);
+ domega_in_dx = (2 * m.dot(domega_out_dx)) * m - domega_out_dx;
+ domega_in_dy = (2 * m.dot(domega_out_dy)) * m - domega_out_dy;
+
+ /* disabled for now - gives texture filtering problems */
+#if 0
+ // Since there is some blur to this reflection, make the
+ // derivatives a bit bigger. In theory this varies with the
+ // roughness but the exact relationship is complex and
+ // requires more ops than are practical.
+ domega_in_dx *= 10;
+ domega_in_dy *= 10;
+#endif
+ }
+ }
+ } else {
+ // CAUTION: the i and o variables are inverted relative to the paper
+ // eq. 39 - compute actual refractive direction
+ Vec3 R, dRdx, dRdy;
+ Vec3 T, dTdx, dTdy;
+ bool inside;
+ fresnel_dielectric(m_eta, m, omega_out, domega_out_dx, domega_out_dy,
+ R, dRdx, dRdy,
+ T, dTdx, dTdy,
+ inside);
+
+ if (!inside) {
+ omega_in = T;
+ domega_in_dx = dTdx;
+ domega_in_dy = dTdy;
+ // eq. 33
+ float cosThetaM2 = cosThetaM * cosThetaM;
+ float cosThetaM4 = cosThetaM2 * cosThetaM2;
+ float D = alpha2 / (float(M_PI) * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2));
+ // eq. 24
+ float pm = D * cosThetaM;
+ // eval BRDF*cosNI
+ float cosNI = m_N.dot(omega_in);
+ // eq. 34: now calculate G1(i,m) and G1(o,m)
+ float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO)));
+ float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI)));
+ float G = G1o * G1i;
+ // eq. 21
+ float cosHI = m.dot(omega_in);
+ float cosHO = m.dot(omega_out);
+ float Ht2 = m_eta * cosHI + cosHO;
+ Ht2 *= Ht2;
+ float out = (fabsf(cosHI * cosHO) * (m_eta * m_eta) * (G * D)) / (cosNO * Ht2);
+ // eq. 38 and eq. 17
+ pdf = pm * (m_eta * m_eta) * fabsf(cosHI) / Ht2;
+ eval.setValue(out, out, out);
+
+ /* disabled for now - gives texture filtering problems */
+#if 0
+ // Since there is some blur to this refraction, make the
+ // derivatives a bit bigger. In theory this varies with the
+ // roughness but the exact relationship is complex and
+ // requires more ops than are practical.
+ domega_in_dx *= 10;
+ domega_in_dy *= 10;
+#endif
+ }
+ }
+ }
+ return Refractive ? Labels::TRANSMIT : Labels::REFLECT;
+ }
+};
+
+// microfacet model with Beckmann facet distribution
+// see http://www.graphics.cornell.edu/~bjw/microfacetbsdf.pdf
+template <int Refractive = 0>
+class MicrofacetBeckmannClosure : public BSDFClosure {
+public:
+ Vec3 m_N;
+ float m_ab; // width parameter (roughness)
+ float m_eta; // index of refraction (for fresnel term)
+ MicrofacetBeckmannClosure() : BSDFClosure(Labels::GLOSSY, Refractive ? Back : Front) { }
+
+ void setup()
+ {
+ m_ab = clamp(m_ab, 1e-5f, 1.0f);
+ }
+
+ bool mergeable (const ClosurePrimitive *other) const {
+ const MicrofacetBeckmannClosure *comp = (const MicrofacetBeckmannClosure *)other;
+ return m_N == comp->m_N && m_ab == comp->m_ab &&
+ m_eta == comp->m_eta && BSDFClosure::mergeable(other);
+ }
+
+ size_t memsize () const { return sizeof(*this); }
+
+ const char * name () const {
+ return Refractive ? "microfacet_beckmann_refraction"
+ : "microfacet_beckmann";
+ }
+
+ void print_on (std::ostream &out) const
+ {
+ out << name() << " (";
+ out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), ";
+ out << m_ab << ", ";
+ out << m_eta;
+ out << ")";
+ }
+
+ float albedo (const Vec3 &omega_out) const
+ {
+ return 1.0f;
+ }
+
+ Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
+ {
+ if (Refractive == 1) return Color3 (0, 0, 0);
+ float cosNO = m_N.dot(omega_out);
+ float cosNI = m_N.dot(omega_in);
+ if (cosNO > 0 && cosNI > 0) {
+ // get half vector
+ Vec3 Hr = omega_in + omega_out;
+ Hr.normalize();
+ // eq. 20: (F*G*D)/(4*in*on)
+ // eq. 25: first we calculate D(m) with m=Hr:
+ float alpha2 = m_ab * m_ab;
+ float cosThetaM = m_N.dot(Hr);
+ float cosThetaM2 = cosThetaM * cosThetaM;
+ float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2;
+ float cosThetaM4 = cosThetaM2 * cosThetaM2;
+ float D = expf(-tanThetaM2 / alpha2) / (float(M_PI) * alpha2 * cosThetaM4);
+ // eq. 26, 27: now calculate G1(i,m) and G1(o,m)
+ float ao = 1 / (m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO)));
+ float ai = 1 / (m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
+ float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f;
+ float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
+ float G = G1o * G1i;
+ float out = (G * D) * 0.25f / cosNO;
+ // eq. 24
+ float pm = D * cosThetaM;
+ // convert into pdf of the sampled direction
+ // eq. 38 - but see also:
+ // eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf
+ pdf = pm * 0.25f / Hr.dot(omega_out);
+ return Color3 (out, out, out);
+ }
+ return Color3 (0, 0, 0);
+ }
+
+ Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
+ {
+ if (Refractive == 0) return Color3 (0, 0, 0);
+ float cosNO = m_N.dot(omega_out);
+ float cosNI = m_N.dot(omega_in);
+ if (cosNO <= 0 || cosNI >= 0)
+ return Color3 (0, 0, 0);
+ // compute half-vector of the refraction (eq. 16)
+ Vec3 ht = -(m_eta * omega_in + omega_out);
+ Vec3 Ht = ht; Ht.normalize();
+ float cosHO = Ht.dot(omega_out);
+
+ float cosHI = Ht.dot(omega_in);
+ // eq. 33: first we calculate D(m) with m=Ht:
+ float alpha2 = m_ab * m_ab;
+ float cosThetaM = m_N.dot(Ht);
+ float cosThetaM2 = cosThetaM * cosThetaM;
+ float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2;
+ float cosThetaM4 = cosThetaM2 * cosThetaM2;
+ float D = expf(-tanThetaM2 / alpha2) / (float(M_PI) * alpha2 * cosThetaM4);
+ // eq. 26, 27: now calculate G1(i,m) and G1(o,m)
+ float ao = 1 / (m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO)));
+ float ai = 1 / (m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
+ float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f;
+ float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
+ float G = G1o * G1i;
+ // probability
+ float invHt2 = 1 / ht.dot(ht);
+ pdf = D * fabsf(cosThetaM) * (fabsf(cosHI) * (m_eta * m_eta)) * invHt2;
+ float out = (fabsf(cosHI * cosHO) * (m_eta * m_eta) * (G * D) * invHt2) / cosNO;
+ return Color3 (out, out, out);
+ }
+
+ ustring sample (const Vec3 &Ng,
+ const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
+ float randu, float randv,
+ Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
+ float &pdf, Color3 &eval) const
+ {
+ float cosNO = m_N.dot(omega_out);
+ if (cosNO > 0) {
+ Vec3 X, Y, Z = m_N;
+ make_orthonormals(Z, X, Y);
+ // generate a random microfacet normal m
+ // eq. 35,36:
+ // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2)
+ // and sin(atan(x)) == x/sqrt(1+x^2)
+ float alpha2 = m_ab * m_ab;
+ float tanThetaM = sqrtf(-alpha2 * logf(1 - randu));
+ float cosThetaM = 1 / sqrtf(1 + tanThetaM * tanThetaM);
+ float sinThetaM = cosThetaM * tanThetaM;
+ float phiM = 2 * float(M_PI) * randv;
+ Vec3 m = (cosf(phiM) * sinThetaM) * X +
+ (sinf(phiM) * sinThetaM) * Y +
+ cosThetaM * Z;
+ if (Refractive == 0) {
+ float cosMO = m.dot(omega_out);
+ if (cosMO > 0) {
+ // eq. 39 - compute actual reflected direction
+ omega_in = 2 * cosMO * m - omega_out;
+ if (Ng.dot(omega_in) > 0) {
+ // microfacet normal is visible to this ray
+ // eq. 25
+ float cosThetaM2 = cosThetaM * cosThetaM;
+ float tanThetaM2 = tanThetaM * tanThetaM;
+ float cosThetaM4 = cosThetaM2 * cosThetaM2;
+ float D = expf(-tanThetaM2 / alpha2) / (float(M_PI) * alpha2 * cosThetaM4);
+ // eq. 24
+ float pm = D * cosThetaM;
+ // convert into pdf of the sampled direction
+ // eq. 38 - but see also:
+ // eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf
+ pdf = pm * 0.25f / cosMO;
+ // Eval BRDF*cosNI
+ float cosNI = m_N.dot(omega_in);
+ // eq. 26, 27: now calculate G1(i,m) and G1(o,m)
+ float ao = 1 / (m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO)));
+ float ai = 1 / (m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
+ float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f;
+ float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
+ float G = G1o * G1i;
+ // eq. 20: (F*G*D)/(4*in*on)
+ float out = (G * D) * 0.25f / cosNO;
+ eval.setValue(out, out, out);
+ domega_in_dx = (2 * m.dot(domega_out_dx)) * m - domega_out_dx;
+ domega_in_dy = (2 * m.dot(domega_out_dy)) * m - domega_out_dy;
+
+ /* disabled for now - gives texture filtering problems */
+#if 0
+ // Since there is some blur to this reflection, make the
+ // derivatives a bit bigger. In theory this varies with the
+ // roughness but the exact relationship is complex and
+ // requires more ops than are practical.
+ domega_in_dx *= 10;
+ domega_in_dy *= 10;
+#endif
+ }
+ }
+ } else {
+ // CAUTION: the i and o variables are inverted relative to the paper
+ // eq. 39 - compute actual refractive direction
+ Vec3 R, dRdx, dRdy;
+ Vec3 T, dTdx, dTdy;
+ bool inside;
+ fresnel_dielectric(m_eta, m, omega_out, domega_out_dx, domega_out_dy,
+ R, dRdx, dRdy,
+ T, dTdx, dTdy,
+ inside);
+ if (!inside) {
+ omega_in = T;
+ domega_in_dx = dTdx;
+ domega_in_dy = dTdy;
+ // eq. 33
+ float cosThetaM2 = cosThetaM * cosThetaM;
+ float tanThetaM2 = tanThetaM * tanThetaM;
+ float cosThetaM4 = cosThetaM2 * cosThetaM2;
+ float D = expf(-tanThetaM2 / alpha2) / (float(M_PI) * alpha2 * cosThetaM4);
+ // eq. 24
+ float pm = D * cosThetaM;
+ // eval BRDF*cosNI
+ float cosNI = m_N.dot(omega_in);
+ // eq. 26, 27: now calculate G1(i,m) and G1(o,m)
+ float ao = 1 / (m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO)));
+ float ai = 1 / (m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
+ float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f;
+ float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
+ float G = G1o * G1i;
+ // eq. 21
+ float cosHI = m.dot(omega_in);
+ float cosHO = m.dot(omega_out);
+ float Ht2 = m_eta * cosHI + cosHO;
+ Ht2 *= Ht2;
+ float out = (fabsf(cosHI * cosHO) * (m_eta * m_eta) * (G * D)) / (cosNO * Ht2);
+ // eq. 38 and eq. 17
+ pdf = pm * (m_eta * m_eta) * fabsf(cosHI) / Ht2;
+ eval.setValue(out, out, out);
+
+ /* disabled for now - gives texture filtering problems */
+#if 0
+ // Since there is some blur to this refraction, make the
+ // derivatives a bit bigger. In theory this varies with the
+ // roughness but the exact relationship is complex and
+ // requires more ops than are practical.
+ domega_in_dx *= 10;
+ domega_in_dy *= 10;
+#endif
+ }
+ }
+ }
+ return Refractive ? Labels::TRANSMIT : Labels::REFLECT;
+ }
+};
+
+
+
+ClosureParam bsdf_microfacet_ggx_params[] = {
+ CLOSURE_VECTOR_PARAM(MicrofacetGGXClosure<0>, m_N),
+ CLOSURE_FLOAT_PARAM (MicrofacetGGXClosure<0>, m_ag),
+ CLOSURE_STRING_KEYPARAM("label"),
+ CLOSURE_FINISH_PARAM(MicrofacetGGXClosure<0>) };
+
+ClosureParam bsdf_microfacet_ggx_refraction_params[] = {
+ CLOSURE_VECTOR_PARAM(MicrofacetGGXClosure<1>, m_N),
+ CLOSURE_FLOAT_PARAM (MicrofacetGGXClosure<1>, m_ag),
+ CLOSURE_FLOAT_PARAM (MicrofacetGGXClosure<1>, m_eta),
+ CLOSURE_STRING_KEYPARAM("label"),
+ CLOSURE_FINISH_PARAM(MicrofacetGGXClosure<1>) };
+
+ClosureParam bsdf_microfacet_beckmann_params[] = {
+ CLOSURE_VECTOR_PARAM(MicrofacetBeckmannClosure<0>, m_N),
+ CLOSURE_FLOAT_PARAM (MicrofacetBeckmannClosure<0>, m_ab),
+ CLOSURE_STRING_KEYPARAM("label"),
+ CLOSURE_FINISH_PARAM(MicrofacetBeckmannClosure<0>) };
+
+ClosureParam bsdf_microfacet_beckmann_refraction_params[] = {
+ CLOSURE_VECTOR_PARAM(MicrofacetBeckmannClosure<1>, m_N),
+ CLOSURE_FLOAT_PARAM (MicrofacetBeckmannClosure<1>, m_ab),
+ CLOSURE_FLOAT_PARAM (MicrofacetBeckmannClosure<1>, m_eta),
+ CLOSURE_STRING_KEYPARAM("label"),
+ CLOSURE_FINISH_PARAM(MicrofacetBeckmannClosure<1>) };
+
+CLOSURE_PREPARE(bsdf_microfacet_ggx_prepare, MicrofacetGGXClosure<0>)
+CLOSURE_PREPARE(bsdf_microfacet_ggx_refraction_prepare, MicrofacetGGXClosure<1>)
+CLOSURE_PREPARE(bsdf_microfacet_beckmann_prepare, MicrofacetBeckmannClosure<0>)
+CLOSURE_PREPARE(bsdf_microfacet_beckmann_refraction_prepare, MicrofacetBeckmannClosure<1>)
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/osl/bsdf_reflection.cpp b/intern/cycles/kernel/osl/bsdf_reflection.cpp
new file mode 100644
index 00000000000..b0caff6df44
--- /dev/null
+++ b/intern/cycles/kernel/osl/bsdf_reflection.cpp
@@ -0,0 +1,108 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <OpenImageIO/fmath.h>
+
+#include <OSL/genclosure.h>
+
+#include "osl_closures.h"
+
+CCL_NAMESPACE_BEGIN
+
+using namespace OSL;
+
+class ReflectionClosure : public BSDFClosure {
+public:
+ Vec3 m_N; // shading normal
+ ReflectionClosure() : BSDFClosure(Labels::SINGULAR) { }
+
+ void setup() {};
+
+ bool mergeable (const ClosurePrimitive *other) const {
+ const ReflectionClosure *comp = (const ReflectionClosure *)other;
+ return m_N == comp->m_N && BSDFClosure::mergeable(other);
+ }
+
+ size_t memsize () const { return sizeof(*this); }
+
+ const char *name () const { return "reflection"; }
+
+ void print_on (std::ostream &out) const {
+ out << name() << " (";
+ out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "))";
+ }
+
+ float albedo (const Vec3 &omega_out) const
+ {
+ return 1.0f;
+ }
+
+ Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
+ {
+ return Color3 (0, 0, 0);
+ }
+
+ Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
+ {
+ return Color3 (0, 0, 0);
+ }
+
+ ustring sample (const Vec3 &Ng,
+ const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
+ float randu, float randv,
+ Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
+ float &pdf, Color3 &eval) const
+ {
+ // only one direction is possible
+ float cosNO = m_N.dot(omega_out);
+ if (cosNO > 0) {
+ omega_in = (2 * cosNO) * m_N - omega_out;
+ if (Ng.dot(omega_in) > 0) {
+ domega_in_dx = 2 * m_N.dot(domega_out_dx) * m_N - domega_out_dx;
+ domega_in_dy = 2 * m_N.dot(domega_out_dy) * m_N - domega_out_dy;
+ pdf = 1;
+ eval.setValue(1, 1, 1);
+ }
+ }
+ return Labels::REFLECT;
+ }
+};
+
+ClosureParam bsdf_reflection_params[] = {
+ CLOSURE_VECTOR_PARAM(ReflectionClosure, m_N),
+ CLOSURE_STRING_KEYPARAM("label"),
+ CLOSURE_FINISH_PARAM(ReflectionClosure) };
+
+CLOSURE_PREPARE(bsdf_reflection_prepare, ReflectionClosure)
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/osl/bsdf_refraction.cpp b/intern/cycles/kernel/osl/bsdf_refraction.cpp
new file mode 100644
index 00000000000..3ae7a3811b4
--- /dev/null
+++ b/intern/cycles/kernel/osl/bsdf_refraction.cpp
@@ -0,0 +1,120 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <OpenImageIO/fmath.h>
+
+#include <OSL/genclosure.h>
+
+#include "osl_closures.h"
+
+CCL_NAMESPACE_BEGIN
+
+using namespace OSL;
+
+class RefractionClosure : public BSDFClosure {
+public:
+ Vec3 m_N; // shading normal
+ float m_eta; // ratio of indices of refraction (inside / outside)
+ RefractionClosure() : BSDFClosure(Labels::SINGULAR, Back) { }
+
+ void setup() {}
+
+ bool mergeable (const ClosurePrimitive *other) const {
+ const RefractionClosure *comp = (const RefractionClosure *)other;
+ return m_N == comp->m_N && m_eta == comp->m_eta &&
+ BSDFClosure::mergeable(other);
+ }
+
+ size_t memsize () const { return sizeof(*this); }
+
+ const char *name () const { return "refraction"; }
+
+ void print_on (std::ostream &out) const {
+ out << name() << " (";
+ out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), ";
+ out << m_eta;
+ out << ")";
+ }
+
+ Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
+ {
+ return Color3 (0, 0, 0);
+ }
+
+ Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
+ {
+ return Color3 (0, 0, 0);
+ }
+
+ float albedo (const Vec3 &omega_out) const
+ {
+ return 1.0f;
+ }
+
+ ustring sample (const Vec3 &Ng,
+ const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
+ float randu, float randv,
+ Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
+ float &pdf, Color3 &eval) const
+ {
+ Vec3 R, dRdx, dRdy;
+ Vec3 T, dTdx, dTdy;
+ bool inside;
+
+ fresnel_dielectric(m_eta, m_N,
+ omega_out, domega_out_dx, domega_out_dy,
+ R, dRdx, dRdy,
+ T, dTdx, dTdy,
+ inside);
+
+ if (!inside) {
+ pdf = 1;
+ eval.setValue(1.0f, 1.0f, 1.0f);
+ omega_in = T;
+ domega_in_dx = dTdx;
+ domega_in_dy = dTdy;
+ }
+
+ return Labels::TRANSMIT;
+ }
+};
+
+ClosureParam bsdf_refraction_params[] = {
+ CLOSURE_VECTOR_PARAM(RefractionClosure, m_N),
+ CLOSURE_FLOAT_PARAM (RefractionClosure, m_eta),
+ CLOSURE_STRING_KEYPARAM("label"),
+ CLOSURE_FINISH_PARAM(RefractionClosure) };
+
+CLOSURE_PREPARE(bsdf_refraction_prepare, RefractionClosure)
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/osl/bsdf_transparent.cpp b/intern/cycles/kernel/osl/bsdf_transparent.cpp
new file mode 100644
index 00000000000..941abd6a483
--- /dev/null
+++ b/intern/cycles/kernel/osl/bsdf_transparent.cpp
@@ -0,0 +1,97 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <OpenImageIO/fmath.h>
+
+#include <OSL/genclosure.h>
+
+#include "osl_closures.h"
+
+CCL_NAMESPACE_BEGIN
+
+using namespace OSL;
+
+class TransparentClosure : public BSDFClosure {
+public:
+ TransparentClosure() : BSDFClosure(Labels::STRAIGHT, Back) { }
+
+ void setup() {}
+
+ size_t memsize () const { return sizeof(*this); }
+
+ const char *name () const { return "transparent"; }
+
+ void print_on (std::ostream &out) const {
+ out << name() << " ()";
+ }
+
+ float albedo (const Vec3 &omega_out) const
+ {
+ return 1.0f;
+ }
+
+ Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
+ {
+ return Color3 (0, 0, 0);
+ }
+
+ Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
+ {
+ return Color3 (0, 0, 0);
+ }
+
+ ustring sample (const Vec3 &Ng,
+ const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
+ float randu, float randv,
+ Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
+ float &pdf, Color3 &eval) const
+ {
+ // only one direction is possible
+ omega_in = -omega_out;
+ domega_in_dx = -domega_out_dx;
+ domega_in_dy = -domega_out_dy;
+ pdf = 1;
+ eval.setValue(1, 1, 1);
+ return Labels::TRANSMIT;
+ }
+};
+
+
+
+ClosureParam bsdf_transparent_params[] = {
+ CLOSURE_STRING_KEYPARAM("label"),
+ CLOSURE_FINISH_PARAM(TransparentClosure) };
+
+CLOSURE_PREPARE(bsdf_transparent_prepare, TransparentClosure)
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/osl/bsdf_ward.cpp b/intern/cycles/kernel/osl/bsdf_ward.cpp
new file mode 100644
index 00000000000..a7742a04d13
--- /dev/null
+++ b/intern/cycles/kernel/osl/bsdf_ward.cpp
@@ -0,0 +1,222 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <OpenImageIO/fmath.h>
+
+#include <OSL/genclosure.h>
+
+#include "osl_closures.h"
+
+#include "util_math.h"
+
+CCL_NAMESPACE_BEGIN
+
+using namespace OSL;
+
+// anisotropic ward - leaks energy at grazing angles
+// see http://www.graphics.cornell.edu/~bjw/wardnotes.pdf
+class WardClosure : public BSDFClosure {
+public:
+ Vec3 m_N;
+ Vec3 m_T;
+ float m_ax, m_ay;
+ WardClosure() : BSDFClosure(Labels::GLOSSY) { }
+
+ void setup()
+ {
+ m_ax = clamp(m_ax, 1e-5f, 1.0f);
+ m_ay = clamp(m_ay, 1e-5f, 1.0f);
+ }
+
+ bool mergeable (const ClosurePrimitive *other) const {
+ const WardClosure *comp = (const WardClosure *)other;
+ return m_N == comp->m_N && m_T == comp->m_T &&
+ m_ax == comp->m_ax && m_ay == comp->m_ay &&
+ BSDFClosure::mergeable(other);
+ }
+
+ size_t memsize () const { return sizeof(*this); }
+
+ const char *name () const { return "ward"; }
+
+ void print_on (std::ostream &out) const {
+ out << name() << " ((";
+ out << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), (";
+ out << m_T[0] << ", " << m_T[1] << ", " << m_T[2] << "), ";
+ out << m_ax << ", " << m_ay << ")";
+ }
+
+ float albedo (const Vec3 &omega_out) const
+ {
+ return 1.0f;
+ }
+
+ Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
+ {
+ float cosNO = m_N.dot(omega_out);
+ float cosNI = m_N.dot(omega_in);
+ if (cosNI > 0 && cosNO > 0) {
+ // get half vector and get x,y basis on the surface for anisotropy
+ Vec3 H = omega_in + omega_out;
+ H.normalize(); // normalize needed for pdf
+ Vec3 X, Y;
+ make_orthonormals(m_N, m_T, X, Y);
+ // eq. 4
+ float dotx = H.dot(X) / m_ax;
+ float doty = H.dot(Y) / m_ay;
+ float dotn = H.dot(m_N);
+ float exp_arg = (dotx * dotx + doty * doty) / (dotn * dotn);
+ float denom = (4 * (float) M_PI * m_ax * m_ay * sqrtf(cosNO * cosNI));
+ float exp_val = expf(-exp_arg);
+ float out = cosNI * exp_val / denom;
+ float oh = H.dot(omega_out);
+ denom = 4 * (float) M_PI * m_ax * m_ay * oh * dotn * dotn * dotn;
+ pdf = exp_val / denom;
+ return Color3 (out, out, out);
+ }
+ return Color3 (0, 0, 0);
+ }
+
+ Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float& pdf) const
+ {
+ return Color3 (0, 0, 0);
+ }
+
+ ustring sample (const Vec3 &Ng,
+ const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
+ float randu, float randv,
+ Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
+ float &pdf, Color3 &eval) const
+ {
+ float cosNO = m_N.dot(omega_out);
+ if (cosNO > 0) {
+ // get x,y basis on the surface for anisotropy
+ Vec3 X, Y;
+ make_orthonormals(m_N, m_T, X, Y);
+ // generate random angles for the half vector
+ // eq. 7 (taking care around discontinuities to keep
+ // output angle in the right quadrant)
+ // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2)
+ // and sin(atan(x)) == x/sqrt(1+x^2)
+ float alphaRatio = m_ay / m_ax;
+ float cosPhi, sinPhi;
+ if (randu < 0.25f) {
+ float val = 4 * randu;
+ float tanPhi = alphaRatio * tanf((float) M_PI_2 * val);
+ cosPhi = 1 / sqrtf(1 + tanPhi * tanPhi);
+ sinPhi = tanPhi * cosPhi;
+ } else if (randu < 0.5) {
+ float val = 1 - 4 * (0.5f - randu);
+ float tanPhi = alphaRatio * tanf((float) M_PI_2 * val);
+ // phi = (float) M_PI - phi;
+ cosPhi = -1 / sqrtf(1 + tanPhi * tanPhi);
+ sinPhi = -tanPhi * cosPhi;
+ } else if (randu < 0.75f) {
+ float val = 4 * (randu - 0.5f);
+ float tanPhi = alphaRatio * tanf((float) M_PI_2 * val);
+ //phi = (float) M_PI + phi;
+ cosPhi = -1 / sqrtf(1 + tanPhi * tanPhi);
+ sinPhi = tanPhi * cosPhi;
+ } else {
+ float val = 1 - 4 * (1 - randu);
+ float tanPhi = alphaRatio * tanf((float) M_PI_2 * val);
+ // phi = 2 * (float) M_PI - phi;
+ cosPhi = 1 / sqrtf(1 + tanPhi * tanPhi);
+ sinPhi = -tanPhi * cosPhi;
+ }
+ // eq. 6
+ // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2)
+ // and sin(atan(x)) == x/sqrt(1+x^2)
+ float thetaDenom = (cosPhi * cosPhi) / (m_ax * m_ax) + (sinPhi * sinPhi) / (m_ay * m_ay);
+ float tanTheta2 = -logf(1 - randv) / thetaDenom;
+ float cosTheta = 1 / sqrtf(1 + tanTheta2);
+ float sinTheta = cosTheta * sqrtf(tanTheta2);
+
+ Vec3 h; // already normalized becaused expressed from spherical coordinates
+ h.x = sinTheta * cosPhi;
+ h.y = sinTheta * sinPhi;
+ h.z = cosTheta;
+ // compute terms that are easier in local space
+ float dotx = h.x / m_ax;
+ float doty = h.y / m_ay;
+ float dotn = h.z;
+ // transform to world space
+ h = h.x * X + h.y * Y + h.z * m_N;
+ // generate the final sample
+ float oh = h.dot(omega_out);
+ omega_in.x = 2 * oh * h.x - omega_out.x;
+ omega_in.y = 2 * oh * h.y - omega_out.y;
+ omega_in.z = 2 * oh * h.z - omega_out.z;
+ if (Ng.dot(omega_in) > 0) {
+ float cosNI = m_N.dot(omega_in);
+ if (cosNI > 0) {
+ // eq. 9
+ float exp_arg = (dotx * dotx + doty * doty) / (dotn * dotn);
+ float denom = 4 * (float) M_PI * m_ax * m_ay * oh * dotn * dotn * dotn;
+ pdf = expf(-exp_arg) / denom;
+ // compiler will reuse expressions already computed
+ denom = (4 * (float) M_PI * m_ax * m_ay * sqrtf(cosNO * cosNI));
+ float power = cosNI * expf(-exp_arg) / denom;
+ eval.setValue(power, power, power);
+ domega_in_dx = (2 * m_N.dot(domega_out_dx)) * m_N - domega_out_dx;
+ domega_in_dy = (2 * m_N.dot(domega_out_dy)) * m_N - domega_out_dy;
+
+ /* disabled for now - gives texture filtering problems */
+#if 0
+ // Since there is some blur to this reflection, make the
+ // derivatives a bit bigger. In theory this varies with the
+ // roughness but the exact relationship is complex and
+ // requires more ops than are practical.
+ domega_in_dx *= 10;
+ domega_in_dy *= 10;
+#endif
+ }
+ }
+ }
+ return Labels::REFLECT;
+ }
+};
+
+
+
+ClosureParam bsdf_ward_params[] = {
+ CLOSURE_VECTOR_PARAM(WardClosure, m_N),
+ CLOSURE_VECTOR_PARAM(WardClosure, m_T),
+ CLOSURE_FLOAT_PARAM (WardClosure, m_ax),
+ CLOSURE_FLOAT_PARAM (WardClosure, m_ay),
+ CLOSURE_STRING_KEYPARAM("label"),
+ CLOSURE_FINISH_PARAM(WardClosure) };
+
+CLOSURE_PREPARE(bsdf_ward_prepare, WardClosure)
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/osl/bsdf_westin.cpp b/intern/cycles/kernel/osl/bsdf_westin.cpp
new file mode 100644
index 00000000000..d322f6a7f7e
--- /dev/null
+++ b/intern/cycles/kernel/osl/bsdf_westin.cpp
@@ -0,0 +1,239 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <OpenImageIO/fmath.h>
+
+#include <OSL/genclosure.h>
+
+#include "osl_closures.h"
+
+#include "util_math.h"
+
+CCL_NAMESPACE_BEGIN
+
+using namespace OSL;
+
+class WestinBackscatterClosure : public BSDFClosure {
+public:
+ Vec3 m_N;
+ float m_roughness;
+ float m_invroughness;
+ WestinBackscatterClosure() : BSDFClosure(Labels::GLOSSY) { }
+
+ void setup()
+ {
+ m_roughness = clamp(m_roughness, 1e-5f, 1.0f);
+ m_invroughness = m_roughness > 0 ? 1 / m_roughness : 0;
+ }
+
+ bool mergeable (const ClosurePrimitive *other) const {
+ const WestinBackscatterClosure *comp = (const WestinBackscatterClosure *)other;
+ return m_N == comp->m_N && m_roughness == comp->m_roughness &&
+ BSDFClosure::mergeable(other);
+ }
+
+ size_t memsize () const { return sizeof(*this); }
+
+ const char *name () const { return "westin_backscatter"; }
+
+ void print_on (std::ostream &out) const
+ {
+ out << name() << " (";
+ out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), ";
+ out << m_roughness;
+ out << ")";
+ }
+
+ float albedo (const Vec3 &omega_out) const
+ {
+ return 1.0f;
+ }
+
+ Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float &pdf) const
+ {
+ // pdf is implicitly 0 (no indirect sampling)
+ float cosNO = m_N.dot(omega_out);
+ float cosNI = m_N.dot(omega_in);
+ if (cosNO > 0 && cosNI > 0) {
+ float cosine = omega_out.dot(omega_in);
+ pdf = cosine > 0 ? (m_invroughness + 1) * powf(cosine, m_invroughness) : 0;
+ pdf *= 0.5f * float(M_1_PI);
+ return Color3 (pdf, pdf, pdf);
+ }
+ return Color3 (0, 0, 0);
+ }
+
+ Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float &pdf) const
+ {
+ return Color3 (0, 0, 0);
+ }
+
+ ustring sample (const Vec3 &Ng,
+ const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
+ float randu, float randv,
+ Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
+ float &pdf, Color3 &eval) const
+ {
+ float cosNO = m_N.dot(omega_out);
+ if (cosNO > 0) {
+ domega_in_dx = domega_out_dx;
+ domega_in_dy = domega_out_dy;
+ Vec3 T, B;
+ make_orthonormals (omega_out, T, B);
+ float phi = 2 * (float) M_PI * randu;
+ float cosTheta = powf(randv, 1 / (m_invroughness + 1));
+ float sinTheta2 = 1 - cosTheta * cosTheta;
+ float sinTheta = sinTheta2 > 0 ? sqrtf(sinTheta2) : 0;
+ omega_in = (cosf(phi) * sinTheta) * T +
+ (sinf(phi) * sinTheta) * B +
+ ( cosTheta) * omega_out;
+ if (Ng.dot(omega_in) > 0)
+ {
+ // common terms for pdf and eval
+ float cosNI = m_N.dot(omega_in);
+ // make sure the direction we chose is still in the right hemisphere
+ if (cosNI > 0)
+ {
+ pdf = 0.5f * (float) M_1_PI * powf(cosTheta, m_invroughness);
+ pdf = (m_invroughness + 1) * pdf;
+ eval.setValue(pdf, pdf, pdf);
+ // Since there is some blur to this reflection, make the
+ // derivatives a bit bigger. In theory this varies with the
+ // exponent but the exact relationship is complex and
+ // requires more ops than are practical.
+ domega_in_dx *= 10;
+ domega_in_dy *= 10;
+ }
+ }
+ }
+ return Labels::REFLECT;
+ }
+
+};
+
+
+class WestinSheenClosure : public BSDFClosure {
+public:
+ Vec3 m_N;
+ float m_edginess;
+// float m_normalization;
+ WestinSheenClosure() : BSDFClosure(Labels::DIFFUSE) { }
+
+ void setup() {};
+
+ bool mergeable (const ClosurePrimitive *other) const {
+ const WestinSheenClosure *comp = (const WestinSheenClosure *)other;
+ return m_N == comp->m_N && m_edginess == comp->m_edginess &&
+ BSDFClosure::mergeable(other);
+ }
+
+ size_t memsize () const { return sizeof(*this); }
+
+ const char *name () const { return "westin_sheen"; }
+
+ void print_on (std::ostream &out) const
+ {
+ out << name() << " (";
+ out << "(" << m_N[0] << ", " << m_N[1] << ", " << m_N[2] << "), ";
+ out << m_edginess;
+ out << ")";
+ }
+
+ float albedo (const Vec3 &omega_out) const
+ {
+ return 1.0f;
+ }
+
+ Color3 eval_reflect (const Vec3 &omega_out, const Vec3 &omega_in, float &pdf) const
+ {
+ // pdf is implicitly 0 (no indirect sampling)
+ float cosNO = m_N.dot(omega_out);
+ float cosNI = m_N.dot(omega_in);
+ if (cosNO > 0 && cosNI > 0) {
+ float sinNO2 = 1 - cosNO * cosNO;
+ pdf = cosNI * float(M_1_PI);
+ float westin = sinNO2 > 0 ? powf(sinNO2, 0.5f * m_edginess) * pdf : 0;
+ return Color3 (westin, westin, westin);
+ }
+ return Color3 (0, 0, 0);
+ }
+
+ Color3 eval_transmit (const Vec3 &omega_out, const Vec3 &omega_in, float &pdf) const
+ {
+ return Color3 (0, 0, 0);
+ }
+
+ ustring sample (const Vec3 &Ng,
+ const Vec3 &omega_out, const Vec3 &domega_out_dx, const Vec3 &domega_out_dy,
+ float randu, float randv,
+ Vec3 &omega_in, Vec3 &domega_in_dx, Vec3 &domega_in_dy,
+ float &pdf, Color3 &eval) const
+ {
+ // we are viewing the surface from the right side - send a ray out with cosine
+ // distribution over the hemisphere
+ sample_cos_hemisphere (m_N, omega_out, randu, randv, omega_in, pdf);
+ if (Ng.dot(omega_in) > 0) {
+ // TODO: account for sheen when sampling
+ float cosNO = m_N.dot(omega_out);
+ float sinNO2 = 1 - cosNO * cosNO;
+ float westin = sinNO2 > 0 ? powf(sinNO2, 0.5f * m_edginess) * pdf : 0;
+ eval.setValue(westin, westin, westin);
+ // TODO: find a better approximation for the diffuse bounce
+ domega_in_dx = (2 * m_N.dot(domega_out_dx)) * m_N - domega_out_dx;
+ domega_in_dy = (2 * m_N.dot(domega_out_dy)) * m_N - domega_out_dy;
+ domega_in_dx *= 125;
+ domega_in_dy *= 125;
+ } else
+ pdf = 0;
+ return Labels::REFLECT;
+ }
+};
+
+
+
+ClosureParam bsdf_westin_backscatter_params[] = {
+ CLOSURE_VECTOR_PARAM(WestinBackscatterClosure, m_N),
+ CLOSURE_FLOAT_PARAM (WestinBackscatterClosure, m_roughness),
+ CLOSURE_STRING_KEYPARAM("label"),
+ CLOSURE_FINISH_PARAM(WestinBackscatterClosure) };
+
+ClosureParam bsdf_westin_sheen_params[] = {
+ CLOSURE_VECTOR_PARAM(WestinSheenClosure, m_N),
+ CLOSURE_FLOAT_PARAM (WestinSheenClosure, m_edginess),
+ CLOSURE_STRING_KEYPARAM("label"),
+ CLOSURE_FINISH_PARAM(WestinSheenClosure) };
+
+CLOSURE_PREPARE(bsdf_westin_backscatter_prepare, WestinBackscatterClosure)
+CLOSURE_PREPARE(bsdf_westin_sheen_prepare, WestinSheenClosure)
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/osl/bssrdf.cpp b/intern/cycles/kernel/osl/bssrdf.cpp
new file mode 100644
index 00000000000..66d7818e677
--- /dev/null
+++ b/intern/cycles/kernel/osl/bssrdf.cpp
@@ -0,0 +1,105 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <OpenImageIO/fmath.h>
+
+#include <OSL/genclosure.h>
+
+#include "osl_closures.h"
+
+CCL_NAMESPACE_BEGIN
+
+using namespace OSL;
+
+class BSSRDFCubicClosure : public BSSRDFClosure {
+public:
+ Color3 m_radius;
+ Color3 m_scale;
+ float m_max_radius;
+
+ template <typename T>
+ static inline T pow3 (const T &x) { return x * x * x; }
+
+ template <typename T>
+ static inline T pow5 (const T &x) { T x2 = x * x; return x2 * x2 * x; }
+
+ BSSRDFCubicClosure() { }
+
+ void setup()
+ {
+ // pre-compute some terms
+ m_max_radius = 0;
+ for (int i = 0; i < 3; i++) {
+ m_scale[i] = m_radius[i] > 0 ? 4 / pow5 (m_radius[i]) : 0;
+ m_max_radius = std::max (m_max_radius, m_radius[i]);
+ }
+ }
+
+ bool mergeable (const ClosurePrimitive *other) const {
+ const BSSRDFCubicClosure *comp = (const BSSRDFCubicClosure *)other;
+ return m_radius == comp->m_radius && BSSRDFClosure::mergeable(other);
+ }
+
+ size_t memsize () const { return sizeof(*this); }
+
+ const char *name () const { return "bssrdf_cubic"; }
+
+ void print_on (std::ostream &out) const
+ {
+ out << name() << " ((" << m_radius[0] << ", " << m_radius[1] << ", " << m_radius[2] << "), ("
+ << m_scale[0] << ", " << m_scale[1] << ", " << m_scale[2] << "))";
+ }
+
+ Color3 eval (float r) const
+ {
+ return Color3 ((r < m_radius.x) ? pow3 (m_radius.x - r) * m_scale.x : 0,
+ (r < m_radius.y) ? pow3 (m_radius.y - r) * m_scale.y : 0,
+ (r < m_radius.z) ? pow3 (m_radius.z - r) * m_scale.z : 0);
+ }
+
+ float max_radius() const
+ {
+ return m_max_radius;
+ }
+};
+
+
+
+ClosureParam closure_bssrdf_cubic_params[] = {
+ CLOSURE_COLOR_PARAM (BSSRDFCubicClosure, m_radius),
+ CLOSURE_STRING_KEYPARAM ("label"),
+ CLOSURE_FINISH_PARAM(BSSRDFCubicClosure) };
+
+CLOSURE_PREPARE(closure_bssrdf_cubic_prepare, BSSRDFCubicClosure)
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/osl/debug.cpp b/intern/cycles/kernel/osl/debug.cpp
new file mode 100644
index 00000000000..8c3f8b2b323
--- /dev/null
+++ b/intern/cycles/kernel/osl/debug.cpp
@@ -0,0 +1,80 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <OpenImageIO/fmath.h>
+
+#include <OSL/genclosure.h>
+
+#include "osl_closures.h"
+
+CCL_NAMESPACE_BEGIN
+
+using namespace OSL;
+
+/// Debug closure
+///
+/// This is going to be used for mask AOV's and similar
+/// purposes. A tag (string) is always associated with
+/// this closure, that "selects: the channel where the
+/// weight should be sent.
+
+class DebugClosure : public ClosurePrimitive {
+public:
+ ustring m_tag;
+
+ DebugClosure () : ClosurePrimitive (Debug) { }
+
+ bool mergeable (const ClosurePrimitive *other) const {
+ const DebugClosure *comp = (const DebugClosure *)other;
+ return m_tag == comp->m_tag &&
+ ClosurePrimitive::mergeable(other);
+ }
+
+ size_t memsize () const { return sizeof(*this); }
+
+ const char *name () const { return "debug"; }
+
+ void print_on (std::ostream &out) const {
+ out << name() << " (\"" << m_tag.c_str() << "\")";
+ }
+
+};
+
+ClosureParam closure_debug_params[] = {
+ CLOSURE_STRING_PARAM(DebugClosure, m_tag),
+ CLOSURE_STRING_KEYPARAM("label"),
+ CLOSURE_FINISH_PARAM(DebugClosure) };
+
+CLOSURE_PREPARE(closure_debug_prepare, DebugClosure)
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/osl/emissive.cpp b/intern/cycles/kernel/osl/emissive.cpp
new file mode 100644
index 00000000000..28d3c73e59b
--- /dev/null
+++ b/intern/cycles/kernel/osl/emissive.cpp
@@ -0,0 +1,107 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <OpenImageIO/fmath.h>
+
+#include <OSL/genclosure.h>
+
+#include "osl_closures.h"
+
+CCL_NAMESPACE_BEGIN
+
+using namespace OSL;
+
+/// Variable cone emissive closure
+///
+/// This primitive emits in a cone having a configurable
+/// penumbra area where the light decays to 0 reaching the
+/// outer_angle limit. It can also behave as a lambertian emitter
+/// if the provided angles are PI/2, which is the default
+///
+class GenericEmissiveClosure : public EmissiveClosure {
+public:
+ GenericEmissiveClosure() { }
+
+ void setup() { }
+
+ size_t memsize () const { return sizeof(*this); }
+
+ const char *name () const { return "emission"; }
+
+ void print_on (std::ostream &out) const {
+ out << name() << "()";
+ }
+
+ Color3 eval (const Vec3 &Ng, const Vec3 &omega_out) const
+ {
+ float cosNO = fabsf(Ng.dot(omega_out));
+ float res = cosNO > 0 ? 1.0f / float(M_PI) : 0.0f;
+ return Color3(res, res, res);
+ }
+
+ void sample (const Vec3 &Ng, float randu, float randv,
+ Vec3 &omega_out, float &pdf) const
+ {
+ // We don't do anything sophisticated here for the step
+ // We just sample the whole cone uniformly to the cosine
+ Vec3 T, B;
+ make_orthonormals(Ng, T, B);
+ float phi = 2 * (float) M_PI * randu;
+ float cosTheta = sqrtf(1.0f - 1.0f * randv);
+ float sinTheta = sqrtf(1.0f - cosTheta * cosTheta);
+ omega_out = (cosf(phi) * sinTheta) * T +
+ (sinf(phi) * sinTheta) * B +
+ cosTheta * Ng;
+ pdf = 1.0f / float(M_PI);
+ }
+
+ /// Return the probability distribution function in the direction omega_out,
+ /// given the parameters and the light's surface normal. This MUST match
+ /// the PDF computed by sample().
+ float pdf (const Vec3 &Ng,
+ const Vec3 &omega_out) const
+ {
+ float cosNO = Ng.dot(omega_out);
+ return cosNO > 0 ? 1.0f / float(M_PI) : 0.0f;
+ }
+};
+
+
+
+ClosureParam closure_emission_params[] = {
+ CLOSURE_STRING_KEYPARAM("label"),
+ CLOSURE_FINISH_PARAM(GenericEmissiveClosure) };
+
+CLOSURE_PREPARE(closure_emission_prepare, GenericEmissiveClosure)
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/osl/nodes/CMakeLists.txt b/intern/cycles/kernel/osl/nodes/CMakeLists.txt
new file mode 100644
index 00000000000..435acc5f680
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/CMakeLists.txt
@@ -0,0 +1,69 @@
+
+# OSL node shaders
+
+SET(osl_sources
+ node_add_closure.osl
+ node_attribute.osl
+ node_background.osl
+ node_blend_texture.osl
+ node_bump.osl
+ node_clouds_texture.osl
+ node_convert_from_color.osl
+ node_convert_from_float.osl
+ node_convert_from_normal.osl
+ node_convert_from_point.osl
+ node_convert_from_vector.osl
+ node_diffuse_bsdf.osl
+ node_distorted_noise_texture.osl
+ node_emission.osl
+ node_environment_texture.osl
+ node_fresnel.osl
+ node_geometry.osl
+ node_glass_bsdf.osl
+ node_glossy_bsdf.osl
+ node_image_texture.osl
+ node_light_path.osl
+ node_magic_texture.osl
+ node_mapping.osl
+ node_marble_texture.osl
+ node_math.osl
+ node_mix.osl
+ node_mix_closure.osl
+ node_musgrave_texture.osl
+ node_noise_texture.osl
+ node_output_displacement.osl
+ node_output_surface.osl
+ node_output_volume.osl
+ node_sky_texture.osl
+ node_stucci_texture.osl
+ node_texture_coordinate.osl
+ node_translucent_bsdf.osl
+ node_transparent_bsdf.osl
+ node_value.osl
+ node_vector_math.osl
+ node_velvet_bsdf.osl
+ node_voronoi_texture.osl
+ node_ward_bsdf.osl
+ node_wood_texture.osl)
+
+SET(osl_headers
+ node_texture.h
+ stdosl.h)
+
+SET(oso_sources)
+
+FOREACH(_file ${osl_sources})
+ SET(osl_file ${CMAKE_CURRENT_SOURCE_DIR}/${_file})
+ STRING(REPLACE ".osl" ".oso" oso_file ${osl_file})
+ STRING(REPLACE ${CMAKE_SOURCE_DIR} ${CMAKE_BINARY_DIR} oso_file ${oso_file})
+ ADD_CUSTOM_COMMAND(
+ OUTPUT ${oso_file}
+ COMMAND ${OSL_COMPILER} -O2 ${osl_file}
+ DEPENDS ${osl_file} ${osl_headers})
+ LIST(APPEND oso_sources ${oso_file})
+ENDFOREACH()
+
+ADD_CUSTOM_TARGET(shader ALL DEPENDS ${oso_sources} ${osl_headers})
+
+INSTALL(FILES ${oso_sources} DESTINATION ${INSTALL_PATH}/cycles/shader)
+
diff --git a/intern/cycles/kernel/osl/nodes/node_add_closure.osl b/intern/cycles/kernel/osl/nodes/node_add_closure.osl
new file mode 100644
index 00000000000..ecf6bf5912e
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_add_closure.osl
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+shader node_add_closure(
+ closure color Closure1 = background(),
+ closure color Closure2 = background(),
+ output closure color Closure = background())
+{
+ Closure = Closure1 + Closure2;
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_attribute.osl b/intern/cycles/kernel/osl/nodes/node_attribute.osl
new file mode 100644
index 00000000000..d273d0c68d7
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_attribute.osl
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+shader node_attribute(
+ string bump_offset = "center",
+ string name = "",
+ output point Vector = point(0.0, 0.0, 0.0),
+ output color Color = color(0.0, 0.0, 0.0),
+ output float Fac = 0.0)
+{
+ getattribute(name, Color);
+ Vector = point(Color);
+ getattribute(name, Fac);
+
+ if(bump_offset == "dx") {
+ Color += Dx(Color);
+ Vector += Dx(Vector);
+ Fac += Dx(Fac);
+ }
+ else if(bump_offset == "dy") {
+ Color += Dy(Color);
+ Vector += Dy(Vector);
+ Fac += Dy(Fac);
+ }
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_background.osl b/intern/cycles/kernel/osl/nodes/node_background.osl
new file mode 100644
index 00000000000..69f8d85a82e
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_background.osl
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+shader node_background(
+ color Color = color(0.8, 0.8, 0.8),
+ float Strength = 1.0,
+ output closure color Background = background())
+{
+ Background = Color*Strength*background();
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_blend_texture.osl b/intern/cycles/kernel/osl/nodes/node_blend_texture.osl
new file mode 100644
index 00000000000..de1bdaca90b
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_blend_texture.osl
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+#include "node_texture.h"
+
+/* Blend */
+
+float blend(point p, string progression, string axis)
+{
+ float x, y;
+
+ if(axis == "Vertical") {
+ x= p[1];
+ y= p[0];
+ }
+ else {
+ x= p[0];
+ y= p[1];
+ }
+
+ float result = 0.0;
+
+ if(progression == "Linear") {
+ result = (1.0 + x)/2.0;
+ }
+ else if(progression == "Quadratic") {
+ float r = max((1.0 + x)/2.0, 0.0);
+ result = r*r;
+ }
+ else if(progression == "Easing") {
+ float r = min(max((1.0 + x)/2.0, 0.0), 1.0);
+ float t = r*r;
+
+ result = (3.0*t - 2.0*t*r);
+ }
+ else if(progression == "Diagonal") {
+ result = (2.0 + x + y)/4.0;
+ }
+ else if(progression == "Radial") {
+ result = atan2(y, x)/(2*M_PI) + 0.5;
+ }
+ else {
+ float r = max(1.0 - sqrt(x*x + y*y + p[2]*p[2]), 0.0);
+
+ if(progression == "Quadratic Sphere")
+ result = r*r;
+ else if(progression == "Spherical")
+ result = r;
+ }
+
+ return result;
+}
+
+shader node_blend_texture(
+ string Progression = "Linear",
+ string Axis = "Horizontal",
+ point Vector = P,
+ output float Fac = 0.0)
+{
+ Fac = blend(Vector, Progression, Axis);
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_bump.osl b/intern/cycles/kernel/osl/nodes/node_bump.osl
new file mode 100644
index 00000000000..a3849e70f98
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_bump.osl
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+/* "Bump Mapping Unparametrized Surfaces on the GPU"
+ * Morten S. Mikkelsen, 2010 */
+
+surface node_bump(
+ float SampleCenter = 0.0,
+ float SampleX = 0.0,
+ float SampleY = 0.0,
+ output normal Normal = N)
+{
+ float dx = SampleX - SampleCenter;
+ float dy = SampleY - SampleCenter;
+
+ vector dPdx = Dx(P);
+ vector dPdy = Dy(P);
+
+ vector Rx = cross(dPdy, N);
+ vector Ry = cross(N, dPdx);
+
+ float det = dot(dPdx, Rx);
+ vector surfgrad = dx*Rx + dy*Ry;
+
+ surfgrad *= 0.1; /* todo: remove this factor */
+
+ Normal = normalize(abs(det)*N - sign(det)*surfgrad);
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_clouds_texture.osl b/intern/cycles/kernel/osl/nodes/node_clouds_texture.osl
new file mode 100644
index 00000000000..6d244d81e27
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_clouds_texture.osl
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+#include "node_texture.h"
+
+/* Turbulence */
+
+shader node_clouds_texture(
+ string Basis = "Perlin",
+ int Hard = 0,
+ int Depth = 2,
+ float Size = 0.25,
+ point Vector = P,
+ output float Fac = 0.0,
+ output color Color = color(0.0, 0.0, 0.0))
+{
+ float size = nonzero(Size, 1e-5);
+ point p = Vector/size;
+
+ Fac = noise_turbulence(p, Basis, Depth, Hard);
+
+ Color[0] = Fac;
+ Color[1] = noise_turbulence(point(p[1], p[0], p[2]), Basis, Depth, Hard);
+ Color[2] = noise_turbulence(point(p[1], p[2], p[0]), Basis, Depth, Hard);
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_convert_from_color.osl b/intern/cycles/kernel/osl/nodes/node_convert_from_color.osl
new file mode 100644
index 00000000000..97356139c48
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_convert_from_color.osl
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+shader node_convert_from_color(
+ color Color = color(0.0, 0.0, 0.0),
+ output float Val = 0.0,
+ output vector Vector = vector(0.0, 0.0, 0.0),
+ output point Point = point(0.0, 0.0, 0.0),
+ output normal Normal = normal(0.0, 0.0, 0.0))
+{
+ Val = Color[0]*0.2126 + Color[1]*0.7152 + Color[2]*0.0722;
+ Vector = vector(Color[0], Color[1], Color[2]);
+ Point = point(Color[0], Color[1], Color[2]);
+ Normal = normal(Color[0], Color[1], Color[2]);
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_convert_from_float.osl b/intern/cycles/kernel/osl/nodes/node_convert_from_float.osl
new file mode 100644
index 00000000000..00e78f3bab4
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_convert_from_float.osl
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+shader node_convert_from_float(
+ float Val = 0.0,
+ output color Color = color(0.0, 0.0, 0.0),
+ output vector Vector = vector(0.0, 0.0, 0.0),
+ output point Point = point(0.0, 0.0, 0.0),
+ output normal Normal = normal(0.0, 0.0, 0.0))
+{
+ Color = color(Val, Val, Val);
+ Vector = vector(Val, Val, Val);
+ Point = point(Val, Val, Val);
+ Normal = normal(Val, Val, Val);
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_convert_from_normal.osl b/intern/cycles/kernel/osl/nodes/node_convert_from_normal.osl
new file mode 100644
index 00000000000..0bb9092591d
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_convert_from_normal.osl
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+shader node_convert_from_normal(
+ normal Normal = normal(0.0, 0.0, 0.0),
+ output float Val = 0.0,
+ output vector Vector = vector(0.0, 0.0, 0.0),
+ output color Color = color(0.0, 0.0, 0.0),
+ output point Point = point(0.0, 0.0, 0.0))
+{
+ Val = (Normal[0] + Normal[1] + Normal[2])*(1.0/3.0);
+ Vector = vector(Normal[0], Normal[1], Normal[2]);
+ Color = color(Normal[0], Normal[1], Normal[2]);
+ Point = point(Normal[0], Normal[1], Normal[2]);
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_convert_from_point.osl b/intern/cycles/kernel/osl/nodes/node_convert_from_point.osl
new file mode 100644
index 00000000000..e66d6a864d6
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_convert_from_point.osl
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+shader node_convert_from_point(
+ point Point = point(0.0, 0.0, 0.0),
+ output float Val = 0.0,
+ output vector Vector = vector(0.0, 0.0, 0.0),
+ output color Color = color(0.0, 0.0, 0.0),
+ output normal Normal = normal(0.0, 0.0, 0.0))
+{
+ Val = (Point[0] + Point[1] + Point[2])*(1.0/3.0);
+ Vector = vector(Point[0], Point[1], Point[2]);
+ Color = color(Point[0], Point[1], Point[2]);
+ Normal = normal(Point[0], Point[1], Point[2]);
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_convert_from_vector.osl b/intern/cycles/kernel/osl/nodes/node_convert_from_vector.osl
new file mode 100644
index 00000000000..37ba9582cad
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_convert_from_vector.osl
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+shader node_convert_from_vector(
+ vector Vector = vector(0.0, 0.0, 0.0),
+ output float Val = 0.0,
+ output color Color = color(0.0, 0.0, 0.0),
+ output point Point = point(0.0, 0.0, 0.0),
+ output normal Normal = normal(0.0, 0.0, 0.0))
+{
+ Val = (Vector[0] + Vector[1] + Vector[2])*(1.0/3.0);
+ Color = color(Vector[0], Vector[1], Vector[2]);
+ Point = point(Vector[0], Vector[1], Vector[2]);
+ Normal = normal(Vector[0], Vector[1], Vector[2]);
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_diffuse_bsdf.osl b/intern/cycles/kernel/osl/nodes/node_diffuse_bsdf.osl
new file mode 100644
index 00000000000..8cf161c17cc
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_diffuse_bsdf.osl
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+shader node_diffuse_bsdf(
+ color Color = color(0.8, 0.8, 0.8),
+ normal Normal = N,
+ output closure color BSDF = diffuse(Normal))
+{
+ BSDF = Color*diffuse(Normal);
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_distorted_noise_texture.osl b/intern/cycles/kernel/osl/nodes/node_distorted_noise_texture.osl
new file mode 100644
index 00000000000..bb338c4ef0f
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_distorted_noise_texture.osl
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+#include "node_texture.h"
+
+/* Distorted Noise (variable lacunarity noise) */
+
+float noise_distorted(point p, string basis, string distortion_basis, float distortion)
+{
+ point r;
+
+ r[0] = noise_basis(p + point(13.5), basis) * distortion;
+ r[1] = noise_basis(p, basis) * distortion;
+ r[2] = noise_basis(p - point(13.5), basis) * distortion;
+
+ return noise_basis(p + r, distortion_basis); /* distorted-domain noise */
+}
+
+shader node_distorted_noise_texture(
+ string Basis = "Perlin",
+ string DistortionBasis = "Perlin",
+ float Distortion = 1.0,
+ float Size = 0.25,
+ point Vector = P,
+ output float Fac = 0.0)
+{
+ float size = nonzero(Size, 1e-5);
+ Fac = noise_distorted(Vector/size, Basis, DistortionBasis, Distortion);
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_emission.osl b/intern/cycles/kernel/osl/nodes/node_emission.osl
new file mode 100644
index 00000000000..8bfd1af173a
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_emission.osl
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+shader node_emission(
+ int TotalPower = 0,
+ color Color = color(0.8, 0.8, 0.8),
+ float Strength = 1.0,
+ output closure color Emission = emission())
+{
+ if(TotalPower)
+ Emission = ((Strength/surfacearea())*Color)*emission();
+ else
+ Emission = (Strength*Color)*emission();
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_environment_texture.osl b/intern/cycles/kernel/osl/nodes/node_environment_texture.osl
new file mode 100644
index 00000000000..569b22d53ec
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_environment_texture.osl
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+shader node_environment_texture(
+ vector Vector = P,
+ string filename = "",
+ output color Color = color(0.0, 0.0, 0.0))
+{
+ Color = (color)environment(filename, Vector);
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_fresnel.h b/intern/cycles/kernel/osl/nodes/node_fresnel.h
new file mode 100644
index 00000000000..0c8a5276ede
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_fresnel.h
@@ -0,0 +1,21 @@
+
+float fresnel_dielectric(vector Incoming, normal Normal, float eta)
+{
+ /* compute fresnel reflectance without explicitly computing
+ the refracted direction */
+ float c = fabs(dot(Incoming, Normal));
+ float g = eta * eta - 1 + c * c;
+ float result;
+
+ if(g > 0) {
+ g = sqrt(g);
+ float A =(g - c)/(g + c);
+ float B =(c *(g + c)- 1)/(c *(g - c)+ 1);
+ result = 0.5 * A * A *(1 + B * B);
+ }
+ else
+ result = 1.0; /* TIR (no refracted component) */
+
+ return result;
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_fresnel.osl b/intern/cycles/kernel/osl/nodes/node_fresnel.osl
new file mode 100644
index 00000000000..ddc86db130f
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_fresnel.osl
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+#include "node_fresnel.h"
+
+shader node_fresnel(
+ float Fresnel = 0.3,
+ normal Normal = N,
+ output float Fac = 0.0)
+{
+ float f = max(1.0 - Fresnel, 0.00001);
+ Fac = fresnel_dielectric(I, Normal, backfacing()? f: 1.0/f);
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_geometry.osl b/intern/cycles/kernel/osl/nodes/node_geometry.osl
new file mode 100644
index 00000000000..bf76e2e597a
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_geometry.osl
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+shader node_geometry(
+ normal NormalIn = N,
+ string bump_offset = "center",
+
+ output point Position = point(0.0, 0.0, 0.0),
+ output normal Normal = normal(0.0, 0.0, 0.0),
+ output normal Tangent = normal(0.0, 0.0, 0.0),
+ output normal TrueNormal = normal(0.0, 0.0, 0.0),
+ output vector Incoming = vector(0.0, 0.0, 0.0),
+ output point UV = point(0.0, 0.0, 0.0),
+ output float Backfacing = 0.0)
+{
+ Position = P;
+ Normal = NormalIn;
+ Tangent = normalize(dPdu);
+ TrueNormal = Ng;
+ Incoming = I;
+ UV = point(u, v, 0.0);
+ Backfacing = backfacing();
+
+ if(bump_offset == "dx") {
+ Position += Dx(Position);
+ UV += Dx(UV);
+ }
+ else if(bump_offset == "dy") {
+ Position += Dy(Position);
+ UV += Dy(UV);
+ }
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_glass_bsdf.osl b/intern/cycles/kernel/osl/nodes/node_glass_bsdf.osl
new file mode 100644
index 00000000000..af946048011
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_glass_bsdf.osl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+#include "node_fresnel.h"
+
+shader node_glass_bsdf(
+ color Color = color(0.8, 0.8, 0.8),
+ string distribution = "Sharp",
+ float Roughness = 0.2,
+ float Fresnel = 0.3,
+ normal Normal = N,
+ output closure color BSDF = diffuse(Normal))
+{
+ float f = clamp(1.0 - Fresnel, 1e-5, 1.0 - 1e-5);
+ float eta = backfacing()? f: 1.0/f;
+ float Fr = fresnel_dielectric(I, Normal, eta);
+
+ if(distribution == "Sharp")
+ BSDF = Color*(Fr*reflection(Normal) + (1.0-Fr)*refraction(Normal, eta));
+ else if(distribution == "Beckmann")
+ BSDF = Color*(Fr*microfacet_beckmann(Normal, Roughness) + (1.0-Fr)*microfacet_beckmann_refraction(Normal, Roughness, eta));
+ else if(distribution == "GGX")
+ BSDF = Color*(Fr*microfacet_ggx(Normal, Roughness) + (1.0-Fr)*microfacet_ggx_refraction(Normal, Roughness, eta));
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_glossy_bsdf.osl b/intern/cycles/kernel/osl/nodes/node_glossy_bsdf.osl
new file mode 100644
index 00000000000..ca6bee74b38
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_glossy_bsdf.osl
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+#include "node_fresnel.h"
+
+shader node_glossy_bsdf(
+ color Color = color(0.8, 0.8, 0.8),
+ string distribution = "Beckmann",
+ float Roughness = 0.2,
+ float Fresnel = 1.0,
+ normal Normal = N,
+ output closure color BSDF = diffuse(Normal))
+{
+ float Fr = 1.0;
+
+ if(Fresnel < 1.0) {
+ float eta = 1.0/clamp(1.0 - Fresnel, 1e-5, 1.0 - 1e-5);
+ Fr = fresnel_dielectric(I, Normal, eta);
+ }
+
+ if(distribution == "Sharp")
+ BSDF = (Fr*Color)*reflection(Normal);
+ else if(distribution == "Beckmann")
+ BSDF = (Fr*Color)*microfacet_beckmann(Normal, Roughness);
+ else if(distribution == "GGX")
+ BSDF = (Fr*Color)*microfacet_ggx(Normal, Roughness);
+
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_image_texture.osl b/intern/cycles/kernel/osl/nodes/node_image_texture.osl
new file mode 100644
index 00000000000..0dbcc122deb
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_image_texture.osl
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+shader node_image_texture(
+ point Vector = P,
+ string filename = "",
+ output color Color = color(0.0, 0.0, 0.0))
+{
+ Color = (color)texture(filename, Vector[0], 1.0-Vector[1], "wrap", "periodic");
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_light_path.osl b/intern/cycles/kernel/osl/nodes/node_light_path.osl
new file mode 100644
index 00000000000..081640428ab
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_light_path.osl
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+shader node_light_path(
+ output float IsCameraRay = 0.0,
+ output float IsShadowRay = 0.0,
+ output float IsDiffuseRay = 0.0,
+ output float IsGlossyRay = 0.0,
+ output float IsReflectionRay = 0.0,
+ output float IsTransmissionRay = 0.0)
+{
+ IsCameraRay = raytype("camera");
+ IsShadowRay = raytype("shadow");
+ IsDiffuseRay = raytype("diffuse");
+ IsGlossyRay = raytype("glossy");
+ IsReflectionRay = raytype("reflection");
+ IsTransmissionRay = raytype("refraction");
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_magic_texture.osl b/intern/cycles/kernel/osl/nodes/node_magic_texture.osl
new file mode 100644
index 00000000000..0b6e980debc
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_magic_texture.osl
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+#include "node_texture.h"
+
+/* Magic */
+
+color magic(point p, int n, float turbulence)
+{
+ float turb = turbulence/5.0;
+
+ float x = sin((p[0] + p[1] + p[2])*5.0);
+ float y = cos((-p[0] + p[1] - p[2])*5.0);
+ float z = -cos((-p[0] - p[1] + p[2])*5.0);
+
+ if(n > 0) {
+ x *= turb;
+ y *= turb;
+ z *= turb;
+ y = -cos(x-y+z);
+ y *= turb;
+
+ if(n > 1) {
+ x= cos(x-y-z);
+ x *= turb;
+
+ if(n > 2) {
+ z= sin(-x-y-z);
+ z *= turb;
+
+ if(n > 3) {
+ x= -cos(-x+y-z);
+ x *= turb;
+
+ if(n > 4) {
+ y= -sin(-x+y+z);
+ y *= turb;
+
+ if(n > 5) {
+ y= -cos(-x+y+z);
+ y *= turb;
+
+ if(n > 6) {
+ x= cos(x+y+z);
+ x *= turb;
+
+ if(n > 7) {
+ z= sin(x+y-z);
+ z *= turb;
+
+ if(n > 8) {
+ x= -cos(-x-y+z);
+ x *= turb;
+
+ if(n > 9) {
+ y= -sin(x-y+z);
+ y *= turb;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(turb != 0.0) {
+ turb *= 2.0;
+ x /= turb;
+ y /= turb;
+ z /= turb;
+ }
+
+ return color(0.5 - x, 0.5 - y, 0.5 - z);
+}
+
+shader node_magic_texture(
+ int Depth = 2,
+ float Turbulence = 5.0,
+ point Vector = P,
+ output color Color = color(0.0, 0.0, 0.0))
+{
+ Color = magic(Vector, Depth, Turbulence);
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_mapping.osl b/intern/cycles/kernel/osl/nodes/node_mapping.osl
new file mode 100644
index 00000000000..f342837d3c9
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_mapping.osl
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+shader node_mapping(
+ matrix Matrix = matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
+ point Vector = point(0.0, 0.0, 0.0),
+ output point Vector_ = point(0.0, 0.0, 0.0))
+{
+ Vector_ = transform(Matrix, Vector);
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_marble_texture.osl b/intern/cycles/kernel/osl/nodes/node_marble_texture.osl
new file mode 100644
index 00000000000..9e18dee3235
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_marble_texture.osl
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+#include "node_texture.h"
+
+/* Marble */
+
+float marble(point p, float size, string type, string wave, string basis, int hard, float turb, int depth)
+{
+ float x = p[0];
+ float y = p[1];
+ float z = p[2];
+
+ float n = 5.0 * (x + y + z);
+
+ float mi = n + turb * noise_turbulence(p/size, basis, depth, hard);
+
+ mi = noise_wave(wave, mi);
+
+ if(type == "Sharp")
+ mi = sqrt(mi);
+ else if(type == "Sharper")
+ mi = sqrt(sqrt(mi));
+
+ return mi;
+}
+
+shader node_marble_texture(
+ string Type = "Soft",
+ string Wave = "Sine",
+ string Basis = "Perlin",
+ int Hard = 0,
+ float Size = 0.25,
+ float Turbulence = 5.0,
+ int Depth = 2,
+ point Vector = P,
+ output float Fac = 0.0)
+{
+ float size = nonzero(Size, 1e-5);
+ Fac = marble(Vector, size, Type, Wave, Basis, Hard, Turbulence, Depth);
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_math.osl b/intern/cycles/kernel/osl/nodes/node_math.osl
new file mode 100644
index 00000000000..be9bb71d511
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_math.osl
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+float safe_divide(float a, float b)
+{
+ float result;
+
+ if(b == 0.0)
+ result = 0.0;
+ else
+ result = a/b;
+
+ return result;
+}
+
+float safe_log(float a, float b)
+{
+ if(a < 0.0 || b < 0.0)
+ return 0.0;
+
+ return log(a)/log(b);
+}
+
+shader node_math(
+ string type = "Add",
+ float Value1 = 0.0,
+ float Value2 = 0.0,
+ output float Value = 0.0)
+{
+ /* OSL asin, acos, pow check for values that could give rise to nan */
+
+ if(type == "Add")
+ Value = Value1 + Value2;
+ if(type == "Subtract")
+ Value = Value1 - Value2;
+ if(type == "Multiply")
+ Value = Value1*Value2;
+ if(type == "Divide")
+ Value = safe_divide(Value1, Value2);
+ if(type == "Sine")
+ Value = sin(Value1);
+ if(type == "Cosine")
+ Value = cos(Value1);
+ if(type == "Tangent")
+ Value = tan(Value1);
+ if(type == "Arcsine")
+ Value = asin(Value1);
+ if(type == "Arccosine")
+ Value = acos(Value1);
+ if(type == "Arctangent")
+ Value = atan(Value1);
+ if(type == "Power")
+ Value = pow(Value1, Value2);
+ if(type == "Logarithm")
+ Value = safe_log(Value1, Value2);
+ if(type == "Minimum")
+ Value = min(Value1, Value2);
+ if(type == "Maximum")
+ Value = max(Value1, Value2);
+ if(type == "Round")
+ Value = floor(Value1 + 0.5);
+ if(type == "Less Than")
+ Value = Value1 < Value2;
+ if(type == "Greater Than")
+ Value = Value1 > Value2;
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_mix.osl b/intern/cycles/kernel/osl/nodes/node_mix.osl
new file mode 100644
index 00000000000..582aa7b3c60
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_mix.osl
@@ -0,0 +1,388 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+color rgb_to_hsv(color rgb)
+{
+ float cmax, cmin, h, s, v, cdelta;
+ color c;
+
+ cmax = max(rgb[0], max(rgb[1], rgb[2]));
+ cmin = min(rgb[0], min(rgb[1], rgb[2]));
+ cdelta = cmax - cmin;
+
+ v = cmax;
+
+ if(cmax != 0.0) {
+ s = cdelta/cmax;
+ }
+ else {
+ s = 0.0;
+ h = 0.0;
+ }
+
+ if(s == 0.0) {
+ h = 0.0;
+ }
+ else {
+ c = (color(cmax, cmax, cmax) - rgb)/cdelta;
+
+ if(rgb[0] == cmax) h = c[2] - c[1];
+ else if(rgb[1] == cmax) h = 2.0 + c[0] - c[2];
+ else h = 4.0 + c[1] - c[0];
+
+ h /= 6.0;
+
+ if(h < 0.0)
+ h += 1.0;
+ }
+
+ return color(h, s, v);
+}
+
+color hsv_to_rgb(color hsv)
+{
+ float i, f, p, q, t, h, s, v;
+ color rgb;
+
+ h = hsv[0];
+ s = hsv[1];
+ v = hsv[2];
+
+ if(s==0.0) {
+ rgb = color(v, v, v);
+ }
+ else {
+ if(h==1.0)
+ h = 0.0;
+
+ h *= 6.0;
+ i = floor(h);
+ f = h - i;
+ rgb = color(f, f, f);
+ p = v*(1.0-s);
+ q = v*(1.0-(s*f));
+ t = v*(1.0-(s*(1.0-f)));
+
+ if(i == 0.0) rgb = color(v, t, p);
+ else if(i == 1.0) rgb = color(q, v, p);
+ else if(i == 2.0) rgb = color(p, v, t);
+ else if(i == 3.0) rgb = color(p, q, v);
+ else if(i == 4.0) rgb = color(t, p, v);
+ else rgb = color(v, p, q);
+ }
+
+ return rgb;
+}
+
+color node_mix_blend(float t, color col1, color col2)
+{
+ return mix(col1, col2, t);
+}
+
+color node_mix_add(float t, color col1, color col2)
+{
+ return mix(col1, col1 + col2, t);
+}
+
+color node_mix_mul(float t, color col1, color col2)
+{
+ return mix(col1, col1 * col2, t);
+}
+
+color node_mix_screen(float t, color col1, color col2)
+{
+ float tm = 1.0 - t;
+
+ return color(1.0) - (color(tm) + t*(color(1.0) - col2))*(color(1.0) - col1);
+}
+
+color node_mix_overlay(float t, color col1, color col2)
+{
+ float tm = 1.0 - t;
+
+ color outcol = col1;
+
+ if(outcol[0] < 0.5)
+ outcol[0] *= tm + 2.0*t*col2[0];
+ else
+ outcol[0] = 1.0 - (tm + 2.0*t*(1.0 - col2[0]))*(1.0 - outcol[0]);
+
+ if(outcol[1] < 0.5)
+ outcol[1] *= tm + 2.0*t*col2[1];
+ else
+ outcol[1] = 1.0 - (tm + 2.0*t*(1.0 - col2[1]))*(1.0 - outcol[1]);
+
+ if(outcol[2] < 0.5)
+ outcol[2] *= tm + 2.0*t*col2[2];
+ else
+ outcol[2] = 1.0 - (tm + 2.0*t*(1.0 - col2[2]))*(1.0 - outcol[2]);
+
+ return outcol;
+}
+
+color node_mix_sub(float t, color col1, color col2)
+{
+ return mix(col1, col1 - col2, t);
+}
+
+color node_mix_div(float t, color col1, color col2)
+{
+ float tm = 1.0 - t;
+
+ color outcol = col1;
+
+ if(col2[0] != 0.0) outcol[0] = tm*outcol[0] + t*outcol[0]/col2[0];
+ if(col2[1] != 0.0) outcol[1] = tm*outcol[1] + t*outcol[1]/col2[1];
+ if(col2[2] != 0.0) outcol[2] = tm*outcol[2] + t*outcol[2]/col2[2];
+
+ return outcol;
+}
+
+color node_mix_diff(float t, color col1, color col2)
+{
+ return mix(col1, abs(col1 - col2), t);
+}
+
+color node_mix_dark(float t, color col1, color col2)
+{
+ return min(col1, col2*t);
+}
+
+color node_mix_light(float t, color col1, color col2)
+{
+ return max(col1, col2*t);
+}
+
+color node_mix_dodge(float t, color col1, color col2)
+{
+ color outcol = col1;
+
+ if(outcol[0] != 0.0) {
+ float tmp = 1.0 - t*col2[0];
+ if(tmp <= 0.0)
+ outcol[0] = 1.0;
+ else if((tmp = outcol[0]/tmp) > 1.0)
+ outcol[0] = 1.0;
+ else
+ outcol[0] = tmp;
+ }
+ if(outcol[1] != 0.0) {
+ float tmp = 1.0 - t*col2[1];
+ if(tmp <= 0.0)
+ outcol[1] = 1.0;
+ else if((tmp = outcol[1]/tmp) > 1.0)
+ outcol[1] = 1.0;
+ else
+ outcol[1] = tmp;
+ }
+ if(outcol[2] != 0.0) {
+ float tmp = 1.0 - t*col2[2];
+ if(tmp <= 0.0)
+ outcol[2] = 1.0;
+ else if((tmp = outcol[2]/tmp) > 1.0)
+ outcol[2] = 1.0;
+ else
+ outcol[2] = tmp;
+ }
+
+ return outcol;
+}
+
+color node_mix_burn(float t, color col1, color col2)
+{
+ float tmp, tm = 1.0 - t;
+
+ color outcol = col1;
+
+ tmp = tm + t*col2[0];
+ if(tmp <= 0.0)
+ outcol[0] = 0.0;
+ else if((tmp = (1.0 - (1.0 - outcol[0])/tmp)) < 0.0)
+ outcol[0] = 0.0;
+ else if(tmp > 1.0)
+ outcol[0] = 1.0;
+ else
+ outcol[0] = tmp;
+
+ tmp = tm + t*col2[1];
+ if(tmp <= 0.0)
+ outcol[1] = 0.0;
+ else if((tmp = (1.0 - (1.0 - outcol[1])/tmp)) < 0.0)
+ outcol[1] = 0.0;
+ else if(tmp > 1.0)
+ outcol[1] = 1.0;
+ else
+ outcol[1] = tmp;
+
+ tmp = tm + t*col2[2];
+ if(tmp <= 0.0)
+ outcol[2] = 0.0;
+ else if((tmp = (1.0 - (1.0 - outcol[2])/tmp)) < 0.0)
+ outcol[2] = 0.0;
+ else if(tmp > 1.0)
+ outcol[2] = 1.0;
+ else
+ outcol[2] = tmp;
+
+ return outcol;
+}
+
+color node_mix_hue(float t, color col1, color col2)
+{
+ color outcol = col1;
+ color hsv2 = rgb_to_hsv(col2);
+
+ if(hsv2[1] != 0.0) {
+ color hsv = rgb_to_hsv(outcol);
+ hsv[0] = hsv2[0];
+ color tmp = hsv_to_rgb(hsv);
+
+ outcol = mix(outcol, tmp, t);
+ }
+
+ return outcol;
+}
+
+color node_mix_sat(float t, color col1, color col2)
+{
+ float tm = 1.0 - t;
+
+ color outcol = col1;
+
+ color hsv = rgb_to_hsv(outcol);
+
+ if(hsv[1] != 0.0) {
+ color hsv2 = rgb_to_hsv(col2);
+
+ hsv[1] = tm*hsv[1] + t*hsv2[1];
+ outcol = hsv_to_rgb(hsv);
+ }
+
+ return outcol;
+}
+
+color node_mix_val(float t, color col1, color col2)
+{
+ float tm = 1.0 - t;
+
+ color hsv = rgb_to_hsv(col1);
+ color hsv2 = rgb_to_hsv(col2);
+
+ hsv[2] = tm*hsv[2] + t*hsv2[2];
+
+ return hsv_to_rgb(hsv);
+}
+
+color node_mix_color(float t, color col1, color col2)
+{
+ color outcol = col1;
+ color hsv2 = rgb_to_hsv(col2);
+
+ if(hsv2[1] != 0.0) {
+ color hsv = rgb_to_hsv(outcol);
+ hsv[0] = hsv2[0];
+ hsv[1] = hsv2[1];
+ color tmp = hsv_to_rgb(hsv);
+
+ outcol = mix(outcol, tmp, t);
+ }
+
+ return outcol;
+}
+
+color node_mix_soft(float t, color col1, color col2)
+{
+ float tm = 1.0 - t;
+
+ color one= color(1.0);
+ color scr= one - (one - col2)*(one - col1);
+
+ return tm*col1 + t*((one - col1)*col2*col1 + col1*scr);
+}
+
+color node_mix_linear(float t, color col1, color col2)
+{
+ color outcol = col1;
+
+ if(col2[0] > 0.5)
+ outcol[0]= col1[0] + t*(2.0*(col2[0] - 0.5));
+ else
+ outcol[0]= col1[0] + t*(2.0*(col2[0]) - 1.0);
+
+ if(col2[1] > 0.5)
+ outcol[1]= col1[1] + t*(2.0*(col2[1] - 0.5));
+ else
+ outcol[1]= col1[1] + t*(2.0*(col2[1]) - 1.0);
+
+ if(col2[2] > 0.5)
+ outcol[2]= col1[2] + t*(2.0*(col2[2] - 0.5));
+ else
+ outcol[2]= col1[2] + t*(2.0*(col2[2]) - 1.0);
+
+ return outcol;
+}
+
+shader node_mix(
+ string type = "Mix",
+ float Fac = 0.5,
+ color Color1 = color(0.0, 0.0, 0.0),
+ color Color2 = color(0.0, 0.0, 0.0),
+ output color Color = color(0.0, 0.0, 0.0))
+{
+ float t = clamp(Fac, 0.0, 1.0);
+
+ if(type == "Mix")
+ Color = node_mix_blend(t, Color1, Color2);
+ if(type == "Add")
+ Color = node_mix_add(t, Color1, Color2);
+ if(type == "Multiply")
+ Color = node_mix_mul(t, Color1, Color2);
+ if(type == "Screen")
+ Color = node_mix_screen(t, Color1, Color2);
+ if(type == "Overlay")
+ Color = node_mix_overlay(t, Color1, Color2);
+ if(type == "Subtract")
+ Color = node_mix_sub(t, Color1, Color2);
+ if(type == "Divide")
+ Color = node_mix_div(t, Color1, Color2);
+ if(type == "Difference")
+ Color = node_mix_diff(t, Color1, Color2);
+ if(type == "Darken")
+ Color = node_mix_dark(t, Color1, Color2);
+ if(type == "Lighten")
+ Color = node_mix_light(t, Color1, Color2);
+ if(type == "Dodge")
+ Color = node_mix_dodge(t, Color1, Color2);
+ if(type == "Burn")
+ Color = node_mix_burn(t, Color1, Color2);
+ if(type == "Hue")
+ Color = node_mix_hue(t, Color1, Color2);
+ if(type == "Saturation")
+ Color = node_mix_sat(t, Color1, Color2);
+ if(type == "Value")
+ Color = node_mix_val (t, Color1, Color2);
+ if(type == "Color")
+ Color = node_mix_color(t, Color1, Color2);
+ if(type == "Soft Light")
+ Color = node_mix_soft(t, Color1, Color2);
+ if(type == "Linear Light")
+ Color = node_mix_linear(t, Color1, Color2);
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_mix_closure.osl b/intern/cycles/kernel/osl/nodes/node_mix_closure.osl
new file mode 100644
index 00000000000..1a377abd381
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_mix_closure.osl
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+shader node_mix_closure(
+ float Fac = 0.5,
+ closure color Closure1 = background(),
+ closure color Closure2 = background(),
+ output closure color Closure = background())
+{
+ float t = clamp(Fac, 0.0, 1.0);
+ Closure = (1.0 - t)*Closure1 + t*Closure2;
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_musgrave_texture.osl b/intern/cycles/kernel/osl/nodes/node_musgrave_texture.osl
new file mode 100644
index 00000000000..fbd0ce5c3bd
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_musgrave_texture.osl
@@ -0,0 +1,218 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+#include "node_texture.h"
+
+/* Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
+
+float noise_musgrave_fBm(point p, string basis, float H, float lacunarity, float octaves)
+{
+ float rmd;
+ float value = 0.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+ int i;
+
+ for(i = 0; i < (int)octaves; i++) {
+ value += noise_basis(p, basis) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if(rmd != 0.0)
+ value += rmd * noise_basis(p, basis) * pwr;
+
+ return value;
+}
+
+/* Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+float noise_musgrave_multi_fractal(point p, string basis, float H, float lacunarity, float octaves)
+{
+ float rmd;
+ float value = 1.0;
+ float pwr = 1.0;
+ float pwHL = pow(lacunarity, -H);
+ int i;
+
+ for(i = 0; i < (int)octaves; i++) {
+ value *= (pwr * noise_basis(p, basis) + 1.0);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if(rmd != 0.0)
+ value *= (rmd * pwr * noise_basis(p, basis) + 1.0); /* correct? */
+
+ return value;
+}
+
+/* Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+float noise_musgrave_hetero_terrain(point p, string basis, float H, float lacunarity, float octaves, float offset)
+{
+ float value, increment, rmd;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+ int i;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ value = offset + noise_basis(p, basis);
+ p *= lacunarity;
+
+ for(i = 1; i < (int)octaves; i++) {
+ increment = (noise_basis(p, basis) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if(rmd != 0.0) {
+ increment = (noise_basis(p, basis) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ return value;
+}
+
+/* Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+float noise_musgrave_hybrid_multi_fractal(point p, string basis, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float result, signal, weight, rmd;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+ int i;
+
+ result = noise_basis(p, basis) + offset;
+ weight = gain * result;
+ p *= lacunarity;
+
+ for(i = 1; (weight > 0.001) && (i < (int)octaves); i++) {
+ if(weight > 1.0)
+ weight = 1.0;
+
+ signal = (noise_basis(p, basis) + offset) * pwr;
+ pwr *= pwHL;
+ result += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if(rmd != 0.0)
+ result += rmd * ((noise_basis(p, basis) + offset) * pwr);
+
+ return result;
+}
+
+/* Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+float noise_musgrave_ridged_multi_fractal(point p, string basis, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float result, signal, weight;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+ int i;
+
+ signal = offset - fabs(noise_basis(p, basis));
+ signal *= signal;
+ result = signal;
+ weight = 1.0;
+
+ for(i = 1; i < (int)octaves; i++) {
+ p *= lacunarity;
+ weight = clamp(signal * gain, 0.0, 1.0);
+ signal = offset - fabs(noise_basis(p, basis));
+ signal *= signal;
+ signal *= weight;
+ result += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ return result;
+}
+
+/* Shader */
+
+shader node_musgrave_texture(
+ string Type = "fBM",
+ string Basis = "Perlin",
+ float Dimension = 2.0,
+ float Lacunarity = 1.0,
+ float Octaves = 2.0,
+ float Offset = 0.0,
+ float Intensity = 1.0,
+ float Gain = 1.0,
+ float Size = 0.25,
+ point Vector = P,
+ output float Fac = 0.0)
+{
+ float dimension = max(Dimension, 0.0);
+ float octaves = max(Octaves, 0.0);
+ float lacunarity = max(Lacunarity, 1e-5);
+ float size = nonzero(Size, 1e-5);
+
+ point p = Vector/size;
+
+ if(Type == "Multifractal")
+ Fac = Intensity*noise_musgrave_multi_fractal(p, Basis, dimension, lacunarity, octaves);
+ else if(Type == "fBM")
+ Fac = Intensity*noise_musgrave_fBm(p, Basis, dimension, lacunarity, octaves);
+ else if(Type == "Hybrid Multifractal")
+ Fac = Intensity*noise_musgrave_hybrid_multi_fractal(p, Basis, dimension, lacunarity, octaves, Offset, Gain);
+ else if(Type == "Ridged Multifractal")
+ Fac = Intensity*noise_musgrave_ridged_multi_fractal(p, Basis, dimension, lacunarity, octaves, Offset, Gain);
+ else if(Type == "Hetero Terrain")
+ Fac = Intensity*noise_musgrave_hetero_terrain(p, Basis, dimension, lacunarity, octaves, Offset);
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_noise_texture.osl b/intern/cycles/kernel/osl/nodes/node_noise_texture.osl
new file mode 100644
index 00000000000..193ed67d16e
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_noise_texture.osl
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+#include "node_texture.h"
+
+shader node_noise_texture(
+ point Vector = P,
+ output color Color = color(0.0, 0.0, 0.0),
+ output float Fac = 0.0)
+{
+ point p = Vector*1e8;
+
+ float r = cellnoise(p);
+ float g = cellnoise(point(p[1], p[0], p[2]));
+ float b = cellnoise(point(p[1], p[2], p[0]));
+
+ Fac = r;
+ Color = color(r, g, b);
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_output_displacement.osl b/intern/cycles/kernel/osl/nodes/node_output_displacement.osl
new file mode 100644
index 00000000000..a6b452c532a
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_output_displacement.osl
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+displacement node_output_displacement(float Displacement = 0.0)
+{
+ P += N*Displacement*0.1; /* todo: get rid of this factor */
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_output_surface.osl b/intern/cycles/kernel/osl/nodes/node_output_surface.osl
new file mode 100644
index 00000000000..6efaf91121b
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_output_surface.osl
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+surface node_output_surface(closure color Surface = background())
+{
+ Ci = Surface;
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_output_volume.osl b/intern/cycles/kernel/osl/nodes/node_output_volume.osl
new file mode 100644
index 00000000000..18094242dc7
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_output_volume.osl
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+volume node_output_volume(closure color Volume = background())
+{
+ Ci = Volume;
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_sky_texture.osl b/intern/cycles/kernel/osl/nodes/node_sky_texture.osl
new file mode 100644
index 00000000000..fdb9b1d9708
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_sky_texture.osl
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+struct KernelSunSky {
+ /* sun direction in spherical and cartesian */
+ float theta, phi;
+ vector dir;
+
+ /* perez function parameters */
+ float zenith_Y, zenith_x, zenith_y;
+ float perez_Y[5], perez_x[5], perez_y[5];
+};
+
+color xyY_to_xyz(float x, float y, float Y)
+{
+ float X, Z;
+
+ if(y != 0.0) X = (x / y) * Y;
+ else X = 0.0;
+
+ if(y != 0.0 && Y != 0.0) Z = ((1.0 - x - y) / y) * Y;
+ else Z = 0.0;
+
+ return color(X, Y, Z);
+}
+
+color xyz_to_rgb(float x, float y, float z)
+{
+ return color(3.240479 * x + -1.537150 * y + -0.498535 * z,
+ -0.969256 * x + 1.875991 * y + 0.041556 * z,
+ 0.055648 * x + -0.204043 * y + 1.057311 * z);
+}
+
+float sky_angle_between(float thetav, float phiv, float theta, float phi)
+{
+ float cospsi = sin(thetav)*sin(theta)*cos(phi - phiv) + cos(thetav)*cos(theta);
+
+ if(cospsi > 1.0)
+ return 0.0;
+ if(cospsi < -1.0)
+ return M_PI;
+
+ return acos(cospsi);
+}
+
+vector sky_spherical_coordinates(vector dir)
+{
+ return vector(acos(dir[2]), atan2(dir[0], dir[1]), 0);
+}
+
+float sky_perez_function(float lam[5], float theta, float gamma)
+{
+ float ctheta = cos(theta);
+ float cgamma = cos(gamma);
+
+ return (1.0 + lam[0]*exp(lam[1] / ctheta)) * (1.0 + lam[2]*exp(lam[3]*gamma) + lam[4]*cgamma*cgamma);
+}
+
+color sky_xyz_radiance(KernelSunSky sunsky, vector dir)
+{
+ /* convert vector to spherical coordinates */
+ vector spherical = sky_spherical_coordinates(dir);
+ float theta = spherical[0];
+ float phi = spherical[1];
+
+ /* angle between sun direction and dir */
+ float gamma = sky_angle_between(theta, phi, sunsky.theta, sunsky.phi);
+
+ /* clamp theta to horizon */
+ theta = min(theta, M_PI_2 - 0.001);
+
+ /* compute xyY color space values */
+ float x = sunsky.zenith_x * sky_perez_function(sunsky.perez_x, theta, gamma);
+ float y = sunsky.zenith_y * sky_perez_function(sunsky.perez_y, theta, gamma);
+ float Y = sunsky.zenith_Y * sky_perez_function(sunsky.perez_Y, theta, gamma);
+
+ /* convert to RGB */
+ color xyz = xyY_to_xyz(x, y, Y);
+ return xyz_to_rgb(xyz[0], xyz[1], xyz[2]);
+}
+
+void precompute_sunsky(vector dir, float turbidity, output KernelSunSky sunsky)
+{
+ vector spherical = sky_spherical_coordinates(dir);
+ float theta = spherical[0];
+ float phi = spherical[1];
+
+ sunsky.theta = theta;
+ sunsky.phi = phi;
+ sunsky.dir = dir;
+
+ float theta2 = theta*theta;
+ float theta3 = theta*theta*theta;
+ float T = turbidity;
+ float T2 = T*T;
+
+ float chi = (4.0/ 9.0- T / 120.0) * (M_PI - 2.0* theta);
+ sunsky.zenith_Y = (4.0453*T - 4.9710) * tan(chi) - 0.2155*T + 2.4192;
+ sunsky.zenith_Y *= 0.06;
+
+ sunsky.zenith_x =
+ (0.00166* theta3 - 0.00375* theta2 + 0.00209* theta)*T2 +
+ (-0.02903* theta3 + 0.06377* theta2 - 0.03202* theta + 0.00394)*T +
+ (0.11693* theta3 - 0.21196* theta2 + 0.06052* theta + 0.25886);
+
+ sunsky.zenith_y =
+ (0.00275* theta3 - 0.00610* theta2 + 0.00317* theta)*T2 +
+ (-0.04214* theta3 + 0.08970* theta2 - 0.04153* theta + 0.00516)*T +
+ (0.15346* theta3 - 0.26756* theta2 + 0.06670* theta + 0.26688);
+
+ sunsky.perez_Y[0] = (0.1787*T - 1.4630);
+ sunsky.perez_Y[1] = (-0.3554*T + 0.4275);
+ sunsky.perez_Y[2] = (-0.0227*T + 5.3251);
+ sunsky.perez_Y[3] = (0.1206*T - 2.5771);
+ sunsky.perez_Y[4] = (-0.0670*T + 0.3703);
+
+ sunsky.perez_x[0] = (-0.0193*T - 0.2592);
+ sunsky.perez_x[1] = (-0.0665*T + 0.0008);
+ sunsky.perez_x[2] = (-0.0004*T + 0.2125);
+ sunsky.perez_x[3] = (-0.0641*T - 0.8989);
+ sunsky.perez_x[4] = (-0.0033*T + 0.0452);
+
+ sunsky.perez_y[0] = (-0.0167*T - 0.2608);
+ sunsky.perez_y[1] = (-0.0950*T + 0.0092);
+ sunsky.perez_y[2] = (-0.0079*T + 0.2102);
+ sunsky.perez_y[3] = (-0.0441*T - 1.6537);
+ sunsky.perez_y[4] = (-0.0109*T + 0.0529);
+
+ sunsky.zenith_Y /= sky_perez_function(sunsky.perez_Y, 0, theta);
+ sunsky.zenith_x /= sky_perez_function(sunsky.perez_x, 0, theta);
+ sunsky.zenith_y /= sky_perez_function(sunsky.perez_y, 0, theta);
+}
+
+shader node_sky_texture(
+ vector Vector = P,
+ vector sun_direction = vector(0, 0, 1),
+ float turbidity = 2.2,
+ output color Color = color(0.0, 0.0, 0.0))
+{
+ KernelSunSky sunsky;
+
+ precompute_sunsky(sun_direction, turbidity, sunsky);
+ Color = sky_xyz_radiance(sunsky, Vector);
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_stucci_texture.osl b/intern/cycles/kernel/osl/nodes/node_stucci_texture.osl
new file mode 100644
index 00000000000..f03e03d9a98
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_stucci_texture.osl
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+#include "node_texture.h"
+
+/* Stucci */
+
+shader node_stucci_texture(
+ string Type = "Plastic",
+ string Basis = "Perlin",
+ int Hard = 0,
+ float Turbulence = 1.0,
+ float Size = 0.25,
+ point Vector = P,
+ output float Fac = 0.0)
+{
+ float size = nonzero(Size, 1e-5);
+ point p = Vector/size;
+
+ float b2 = noise_basis_hard(p, Basis, Hard);
+ float ofs = Turbulence/200.0;
+
+ if(Type != "Plastic")
+ ofs *= b2*b2;
+
+ Fac = noise_basis_hard(point(p[0], p[1], p[2]+ofs), Basis, Hard);
+
+ if(Type == "Wall Out")
+ Fac = 1.0 - Fac;
+
+ Fac = max(Fac, 0.0);
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_texture.h b/intern/cycles/kernel/osl/nodes/node_texture.h
new file mode 100644
index 00000000000..8adb0e8aeb5
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_texture.h
@@ -0,0 +1,251 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/* Voronoi Distances */
+
+float voronoi_distance(string distance_metric, vector d, float e)
+{
+ float result = 0.0;
+
+ if(distance_metric == "Distance Squared")
+ result = dot(d, d);
+ if(distance_metric == "Actual Distance")
+ result = length(d);
+ if(distance_metric == "Manhattan")
+ result = fabs(d[0]) + fabs(d[1]) + fabs(d[2]);
+ if(distance_metric == "Chebychev")
+ result = max(fabs(d[0]), max(fabs(d[1]), fabs(d[2])));
+ if(distance_metric == "Minkovsky 1/2")
+ result = sqrt(fabs(d[0])) + sqrt(fabs(d[1])) + sqrt(fabs(d[1]));
+ if(distance_metric == "Minkovsky 4")
+ result = sqrt(sqrt(dot(d*d, d*d)));
+ if(distance_metric == "Minkovsky")
+ result = pow(pow(fabs(d[0]), e) + pow(fabs(d[1]), e) + pow(fabs(d[2]), e), 1.0/e);
+
+ return result;
+}
+
+/* Voronoi / Worley like */
+
+color cellnoise_color(point p)
+{
+ float r = cellnoise(p);
+ float g = cellnoise(point(p[1], p[0], p[2]));
+ float b = cellnoise(point(p[1], p[2], p[0]));
+
+ return color(r, g, b);
+}
+
+void voronoi(point p, string distance_metric, float e, float da[4], point pa[4])
+{
+ /* returns distances in da and point coords in pa */
+ int xx, yy, zz, xi, yi, zi;
+
+ xi = (int)floor(p[0]);
+ yi = (int)floor(p[1]);
+ zi = (int)floor(p[2]);
+
+ da[0] = 1e10;
+ da[1] = 1e10;
+ da[2] = 1e10;
+ da[3] = 1e10;
+
+ for(xx = xi-1; xx <= xi+1; xx++) {
+ for(yy = yi-1; yy <= yi+1; yy++) {
+ for(zz = zi-1; zz <= zi+1; zz++) {
+ point ip = point(xx, yy, zz);
+ point vp = (point)cellnoise_color(ip);
+ point pd = p - (vp + ip);
+ float d = voronoi_distance(distance_metric, pd, e);
+
+ vp += point(xx, yy, zz);
+
+ if(d < da[0]) {
+ da[3] = da[2];
+ da[2] = da[1];
+ da[1] = da[0];
+ da[0] = d;
+
+ pa[3] = pa[2];
+ pa[2] = pa[1];
+ pa[1] = pa[0];
+ pa[0] = vp;
+ }
+ else if(d < da[1]) {
+ da[3] = da[2];
+ da[2] = da[1];
+ da[1] = d;
+
+ pa[3] = pa[2];
+ pa[2] = pa[1];
+ pa[1] = vp;
+ }
+ else if(d < da[2]) {
+ da[3] = da[2];
+ da[2] = d;
+
+ pa[3] = pa[2];
+ pa[2] = vp;
+ }
+ else if(d < da[3]) {
+ da[3] = d;
+ pa[3] = vp;
+ }
+ }
+ }
+ }
+}
+
+float voronoi_Fn(point p, int n)
+{
+ float da[4];
+ point pa[4];
+
+ voronoi(p, "Distance Squared", 0, da, pa);
+
+ return da[n];
+}
+
+float voronoi_FnFn(point p, int n1, int n2)
+{
+ float da[4];
+ point pa[4];
+
+ voronoi(p, "Distance Squared", 0, da, pa);
+
+ return da[n2] - da[n1];
+}
+
+float voronoi_F1(point p) { return voronoi_Fn(p, 0); }
+float voronoi_F2(point p) { return voronoi_Fn(p, 1); }
+float voronoi_F3(point p) { return voronoi_Fn(p, 2); }
+float voronoi_F4(point p) { return voronoi_Fn(p, 3); }
+float voronoi_F1F2(point p) { return voronoi_FnFn(p, 0, 1); }
+
+float voronoi_Cr(point p)
+{
+ /* crackle type pattern, just a scale/clamp of F2-F1 */
+ float t = 10.0*voronoi_F1F2(p);
+ return (t > 1.0)? 1.0: t;
+}
+
+float voronoi_F1S(point p) { return 2.0*voronoi_F1(p) - 1.0; }
+float voronoi_F2S(point p) { return 2.0*voronoi_F2(p) - 1.0; }
+float voronoi_F3S(point p) { return 2.0*voronoi_F3(p) - 1.0; }
+float voronoi_F4S(point p) { return 2.0*voronoi_F4(p) - 1.0; }
+float voronoi_F1F2S(point p) { return 2.0*voronoi_F1F2(p) - 1.0; }
+float voronoi_CrS(point p) { return 2.0*voronoi_Cr(p) - 1.0; }
+
+/* Noise Bases */
+
+float noise_basis(point p, string basis)
+{
+ float result = 0.0;
+
+ if(basis == "Perlin")
+ result = noise(p);
+ if(basis == "Voronoi F1")
+ result = voronoi_F1S(p);
+ if(basis == "Voronoi F2")
+ result = voronoi_F2S(p);
+ if(basis == "Voronoi F3")
+ result = voronoi_F3S(p);
+ if(basis == "Voronoi F4")
+ result = voronoi_F4S(p);
+ if(basis == "Voronoi F2-F1")
+ result = voronoi_F1F2S(p);
+ if(basis == "Voronoi Crackle")
+ result = voronoi_CrS(p);
+ if(basis == "Cell Noise")
+ result = cellnoise(p);
+
+ return result;
+}
+
+/* Soft/Hard Noise */
+
+float noise_basis_hard(point p, string basis, int hard)
+{
+ float t = noise_basis(p, basis);
+ return (hard)? fabs(2.0*t - 1.0): t;
+}
+
+/* Waves */
+
+float noise_wave(string wave, float a)
+{
+ float result = 0.0;
+
+ if(wave == "Sine") {
+ result = 0.5 + 0.5*sin(a);
+ }
+ else if(wave == "Saw") {
+ float b = 2*M_PI;
+ int n = (int)(a / b);
+ a -= n*b;
+ if(a < 0) a += b;
+
+ result = a / b;
+ }
+ else if(wave == "Tri") {
+ float b = 2*M_PI;
+ float rmax = 1.0;
+
+ result = rmax - 2.0*fabs(floor((a*(1.0/b))+0.5) - (a*(1.0/b)));
+ }
+
+ return result;
+}
+
+/* Turbulence */
+
+float noise_turbulence(point p, string basis, int octaves, int hard)
+{
+ float fscale = 1.0;
+ float amp = 1.0;
+ float sum = 0.0;
+ int i;
+
+ for(i = 0; i <= octaves; i++) {
+ float t = noise_basis(fscale*p, basis);
+
+ if(hard)
+ t = fabs(2.0*t - 1.0);
+
+ sum += t*amp;
+ amp *= 0.5;
+ fscale *= 2.0;
+ }
+
+ sum *= ((float)(1 << octaves)/(float)((1 << (octaves+1)) - 1));
+
+ return sum;
+}
+
+/* Utility */
+
+float nonzero(float f, float eps)
+{
+ float r;
+
+ if(abs(f) < eps)
+ r = sign(f)*eps;
+ else
+ r = f;
+
+ return r;
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_texture_coordinate.osl b/intern/cycles/kernel/osl/nodes/node_texture_coordinate.osl
new file mode 100644
index 00000000000..2acf72aef54
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_texture_coordinate.osl
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+shader node_texture_coordinate(
+ normal Normal = N,
+ int is_background = 0,
+ string bump_offset = "center",
+
+ output point Generated = point(0.0, 0.0, 0.0),
+ output point UV = point(0.0, 0.0, 0.0),
+ output point Object = point(0.0, 0.0, 0.0),
+ output point Camera = point(0.0, 0.0, 0.0),
+ output point Window = point(0.0, 0.0, 0.0),
+ output point Reflection = point(0.0, 0.0, 0.0))
+{
+ if(is_background) {
+ Generated = P;
+ UV = point(0.0, 0.0, 0.0);
+ Object = P;
+ point Pcam = transform("camera", "world", point(0, 0, 0));
+ Camera = transform("camera", P + Pcam);
+ Window = transform("NDC", P + Pcam);
+ Reflection = I;
+ }
+ else {
+ getattribute("std::generated", Generated);
+ getattribute("std::uv", UV);
+ Object = transform("object", P);
+ Camera = transform("camera", P);
+ Window = transform("NDC", P);
+ Reflection = reflect(I, Normal);
+ }
+
+ if(bump_offset == "dx") {
+ Generated += Dx(Generated);
+ UV += Dx(UV);
+ Object += Dx(Object);
+ Camera += Dx(Camera);
+ Window += Dx(Window);
+ }
+ else if(bump_offset == "dy") {
+ Generated += Dy(Generated);
+ UV += Dy(UV);
+ Object += Dy(Object);
+ Camera += Dy(Camera);
+ Window += Dy(Window);
+ }
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_translucent_bsdf.osl b/intern/cycles/kernel/osl/nodes/node_translucent_bsdf.osl
new file mode 100644
index 00000000000..9acd46756d2
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_translucent_bsdf.osl
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+shader node_translucent_bsdf(
+ color Color = color(0.8, 0.8, 0.8),
+ normal Normal = N,
+ output closure color BSDF = diffuse(Normal))
+{
+ BSDF = Color*translucent(Normal);
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_transparent_bsdf.osl b/intern/cycles/kernel/osl/nodes/node_transparent_bsdf.osl
new file mode 100644
index 00000000000..b347bfb116b
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_transparent_bsdf.osl
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+shader node_transparent_bsdf(
+ color Color = color(0.8, 0.8, 0.8),
+ normal Normal = N,
+ output closure color BSDF = diffuse(Normal))
+{
+ BSDF = Color*transparent();
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_value.osl b/intern/cycles/kernel/osl/nodes/node_value.osl
new file mode 100644
index 00000000000..bee6f39f2bc
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_value.osl
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+shader node_value(
+ float value_value = 0.0,
+ vector vector_value = vector(0.0, 0.0, 0.0),
+ color color_value = color(0.0, 0.0, 0.0),
+ output float Value = 0.0,
+ output vector Vector = vector(0.0, 0.0, 0.0),
+ output color Color = color(0.0, 0.0, 0.0))
+{
+ Value = value_value;
+ Vector = vector_value;
+ Color = color_value;
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_vector_math.osl b/intern/cycles/kernel/osl/nodes/node_vector_math.osl
new file mode 100644
index 00000000000..c6231d4350d
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_vector_math.osl
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+shader node_vector_math(
+ string type = "Add",
+ vector Vector1 = vector(0.0, 0.0, 0.0),
+ vector Vector2 = vector(0.0, 0.0, 0.0),
+ output float Fac = 0.0,
+ output vector Vector = vector(0.0, 0.0, 0.0))
+{
+ if(type == "Add") {
+ Vector = Vector1 + Vector2;
+ Fac = (abs(Vector[0]) + abs(Vector[1]) + abs(Vector[2]))/3.0;
+ }
+ if(type == "Subtract") {
+ Vector = Vector1 + Vector2;
+ Fac = (abs(Vector[0]) + abs(Vector[1]) + abs(Vector[2]))/3.0;
+ }
+ if(type == "Average") {
+ Fac = length(Vector1 + Vector2);
+ Vector = normalize(Vector1 + Vector2);
+ }
+ if(type == "Dot Product") {
+ Fac = dot(Vector1, Vector2);
+ }
+ if(type == "Cross Product") {
+ vector c = cross(Vector1, Vector2);
+ Fac = length(c);
+ Vector = normalize(c);
+ }
+ if(type == "Normalize") {
+ Fac = length(Vector1);
+ Vector = normalize(Vector1);
+ }
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_velvet_bsdf.osl b/intern/cycles/kernel/osl/nodes/node_velvet_bsdf.osl
new file mode 100644
index 00000000000..2b6219f6325
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_velvet_bsdf.osl
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+#include "node_fresnel.h"
+
+shader node_velvet_bsdf(
+ color Color = color(0.8, 0.8, 0.8),
+ float Sigma = 0.0,
+ float Fresnel = 0.3,
+ normal Normal = N,
+ output closure color BSDF = diffuse(Normal))
+{
+ float Fr = 1.0;
+
+ if(Fresnel < 1.0) {
+ float eta = 1.0/clamp(1.0 - Fresnel, 1e-5, 1.0 - 1e-5);
+ Fr = fresnel_dielectric(I, Normal, eta);
+ }
+
+ float sigma = clamp(Sigma, 0.0, 1.0);
+
+ BSDF = (Fr*Color)*ashikhmin_velvet(Normal, sigma);
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_voronoi_texture.osl b/intern/cycles/kernel/osl/nodes/node_voronoi_texture.osl
new file mode 100644
index 00000000000..140ba6a6ba1
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_voronoi_texture.osl
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+#include "node_texture.h"
+
+/* Voronoi */
+
+shader node_voronoi_texture(
+ string DistanceMetric = "Actual Distance",
+ string Coloring = "Intensity",
+ float Weight1 = 1.0,
+ float Weight2 = 0.0,
+ float Weight3 = 0.0,
+ float Weight4 = 0.0,
+ float Exponent = 2.5,
+ float Intensity = 1.0,
+ float Size = 0.25,
+ point Vector = P,
+ output float Fac = 0.0,
+ output color Color = color(0.0, 0.0, 0.0))
+{
+ float exponent = max(Exponent, 1e-5);
+ float size = nonzero(Size, 1e-5);
+
+ float aw1 = fabs(Weight1);
+ float aw2 = fabs(Weight2);
+ float aw3 = fabs(Weight3);
+ float aw4 = fabs(Weight4);
+ float sc = (aw1 + aw2 + aw3 + aw4);
+
+ if(sc != 0.0)
+ sc = Intensity/sc;
+
+ /* compute distance and point coordinate of 4 nearest neighbours */
+ float da[4];
+ point pa[4];
+
+ voronoi(Vector/size, DistanceMetric, exponent, da, pa);
+
+ /* Scalar output */
+ Fac = sc * fabs(Weight1*da[0] + Weight2*da[1] + Weight3*da[2] + Weight4*da[3]);
+
+ /* Colored output */
+ if(Coloring == "Intensity") {
+ Color = color(Fac, Fac, Fac);
+ }
+ else {
+ Color = aw1*cellnoise_color(pa[0]);
+ Color += aw2*cellnoise_color(pa[1]);
+ Color += aw3*cellnoise_color(pa[2]);
+ Color += aw4*cellnoise_color(pa[3]);
+
+ if(Coloring != "Position") {
+ float t1 = min((da[1] - da[0])*10.0, 1.0);
+
+ if(Coloring == "Position, Outline, and Intensity")
+ Color *= t1*Fac;
+ else if(Coloring == "Position and Outline")
+ Color *= t1*sc;
+ }
+ else {
+ Color *= sc;
+ }
+ }
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_ward_bsdf.osl b/intern/cycles/kernel/osl/nodes/node_ward_bsdf.osl
new file mode 100644
index 00000000000..68db07109ed
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_ward_bsdf.osl
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+
+shader node_ward_bsdf(
+ color Color = color(0.8, 0.8, 0.8),
+ float RoughnessU = 0.0,
+ float RoughnessV = 0.0,
+ normal Normal = N,
+ output closure color BSDF = diffuse(Normal))
+{
+ BSDF = Color*ward(Normal, normalize(dPdu), RoughnessU, RoughnessV);
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/node_wood_texture.osl b/intern/cycles/kernel/osl/nodes/node_wood_texture.osl
new file mode 100644
index 00000000000..f1d2e278597
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/node_wood_texture.osl
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "stdosl.h"
+#include "node_texture.h"
+
+/* Wood */
+
+float wood(point p, float size, string type, string wave, string basis, int hard, float turb)
+{
+ float x = p[0];
+ float y = p[1];
+ float z = p[2];
+
+ float result = 0.0;
+
+ if(type == "Bands") {
+ result = noise_wave(wave, (x + y + z)*10.0);
+ }
+ else if(type == "Rings") {
+ result = noise_wave(wave, sqrt(x*x + y*y + z*z)*20.0);
+ }
+ else if (type == "Band Noise") {
+ float wi = turb*noise_basis_hard(p/size, basis, hard);
+ result = noise_wave(wave, (x + y + z)*10.0 + wi);
+ }
+ else if (type == "Ring Noise") {
+ float wi = turb*noise_basis_hard(p/size, basis, hard);
+ result = noise_wave(wave, sqrt(x*x + y*y + z*z)*20.0 + wi);
+ }
+
+ return result;
+}
+
+shader node_wood_texture(
+ string Type = "Bands",
+ string Wave = "Sine",
+ string Basis = "Perlin",
+ int Hard = 0,
+ float Size = 0.25,
+ float Turbulence = 5.0,
+ point Vector = P,
+ output float Fac = 0.0)
+{
+ float size = nonzero(Size, 1e-5);
+ Fac = wood(Vector, size, Type, Wave, Basis, Hard, Turbulence);
+}
+
diff --git a/intern/cycles/kernel/osl/nodes/stdosl.h b/intern/cycles/kernel/osl/nodes/stdosl.h
new file mode 100644
index 00000000000..6fe4f52df4a
--- /dev/null
+++ b/intern/cycles/kernel/osl/nodes/stdosl.h
@@ -0,0 +1,471 @@
+/////////////////////////////////////////////////////////////////////////////
+// Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al. All Rights Reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+// * Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+// * Neither the name of Sony Pictures Imageworks nor the names of its
+// contributors may be used to endorse or promote products derived from
+// this software without specific prior written permission.
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+/////////////////////////////////////////////////////////////////////////////
+
+
+#ifndef CCL_STDOSL_H
+#define CCL_STDOSL_H
+
+
+#ifndef M_PI
+#define M_PI 3.1415926535897932 /* pi */
+#define M_PI_2 1.5707963267948966 /* pi/2 */
+#define M_PI_4 0.7853981633974483 /* pi/4 */
+#define M_2_PI 0.6366197723675813 /* 2/pi */
+#define M_2_SQRTPI 1.1283791670955126 /* 2/sqrt(pi) */
+#define M_E 2.7182818284590452 /* e (Euler's number) */
+#define M_LN2 0.6931471805599453 /* ln(2) */
+#define M_LN10 2.3025850929940457 /* ln(10) */
+#define M_LOG2E 1.4426950408889634 /* log_2(e) */
+#define M_LOG10E 0.4342944819032518 /* log_10(e) */
+#define M_SQRT2 1.4142135623730950 /* sqrt(2) */
+#define M_SQRT1_2 0.7071067811865475 /* 1/sqrt(2) */
+#endif
+
+
+
+// Declaration of built-in functions and closures
+#define BUILTIN [[ int builtin = 1 ]]
+#define BUILTIN_DERIV [[ int builtin = 1, int deriv = 1 ]]
+
+#define PERCOMP1(name) \
+ normal name (normal x) BUILTIN; \
+ vector name (vector x) BUILTIN; \
+ point name (point x) BUILTIN; \
+ color name (color x) BUILTIN; \
+ float name (float x) BUILTIN;
+
+#define PERCOMP2(name) \
+ normal name (normal x, normal y) BUILTIN; \
+ vector name (vector x, vector y) BUILTIN; \
+ point name (point x, point y) BUILTIN; \
+ color name (color x, color y) BUILTIN; \
+ float name (float x, float y) BUILTIN;
+
+#define PERCOMP2F(name) \
+ normal name (normal x, float y) BUILTIN; \
+ vector name (vector x, float y) BUILTIN; \
+ point name (point x, float y) BUILTIN; \
+ color name (color x, float y) BUILTIN; \
+ float name (float x, float y) BUILTIN;
+
+
+// Basic math
+normal degrees (normal x) { return x*(180.0/M_PI); }
+vector degrees (vector x) { return x*(180.0/M_PI); }
+point degrees (point x) { return x*(180.0/M_PI); }
+color degrees (color x) { return x*(180.0/M_PI); }
+float degrees (float x) { return x*(180.0/M_PI); }
+normal radians (normal x) { return x*(M_PI/180.0); }
+vector radians (vector x) { return x*(M_PI/180.0); }
+point radians (point x) { return x*(M_PI/180.0); }
+color radians (color x) { return x*(M_PI/180.0); }
+float radians (float x) { return x*(M_PI/180.0); }
+PERCOMP1 (cos)
+PERCOMP1 (sin)
+PERCOMP1 (tan)
+PERCOMP1 (acos)
+PERCOMP1 (asin)
+PERCOMP1 (atan)
+PERCOMP2 (atan2)
+PERCOMP1 (cosh)
+PERCOMP1 (sinh)
+PERCOMP1 (tanh)
+PERCOMP2F (pow)
+PERCOMP1 (exp)
+PERCOMP1 (exp2)
+PERCOMP1 (expm1)
+PERCOMP1 (log)
+point log (point a, float b) { return log(a)/log(b); }
+vector log (vector a, float b) { return log(a)/log(b); }
+color log (color a, float b) { return log(a)/log(b); }
+float log (float a, float b) { return log(a)/log(b); }
+PERCOMP1 (log2)
+PERCOMP1 (log10)
+PERCOMP1 (logb)
+PERCOMP1 (sqrt)
+PERCOMP1 (inversesqrt)
+float hypot (float a, float b) { return sqrt (a*a + b*b); }
+float hypot (float a, float b, float c) { return sqrt (a*a + b*b + c*c); }
+PERCOMP1 (abs)
+int abs (int x) BUILTIN;
+PERCOMP1 (fabs)
+int fabs (int x) BUILTIN;
+PERCOMP1 (sign)
+PERCOMP1 (floor)
+PERCOMP1 (ceil)
+PERCOMP1 (round)
+PERCOMP1 (trunc)
+PERCOMP2 (fmod)
+PERCOMP2F (fmod)
+PERCOMP2 (mod)
+PERCOMP2F (mod)
+int mod (int x, int y) BUILTIN;
+PERCOMP2 (min)
+PERCOMP2 (max)
+normal clamp (normal x, normal minval, normal maxval) { return max(min(x,maxval),minval); }
+vector clamp (vector x, vector minval, vector maxval) { return max(min(x,maxval),minval); }
+point clamp (point x, point minval, point maxval) { return max(min(x,maxval),minval); }
+color clamp (color x, color minval, color maxval) { return max(min(x,maxval),minval); }
+float clamp (float x, float minval, float maxval) { return max(min(x,maxval),minval); }
+//normal clamp (normal x, normal minval, normal maxval) BUILTIN;
+//vector clamp (vector x, vector minval, vector maxval) BUILTIN;
+//point clamp (point x, point minval, point maxval) BUILTIN;
+//color clamp (color x, color minval, color maxval) BUILTIN;
+//float clamp (float x, float minval, float maxval) BUILTIN;
+normal mix (normal x, normal y, normal a) { return x*(1-a) + y*a; }
+normal mix (normal x, normal y, float a) { return x*(1-a) + y*a; }
+vector mix (vector x, vector y, vector a) { return x*(1-a) + y*a; }
+vector mix (vector x, vector y, float a) { return x*(1-a) + y*a; }
+point mix (point x, point y, point a) { return x*(1-a) + y*a; }
+point mix (point x, point y, float a) { return x*(1-a) + y*a; }
+color mix (color x, color y, color a) { return x*(1-a) + y*a; }
+color mix (color x, color y, float a) { return x*(1-a) + y*a; }
+float mix (float x, float y, float a) { return x*(1-a) + y*a; }
+int isnan (float x) BUILTIN;
+int isinf (float x) BUILTIN;
+int isfinite (float x) BUILTIN;
+float erf (float x) BUILTIN;
+float erfc (float x) BUILTIN;
+
+// Vector functions
+
+vector cross (vector a, vector b) BUILTIN;
+float dot (vector a, vector b) BUILTIN;
+float length (vector v) BUILTIN;
+float distance (point a, point b) BUILTIN;
+float distance (point a, point b, point q) BUILTIN;
+normal normalize (normal v) BUILTIN;
+vector normalize (vector v) BUILTIN;
+vector faceforward (vector N, vector I, vector Nref) BUILTIN;
+vector faceforward (vector N, vector I) BUILTIN;
+vector reflect (vector I, vector N) { return I - 2*dot(N,I)*N; }
+vector refract (vector I, vector N, float eta) {
+ float IdotN = dot (I, N);
+ float k = 1 - eta*eta * (1 - IdotN*IdotN);
+ return (k < 0) ? vector(0,0,0) : (eta*I - N * (eta*IdotN + sqrt(k)));
+}
+void fresnel (vector I, normal N, float eta,
+ output float Kr, output float Kt,
+ output vector R, output vector T)
+{
+ float sqr(float x) { return x*x; }
+ float c = dot(I, N);
+ if (c < 0)
+ c = -c;
+ R = reflect(I, N);
+ float g = 1.0 / sqr(eta) - 1.0 + c * c;
+ if (g >= 0.0) {
+ g = sqrt (g);
+ float beta = g - c;
+ float F = (c * (g+c) - 1.0) / (c * beta + 1.0);
+ F = 0.5 * (1.0 + sqr(F));
+ F *= sqr (beta / (g+c));
+ Kr = F;
+ Kt = (1.0 - Kr) * eta*eta;
+ // OPT: the following recomputes some of the above values, but it
+ // gives us the same result as if the shader-writer called refract()
+ T = refract(I, N, eta);
+ } else {
+ // total internal reflection
+ Kr = 1.0;
+ Kt = 0.0;
+ T = vector (0,0,0);
+ }
+#undef sqr
+}
+
+void fresnel (vector I, normal N, float eta,
+ output float Kr, output float Kt)
+{
+ vector R, T;
+ fresnel(I, N, eta, Kr, Kt, R, T);
+}
+
+point rotate (point q, float angle, point a, point b) BUILTIN;
+
+normal transform (matrix Mto, normal p) BUILTIN;
+vector transform (matrix Mto, vector p) BUILTIN;
+point transform (matrix Mto, point p) BUILTIN;
+
+// Implementation of transform-with-named-space in terms of matrices:
+
+point transform (string tospace, point x)
+{
+ return transform (matrix ("common", tospace), x);
+}
+
+point transform (string fromspace, string tospace, point x)
+{
+ return transform (matrix (fromspace, tospace), x);
+}
+
+
+vector transform (string tospace, vector x)
+{
+ return transform (matrix ("common", tospace), x);
+}
+
+vector transform (string fromspace, string tospace, vector x)
+{
+ return transform (matrix (fromspace, tospace), x);
+}
+
+
+normal transform (string tospace, normal x)
+{
+ return transform (matrix ("common", tospace), x);
+}
+
+normal transform (string fromspace, string tospace, normal x)
+{
+ return transform (matrix (fromspace, tospace), x);
+}
+
+float transformu (string tounits, float x) BUILTIN;
+float transformu (string fromunits, string tounits, float x) BUILTIN;
+
+
+// Color functions
+
+float luminance (color c) {
+ return dot ((vector)c, vector(0.2126, 0.7152, 0.0722));
+}
+
+
+
+color transformc (string to, color x)
+{
+ color rgb_to_hsv (color rgb) { // See Foley & van Dam
+ float r = rgb[0], g = rgb[1], b = rgb[2];
+ float mincomp = min (r, min (g, b));
+ float maxcomp = max (r, max (g, b));
+ float delta = maxcomp - mincomp; // chroma
+ float h, s, v;
+ v = maxcomp;
+ if (maxcomp > 0)
+ s = delta / maxcomp;
+ else s = 0;
+ if (s <= 0)
+ h = 0;
+ else {
+ if (r >= maxcomp) h = (g-b) / delta;
+ else if (g >= maxcomp) h = 2 + (b-r) / delta;
+ else h = 4 + (r-g) / delta;
+ h /= 6;
+ if (h < 0)
+ h += 1;
+ }
+ return color (h, s, v);
+ }
+
+ color rgb_to_hsl (color rgb) { // See Foley & van Dam
+ // First convert rgb to hsv, then to hsl
+ float minval = min (rgb[0], min (rgb[1], rgb[2]));
+ color hsv = rgb_to_hsv (rgb);
+ float maxval = hsv[2]; // v == maxval
+ float h = hsv[0], s, l = (minval+maxval) / 2;
+ if (minval == maxval)
+ s = 0; // special 'achromatic' case, hue is 0
+ else if (l <= 0.5)
+ s = (maxval - minval) / (maxval + minval);
+ else
+ s = (maxval - minval) / (2 - maxval - minval);
+ return color (h, s, l);
+ }
+
+ color r;
+ if (to == "rgb" || to == "RGB")
+ r = x;
+ else if (to == "hsv")
+ r = rgb_to_hsv (x);
+ else if (to == "hsl")
+ r = rgb_to_hsl (x);
+ else if (to == "YIQ")
+ r = color (dot (vector(0.299, 0.587, 0.114), (vector)x),
+ dot (vector(0.596, -0.275, -0.321), (vector)x),
+ dot (vector(0.212, -0.523, 0.311), (vector)x));
+ else if (to == "xyz")
+ r = color (dot (vector(0.412453, 0.357580, 0.180423), (vector)x),
+ dot (vector(0.212671, 0.715160, 0.072169), (vector)x),
+ dot (vector(0.019334, 0.119193, 0.950227), (vector)x));
+ else {
+ error ("Unknown color space \"%s\"", to);
+ r = x;
+ }
+ return r;
+}
+
+
+color transformc (string from, string to, color x)
+{
+ color hsv_to_rgb (color c) { // Reference: Foley & van Dam
+ float h = c[0], s = c[1], v = c[2];
+ color r;
+ if (s < 0.0001) {
+ r = v;
+ } else {
+ h = 6 * (h - floor(h)); // expand to [0..6)
+ int hi = (int)h;
+ float f = h - hi;
+ float p = v * (1-s);
+ float q = v * (1-s*f);
+ float t = v * (1-s*(1-f));
+ if (hi == 0) r = color (v, t, p);
+ else if (hi == 1) r = color (q, v, p);
+ else if (hi == 2) r = color (p, v, t);
+ else if (hi == 3) r = color (p, q, v);
+ else if (hi == 4) r = color (t, p, v);
+ else r = color (v, p, q);
+ }
+ return r;
+ }
+
+ color hsl_to_rgb (color c) {
+ float h = c[0], s = c[1], l = c[2];
+ // Easiest to convert hsl -> hsv, then hsv -> RGB (per Foley & van Dam)
+ float v = (l <= 0.5) ? (l * (1 + s)) : (l * (1 - s) + s);
+ color r;
+ if (v <= 0) {
+ r = 0;
+ } else {
+ float min = 2 * l - v;
+ s = (v - min) / v;
+ r = hsv_to_rgb (color (h, s, v));
+ }
+ return r;
+ }
+
+ color r;
+ if (from == "rgb" || from == "RGB")
+ r = x;
+ else if (from == "hsv")
+ r = hsv_to_rgb (x);
+ else if (from == "hsl")
+ r = hsl_to_rgb (x);
+ else if (from == "YIQ")
+ r = color (dot (vector(1, 0.9557, 0.6199), (vector)x),
+ dot (vector(1, -0.2716, -0.6469), (vector)x),
+ dot (vector(1, -1.1082, 1.7051), (vector)x));
+ else if (from == "xyz")
+ r = color (dot (vector( 3.240479, -1.537150, -0.498535), (vector)x),
+ dot (vector(-0.969256, 1.875991, 0.041556), (vector)x),
+ dot (vector( 0.055648, -0.204043, 1.057311), (vector)x));
+ else {
+ error ("Unknown color space \"%s\"", to);
+ r = x;
+ }
+ return transformc (to, r);
+}
+
+
+
+// Matrix functions
+
+float determinant (matrix m) BUILTIN;
+matrix transpose (matrix m) BUILTIN;
+
+
+
+// Pattern generation
+
+float step (float edge, float x) BUILTIN;
+color step (color edge, color x) BUILTIN;
+point step (point edge, point x) BUILTIN;
+vector step (vector edge, vector x) BUILTIN;
+normal step (normal edge, normal x) BUILTIN;
+float smoothstep (float edge0, float edge1, float x) BUILTIN;
+
+
+// Derivatives and area operators
+
+
+// Displacement functions
+
+
+// String functions
+
+int strlen (string s) BUILTIN;
+int startswith (string s, string prefix) BUILTIN;
+int endswith (string s, string suffix) BUILTIN;
+string substr (string s, int start, int len) BUILTIN;
+string substr (string s, int start) { return substr (s, start, strlen(s)); }
+
+// Define concat in terms of shorter concat
+string concat (string a, string b, string c) {
+ return concat(concat(a,b), c);
+}
+string concat (string a, string b, string c, string d) {
+ return concat(concat(a,b,c), d);
+}
+string concat (string a, string b, string c, string d, string e) {
+ return concat(concat(a,b,c,d), e);
+}
+string concat (string a, string b, string c, string d, string e, string f) {
+ return concat(concat(a,b,c,d,e), f);
+}
+
+
+// Texture
+
+
+// Closures
+
+closure color diffuse(normal N) BUILTIN;
+closure color translucent(normal N) BUILTIN;
+closure color reflection(normal N, float eta) BUILTIN;
+closure color reflection(normal N) { return reflection (N, 0.0); }
+closure color refraction(normal N, float eta) BUILTIN;
+closure color dielectric(normal N, float eta) BUILTIN;
+closure color transparent() BUILTIN;
+closure color microfacet_ggx(normal N, float ag) BUILTIN;
+closure color microfacet_ggx_refraction(normal N, float ag, float eta) BUILTIN;
+closure color microfacet_beckmann(normal N, float ab) BUILTIN;
+closure color microfacet_beckmann_refraction(normal N, float ab, float eta) BUILTIN;
+closure color ward(normal N, vector T,float ax, float ay) BUILTIN;
+closure color ashikhmin_velvet(normal N, float sigma) BUILTIN;
+closure color westin_backscatter(normal N, float roughness) BUILTIN;
+closure color westin_sheen(normal N, float edginess) BUILTIN;
+closure color bssrdf_cubic(color radius) BUILTIN;
+closure color emission(float inner_angle, float outer_angle) BUILTIN;
+closure color emission(float outer_angle) BUILTIN;
+closure color emission() BUILTIN;
+closure color debug(string tag) BUILTIN;
+closure color background() BUILTIN;
+closure color holdout() BUILTIN;
+closure color subsurface(float eta, float g, float mfp, float albedo) BUILTIN;
+
+// Renderer state
+int raytype (string typename) BUILTIN;
+
+#undef BUILTIN
+#undef BUILTIN_DERIV
+#undef PERCOMP1
+#undef PERCOMP2
+#undef PERCOMP2F
+
+#endif /* CCL_STDOSL_H */
+
diff --git a/intern/cycles/kernel/osl/osl_closures.cpp b/intern/cycles/kernel/osl/osl_closures.cpp
new file mode 100644
index 00000000000..4c2261942fd
--- /dev/null
+++ b/intern/cycles/kernel/osl/osl_closures.cpp
@@ -0,0 +1,93 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., closure_et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <OSL/genclosure.h>
+#include <OSL/oslclosure.h>
+
+#include "osl_closures.h"
+#include "osl_shader.h"
+
+#include "util_debug.h"
+#include "util_param.h"
+
+CCL_NAMESPACE_BEGIN
+
+static void generic_closure_setup(OSL::RendererServices *, int id, void *data)
+{
+ assert(data);
+ OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive *)data;
+ prim->setup();
+}
+
+static bool generic_closure_mergeable(int id, const void *dataA, const void *dataB)
+{
+ assert(dataA && dataB);
+
+ OSL::ClosurePrimitive *primA = (OSL::ClosurePrimitive *)dataA;
+ OSL::ClosurePrimitive *primB = (OSL::ClosurePrimitive *)dataB;
+ return primA->mergeable(primB);
+}
+
+static void register_closure(OSL::ShadingSystem *ss, const char *name, int id, OSL::ClosureParam *params, OSL::PrepareClosureFunc prepare)
+{
+ int j;
+ for(j = 0; params[j].type != TypeDesc(); ++j) {}
+ int size = params[j].offset;
+
+ ss->register_closure(name, id, params, size, prepare, generic_closure_setup, generic_closure_mergeable);
+}
+
+void OSLShader::register_closures(OSL::ShadingSystem *ss)
+{
+ register_closure(ss, "diffuse", OSL_CLOSURE_BSDF_DIFFUSE_ID, bsdf_diffuse_params, bsdf_diffuse_prepare);
+ register_closure(ss, "translucent", OSL_CLOSURE_BSDF_TRANSLUCENT_ID, bsdf_translucent_params, bsdf_translucent_prepare);
+ register_closure(ss, "reflection", OSL_CLOSURE_BSDF_REFLECTION_ID, bsdf_reflection_params, bsdf_reflection_prepare);
+ register_closure(ss, "refraction", OSL_CLOSURE_BSDF_REFRACTION_ID, bsdf_refraction_params, bsdf_refraction_prepare);
+ register_closure(ss, "transparent", OSL_CLOSURE_BSDF_TRANSPARENT_ID, bsdf_transparent_params, bsdf_transparent_prepare);
+ register_closure(ss, "microfacet_ggx", OSL_CLOSURE_BSDF_MICROFACET_GGX_ID, bsdf_microfacet_ggx_params, bsdf_microfacet_ggx_prepare);
+ register_closure(ss, "microfacet_ggx_refraction", OSL_CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID, bsdf_microfacet_ggx_refraction_params, bsdf_microfacet_ggx_refraction_prepare);
+ register_closure(ss, "microfacet_beckmann", OSL_CLOSURE_BSDF_MICROFACET_BECKMANN_ID, bsdf_microfacet_beckmann_params, bsdf_microfacet_beckmann_prepare);
+ register_closure(ss, "microfacet_beckmann_refraction", OSL_CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID, bsdf_microfacet_beckmann_refraction_params, bsdf_microfacet_beckmann_refraction_prepare);
+ register_closure(ss, "ward", OSL_CLOSURE_BSDF_WARD_ID, bsdf_ward_params, bsdf_ward_prepare);
+ register_closure(ss, "ashikhmin_velvet", OSL_CLOSURE_BSDF_ASHIKHMIN_VELVET_ID, bsdf_ashikhmin_velvet_params, bsdf_ashikhmin_velvet_prepare);
+ register_closure(ss, "westin_backscatter", OSL_CLOSURE_BSDF_WESTIN_BACKSCATTER_ID, bsdf_westin_backscatter_params, bsdf_westin_backscatter_prepare);
+ register_closure(ss, "westin_sheen", OSL_CLOSURE_BSDF_WESTIN_SHEEN_ID, bsdf_westin_sheen_params, bsdf_westin_sheen_prepare);
+ register_closure(ss, "bssrdf_cubic", OSL_CLOSURE_BSSRDF_CUBIC_ID, closure_bssrdf_cubic_params, closure_bssrdf_cubic_prepare);
+ register_closure(ss, "emission", OSL_CLOSURE_EMISSION_ID, closure_emission_params, closure_emission_prepare);
+ register_closure(ss, "debug", OSL_CLOSURE_DEBUG_ID, closure_debug_params, closure_debug_prepare);
+ register_closure(ss, "background", OSL_CLOSURE_BACKGROUND_ID, closure_background_params, closure_background_prepare);
+ register_closure(ss, "holdout", OSL_CLOSURE_HOLDOUT_ID, closure_holdout_params, closure_holdout_prepare);
+ register_closure(ss, "subsurface", OSL_CLOSURE_SUBSURFACE_ID, closure_subsurface_params, closure_subsurface_prepare);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/osl/osl_closures.h b/intern/cycles/kernel/osl/osl_closures.h
new file mode 100644
index 00000000000..20a759586b0
--- /dev/null
+++ b/intern/cycles/kernel/osl/osl_closures.h
@@ -0,0 +1,114 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef __OSL_CLOSURES_H__
+#define __OSL_CLOSURES_H__
+
+#include <OSL/oslclosure.h>
+#include <OSL/oslexec.h>
+#include <OSL/genclosure.h>
+
+CCL_NAMESPACE_BEGIN
+
+enum {
+ OSL_CLOSURE_BSDF_DIFFUSE_ID,
+ OSL_CLOSURE_BSDF_TRANSLUCENT_ID,
+ OSL_CLOSURE_BSDF_REFLECTION_ID,
+ OSL_CLOSURE_BSDF_REFRACTION_ID,
+ OSL_CLOSURE_BSDF_TRANSPARENT_ID,
+ OSL_CLOSURE_BSDF_MICROFACET_GGX_ID,
+ OSL_CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID,
+ OSL_CLOSURE_BSDF_MICROFACET_BECKMANN_ID,
+ OSL_CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID,
+ OSL_CLOSURE_BSDF_WARD_ID,
+ OSL_CLOSURE_BSDF_ASHIKHMIN_VELVET_ID,
+ OSL_CLOSURE_BSDF_WESTIN_BACKSCATTER_ID,
+ OSL_CLOSURE_BSDF_WESTIN_SHEEN_ID,
+ OSL_CLOSURE_BSSRDF_CUBIC_ID,
+ OSL_CLOSURE_EMISSION_ID,
+ OSL_CLOSURE_DEBUG_ID,
+ OSL_CLOSURE_BACKGROUND_ID,
+ OSL_CLOSURE_HOLDOUT_ID,
+ OSL_CLOSURE_SUBSURFACE_ID
+};
+
+extern OSL::ClosureParam bsdf_diffuse_params[];
+extern OSL::ClosureParam bsdf_translucent_params[];
+extern OSL::ClosureParam bsdf_reflection_params[];
+extern OSL::ClosureParam bsdf_refraction_params[];
+extern OSL::ClosureParam bsdf_transparent_params[];
+extern OSL::ClosureParam bsdf_microfacet_ggx_params[];
+extern OSL::ClosureParam bsdf_microfacet_ggx_refraction_params[];
+extern OSL::ClosureParam bsdf_microfacet_beckmann_params[];
+extern OSL::ClosureParam bsdf_microfacet_beckmann_refraction_params[];
+extern OSL::ClosureParam bsdf_ward_params[];
+extern OSL::ClosureParam bsdf_ashikhmin_velvet_params[];
+extern OSL::ClosureParam bsdf_westin_backscatter_params[];
+extern OSL::ClosureParam bsdf_westin_sheen_params[];
+extern OSL::ClosureParam closure_bssrdf_cubic_params[];
+extern OSL::ClosureParam closure_emission_params[];
+extern OSL::ClosureParam closure_debug_params[];
+extern OSL::ClosureParam closure_background_params[];
+extern OSL::ClosureParam closure_holdout_params[];
+extern OSL::ClosureParam closure_subsurface_params[];
+
+void bsdf_diffuse_prepare(OSL::RendererServices *, int id, void *data);
+void bsdf_translucent_prepare(OSL::RendererServices *, int id, void *data);
+void bsdf_reflection_prepare(OSL::RendererServices *, int id, void *data);
+void bsdf_refraction_prepare(OSL::RendererServices *, int id, void *data);
+void bsdf_transparent_prepare(OSL::RendererServices *, int id, void *data);
+void bsdf_microfacet_ggx_prepare(OSL::RendererServices *, int id, void *data);
+void bsdf_microfacet_ggx_refraction_prepare(OSL::RendererServices *, int id, void *data);
+void bsdf_microfacet_beckmann_prepare(OSL::RendererServices *, int id, void *data);
+void bsdf_microfacet_beckmann_refraction_prepare(OSL::RendererServices *, int id, void *data);
+void bsdf_ward_prepare(OSL::RendererServices *, int id, void *data);
+void bsdf_ashikhmin_velvet_prepare(OSL::RendererServices *, int id, void *data);
+void bsdf_westin_backscatter_prepare(OSL::RendererServices *, int id, void *data);
+void bsdf_westin_sheen_prepare(OSL::RendererServices *, int id, void *data);
+void closure_bssrdf_cubic_prepare(OSL::RendererServices *, int id, void *data);
+void closure_emission_prepare(OSL::RendererServices *, int id, void *data);
+void closure_debug_prepare(OSL::RendererServices *, int id, void *data);
+void closure_background_prepare(OSL::RendererServices *, int id, void *data);
+void closure_holdout_prepare(OSL::RendererServices *, int id, void *data);
+void closure_subsurface_prepare(OSL::RendererServices *, int id, void *data);
+
+#define CLOSURE_PREPARE(name, classname) \
+void name(RendererServices *, int id, void *data) \
+{ \
+ memset(data, 0, sizeof(classname)); \
+ new (data) classname(); \
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __OSL_CLOSURES_H__ */
+
diff --git a/intern/cycles/kernel/osl/osl_globals.h b/intern/cycles/kernel/osl/osl_globals.h
new file mode 100644
index 00000000000..90746c385c7
--- /dev/null
+++ b/intern/cycles/kernel/osl/osl_globals.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __OSL_GLOBALS_H__
+#define __OSL_GLOBALS_H__
+
+#ifdef WITH_OSL
+
+#include <OSL/oslexec.h>
+
+#include "util_map.h"
+#include "util_param.h"
+#include "util_thread.h"
+#include "util_vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+struct OSLGlobals {
+ /* use */
+ bool use;
+
+ /* shading system */
+ OSL::ShadingSystem *ss;
+
+ /* shader states */
+ vector<OSL::ShadingAttribStateRef> surface_state;
+ vector<OSL::ShadingAttribStateRef> volume_state;
+ vector<OSL::ShadingAttribStateRef> displacement_state;
+ OSL::ShadingAttribStateRef background_state;
+
+ /* attributes */
+ struct Attribute {
+ TypeDesc type;
+ AttributeElement elem;
+ int offset;
+ ParamValue value;
+ };
+
+ typedef unordered_map<ustring, Attribute, ustringHash> AttributeMap;
+ typedef unordered_map<ustring, int, ustringHash> ObjectNameMap;
+
+ vector<AttributeMap> attribute_map;
+ ObjectNameMap object_name_map;
+
+ /* thread key for thread specific data lookup */
+ struct ThreadData {
+ OSL::ShaderGlobals globals;
+ void *thread_info;
+ };
+
+ static tls_ptr(ThreadData, thread_data);
+};
+
+CCL_NAMESPACE_END
+
+#endif
+
+#endif /* __OSL_GLOBALS_H__ */
+
diff --git a/intern/cycles/kernel/osl/osl_services.cpp b/intern/cycles/kernel/osl/osl_services.cpp
new file mode 100644
index 00000000000..ded3a68d667
--- /dev/null
+++ b/intern/cycles/kernel/osl/osl_services.cpp
@@ -0,0 +1,424 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <string.h>
+
+#include "mesh.h"
+#include "object.h"
+#include "scene.h"
+
+#include "osl_services.h"
+#include "osl_shader.h"
+
+#include "util_foreach.h"
+#include "util_string.h"
+
+#include "kernel_compat_cpu.h"
+#include "kernel_globals.h"
+#include "kernel_object.h"
+#include "kernel_triangle.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* RenderServices implementation */
+
+#define TO_MATRIX44(m) (*(OSL::Matrix44*)&(m))
+
+/* static ustrings */
+ustring OSLRenderServices::u_distance("distance");
+ustring OSLRenderServices::u_index("index");
+ustring OSLRenderServices::u_camera("camera");
+ustring OSLRenderServices::u_screen("screen");
+ustring OSLRenderServices::u_raster("raster");
+ustring OSLRenderServices::u_ndc("NDC");
+ustring OSLRenderServices::u_empty;
+
+OSLRenderServices::OSLRenderServices()
+{
+ kernel_globals = NULL;
+}
+
+OSLRenderServices::~OSLRenderServices()
+{
+}
+
+void OSLRenderServices::thread_init(KernelGlobals *kernel_globals_)
+{
+ kernel_globals = kernel_globals_;
+}
+
+bool OSLRenderServices::get_matrix(OSL::Matrix44 &result, OSL::TransformationPtr xform, float time)
+{
+ /* this is only used for shader and object space, we don't really have
+ a concept of shader space, so we just use object space for both. */
+ if(xform) {
+ KernelGlobals *kg = kernel_globals;
+ const ShaderData *sd = (const ShaderData*)xform;
+ int object = sd->object;
+
+ if(object != ~0) {
+ Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
+ tfm = transform_transpose(tfm);
+ result = TO_MATRIX44(tfm);
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool OSLRenderServices::get_inverse_matrix(OSL::Matrix44 &result, OSL::TransformationPtr xform, float time)
+{
+ /* this is only used for shader and object space, we don't really have
+ a concept of shader space, so we just use object space for both. */
+ if(xform) {
+ KernelGlobals *kg = kernel_globals;
+ const ShaderData *sd = (const ShaderData*)xform;
+ int object = sd->object;
+
+ if(object != ~0) {
+ Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
+ tfm = transform_transpose(tfm);
+ result = TO_MATRIX44(tfm);
+
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool OSLRenderServices::get_matrix(OSL::Matrix44 &result, ustring from, float time)
+{
+ KernelGlobals *kg = kernel_globals;
+
+ if(from == u_ndc) {
+ Transform tfm = transform_transpose(kernel_data.cam.ndctoworld);
+ result = TO_MATRIX44(tfm);
+ return true;
+ }
+ else if(from == u_raster) {
+ Transform tfm = transform_transpose(kernel_data.cam.rastertoworld);
+ result = TO_MATRIX44(tfm);
+ return true;
+ }
+ else if(from == u_screen) {
+ Transform tfm = transform_transpose(kernel_data.cam.screentoworld);
+ result = TO_MATRIX44(tfm);
+ return true;
+ }
+ else if(from == u_camera) {
+ Transform tfm = transform_transpose(kernel_data.cam.cameratoworld);
+ result = TO_MATRIX44(tfm);
+ return true;
+ }
+
+ return false;
+}
+
+bool OSLRenderServices::get_inverse_matrix(OSL::Matrix44 &result, ustring to, float time)
+{
+ KernelGlobals *kg = kernel_globals;
+
+ if(to == u_ndc) {
+ Transform tfm = transform_transpose(kernel_data.cam.worldtondc);
+ result = TO_MATRIX44(tfm);
+ return true;
+ }
+ else if(to == u_raster) {
+ Transform tfm = transform_transpose(kernel_data.cam.worldtoraster);
+ result = TO_MATRIX44(tfm);
+ return true;
+ }
+ else if(to == u_screen) {
+ Transform tfm = transform_transpose(kernel_data.cam.worldtoscreen);
+ result = TO_MATRIX44(tfm);
+ return true;
+ }
+ else if(to == u_camera) {
+ Transform tfm = transform_transpose(kernel_data.cam.worldtocamera);
+ result = TO_MATRIX44(tfm);
+ return true;
+ }
+
+ return false;
+}
+
+bool OSLRenderServices::get_array_attribute(void *renderstate, bool derivatives,
+ ustring object, TypeDesc type, ustring name,
+ int index, void *val)
+{
+ return false;
+}
+
+static bool get_mesh_attribute(KernelGlobals *kg, const ShaderData *sd,
+ const OSLGlobals::Attribute& attr, bool derivatives, void *val)
+{
+ if(attr.type == TypeDesc::TypeFloat) {
+ float *fval = (float*)val;
+ fval[0] = triangle_attribute_float(kg, sd, attr.elem, attr.offset,
+ (derivatives)? &fval[1]: NULL, (derivatives)? &fval[2]: NULL);
+ }
+ else {
+ float3 *fval = (float3*)val;
+ fval[0] = triangle_attribute_float3(kg, sd, attr.elem, attr.offset,
+ (derivatives)? &fval[1]: NULL, (derivatives)? &fval[2]: NULL);
+ }
+
+ return true;
+}
+
+static bool get_mesh_attribute_convert(KernelGlobals *kg, const ShaderData *sd,
+ const OSLGlobals::Attribute& attr, const TypeDesc& type, bool derivatives, void *val)
+{
+ if(attr.type == TypeDesc::TypeFloat) {
+ float tmp[3];
+ float3 *fval = (float3*)val;
+
+ get_mesh_attribute(kg, sd, attr, derivatives, tmp);
+
+ fval[0] = make_float3(tmp[0], tmp[0], tmp[0]);
+ if(derivatives) {
+ fval[1] = make_float3(tmp[1], tmp[1], tmp[1]);
+ fval[2] = make_float3(tmp[2], tmp[2], tmp[2]);
+ }
+
+ return true;
+ }
+ else if(attr.type == TypeDesc::TypePoint || attr.type == TypeDesc::TypeVector ||
+ attr.type == TypeDesc::TypeNormal || attr.type == TypeDesc::TypeColor) {
+ float3 tmp[3];
+ float *fval = (float*)val;
+
+ get_mesh_attribute(kg, sd, attr, derivatives, tmp);
+
+ fval[0] = average(tmp[0]);
+ if(derivatives) {
+ fval[1] = average(tmp[1]);
+ fval[2] = average(tmp[2]);
+ }
+
+ return true;
+ }
+ else
+ return false;
+}
+
+static void get_object_attribute(const OSLGlobals::Attribute& attr, bool derivatives, void *val)
+{
+ size_t datasize = attr.value.datasize();
+
+ memcpy(val, attr.value.data(), datasize);
+ if(derivatives)
+ memset((char*)val + datasize, 0, datasize*2);
+}
+
+bool OSLRenderServices::get_attribute(void *renderstate, bool derivatives, ustring object_name,
+ TypeDesc type, ustring name, void *val)
+{
+ KernelGlobals *kg = kernel_globals;
+ const ShaderData *sd = (const ShaderData*)renderstate;
+ int object = sd->object;
+ int tri = sd->prim;
+
+ /* lookup of attribute on another object */
+ if(object_name != u_empty) {
+ OSLGlobals::ObjectNameMap::iterator it = kg->osl.object_name_map.find(object_name);
+
+ if(it == kg->osl.object_name_map.end())
+ return false;
+
+ object = it->second;
+ tri = ~0;
+ }
+ else if(object == ~0) {
+ /* no background attributes supported */
+ return false;
+ }
+
+ /* find attribute on object */
+ OSLGlobals::AttributeMap& attribute_map = kg->osl.attribute_map[object];
+ OSLGlobals::AttributeMap::iterator it = attribute_map.find(name);
+
+ if(it == attribute_map.end())
+ return false;
+
+ /* type mistmatch? */
+ const OSLGlobals::Attribute& attr = it->second;
+
+ if(attr.elem != ATTR_ELEMENT_VALUE) {
+ /* triangle and vertex attributes */
+ if(tri != ~0) {
+ if(attr.type == type || (attr.type == TypeDesc::TypeColor &&
+ (type == TypeDesc::TypePoint || type == TypeDesc::TypeVector || type == TypeDesc::TypeNormal)))
+ return get_mesh_attribute(kg, sd, attr, derivatives, val);
+ else
+ return get_mesh_attribute_convert(kg, sd, attr, type, derivatives, val);
+ }
+ }
+ else {
+ /* object attribute */
+ get_object_attribute(attr, derivatives, val);
+ return true;
+ }
+
+ return false;
+}
+
+bool OSLRenderServices::get_userdata(bool derivatives, ustring name, TypeDesc type,
+ void *renderstate, void *val)
+{
+ return false; /* disabled by lockgeom */
+}
+
+bool OSLRenderServices::has_userdata(ustring name, TypeDesc type, void *renderstate)
+{
+ return false; /* never called by OSL */
+}
+
+void *OSLRenderServices::get_pointcloud_attr_query(ustring *attr_names,
+ TypeDesc *attr_types, int nattrs)
+{
+#ifdef WITH_PARTIO
+ m_attr_queries.push_back(AttrQuery());
+ AttrQuery &query = m_attr_queries.back();
+
+ /* make space for what we need. the only reason to use
+ std::vector is to skip the delete */
+ query.attr_names.resize(nattrs);
+ query.attr_partio_types.resize(nattrs);
+ /* capacity will keep the length of the smallest array passed
+ to the query. Just to prevent buffer overruns */
+ query.capacity = -1;
+
+ for(int i = 0; i < nattrs; ++i)
+ {
+ query.attr_names[i] = attr_names[i];
+
+ TypeDesc element_type = attr_types[i].elementtype ();
+
+ if(query.capacity < 0)
+ query.capacity = attr_types[i].numelements();
+ else
+ query.capacity = min(query.capacity, (int)attr_types[i].numelements());
+
+ /* convert the OSL (OIIO) type to the equivalent Partio type so
+ we can do a fast check at query time. */
+ if(element_type == TypeDesc::TypeFloat)
+ query.attr_partio_types[i] = Partio::FLOAT;
+ else if(element_type == TypeDesc::TypeInt)
+ query.attr_partio_types[i] = Partio::INT;
+ else if(element_type == TypeDesc::TypeColor || element_type == TypeDesc::TypePoint ||
+ element_type == TypeDesc::TypeVector || element_type == TypeDesc::TypeNormal)
+ query.attr_partio_types[i] = Partio::VECTOR;
+ else
+ return NULL; /* report some error of unknown type */
+ }
+
+ /* this is valid until the end of RenderServices */
+ return &query;
+#else
+ return NULL;
+#endif
+}
+
+#ifdef WITH_PARTIO
+Partio::ParticlesData *OSLRenderServices::get_pointcloud(ustring filename)
+{
+ return Partio::readCached(filename.c_str(), true);
+}
+
+#endif
+
+int OSLRenderServices::pointcloud(ustring filename, const OSL::Vec3 &center, float radius,
+ int max_points, void *_attr_query, void **attr_outdata)
+{
+ /* todo: this code has never been tested, and most likely does not
+ work. it's based on the example code in OSL */
+
+#ifdef WITH_PARTIO
+ /* query Partio for this pointcloud lookup using cached attr_query */
+ if(!_attr_query)
+ return 0;
+
+ AttrQuery *attr_query = (AttrQuery *)_attr_query;
+ if(attr_query->capacity < max_points)
+ return 0;
+
+ /* get the pointcloud entry for the given filename */
+ Partio::ParticlesData *cloud = get_pointcloud(filename);
+
+ /* now we have to look up all the attributes in the file. we can't do this
+ before hand cause we never know what we are going to load. */
+ int nattrs = attr_query->attr_names.size();
+ Partio::ParticleAttribute *attr = (Partio::ParticleAttribute *)alloca(sizeof(Partio::ParticleAttribute) * nattrs);
+
+ for(int i = 0; i < nattrs; ++i) {
+ /* special case attributes */
+ if(attr_query->attr_names[i] == u_distance || attr_query->attr_names[i] == u_index)
+ continue;
+
+ /* lookup the attribute by name*/
+ if(!cloud->attributeInfo(attr_query->attr_names[i].c_str(), attr[i])) {
+ /* issue an error here and return, types don't match */
+ Partio::endCachedAccess(cloud);
+ cloud->release();
+ return 0;
+ }
+ }
+
+ std::vector<Partio::ParticleIndex> indices;
+ std::vector<float> dist2;
+
+ Partio::beginCachedAccess(cloud);
+
+ /* finally, do the lookup */
+ cloud->findNPoints((const float *)&center, max_points, radius, indices, dist2);
+ int count = indices.size();
+
+ /* retrieve the attributes directly to user space */
+ for(int j = 0; j < nattrs; ++j) {
+ /* special cases */
+ if(attr_query->attr_names[j] == u_distance) {
+ for(int i = 0; i < count; ++i)
+ ((float *)attr_outdata[j])[i] = sqrtf(dist2[i]);
+ }
+ else if(attr_query->attr_names[j] == u_index) {
+ for(int i = 0; i < count; ++i)
+ ((int *)attr_outdata[j])[i] = indices[i];
+ }
+ else {
+ /* note we make a single call per attribute, we don't loop over the
+ points. Partio does it, so it is there that we have to care about
+ performance */
+ cloud->data(attr[j], count, &indices[0], true, attr_outdata[j]);
+ }
+ }
+
+ Partio::endCachedAccess(cloud);
+ cloud->release();
+
+ return count;
+#else
+ return 0;
+#endif
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/osl/osl_services.h b/intern/cycles/kernel/osl/osl_services.h
new file mode 100644
index 00000000000..e5003074822
--- /dev/null
+++ b/intern/cycles/kernel/osl/osl_services.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __OSL_SERVICES_H__
+#define __OSL_SERVICES_H__
+
+/* OSL Render Services
+ *
+ * Implementation of OSL render services, to retriever matrices, attributes,
+ * textures and point clouds. In principle this should only be accessing
+ * kernel data, but currently we also reach back into the Scene to retrieve
+ * attributes.
+ */
+
+#include <OSL/oslexec.h>
+#include <OSL/oslclosure.h>
+
+#ifdef WITH_PARTIO
+#include <Partio.h>
+#endif
+
+CCL_NAMESPACE_BEGIN
+
+class Object;
+class Scene;
+class Shader;
+class ShaderData;
+class float3;
+class KernelGlobals;
+
+class OSLRenderServices : public OSL::RendererServices
+{
+public:
+ OSLRenderServices();
+ ~OSLRenderServices();
+
+ void thread_init(KernelGlobals *kernel_globals);
+
+ bool get_matrix(OSL::Matrix44 &result, OSL::TransformationPtr xform, float time);
+ bool get_inverse_matrix(OSL::Matrix44 &result, OSL::TransformationPtr xform, float time);
+ bool get_matrix(OSL::Matrix44 &result, ustring from, float time);
+ bool get_inverse_matrix(OSL::Matrix44 &result, ustring to, float time);
+
+ bool get_array_attribute(void *renderstate, bool derivatives,
+ ustring object, TypeDesc type, ustring name,
+ int index, void *val);
+ bool get_attribute(void *renderstate, bool derivatives, ustring object,
+ TypeDesc type, ustring name, void *val);
+
+ bool get_userdata(bool derivatives, ustring name, TypeDesc type,
+ void *renderstate, void *val);
+ bool has_userdata(ustring name, TypeDesc type, void *renderstate);
+
+ void *get_pointcloud_attr_query(ustring *attr_names,
+ TypeDesc *attr_types, int nattrs);
+ int pointcloud(ustring filename, const OSL::Vec3 &center, float radius,
+ int max_points, void *attr_query, void **attr_outdata);
+
+private:
+ KernelGlobals *kernel_globals;
+
+#ifdef WITH_PARTIO
+ /* OSL gets pointers to this but its definition is private.
+ right now it only caches the types already converted to
+ Partio constants. this is what get_pointcloud_attr_query
+ returns */
+ struct AttrQuery
+ {
+ /* names of the attributes to query */
+ std::vector<ustring> attr_names;
+ /* types as (enum Partio::ParticleAttributeType) of the
+ attributes in the query */
+ std::vector<int> attr_partio_types;
+ /* for sanity checks, capacity of the output arrays */
+ int capacity;
+ };
+
+ Partio::ParticlesData *get_pointcloud(ustring filename);
+
+ /* keep a list so adding elements doesn't invalidate pointers */
+ std::list<AttrQuery> m_attr_queries;
+#endif
+
+ static ustring u_distance;
+ static ustring u_index;
+ static ustring u_camera;
+ static ustring u_screen;
+ static ustring u_raster;
+ static ustring u_ndc;
+ static ustring u_empty;
+};
+
+CCL_NAMESPACE_END
+
+#endif /* __OSL_SERVICES_H__ */
+
diff --git a/intern/cycles/kernel/osl/osl_shader.cpp b/intern/cycles/kernel/osl/osl_shader.cpp
new file mode 100644
index 00000000000..f4ae0248bef
--- /dev/null
+++ b/intern/cycles/kernel/osl/osl_shader.cpp
@@ -0,0 +1,559 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "kernel_compat_cpu.h"
+#include "kernel_types.h"
+#include "kernel_globals.h"
+#include "kernel_object.h"
+
+#include "osl_services.h"
+#include "osl_shader.h"
+
+#include "util_foreach.h"
+
+#include <OSL/oslexec.h>
+#include <oslexec_pvt.h>
+
+CCL_NAMESPACE_BEGIN
+
+tls_ptr(ThreadData, OSLGlobals::thread_data);
+
+/* Threads */
+
+void OSLShader::thread_init(KernelGlobals *kg)
+{
+ OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl*)kg->osl.ss;
+
+ OSLGlobals::ThreadData *tdata = new OSLGlobals::ThreadData();
+
+ memset(&tdata->globals, 0, sizeof(OSL::ShaderGlobals));
+ tdata->thread_info = ssi->create_thread_info();
+
+ tls_set(kg->osl.thread_data, tdata);
+
+ ((OSLRenderServices*)ssi->renderer())->thread_init(kg);
+}
+
+void OSLShader::thread_free(KernelGlobals *kg)
+{
+ OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl*)kg->osl.ss;
+
+ OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data);
+
+ ssi->destroy_thread_info(tdata->thread_info);
+
+ delete tdata;
+}
+
+/* Globals */
+
+#define TO_VEC3(v) (*(OSL::Vec3*)&(v))
+#define TO_COLOR3(v) (*(OSL::Color3*)&(v))
+#define TO_FLOAT3(v) make_float3(v[0], v[1], v[2])
+
+static void shaderdata_to_shaderglobals(KernelGlobals *kg, ShaderData *sd,
+ int path_flag, OSL::ShaderGlobals *globals)
+{
+ /* copy from shader data to shader globals */
+ globals->P = TO_VEC3(sd->P);
+ globals->dPdx = TO_VEC3(sd->dP.dx);
+ globals->dPdy = TO_VEC3(sd->dP.dy);
+ globals->I = TO_VEC3(sd->I);
+ globals->dIdx = TO_VEC3(sd->dI.dx);
+ globals->dIdy = TO_VEC3(sd->dI.dy);
+ globals->N = TO_VEC3(sd->N);
+ globals->Ng = TO_VEC3(sd->Ng);
+ globals->u = sd->u;
+ globals->dudx = sd->du.dx;
+ globals->dudy = sd->du.dy;
+ globals->v = sd->v;
+ globals->dvdx = sd->dv.dx;
+ globals->dvdy = sd->dv.dy;
+ globals->dPdu = TO_VEC3(sd->dPdu);
+ globals->dPdv = TO_VEC3(sd->dPdv);
+ globals->surfacearea = (sd->object == ~0)? 1.0f: object_surface_area(kg, sd->object);
+
+ /* booleans */
+ globals->raytype = path_flag;
+ globals->backfacing = (sd->flag & SD_BACKFACING);
+
+ /* don't know yet if we need this */
+ globals->flipHandedness = false;
+
+ /* shader data to be used in services callbacks */
+ globals->renderstate = sd;
+
+ /* hacky, we leave it to services to fetch actual object matrix */
+ globals->shader2common = sd;
+ globals->object2common = sd;
+
+ /* must be set to NULL before execute */
+ globals->Ci = NULL;
+}
+
+/* Surface */
+
+static void flatten_surface_closure_tree(ShaderData *sd, bool no_glossy,
+ const OSL::ClosureColor *closure, float3 weight = make_float3(1.0f, 1.0f, 1.0f))
+{
+ /* OSL gives use a closure tree, we flatten it into arrays per
+ * closure type, for evaluation, sampling, etc later on. */
+
+ if(closure->type == OSL::ClosureColor::COMPONENT) {
+ OSL::ClosureComponent *comp = (OSL::ClosureComponent*)closure;
+ OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive*)comp->data();
+
+ if(prim) {
+ FlatClosure flat;
+ flat.prim = prim;
+ flat.weight = weight;
+
+ switch(prim->category()) {
+ case ClosurePrimitive::BSDF: {
+ if(sd->osl_closure.num_bsdf == MAX_OSL_CLOSURE)
+ return;
+
+ OSL::BSDFClosure *bsdf = (OSL::BSDFClosure*)prim;
+ ustring scattering = bsdf->scattering();
+
+ /* no caustics option */
+ if(no_glossy && scattering == OSL::Labels::GLOSSY)
+ return;
+
+ /* sample weight */
+ float albedo = bsdf->albedo(TO_VEC3(sd->I));
+ float sample_weight = fabsf(average(weight))*albedo;
+ float sample_sum = sd->osl_closure.bsdf_sample_sum + sample_weight;
+
+ flat.sample_weight = sample_weight;
+ sd->osl_closure.bsdf_sample_sum = sample_sum;
+
+ /* scattering flags */
+ if(scattering == OSL::Labels::DIFFUSE)
+ sd->flag |= SD_BSDF_HAS_EVAL;
+ else if(scattering == OSL::Labels::GLOSSY)
+ sd->flag |= SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY;
+
+ /* add */
+ sd->osl_closure.bsdf[sd->osl_closure.num_bsdf++] = flat;
+ break;
+ }
+ case ClosurePrimitive::Emissive: {
+ if(sd->osl_closure.num_bsdf == MAX_OSL_CLOSURE)
+ return;
+
+ /* sample weight */
+ float sample_weight = fabsf(average(weight));
+ float sample_sum = sd->osl_closure.emissive_sample_sum + sample_weight;
+
+ flat.sample_weight = sample_weight;
+ sd->osl_closure.emissive_sample_sum = sample_sum;
+
+ /* flag */
+ sd->flag |= SD_EMISSION;
+
+ sd->osl_closure.emissive[sd->osl_closure.num_emissive++] = flat;
+ break;
+ }
+ case ClosurePrimitive::BSSRDF:
+ case ClosurePrimitive::Holdout:
+ case ClosurePrimitive::Debug:
+ break; /* not implemented */
+ case ClosurePrimitive::Background:
+ case ClosurePrimitive::Volume:
+ break; /* not relevant */
+ }
+ }
+ }
+ else if(closure->type == OSL::ClosureColor::MUL) {
+ OSL::ClosureMul *mul = (OSL::ClosureMul*)closure;
+ flatten_surface_closure_tree(sd, no_glossy, mul->closure, TO_FLOAT3(mul->weight) * weight);
+ }
+ else if(closure->type == OSL::ClosureColor::ADD) {
+ OSL::ClosureAdd *add = (OSL::ClosureAdd*)closure;
+ flatten_surface_closure_tree(sd, no_glossy, add->closureA, weight);
+ flatten_surface_closure_tree(sd, no_glossy, add->closureB, weight);
+ }
+}
+
+void OSLShader::eval_surface(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag)
+{
+ /* gather pointers */
+ OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl*)kg->osl.ss;
+ OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data);
+ OSL::ShaderGlobals *globals = &tdata->globals;
+ OSL::pvt::ShadingContext *ctx = ssi->get_context(tdata->thread_info);
+
+ /* setup shader globals from shader data */
+ sd->osl_ctx = ctx;
+ shaderdata_to_shaderglobals(kg, sd, path_flag, globals);
+
+ /* execute shader for this point */
+ if(kg->osl.surface_state[sd->shader])
+ ctx->execute(OSL::pvt::ShadUseSurface, *(kg->osl.surface_state[sd->shader]), *globals);
+
+ /* flatten closure tree */
+ sd->osl_closure.bsdf_sample_sum = 0.0f;
+ sd->osl_closure.emissive_sample_sum = 0.0f;
+ sd->osl_closure.num_bsdf = 0;
+ sd->osl_closure.num_emissive = 0;
+ sd->osl_closure.randb = randb;
+
+ if(globals->Ci) {
+ bool no_glossy = (path_flag & PATH_RAY_DIFFUSE) && kernel_data.integrator.no_caustics;
+ flatten_surface_closure_tree(sd, no_glossy, globals->Ci);
+ }
+}
+
+/* Background */
+
+static float3 flatten_background_closure_tree(const OSL::ClosureColor *closure)
+{
+ /* OSL gives use a closure tree, if we are shading for background there
+ * is only one supported closure type at the moment, which has no evaluation
+ * functions, so we just sum the weights */
+
+ if(closure->type == OSL::ClosureColor::COMPONENT) {
+ OSL::ClosureComponent *comp = (OSL::ClosureComponent*)closure;
+ OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive*)comp->data();
+
+ if(prim && prim->category() == OSL::ClosurePrimitive::Background)
+ return make_float3(1.0f, 1.0f, 1.0f);
+ }
+ else if(closure->type == OSL::ClosureColor::MUL) {
+ OSL::ClosureMul *mul = (OSL::ClosureMul*)closure;
+
+ return TO_FLOAT3(mul->weight) * flatten_background_closure_tree(mul->closure);
+ }
+ else if(closure->type == OSL::ClosureColor::ADD) {
+ OSL::ClosureAdd *add = (OSL::ClosureAdd*)closure;
+
+ return flatten_background_closure_tree(add->closureA) +
+ flatten_background_closure_tree(add->closureB);
+ }
+
+ return make_float3(0.0f, 0.0f, 0.0f);
+}
+
+float3 OSLShader::eval_background(KernelGlobals *kg, ShaderData *sd, int path_flag)
+{
+ /* gather pointers */
+ OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl*)kg->osl.ss;
+ OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data);
+ OSL::ShaderGlobals *globals = &tdata->globals;
+ OSL::pvt::ShadingContext *ctx = ssi->get_context(tdata->thread_info);
+
+ /* setup shader globals from shader data */
+ sd->osl_ctx = ctx;
+ shaderdata_to_shaderglobals(kg, sd, path_flag, globals);
+
+ /* execute shader for this point */
+ if(kg->osl.background_state)
+ ctx->execute(OSL::pvt::ShadUseSurface, *kg->osl.background_state, *globals);
+
+ /* return background color immediately */
+ if(globals->Ci)
+ return flatten_background_closure_tree(globals->Ci);
+
+ return make_float3(0.0f, 0.0f, 0.0f);
+}
+
+/* Volume */
+
+static void flatten_volume_closure_tree(ShaderData *sd,
+ const OSL::ClosureColor *closure, float3 weight = make_float3(1.0f, 1.0f, 1.0f))
+{
+ /* OSL gives use a closure tree, we flatten it into arrays per
+ * closure type, for evaluation, sampling, etc later on. */
+
+ if(closure->type == OSL::ClosureColor::COMPONENT) {
+ OSL::ClosureComponent *comp = (OSL::ClosureComponent*)closure;
+ OSL::ClosurePrimitive *prim = (OSL::ClosurePrimitive*)comp->data();
+
+ if(prim) {
+ FlatClosure flat;
+ flat.prim = prim;
+ flat.weight = weight;
+
+ switch(prim->category()) {
+ case ClosurePrimitive::Volume: {
+ if(sd->osl_closure.num_bsdf == MAX_OSL_CLOSURE)
+ return;
+
+ /* sample weight */
+ float sample_weight = fabsf(average(weight));
+ float sample_sum = sd->osl_closure.volume_sample_sum + sample_weight;
+
+ flat.sample_weight = sample_weight;
+ sd->osl_closure.volume_sample_sum = sample_sum;
+
+ /* add */
+ sd->osl_closure.volume[sd->osl_closure.num_volume++] = flat;
+ break;
+ }
+ case ClosurePrimitive::Holdout:
+ case ClosurePrimitive::Debug:
+ break; /* not implemented */
+ case ClosurePrimitive::Background:
+ case ClosurePrimitive::BSDF:
+ case ClosurePrimitive::Emissive:
+ case ClosurePrimitive::BSSRDF:
+ break; /* not relevant */
+ }
+ }
+ }
+ else if(closure->type == OSL::ClosureColor::MUL) {
+ OSL::ClosureMul *mul = (OSL::ClosureMul*)closure;
+ flatten_volume_closure_tree(sd, mul->closure, TO_FLOAT3(mul->weight) * weight);
+ }
+ else if(closure->type == OSL::ClosureColor::ADD) {
+ OSL::ClosureAdd *add = (OSL::ClosureAdd*)closure;
+ flatten_volume_closure_tree(sd, add->closureA, weight);
+ flatten_volume_closure_tree(sd, add->closureB, weight);
+ }
+}
+
+void OSLShader::eval_volume(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag)
+{
+ /* gather pointers */
+ OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl*)kg->osl.ss;
+ OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data);
+ OSL::ShaderGlobals *globals = &tdata->globals;
+ OSL::pvt::ShadingContext *ctx = ssi->get_context(tdata->thread_info);
+
+ /* setup shader globals from shader data */
+ sd->osl_ctx = ctx;
+ shaderdata_to_shaderglobals(kg, sd, path_flag, globals);
+
+ /* execute shader */
+ ctx->execute(OSL::pvt::ShadUseSurface, *(kg->osl.volume_state[sd->shader]), *globals);
+
+ /* retrieve resulting closures */
+ sd->osl_closure.volume_sample_sum = 0.0f;
+ sd->osl_closure.num_volume = 0;
+ sd->osl_closure.randb = randb;
+
+ if(globals->Ci)
+ flatten_volume_closure_tree(sd, globals->Ci);
+}
+
+/* Displacement */
+
+void OSLShader::eval_displacement(KernelGlobals *kg, ShaderData *sd)
+{
+ /* gather pointers */
+ OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl*)kg->osl.ss;
+ OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data);
+ OSL::ShaderGlobals *globals = &tdata->globals;
+ OSL::pvt::ShadingContext *ctx = ssi->get_context(tdata->thread_info);
+
+ /* setup shader globals from shader data */
+ sd->osl_ctx = ctx;
+ shaderdata_to_shaderglobals(kg, sd, 0, globals);
+
+ /* execute shader */
+ ctx->execute(OSL::pvt::ShadUseSurface, *(kg->osl.displacement_state[sd->shader]), *globals);
+
+ /* get back position */
+ sd->P = TO_FLOAT3(globals->P);
+}
+
+void OSLShader::release(KernelGlobals *kg, const ShaderData *sd)
+{
+ OSL::pvt::ShadingSystemImpl *ssi = (OSL::pvt::ShadingSystemImpl*)kg->osl.ss;
+ OSLGlobals::ThreadData *tdata = tls_get(OSLGlobals::ThreadData, kg->osl.thread_data);
+
+ ssi->release_context((OSL::pvt::ShadingContext*)sd->osl_ctx, tdata->thread_info);
+}
+
+/* BSDF Closure */
+
+int OSLShader::bsdf_sample(const ShaderData *sd, float randu, float randv, float3& eval, float3& omega_in, differential3& domega_in, float& pdf)
+{
+ OSL::BSDFClosure *sample_bsdf = NULL;
+ int label = LABEL_NONE;
+ float r = sd->osl_closure.randb*sd->osl_closure.bsdf_sample_sum;
+ float sample_sum = 0.0f;
+
+ pdf = 0.0f;
+
+ if(sd->osl_closure.bsdf_sample_sum == 0.0f)
+ return LABEL_NONE;
+
+ /* find a closure to sample */
+ for(int i = 0; i < sd->osl_closure.num_bsdf; i++) {
+ const FlatClosure *flat = &sd->osl_closure.bsdf[i];
+ sample_sum += flat->sample_weight;
+
+ if(r > sample_sum)
+ continue;
+
+ /* sample BSDF closure */
+ sample_bsdf = (OSL::BSDFClosure*)flat->prim;
+ ustring ulabel;
+
+ ulabel = sample_bsdf->sample(TO_VEC3(sd->Ng),
+ TO_VEC3(sd->I), TO_VEC3(sd->dI.dx), TO_VEC3(sd->dI.dy),
+ randu, randv,
+ TO_VEC3(omega_in), TO_VEC3(domega_in.dx), TO_VEC3(domega_in.dy),
+ pdf, TO_COLOR3(eval));
+
+ /* convert OSL label */
+ if(ulabel == OSL::Labels::REFLECT)
+ label = LABEL_REFLECT;
+ else if(ulabel == OSL::Labels::TRANSMIT)
+ label = LABEL_TRANSMIT;
+ else
+ return LABEL_NONE; /* sampling failed */
+
+ /* convert scattering to our bitflag label */
+ ustring uscattering = sample_bsdf->scattering();
+
+ if(uscattering == OSL::Labels::DIFFUSE)
+ label |= LABEL_DIFFUSE;
+ else if(uscattering == OSL::Labels::GLOSSY)
+ label |= LABEL_GLOSSY;
+ else if(uscattering == OSL::Labels::SINGULAR)
+ label |= LABEL_SINGULAR;
+ else
+ label |= LABEL_STRAIGHT;
+
+ /* eval + pdf */
+ eval *= flat->weight;
+ pdf *= flat->sample_weight;
+
+ break;
+ }
+
+ if(!sample_bsdf || pdf == 0.0f)
+ return LABEL_NONE;
+
+ /* add eval/pdf from other BSDF closures */
+ for(int i = 0; i < sd->osl_closure.num_bsdf; i++) {
+ const FlatClosure *flat = &sd->osl_closure.bsdf[i];
+ OSL::BSDFClosure *bsdf = (OSL::BSDFClosure*)flat->prim;
+
+ if(bsdf != sample_bsdf) {
+ OSL::Color3 bsdf_eval;
+ float bsdf_pdf = 0.0f;
+
+ if(dot(sd->Ng, omega_in) >= 0.0f)
+ bsdf_eval = bsdf->eval_reflect(TO_VEC3(sd->I), TO_VEC3(omega_in), bsdf_pdf);
+ else
+ bsdf_eval = bsdf->eval_transmit(TO_VEC3(sd->I), TO_VEC3(omega_in), bsdf_pdf);
+
+ if(bsdf_pdf != 0.0f) {
+ eval += TO_FLOAT3(bsdf_eval)*flat->weight;
+ pdf += bsdf_pdf*flat->sample_weight;
+ }
+ }
+ }
+
+ pdf *= 1.0f/(sd->osl_closure.bsdf_sample_sum);
+
+ return label;
+}
+
+float3 OSLShader::bsdf_eval(const ShaderData *sd, const float3& omega_in, float& pdf)
+{
+ float3 eval = make_float3(0.0f, 0.0f, 0.0f);
+
+ pdf = 0.0f;
+
+ for(int i = 0; i < sd->osl_closure.num_bsdf; i++) {
+ const FlatClosure *flat = &sd->osl_closure.bsdf[i];
+ OSL::BSDFClosure *bsdf = (OSL::BSDFClosure*)flat->prim;
+ OSL::Color3 bsdf_eval;
+ float bsdf_pdf = 0.0f;
+
+ if(dot(sd->Ng, omega_in) >= 0.0f)
+ bsdf_eval = bsdf->eval_reflect(TO_VEC3(sd->I), TO_VEC3(omega_in), bsdf_pdf);
+ else
+ bsdf_eval = bsdf->eval_transmit(TO_VEC3(sd->I), TO_VEC3(omega_in), bsdf_pdf);
+
+ if(bsdf_pdf != 0.0f) {
+ eval += TO_FLOAT3(bsdf_eval)*flat->weight;
+ pdf += bsdf_pdf*flat->sample_weight;
+ }
+ }
+
+ pdf *= 1.0f/sd->osl_closure.bsdf_sample_sum;
+
+ return eval;
+}
+
+/* Emissive Closure */
+
+float3 OSLShader::emissive_eval(const ShaderData *sd)
+{
+ float3 eval = make_float3(0.0f, 0.0f, 0.0f);
+
+ for(int i = 0; i < sd->osl_closure.num_emissive; i++) {
+ const FlatClosure *flat = &sd->osl_closure.emissive[i];
+ OSL::EmissiveClosure *emissive = (OSL::EmissiveClosure*)flat->prim;
+ OSL::Color3 emissive_eval = emissive->eval(TO_VEC3(sd->Ng), TO_VEC3(sd->I));
+ eval += TO_FLOAT3(emissive_eval)*flat->weight;
+ }
+
+ return eval;
+}
+
+void OSLShader::emissive_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *I, float *pdf)
+{
+ float r = sd->osl_closure.randb*sd->osl_closure.emissive_sample_sum;
+ float sample_sum = 0.0f;
+
+ *pdf = 0.0f;
+
+ if(sd->osl_closure.emissive_sample_sum == 0.0f)
+ return;
+
+ /* find a closure to sample */
+ for(int i = 0; i < sd->osl_closure.num_emissive; i++) {
+ const FlatClosure *flat = &sd->osl_closure.emissive[i];
+ sample_sum += flat->sample_weight;
+
+ if(r <= sample_sum) {
+ /* sample emissive closure */
+ OSL::EmissiveClosure *emissive = (OSL::EmissiveClosure*)flat->prim;
+ emissive->sample(TO_VEC3(sd->Ng), randu, randv, TO_VEC3(*I), *pdf);
+ *eval = flat->weight;
+ *pdf *= flat->sample_weight/sd->osl_closure.emissive_sample_sum;
+ return;
+ }
+ }
+}
+
+/* Volume Closure */
+
+float3 OSLShader::volume_eval_phase(const ShaderData *sd, const float3 omega_in, const float3 omega_out)
+{
+ float3 eval = make_float3(0.0f, 0.0f, 0.0f);
+
+ for(int i = 0; i < sd->osl_closure.num_volume; i++) {
+ const FlatClosure *flat = &sd->osl_closure.volume[i];
+ OSL::VolumeClosure *volume = (OSL::VolumeClosure*)flat->prim;
+ OSL::Color3 volume_eval = volume->eval_phase(TO_VEC3(omega_in), TO_VEC3(omega_out));
+ eval += TO_FLOAT3(volume_eval)*flat->weight;
+ }
+
+ return eval;
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/osl/osl_shader.h b/intern/cycles/kernel/osl/osl_shader.h
new file mode 100644
index 00000000000..2e5279c12ce
--- /dev/null
+++ b/intern/cycles/kernel/osl/osl_shader.h
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __OSL_SHADER_H__
+#define __OSL_SHADER_H__
+
+#ifdef WITH_OSL
+
+/* OSL Shader Engine
+ *
+ * Holds all variables to execute and use OSL shaders from the kernel. These
+ * are initialized externally by OSLShaderManager before rendering starts.
+ *
+ * Before/after a thread starts rendering, thread_init/thread_free must be
+ * called, which will store any per thread OSL state in thread local storage.
+ * This means no thread state must be passed along in the kernel itself.
+ */
+
+#include <OSL/oslexec.h>
+#include <OSL/oslclosure.h>
+
+#include "kernel_types.h"
+
+#include "util_map.h"
+#include "util_param.h"
+#include "util_vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+namespace OSL = ::OSL;
+
+class OSLRenderServices;
+class Scene;
+class ShaderData;
+class differential3;
+class KernelGlobals;
+
+class OSLShader {
+public:
+ /* init */
+ static void register_closures(OSL::ShadingSystem *ss);
+
+ /* per thread data */
+ static void thread_init(KernelGlobals *kg);
+ static void thread_free(KernelGlobals *kg);
+
+ /* eval */
+ static void eval_surface(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag);
+ static float3 eval_background(KernelGlobals *kg, ShaderData *sd, int path_flag);
+ static void eval_volume(KernelGlobals *kg, ShaderData *sd, float randb, int path_flag);
+ static void eval_displacement(KernelGlobals *kg, ShaderData *sd);
+
+ /* sample & eval */
+ static int bsdf_sample(const ShaderData *sd, float randu, float randv,
+ float3& eval, float3& omega_in, differential3& domega_in, float& pdf);
+ static float3 bsdf_eval(const ShaderData *sd, const float3& omega_in, float& pdf);
+ static float3 emissive_eval(const ShaderData *sd);
+ static void emissive_sample(const ShaderData *sd, float randu, float randv,
+ float3 *eval, float3 *I, float *pdf);
+ static float3 volume_eval_phase(const ShaderData *sd, const float3 omega_in,
+ const float3 omega_out);
+
+ /* release */
+ static void release(KernelGlobals *kg, const ShaderData *sd);
+};
+
+CCL_NAMESPACE_END
+
+#endif
+
+#endif /* __OSL_SHADER_H__ */
+
diff --git a/intern/cycles/kernel/osl/vol_subsurface.cpp b/intern/cycles/kernel/osl/vol_subsurface.cpp
new file mode 100644
index 00000000000..0cd3060051b
--- /dev/null
+++ b/intern/cycles/kernel/osl/vol_subsurface.cpp
@@ -0,0 +1,135 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <OpenImageIO/fmath.h>
+
+#include <OSL/genclosure.h>
+
+#include "osl_closures.h"
+
+CCL_NAMESPACE_BEGIN
+
+using namespace OSL;
+
+// Computes scattering properties based on Jensen's reparameterization
+// described in:
+// http://graphics.ucsd.edu/~henrik/papers/fast_bssrdf/
+
+class SubsurfaceClosure : public VolumeClosure {
+public:
+ float m_g;
+ float m_eta;
+ Color3 m_mfp, m_albedo;
+ static float root_find_Rd(const float Rd0, const float A) {
+ // quick exit for trivial cases
+ if (Rd0 <= 0) return 0;
+ const float A43 = A * 4.0f / 3.0f;
+ // Find alpha such that f(alpha) = Rd (see eq.15). A simple bisection
+ // method can be used because this function is monotonicaly increasing.
+ float lo = 0, hi = 1;
+ for (int i = 0; i < 20; i++) { // 2^20 divisions should be sufficient
+ // eval function at midpoint
+ float alpha = 0.5f * (lo + hi);
+ float a1 = sqrtf(3 * (1 - alpha));
+ float e1 = expf(-a1);
+ float e2 = expf(-A43 * a1);
+ float Rd = 0.5f * alpha * (1 + e2) * e1 - Rd0;
+ if (fabsf(Rd) < 1e-6f)
+ return alpha; // close enough
+ else if (Rd > 0)
+ hi = alpha; // root is on left side
+ else
+ lo = alpha; // root is on right side
+ }
+ // didn't quite converge, pick result in the middle of remaining interval
+ return 0.5f * (lo + hi);
+ }
+ SubsurfaceClosure() { }
+
+ void setup()
+ {
+ ior(m_eta);
+
+ if (m_g >= 0.99f) m_g = 0.99f;
+ if (m_g <= -0.99f) m_g = -0.99f;
+
+ // eq.10
+ float inv_eta = 1 / m_eta;
+ float Fdr = -1.440f * inv_eta * inv_eta + 0.710 * inv_eta + 0.668f + 0.0636 * m_eta;
+ float A = (1 + Fdr) / (1 - Fdr);
+ // compute sigma_s, sigma_a (eq.16)
+ Color3 alpha_prime = Color3 (root_find_Rd(m_albedo[0], A),
+ root_find_Rd(m_albedo[1], A),
+ root_find_Rd(m_albedo[2], A));
+ Color3 sigma_t_prime = Color3 (m_mfp.x > 0 ? 1.0f / (m_mfp[0] * sqrtf(3 * (1 - alpha_prime[0]))) : 0.0f,
+ m_mfp.y > 0 ? 1.0f / (m_mfp[1] * sqrtf(3 * (1 - alpha_prime[1]))) : 0.0f,
+ m_mfp.z > 0 ? 1.0f / (m_mfp[2] * sqrtf(3 * (1 - alpha_prime[2]))) : 0.0f);
+ Color3 sigma_s_prime = alpha_prime * sigma_t_prime;
+
+ sigma_s((1.0f / (1 - m_g)) * sigma_s_prime);
+ sigma_a(sigma_t_prime - sigma_s_prime);
+ }
+
+ bool mergeable (const ClosurePrimitive *other) const {
+ const SubsurfaceClosure *comp = (const SubsurfaceClosure *)other;
+ return m_g == comp->m_g && VolumeClosure::mergeable(other);
+ }
+
+ size_t memsize () const { return sizeof(*this); }
+
+ const char *name () const { return "subsurface"; }
+
+ void print_on (std::ostream &out) const {
+ out << name() << " ()";
+ }
+
+ virtual Color3 eval_phase(const Vec3 &omega_in, const Vec3 &omega_out) const {
+ float costheta = omega_in.dot(omega_out);
+ float ph = 0.25f * float(M_1_PI) * ((1 - m_g * m_g) / powf(1 + m_g * m_g - 2.0f * m_g * costheta, 1.5f));
+ return Color3 (ph, ph, ph);
+ }
+};
+
+
+
+ClosureParam closure_subsurface_params[] = {
+ CLOSURE_FLOAT_PARAM (SubsurfaceClosure, m_eta),
+ CLOSURE_FLOAT_PARAM (SubsurfaceClosure, m_g),
+ CLOSURE_COLOR_PARAM (SubsurfaceClosure, m_mfp),
+ CLOSURE_COLOR_PARAM (SubsurfaceClosure, m_albedo),
+ CLOSURE_STRING_KEYPARAM("label"),
+ CLOSURE_FINISH_PARAM(SubsurfaceClosure) };
+
+CLOSURE_PREPARE(closure_subsurface_prepare, SubsurfaceClosure)
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/bsdf.h b/intern/cycles/kernel/svm/bsdf.h
new file mode 100644
index 00000000000..18c1da73fbd
--- /dev/null
+++ b/intern/cycles/kernel/svm/bsdf.h
@@ -0,0 +1,135 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __OSL_BSDF_H__
+#define __OSL_BSDF_H__
+
+CCL_NAMESPACE_BEGIN
+
+__device float fresnel_dielectric(float eta, const float3 N,
+ const float3 I, float3 *R, float3 *T,
+#ifdef __RAY_DIFFERENTIALS__
+ const float3 dIdx, const float3 dIdy,
+ float3 *dRdx, float3 *dRdy,
+ float3 *dTdx, float3 *dTdy,
+#endif
+ bool *is_inside)
+{
+ float cos = dot(N, I), neta;
+ float3 Nn;
+ // compute reflection
+ *R =(2 * cos)* N - I;
+#ifdef __RAY_DIFFERENTIALS__
+ *dRdx = (2 * dot(N, dIdx)) * N - dIdx;
+ *dRdy = (2 * dot(N, dIdy)) * N - dIdy;
+#endif
+ // check which side of the surface we are on
+ if(cos > 0) {
+ // we are on the outside of the surface, going in
+ neta = 1 / eta;
+ Nn = N;
+ *is_inside = false;
+ } else {
+ // we are inside the surface,
+ cos = -cos;
+ neta = eta;
+ Nn = -N;
+ *is_inside = true;
+ }
+ *R =(2 * cos)* Nn - I;
+ float arg = 1 -(neta * neta *(1 -(cos * cos)));
+ if(arg < 0) {
+ *T= make_float3(0.0f, 0.0f, 0.0f);
+#ifdef __RAY_DIFFERENTIALS__
+ *dTdx= make_float3(0.0f, 0.0f, 0.0f);
+ *dTdy= make_float3(0.0f, 0.0f, 0.0f);
+#endif
+ return 1; // total internal reflection
+ } else {
+ float dnp = sqrtf(arg);
+ float nK =(neta * cos)- dnp;
+ *T = -(neta * I)+(nK * Nn);
+#ifdef __RAY_DIFFERENTIALS__
+ *dTdx = -(neta * dIdx) + ((neta - neta * neta * cos / dnp) * dot(dIdx, Nn)) * Nn;
+ *dTdy = -(neta * dIdy) + ((neta - neta * neta * cos / dnp) * dot(dIdy, Nn)) * Nn;
+#endif
+ // compute Fresnel terms
+ float cosTheta1 = cos; // N.R
+ float cosTheta2 = -dot(Nn, *T);
+ float pPara =(cosTheta1 - eta * cosTheta2)/(cosTheta1 + eta * cosTheta2);
+ float pPerp =(eta * cosTheta1 - cosTheta2)/(eta * cosTheta1 + cosTheta2);
+ return 0.5f * (pPara * pPara + pPerp * pPerp);
+ }
+}
+
+__device float fresnel_dielectric_cos(float cosi, float eta)
+{
+ // compute fresnel reflectance without explicitly computing
+ // the refracted direction
+ float c = fabsf(cosi);
+ float g = eta * eta - 1 + c * c;
+ if(g > 0) {
+ g = sqrtf(g);
+ float A =(g - c)/(g + c);
+ float B =(c *(g + c)- 1)/(c *(g - c)+ 1);
+ return 0.5f * A * A *(1 + B * B);
+ }
+ return 1.0f; // TIR(no refracted component)
+}
+
+__device float fresnel_conductor(float cosi, float eta, float k)
+{
+ float tmp_f = eta * eta + k * k;
+ float tmp = tmp_f * cosi * cosi;
+ float Rparl2 =(tmp -(2.0f * eta * cosi)+ 1)/
+ (tmp +(2.0f * eta * cosi)+ 1);
+ float Rperp2 =(tmp_f -(2.0f * eta * cosi)+ cosi * cosi)/
+ (tmp_f +(2.0f * eta * cosi)+ cosi * cosi);
+ return(Rparl2 + Rperp2) * 0.5f;
+}
+
+__device float smooth_step(float edge0, float edge1, float x)
+{
+ float result;
+ if(x < edge0) result = 0.0f;
+ else if(x >= edge1) result = 1.0f;
+ else {
+ float t = (x - edge0)/(edge1 - edge0);
+ result = (3.0f-2.0f*t)*(t*t);
+ }
+ return result;
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __OSL_BSDF_H__ */
+
diff --git a/intern/cycles/kernel/svm/bsdf_ashikhmin_velvet.h b/intern/cycles/kernel/svm/bsdf_ashikhmin_velvet.h
new file mode 100644
index 00000000000..40bae72a6c5
--- /dev/null
+++ b/intern/cycles/kernel/svm/bsdf_ashikhmin_velvet.h
@@ -0,0 +1,154 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __BSDF_ASHIKHMIN_VELVET_H__
+#define __BSDF_ASHIKHMIN_VELVET_H__
+
+CCL_NAMESPACE_BEGIN
+
+typedef struct BsdfAshikhminVelvetClosure {
+ //float3 m_N;
+ float m_invsigma2;
+} BsdfAshikhminVelvetClosure;
+
+__device void bsdf_ashikhmin_velvet_setup(ShaderData *sd, float3 N, float sigma)
+{
+ BsdfAshikhminVelvetClosure *self = (BsdfAshikhminVelvetClosure*)sd->svm_closure_data;
+
+ sigma = fmaxf(sigma, 0.01f);
+
+ //self->m_N = N;
+ self->m_invsigma2 = 1.0f/(sigma * sigma);
+
+ sd->svm_closure = CLOSURE_BSDF_ASHIKHMIN_VELVET_ID;
+ sd->flag |= SD_BSDF_HAS_EVAL;
+}
+
+__device void bsdf_ashikhmin_velvet_blur(ShaderData *sd, float roughness)
+{
+}
+
+__device float3 bsdf_ashikhmin_velvet_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
+{
+ const BsdfAshikhminVelvetClosure *self = (const BsdfAshikhminVelvetClosure*)sd->svm_closure_data;
+ float3 m_N = sd->N;
+
+ float cosNO = dot(m_N, I);
+ float cosNI = dot(m_N, omega_in);
+ if(cosNO > 0 && cosNI > 0) {
+ float3 H = normalize(omega_in + I);
+
+ float cosNH = dot(m_N, H);
+ float cosHO = fabsf(dot(I, H));
+
+ float cosNHdivHO = cosNH / cosHO;
+ cosNHdivHO = fmaxf(cosNHdivHO, 0.00001f);
+
+ float fac1 = 2 * fabsf(cosNHdivHO * cosNO);
+ float fac2 = 2 * fabsf(cosNHdivHO * cosNI);
+
+ float sinNH2 = 1 - cosNH * cosNH;
+ float sinNH4 = sinNH2 * sinNH2;
+ float cotangent2 = (cosNH * cosNH) / sinNH2;
+
+ float D = expf(-cotangent2 * self->m_invsigma2) * self->m_invsigma2 * M_1_PI_F / sinNH4;
+ float G = min(1.0f, min(fac1, fac2)); // TODO: derive G from D analytically
+
+ float out = 0.25f * (D * G) / cosNO;
+
+ *pdf = 0.5f * M_1_PI_F;
+ return make_float3(out, out, out);
+ }
+ return make_float3(0, 0, 0);
+}
+
+__device float3 bsdf_ashikhmin_velvet_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
+{
+ return make_float3(0.0f, 0.0f, 0.0f);
+}
+
+__device float bsdf_ashikhmin_velvet_albedo(const ShaderData *sd, const float3 I)
+{
+ return 1.0f;
+}
+
+__device int bsdf_ashikhmin_velvet_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
+{
+ const BsdfAshikhminVelvetClosure *self = (const BsdfAshikhminVelvetClosure*)sd->svm_closure_data;
+ float3 m_N = sd->N;
+
+ // we are viewing the surface from above - send a ray out with uniform
+ // distribution over the hemisphere
+ sample_uniform_hemisphere(m_N, randu, randv, omega_in, pdf);
+
+ if(dot(sd->Ng, *omega_in) > 0) {
+ float3 H = normalize(*omega_in + sd->I);
+
+ float cosNI = dot(m_N, *omega_in);
+ float cosNO = dot(m_N, sd->I);
+ float cosNH = dot(m_N, H);
+ float cosHO = fabsf(dot(sd->I, H));
+
+ float cosNHdivHO = cosNH / cosHO;
+ cosNHdivHO = fmaxf(cosNHdivHO, 0.00001f);
+
+ float fac1 = 2 * fabsf(cosNHdivHO * cosNO);
+ float fac2 = 2 * fabsf(cosNHdivHO * cosNI);
+
+ float sinNH2 = 1 - cosNH * cosNH;
+ float sinNH4 = sinNH2 * sinNH2;
+ float cotangent2 = (cosNH * cosNH) / sinNH2;
+
+ float D = expf(-cotangent2 * self->m_invsigma2) * self->m_invsigma2 * M_1_PI_F / sinNH4;
+ float G = min(1.0f, min(fac1, fac2)); // TODO: derive G from D analytically
+
+ float power = 0.25f * (D * G) / cosNO;
+
+ *eval = make_float3(power, power, power);
+
+#ifdef __RAY_DIFFERENTIALS__
+ // TODO: find a better approximation for the retroreflective bounce
+ *domega_in_dx = (2 * dot(m_N, sd->dI.dx)) * m_N - sd->dI.dx;
+ *domega_in_dy = (2 * dot(m_N, sd->dI.dy)) * m_N - sd->dI.dy;
+ *domega_in_dx *= 125;
+ *domega_in_dy *= 125;
+#endif
+ } else
+ *pdf = 0.0f;
+
+ return LABEL_REFLECT|LABEL_DIFFUSE;
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __BSDF_ASHIKHMIN_VELVET_H__ */
+
diff --git a/intern/cycles/kernel/svm/bsdf_diffuse.h b/intern/cycles/kernel/svm/bsdf_diffuse.h
new file mode 100644
index 00000000000..c505de036aa
--- /dev/null
+++ b/intern/cycles/kernel/svm/bsdf_diffuse.h
@@ -0,0 +1,166 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __BSDF_DIFFUSE_H__
+#define __BSDF_DIFFUSE_H__
+
+CCL_NAMESPACE_BEGIN
+
+/* DIFFUSE */
+
+typedef struct BsdfDiffuseClosure {
+ //float3 m_N;
+} BsdfDiffuseClosure;
+
+__device void bsdf_diffuse_setup(ShaderData *sd, float3 N)
+{
+ //BsdfDiffuseClosure *self = (BsdfDiffuseClosure*)sd->svm_closure_data;
+ //self->m_N = N;
+
+ sd->svm_closure = CLOSURE_BSDF_DIFFUSE_ID;
+ sd->flag |= SD_BSDF_HAS_EVAL;
+}
+
+__device void bsdf_diffuse_blur(ShaderData *sd, float roughness)
+{
+}
+
+__device float3 bsdf_diffuse_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
+{
+ //const BsdfDiffuseClosure *self = (const BsdfDiffuseClosure*)sd->svm_closure_data;
+ float3 m_N = sd->N;
+
+ float cos_pi = fmaxf(dot(m_N, omega_in), 0.0f) * M_1_PI_F;
+ *pdf = cos_pi;
+ return make_float3(cos_pi, cos_pi, cos_pi);
+}
+
+__device float3 bsdf_diffuse_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
+{
+ return make_float3(0.0f, 0.0f, 0.0f);
+}
+
+__device float bsdf_diffuse_albedo(const ShaderData *sd, const float3 I)
+{
+ return 1.0f;
+}
+
+__device int bsdf_diffuse_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
+{
+ //const BsdfDiffuseClosure *self = (const BsdfDiffuseClosure*)sd->svm_closure_data;
+ float3 m_N = sd->N;
+
+ // distribution over the hemisphere
+ sample_cos_hemisphere(m_N, randu, randv, omega_in, pdf);
+
+ if(dot(sd->Ng, *omega_in) > 0.0f) {
+ *eval = make_float3(*pdf, *pdf, *pdf);
+#ifdef __RAY_DIFFERENTIALS__
+ // TODO: find a better approximation for the diffuse bounce
+ *domega_in_dx = (2 * dot(m_N, sd->dI.dx)) * m_N - sd->dI.dx;
+ *domega_in_dy = (2 * dot(m_N, sd->dI.dy)) * m_N - sd->dI.dy;
+ *domega_in_dx *= 125;
+ *domega_in_dy *= 125;
+#endif
+ }
+ else
+ *pdf = 0.0f;
+
+ return LABEL_REFLECT|LABEL_DIFFUSE;
+}
+
+/* TRANSLUCENT */
+
+typedef struct BsdfTranslucentClosure {
+ //float3 m_N;
+} BsdfTranslucentClosure;
+
+__device void bsdf_translucent_setup(ShaderData *sd, float3 N)
+{
+ //BsdfTranslucentClosure *self = (BsdfTranslucentClosure*)sd->svm_closure_data;
+ //self->m_N = N;
+
+ sd->svm_closure = CLOSURE_BSDF_TRANSLUCENT_ID;
+ sd->flag |= SD_BSDF_HAS_EVAL;
+}
+
+__device void bsdf_translucent_blur(ShaderData *sd, float roughness)
+{
+}
+
+__device float3 bsdf_translucent_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
+{
+ return make_float3(0.0f, 0.0f, 0.0f);
+}
+
+__device float3 bsdf_translucent_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
+{
+ //const BsdfTranslucentClosure *self = (const BsdfTranslucentClosure*)sd->svm_closure_data;
+ float3 m_N = sd->N;
+
+ float cos_pi = fmaxf(-dot(m_N, omega_in), 0.0f) * M_1_PI_F;
+ *pdf = cos_pi;
+ return make_float3 (cos_pi, cos_pi, cos_pi);
+}
+
+__device float bsdf_translucent_albedo(const ShaderData *sd, const float3 I)
+{
+ return 1.0f;
+}
+
+__device int bsdf_translucent_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
+{
+ //const BsdfTranslucentClosure *self = (const BsdfTranslucentClosure*)sd->svm_closure_data;
+ float3 m_N = sd->N;
+
+ // we are viewing the surface from the right side - send a ray out with cosine
+ // distribution over the hemisphere
+ sample_cos_hemisphere (-m_N, randu, randv, omega_in, pdf);
+ if(dot(sd->Ng, *omega_in) < 0) {
+ *eval = make_float3(*pdf, *pdf, *pdf);
+#ifdef __RAY_DIFFERENTIALS__
+ // TODO: find a better approximation for the diffuse bounce
+ *domega_in_dx = (2 * dot(m_N, sd->dI.dx)) * m_N - sd->dI.dx;
+ *domega_in_dy = (2 * dot(m_N, sd->dI.dy)) * m_N - sd->dI.dy;
+ *domega_in_dx *= -125;
+ *domega_in_dy *= -125;
+#endif
+ } else
+ *pdf = 0;
+
+ return LABEL_TRANSMIT|LABEL_DIFFUSE;
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __BSDF_DIFFUSE_H__ */
+
diff --git a/intern/cycles/kernel/svm/bsdf_microfacet.h b/intern/cycles/kernel/svm/bsdf_microfacet.h
new file mode 100644
index 00000000000..b6baa1e90d8
--- /dev/null
+++ b/intern/cycles/kernel/svm/bsdf_microfacet.h
@@ -0,0 +1,493 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __BSDF_MICROFACET_H__
+#define __BSDF_MICROFACET_H__
+
+CCL_NAMESPACE_BEGIN
+
+/* GGX */
+
+typedef struct BsdfMicrofacetGGXClosure {
+ //float3 m_N;
+ float m_ag;
+ float m_eta;
+ int m_refractive;
+} BsdfMicrofacetGGXClosure;
+
+__device void bsdf_microfacet_ggx_setup(ShaderData *sd, float3 N, float ag, float eta, bool refractive)
+{
+ BsdfMicrofacetGGXClosure *self = (BsdfMicrofacetGGXClosure*)sd->svm_closure_data;
+
+ //self->m_N = N;
+ self->m_ag = clamp(ag, 1e-5f, 1.0f);
+ self->m_eta = eta;
+ self->m_refractive = (refractive)? 1: 0;
+
+ if(refractive)
+ sd->svm_closure = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
+ else
+ sd->svm_closure = CLOSURE_BSDF_MICROFACET_GGX_ID;
+
+ sd->flag |= SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY;
+}
+
+__device void bsdf_microfacet_ggx_blur(ShaderData *sd, float roughness)
+{
+ BsdfMicrofacetGGXClosure *self = (BsdfMicrofacetGGXClosure*)sd->svm_closure_data;
+ self->m_ag = fmaxf(roughness, self->m_ag);
+}
+
+__device float3 bsdf_microfacet_ggx_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
+{
+ const BsdfMicrofacetGGXClosure *self = (const BsdfMicrofacetGGXClosure*)sd->svm_closure_data;
+ float3 m_N = sd->N;
+
+ if(self->m_refractive == 1) return make_float3 (0, 0, 0);
+ float cosNO = dot(m_N, I);
+ float cosNI = dot(m_N, omega_in);
+ if(cosNI > 0 && cosNO > 0) {
+ // get half vector
+ float3 Hr = normalize(omega_in + I);
+ // eq. 20: (F*G*D)/(4*in*on)
+ // eq. 33: first we calculate D(m) with m=Hr:
+ float alpha2 = self->m_ag * self->m_ag;
+ float cosThetaM = dot(m_N, Hr);
+ float cosThetaM2 = cosThetaM * cosThetaM;
+ float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2;
+ float cosThetaM4 = cosThetaM2 * cosThetaM2;
+ float D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2));
+ // eq. 34: now calculate G1(i,m) and G1(o,m)
+ float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO)));
+ float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI)));
+ float G = G1o * G1i;
+ float out = (G * D) * 0.25f / cosNO;
+ // eq. 24
+ float pm = D * cosThetaM;
+ // convert into pdf of the sampled direction
+ // eq. 38 - but see also:
+ // eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf
+ *pdf = pm * 0.25f / dot(Hr, I);
+ return make_float3 (out, out, out);
+ }
+ return make_float3 (0, 0, 0);
+}
+
+__device float3 bsdf_microfacet_ggx_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
+{
+ const BsdfMicrofacetGGXClosure *self = (const BsdfMicrofacetGGXClosure*)sd->svm_closure_data;
+ float3 m_N = sd->N;
+
+ if(self->m_refractive == 0) return make_float3 (0, 0, 0);
+ float cosNO = dot(m_N, I);
+ float cosNI = dot(m_N, omega_in);
+ if(cosNO <= 0 || cosNI >= 0)
+ return make_float3 (0, 0, 0); // vectors on same side -- not possible
+ // compute half-vector of the refraction (eq. 16)
+ float3 ht = -(self->m_eta * omega_in + I);
+ float3 Ht = normalize(ht);
+ float cosHO = dot(Ht, I);
+
+ float cosHI = dot(Ht, omega_in);
+ // eq. 33: first we calculate D(m) with m=Ht:
+ float alpha2 = self->m_ag * self->m_ag;
+ float cosThetaM = dot(m_N, Ht);
+ float cosThetaM2 = cosThetaM * cosThetaM;
+ float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2;
+ float cosThetaM4 = cosThetaM2 * cosThetaM2;
+ float D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2));
+ // eq. 34: now calculate G1(i,m) and G1(o,m)
+ float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO)));
+ float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI)));
+ float G = G1o * G1i;
+ // probability
+ float invHt2 = 1 / dot(ht, ht);
+ *pdf = D * fabsf(cosThetaM) * (fabsf(cosHI) * (self->m_eta * self->m_eta)) * invHt2;
+ float out = (fabsf(cosHI * cosHO) * (self->m_eta * self->m_eta) * (G * D) * invHt2) / cosNO;
+ return make_float3 (out, out, out);
+}
+
+__device float bsdf_microfacet_ggx_albedo(const ShaderData *sd, const float3 I)
+{
+ return 1.0f;
+}
+
+__device int bsdf_microfacet_ggx_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
+{
+ const BsdfMicrofacetGGXClosure *self = (const BsdfMicrofacetGGXClosure*)sd->svm_closure_data;
+ float3 m_N = sd->N;
+
+ float cosNO = dot(m_N, sd->I);
+ if(cosNO > 0) {
+ float3 X, Y, Z = m_N;
+ make_orthonormals(Z, &X, &Y);
+ // generate a random microfacet normal m
+ // eq. 35,36:
+ // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2)
+ //tttt and sin(atan(x)) == x/sqrt(1+x^2)
+ float alpha2 = self->m_ag * self->m_ag;
+ float tanThetaM2 = alpha2 * randu / (1 - randu);
+ float cosThetaM = 1 / sqrtf(1 + tanThetaM2);
+ float sinThetaM = cosThetaM * sqrtf(tanThetaM2);
+ float phiM = 2 * M_PI_F * randv;
+ float3 m = (cosf(phiM) * sinThetaM) * X +
+ (sinf(phiM) * sinThetaM) * Y +
+ cosThetaM * Z;
+ if(self->m_refractive == 0) {
+ float cosMO = dot(m, sd->I);
+ if(cosMO > 0) {
+ // eq. 39 - compute actual reflected direction
+ *omega_in = 2 * cosMO * m - sd->I;
+ if(dot(sd->Ng, *omega_in) > 0) {
+ // microfacet normal is visible to this ray
+ // eq. 33
+ float cosThetaM2 = cosThetaM * cosThetaM;
+ float cosThetaM4 = cosThetaM2 * cosThetaM2;
+ float D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2));
+ // eq. 24
+ float pm = D * cosThetaM;
+ // convert into pdf of the sampled direction
+ // eq. 38 - but see also:
+ // eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf
+ *pdf = pm * 0.25f / cosMO;
+ // eval BRDF*cosNI
+ float cosNI = dot(m_N, *omega_in);
+ // eq. 34: now calculate G1(i,m) and G1(o,m)
+ float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO)));
+ float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI)));
+ float G = G1o * G1i;
+ // eq. 20: (F*G*D)/(4*in*on)
+ float out = (G * D) * 0.25f / cosNO;
+ *eval = make_float3(out, out, out);
+#ifdef __RAY_DIFFERENTIALS__
+ *domega_in_dx = (2 * dot(m, sd->dI.dx)) * m - sd->dI.dx;
+ *domega_in_dy = (2 * dot(m, sd->dI.dy)) * m - sd->dI.dy;
+ // Since there is some blur to this reflection, make the
+ // derivatives a bit bigger. In theory this varies with the
+ // roughness but the exact relationship is complex and
+ // requires more ops than are practical.
+ *domega_in_dx *= 10;
+ *domega_in_dy *= 10;
+#endif
+ }
+ }
+ } else {
+ // CAUTION: the i and o variables are inverted relative to the paper
+ // eq. 39 - compute actual refractive direction
+ float3 R, T;
+#ifdef __RAY_DIFFERENTIALS__
+ float3 dRdx, dRdy, dTdx, dTdy;
+#endif
+ bool inside;
+ fresnel_dielectric(self->m_eta, m, sd->I, &R, &T,
+#ifdef __RAY_DIFFERENTIALS__
+ sd->dI.dx, sd->dI.dy, &dRdx, &dRdy, &dTdx, &dTdy,
+#endif
+ &inside);
+
+ if(!inside) {
+ *omega_in = T;
+#ifdef __RAY_DIFFERENTIALS__
+ *domega_in_dx = dTdx;
+ *domega_in_dy = dTdy;
+#endif
+ // eq. 33
+ float cosThetaM2 = cosThetaM * cosThetaM;
+ float cosThetaM4 = cosThetaM2 * cosThetaM2;
+ float D = alpha2 / (M_PI_F * cosThetaM4 * (alpha2 + tanThetaM2) * (alpha2 + tanThetaM2));
+ // eq. 24
+ float pm = D * cosThetaM;
+ // eval BRDF*cosNI
+ float cosNI = dot(m_N, *omega_in);
+ // eq. 34: now calculate G1(i,m) and G1(o,m)
+ float G1o = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNO * cosNO) / (cosNO * cosNO)));
+ float G1i = 2 / (1 + sqrtf(1 + alpha2 * (1 - cosNI * cosNI) / (cosNI * cosNI)));
+ float G = G1o * G1i;
+ // eq. 21
+ float cosHI = dot(m, *omega_in);
+ float cosHO = dot(m, sd->I);
+ float Ht2 = self->m_eta * cosHI + cosHO;
+ Ht2 *= Ht2;
+ float out = (fabsf(cosHI * cosHO) * (self->m_eta * self->m_eta) * (G * D)) / (cosNO * Ht2);
+ // eq. 38 and eq. 17
+ *pdf = pm * (self->m_eta * self->m_eta) * fabsf(cosHI) / Ht2;
+ *eval = make_float3(out, out, out);
+#ifdef __RAY_DIFFERENTIALS__
+ // Since there is some blur to this refraction, make the
+ // derivatives a bit bigger. In theory this varies with the
+ // roughness but the exact relationship is complex and
+ // requires more ops than are practical.
+ *domega_in_dx *= 10;
+ *domega_in_dy *= 10;
+#endif
+ }
+ }
+ }
+ return (self->m_refractive == 1) ? LABEL_TRANSMIT|LABEL_GLOSSY : LABEL_REFLECT|LABEL_GLOSSY;
+}
+
+/* BECKMANN */
+
+typedef struct BsdfMicrofacetBeckmannClosure {
+ //float3 m_N;
+ float m_ab;
+ float m_eta;
+ int m_refractive;
+} BsdfMicrofacetBeckmannClosure;
+
+__device void bsdf_microfacet_beckmann_setup(ShaderData *sd, float3 N, float ab, float eta, bool refractive)
+{
+ BsdfMicrofacetBeckmannClosure *self = (BsdfMicrofacetBeckmannClosure*)sd->svm_closure_data;
+
+ //self->m_N = N;
+ self->m_ab = clamp(ab, 1e-5f, 1.0f);
+ self->m_eta = eta;
+ self->m_refractive = (refractive)? 1: 0;
+
+ if(refractive)
+ sd->svm_closure = CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID;
+ else
+ sd->svm_closure = CLOSURE_BSDF_MICROFACET_BECKMANN_ID;
+
+ sd->flag |= SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY;
+}
+
+__device void bsdf_microfacet_beckmann_blur(ShaderData *sd, float roughness)
+{
+ BsdfMicrofacetBeckmannClosure *self = (BsdfMicrofacetBeckmannClosure*)sd->svm_closure_data;
+ self->m_ab = fmaxf(roughness, self->m_ab);
+}
+
+__device float3 bsdf_microfacet_beckmann_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
+{
+ const BsdfMicrofacetBeckmannClosure *self = (const BsdfMicrofacetBeckmannClosure*)sd->svm_closure_data;
+ float3 m_N = sd->N;
+
+ if(self->m_refractive == 1) return make_float3 (0, 0, 0);
+ float cosNO = dot(m_N, I);
+ float cosNI = dot(m_N, omega_in);
+ if(cosNO > 0 && cosNI > 0) {
+ // get half vector
+ float3 Hr = normalize(omega_in + I);
+ // eq. 20: (F*G*D)/(4*in*on)
+ // eq. 25: first we calculate D(m) with m=Hr:
+ float alpha2 = self->m_ab * self->m_ab;
+ float cosThetaM = dot(m_N, Hr);
+ float cosThetaM2 = cosThetaM * cosThetaM;
+ float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2;
+ float cosThetaM4 = cosThetaM2 * cosThetaM2;
+ float D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4);
+ // eq. 26, 27: now calculate G1(i,m) and G1(o,m)
+ float ao = 1 / (self->m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO)));
+ float ai = 1 / (self->m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
+ float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f;
+ float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
+ float G = G1o * G1i;
+ float out = (G * D) * 0.25f / cosNO;
+ // eq. 24
+ float pm = D * cosThetaM;
+ // convert into pdf of the sampled direction
+ // eq. 38 - but see also:
+ // eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf
+ *pdf = pm * 0.25f / dot(Hr, I);
+ return make_float3 (out, out, out);
+ }
+ return make_float3 (0, 0, 0);
+}
+
+__device float3 bsdf_microfacet_beckmann_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
+{
+ const BsdfMicrofacetBeckmannClosure *self = (const BsdfMicrofacetBeckmannClosure*)sd->svm_closure_data;
+ float3 m_N = sd->N;
+
+ if(self->m_refractive == 0) return make_float3 (0, 0, 0);
+ float cosNO = dot(m_N, I);
+ float cosNI = dot(m_N, omega_in);
+ if(cosNO <= 0 || cosNI >= 0)
+ return make_float3 (0, 0, 0);
+ // compute half-vector of the refraction (eq. 16)
+ float3 ht = -(self->m_eta * omega_in + I);
+ float3 Ht = normalize(ht);
+ float cosHO = dot(Ht, I);
+
+ float cosHI = dot(Ht, omega_in);
+ // eq. 33: first we calculate D(m) with m=Ht:
+ float alpha2 = self->m_ab * self->m_ab;
+ float cosThetaM = dot(m_N, Ht);
+ float cosThetaM2 = cosThetaM * cosThetaM;
+ float tanThetaM2 = (1 - cosThetaM2) / cosThetaM2;
+ float cosThetaM4 = cosThetaM2 * cosThetaM2;
+ float D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4);
+ // eq. 26, 27: now calculate G1(i,m) and G1(o,m)
+ float ao = 1 / (self->m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO)));
+ float ai = 1 / (self->m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
+ float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f;
+ float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
+ float G = G1o * G1i;
+ // probability
+ float invHt2 = 1 / dot(ht, ht);
+ *pdf = D * fabsf(cosThetaM) * (fabsf(cosHI) * (self->m_eta * self->m_eta)) * invHt2;
+ float out = (fabsf(cosHI * cosHO) * (self->m_eta * self->m_eta) * (G * D) * invHt2) / cosNO;
+ return make_float3 (out, out, out);
+}
+
+__device float bsdf_microfacet_beckmann_albedo(const ShaderData *sd, const float3 I)
+{
+ return 1.0f;
+}
+
+__device int bsdf_microfacet_beckmann_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
+{
+ const BsdfMicrofacetBeckmannClosure *self = (const BsdfMicrofacetBeckmannClosure*)sd->svm_closure_data;
+ float3 m_N = sd->N;
+
+ float cosNO = dot(m_N, sd->I);
+ if(cosNO > 0) {
+ float3 X, Y, Z = m_N;
+ make_orthonormals(Z, &X, &Y);
+ // generate a random microfacet normal m
+ // eq. 35,36:
+ // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2)
+ //tttt and sin(atan(x)) == x/sqrt(1+x^2)
+ float alpha2 = self->m_ab * self->m_ab;
+ float tanThetaM = sqrtf(-alpha2 * logf(1 - randu));
+ float cosThetaM = 1 / sqrtf(1 + tanThetaM * tanThetaM);
+ float sinThetaM = cosThetaM * tanThetaM;
+ float phiM = 2 * M_PI_F * randv;
+ float3 m = (cosf(phiM) * sinThetaM) * X +
+ (sinf(phiM) * sinThetaM) * Y +
+ cosThetaM * Z;
+
+ if(self->m_refractive == 0) {
+ float cosMO = dot(m, sd->I);
+ if(cosMO > 0) {
+ // eq. 39 - compute actual reflected direction
+ *omega_in = 2 * cosMO * m - sd->I;
+ if(dot(sd->Ng, *omega_in) > 0) {
+ // microfacet normal is visible to this ray
+ // eq. 25
+ float cosThetaM2 = cosThetaM * cosThetaM;
+ float tanThetaM2 = tanThetaM * tanThetaM;
+ float cosThetaM4 = cosThetaM2 * cosThetaM2;
+ float D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4);
+ // eq. 24
+ float pm = D * cosThetaM;
+ // convert into pdf of the sampled direction
+ // eq. 38 - but see also:
+ // eq. 17 in http://www.graphics.cornell.edu/~bjw/wardnotes.pdf
+ *pdf = pm * 0.25f / cosMO;
+ // Eval BRDF*cosNI
+ float cosNI = dot(m_N, *omega_in);
+ // eq. 26, 27: now calculate G1(i,m) and G1(o,m)
+ float ao = 1 / (self->m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO)));
+ float ai = 1 / (self->m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
+ float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f;
+ float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
+ float G = G1o * G1i;
+ // eq. 20: (F*G*D)/(4*in*on)
+ float out = (G * D) * 0.25f / cosNO;
+ *eval = make_float3(out, out, out);
+#ifdef __RAY_DIFFERENTIALS__
+ *domega_in_dx = (2 * dot(m, sd->dI.dx)) * m - sd->dI.dx;
+ *domega_in_dy = (2 * dot(m, sd->dI.dy)) * m - sd->dI.dy;
+ // Since there is some blur to this reflection, make the
+ // derivatives a bit bigger. In theory this varies with the
+ // roughness but the exact relationship is complex and
+ // requires more ops than are practical.
+ *domega_in_dx *= 10;
+ *domega_in_dy *= 10;
+#endif
+ }
+ }
+ } else {
+ // CAUTION: the i and o variables are inverted relative to the paper
+ // eq. 39 - compute actual refractive direction
+ float3 R, T;
+#ifdef __RAY_DIFFERENTIALS__
+ float3 dRdx, dRdy, dTdx, dTdy;
+#endif
+ bool inside;
+ fresnel_dielectric(self->m_eta, m, sd->I, &R, &T,
+#ifdef __RAY_DIFFERENTIALS__
+ sd->dI.dx, sd->dI.dy, &dRdx, &dRdy, &dTdx, &dTdy,
+#endif
+ &inside);
+
+ if(!inside) {
+ *omega_in = T;
+#ifdef __RAY_DIFFERENTIALS__
+ *domega_in_dx = dTdx;
+ *domega_in_dy = dTdy;
+#endif
+
+ // eq. 33
+ float cosThetaM2 = cosThetaM * cosThetaM;
+ float tanThetaM2 = tanThetaM * tanThetaM;
+ float cosThetaM4 = cosThetaM2 * cosThetaM2;
+ float D = expf(-tanThetaM2 / alpha2) / (M_PI_F * alpha2 * cosThetaM4);
+ // eq. 24
+ float pm = D * cosThetaM;
+ // eval BRDF*cosNI
+ float cosNI = dot(m_N, *omega_in);
+ // eq. 26, 27: now calculate G1(i,m) and G1(o,m)
+ float ao = 1 / (self->m_ab * sqrtf((1 - cosNO * cosNO) / (cosNO * cosNO)));
+ float ai = 1 / (self->m_ab * sqrtf((1 - cosNI * cosNI) / (cosNI * cosNI)));
+ float G1o = ao < 1.6f ? (3.535f * ao + 2.181f * ao * ao) / (1 + 2.276f * ao + 2.577f * ao * ao) : 1.0f;
+ float G1i = ai < 1.6f ? (3.535f * ai + 2.181f * ai * ai) / (1 + 2.276f * ai + 2.577f * ai * ai) : 1.0f;
+ float G = G1o * G1i;
+ // eq. 21
+ float cosHI = dot(m, *omega_in);
+ float cosHO = dot(m, sd->I);
+ float Ht2 = self->m_eta * cosHI + cosHO;
+ Ht2 *= Ht2;
+ float out = (fabsf(cosHI * cosHO) * (self->m_eta * self->m_eta) * (G * D)) / (cosNO * Ht2);
+ // eq. 38 and eq. 17
+ *pdf = pm * (self->m_eta * self->m_eta) * fabsf(cosHI) / Ht2;
+ *eval = make_float3(out, out, out);
+#ifdef __RAY_DIFFERENTIALS__
+ // Since there is some blur to this refraction, make the
+ // derivatives a bit bigger. In theory this varies with the
+ // roughness but the exact relationship is complex and
+ // requires more ops than are practical.
+ *domega_in_dx *= 10;
+ *domega_in_dy *= 10;
+#endif
+ }
+ }
+ }
+ return (self->m_refractive == 1) ? LABEL_TRANSMIT|LABEL_GLOSSY : LABEL_REFLECT|LABEL_GLOSSY;
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __BSDF_MICROFACET_H__ */
+
diff --git a/intern/cycles/kernel/svm/bsdf_reflection.h b/intern/cycles/kernel/svm/bsdf_reflection.h
new file mode 100644
index 00000000000..287cc9c2506
--- /dev/null
+++ b/intern/cycles/kernel/svm/bsdf_reflection.h
@@ -0,0 +1,95 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __BSDF_REFLECTION_H__
+#define __BSDF_REFLECTION_H__
+
+CCL_NAMESPACE_BEGIN
+
+/* REFLECTION */
+
+typedef struct BsdfReflectionClosure {
+ //float3 m_N;
+} BsdfReflectionClosure;
+
+__device void bsdf_reflection_setup(ShaderData *sd, float3 N)
+{
+ //BsdfReflectionClosure *self = (BsdfReflectionClosure*)sd->svm_closure_data;
+ //self->m_N = N;
+
+ sd->svm_closure = CLOSURE_BSDF_REFLECTION_ID;
+}
+
+__device void bsdf_reflection_blur(ShaderData *sd, float roughness)
+{
+}
+
+__device float3 bsdf_reflection_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
+{
+ return make_float3(0.0f, 0.0f, 0.0f);
+}
+
+__device float3 bsdf_reflection_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
+{
+ return make_float3(0.0f, 0.0f, 0.0f);
+}
+
+__device float bsdf_reflection_albedo(const ShaderData *sd, const float3 I)
+{
+ return 1.0f;
+}
+
+__device int bsdf_reflection_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
+{
+ //const BsdfReflectionClosure *self = (const BsdfReflectionClosure*)sd->svm_closure_data;
+ float3 m_N = sd->N;
+
+ // only one direction is possible
+ float cosNO = dot(m_N, sd->I);
+ if(cosNO > 0) {
+ *omega_in = (2 * cosNO) * m_N - sd->I;
+ if(dot(sd->Ng, *omega_in) > 0) {
+#ifdef __RAY_DIFFERENTIALS__
+ *domega_in_dx = 2 * dot(m_N, sd->dI.dx) * m_N - sd->dI.dx;
+ *domega_in_dy = 2 * dot(m_N, sd->dI.dy) * m_N - sd->dI.dy;
+#endif
+ *pdf = 1;
+ *eval = make_float3(1, 1, 1);
+ }
+ }
+ return LABEL_REFLECT|LABEL_SINGULAR;
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __BSDF_REFLECTION_H__ */
+
diff --git a/intern/cycles/kernel/svm/bsdf_refraction.h b/intern/cycles/kernel/svm/bsdf_refraction.h
new file mode 100644
index 00000000000..55a914f8334
--- /dev/null
+++ b/intern/cycles/kernel/svm/bsdf_refraction.h
@@ -0,0 +1,103 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __BSDF_REFRACTION_H__
+#define __BSDF_REFRACTION_H__
+
+CCL_NAMESPACE_BEGIN
+
+/* REFRACTION */
+
+typedef struct BsdfRefractionClosure {
+ float m_eta;
+} BsdfRefractionClosure;
+
+__device void bsdf_refraction_setup(ShaderData *sd, float3 N, float eta)
+{
+ BsdfRefractionClosure *self = (BsdfRefractionClosure*)sd->svm_closure_data;
+
+ self->m_eta = eta;
+
+ sd->svm_closure = CLOSURE_BSDF_REFRACTION_ID;
+}
+
+__device void bsdf_refraction_blur(ShaderData *sd, float roughness)
+{
+}
+
+__device float3 bsdf_refraction_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
+{
+ return make_float3(0.0f, 0.0f, 0.0f);
+}
+
+__device float3 bsdf_refraction_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
+{
+ return make_float3(0.0f, 0.0f, 0.0f);
+}
+
+__device float bsdf_refraction_albedo(const ShaderData *sd, const float3 I)
+{
+ return 1.0f;
+}
+
+__device int bsdf_refraction_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
+{
+ const BsdfRefractionClosure *self = (const BsdfRefractionClosure*)sd->svm_closure_data;
+ float3 m_N = sd->N;
+
+ float3 R, T;
+#ifdef __RAY_DIFFERENTIALS__
+ float3 dRdx, dRdy, dTdx, dTdy;
+#endif
+ bool inside;
+ fresnel_dielectric(self->m_eta, m_N, sd->I, &R, &T,
+#ifdef __RAY_DIFFERENTIALS__
+ sd->dI.dx, sd->dI.dy, &dRdx, &dRdy, &dTdx, &dTdy,
+#endif
+ &inside);
+
+ if(!inside) {
+ *pdf = 1;
+ *eval = make_float3(1.0f, 1.0f, 1.0f);
+ *omega_in = T;
+#ifdef __RAY_DIFFERENTIALS__
+ *domega_in_dx = dTdx;
+ *domega_in_dy = dTdy;
+#endif
+ }
+ return LABEL_TRANSMIT|LABEL_SINGULAR;
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __BSDF_REFRACTION_H__ */
+
diff --git a/intern/cycles/kernel/svm/bsdf_transparent.h b/intern/cycles/kernel/svm/bsdf_transparent.h
new file mode 100644
index 00000000000..e689e3db357
--- /dev/null
+++ b/intern/cycles/kernel/svm/bsdf_transparent.h
@@ -0,0 +1,78 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __BSDF_TRANSPARENT_H__
+#define __BSDF_TRANSPARENT_H__
+
+CCL_NAMESPACE_BEGIN
+
+__device void bsdf_transparent_setup(ShaderData *sd)
+{
+ sd->svm_closure = CLOSURE_BSDF_TRANSPARENT_ID;
+}
+
+__device void bsdf_transparent_blur(ShaderData *sd, float roughness)
+{
+}
+
+__device float3 bsdf_transparent_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
+{
+ return make_float3(0.0f, 0.0f, 0.0f);
+}
+
+__device float3 bsdf_transparent_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
+{
+ return make_float3(0.0f, 0.0f, 0.0f);
+}
+
+__device float bsdf_transparent_albedo(const ShaderData *sd, const float3 I)
+{
+ return 1.0f;
+}
+
+__device int bsdf_transparent_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
+{
+ // only one direction is possible
+ *omega_in = -sd->I;
+#ifdef __RAY_DIFFERENTIALS__
+ *domega_in_dx = -sd->dI.dx;
+ *domega_in_dy = -sd->dI.dy;
+#endif
+ *pdf = 1;
+ *eval = make_float3(1, 1, 1);
+ return LABEL_TRANSMIT|LABEL_STRAIGHT;
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __BSDF_TRANSPARENT_H__ */
+
diff --git a/intern/cycles/kernel/svm/bsdf_ward.h b/intern/cycles/kernel/svm/bsdf_ward.h
new file mode 100644
index 00000000000..bf591acc9fa
--- /dev/null
+++ b/intern/cycles/kernel/svm/bsdf_ward.h
@@ -0,0 +1,202 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __BSDF_WARD_H__
+#define __BSDF_WARD_H__
+
+CCL_NAMESPACE_BEGIN
+
+/* WARD */
+
+typedef struct BsdfWardClosure {
+ //float3 m_N;
+ //float3 m_T;
+ float m_ax;
+ float m_ay;
+} BsdfWardClosure;
+
+__device void bsdf_ward_setup(ShaderData *sd, float3 N, float3 T, float ax, float ay)
+{
+ BsdfWardClosure *self = (BsdfWardClosure*)sd->svm_closure_data;
+
+ //self->m_N = N;
+ //self->m_T = T;
+ self->m_ax = clamp(ax, 1e-5f, 1.0f);
+ self->m_ay = clamp(ay, 1e-5f, 1.0f);
+
+ sd->svm_closure = CLOSURE_BSDF_WARD_ID;
+ sd->flag |= SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY;
+}
+
+__device void bsdf_ward_blur(ShaderData *sd, float roughness)
+{
+ BsdfWardClosure *self = (BsdfWardClosure*)sd->svm_closure_data;
+
+ self->m_ax = fmaxf(roughness, self->m_ax);
+ self->m_ay = fmaxf(roughness, self->m_ay);
+}
+
+__device float3 bsdf_ward_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
+{
+ const BsdfWardClosure *self = (const BsdfWardClosure*)sd->svm_closure_data;
+ float3 m_N = sd->N;
+ float3 m_T = normalize(sd->dPdu);
+
+ float cosNO = dot(m_N, I);
+ float cosNI = dot(m_N, omega_in);
+ if(cosNI > 0 && cosNO > 0) {
+ // get half vector and get x,y basis on the surface for anisotropy
+ float3 H = normalize(omega_in + I); // normalize needed for pdf
+ float3 X, Y;
+ make_orthonormals_tangent(m_N, m_T, &X, &Y);
+ // eq. 4
+ float dotx = dot(H, X) / self->m_ax;
+ float doty = dot(H, Y) / self->m_ay;
+ float dotn = dot(H, m_N);
+ float exp_arg = (dotx * dotx + doty * doty) / (dotn * dotn);
+ float denom = (4 * M_PI_F * self->m_ax * self->m_ay * sqrtf(cosNO * cosNI));
+ float exp_val = expf(-exp_arg);
+ float out = cosNI * exp_val / denom;
+ float oh = dot(H, I);
+ denom = 4 * M_PI_F * self->m_ax * self->m_ay * oh * dotn * dotn * dotn;
+ *pdf = exp_val / denom;
+ return make_float3 (out, out, out);
+ }
+ return make_float3 (0, 0, 0);
+}
+
+__device float3 bsdf_ward_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
+{
+ return make_float3(0.0f, 0.0f, 0.0f);
+}
+
+__device float bsdf_ward_albedo(const ShaderData *sd, const float3 I)
+{
+ return 1.0f;
+}
+
+__device int bsdf_ward_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
+{
+ const BsdfWardClosure *self = (const BsdfWardClosure*)sd->svm_closure_data;
+ float3 m_N = sd->N;
+ float3 m_T = normalize(sd->dPdu);
+
+ float cosNO = dot(m_N, sd->I);
+ if(cosNO > 0) {
+ // get x,y basis on the surface for anisotropy
+ float3 X, Y;
+ make_orthonormals_tangent(m_N, m_T, &X, &Y);
+ // generate random angles for the half vector
+ // eq. 7 (taking care around discontinuities to keep
+ //ttoutput angle in the right quadrant)
+ // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2)
+ //tttt and sin(atan(x)) == x/sqrt(1+x^2)
+ float alphaRatio = self->m_ay / self->m_ax;
+ float cosPhi, sinPhi;
+ if(randu < 0.25f) {
+ float val = 4 * randu;
+ float tanPhi = alphaRatio * tanf(M_PI_2_F * val);
+ cosPhi = 1 / sqrtf(1 + tanPhi * tanPhi);
+ sinPhi = tanPhi * cosPhi;
+ } else if(randu < 0.5f) {
+ float val = 1 - 4 * (0.5f - randu);
+ float tanPhi = alphaRatio * tanf(M_PI_2_F * val);
+ // phi = M_PI_F - phi;
+ cosPhi = -1 / sqrtf(1 + tanPhi * tanPhi);
+ sinPhi = -tanPhi * cosPhi;
+ } else if(randu < 0.75f) {
+ float val = 4 * (randu - 0.5f);
+ float tanPhi = alphaRatio * tanf(M_PI_2_F * val);
+ //phi = M_PI_F + phi;
+ cosPhi = -1 / sqrtf(1 + tanPhi * tanPhi);
+ sinPhi = tanPhi * cosPhi;
+ } else {
+ float val = 1 - 4 * (1 - randu);
+ float tanPhi = alphaRatio * tanf(M_PI_2_F * val);
+ // phi = 2 * M_PI_F - phi;
+ cosPhi = 1 / sqrtf(1 + tanPhi * tanPhi);
+ sinPhi = -tanPhi * cosPhi;
+ }
+ // eq. 6
+ // we take advantage of cos(atan(x)) == 1/sqrt(1+x^2)
+ //tttt and sin(atan(x)) == x/sqrt(1+x^2)
+ float thetaDenom = (cosPhi * cosPhi) / (self->m_ax * self->m_ax) + (sinPhi * sinPhi) / (self->m_ay * self->m_ay);
+ float tanTheta2 = -logf(1 - randv) / thetaDenom;
+ float cosTheta = 1 / sqrtf(1 + tanTheta2);
+ float sinTheta = cosTheta * sqrtf(tanTheta2);
+
+ float3 h; // already normalized becaused expressed from spherical coordinates
+ h.x = sinTheta * cosPhi;
+ h.y = sinTheta * sinPhi;
+ h.z = cosTheta;
+ // compute terms that are easier in local space
+ float dotx = h.x / self->m_ax;
+ float doty = h.y / self->m_ay;
+ float dotn = h.z;
+ // transform to world space
+ h = h.x * X + h.y * Y + h.z * m_N;
+ // generate the final sample
+ float oh = dot(h, sd->I);
+ omega_in->x = 2 * oh * h.x - sd->I.x;
+ omega_in->y = 2 * oh * h.y - sd->I.y;
+ omega_in->z = 2 * oh * h.z - sd->I.z;
+ if(dot(sd->Ng, *omega_in) > 0) {
+ float cosNI = dot(m_N, *omega_in);
+ if(cosNI > 0) {
+ // eq. 9
+ float exp_arg = (dotx * dotx + doty * doty) / (dotn * dotn);
+ float denom = 4 * M_PI_F * self->m_ax * self->m_ay * oh * dotn * dotn * dotn;
+ *pdf = expf(-exp_arg) / denom;
+ // compiler will reuse expressions already computed
+ denom = (4 * M_PI_F * self->m_ax * self->m_ay * sqrtf(cosNO * cosNI));
+ float power = cosNI * expf(-exp_arg) / denom;
+ *eval = make_float3(power, power, power);
+#ifdef __RAY_DIFFERENTIALS__
+ *domega_in_dx = (2 * dot(m_N, sd->dI.dx)) * m_N - sd->dI.dx;
+ *domega_in_dy = (2 * dot(m_N, sd->dI.dy)) * m_N - sd->dI.dy;
+ // Since there is some blur to this reflection, make the
+ // derivatives a bit bigger. In theory this varies with the
+ // roughness but the exact relationship is complex and
+ // requires more ops than are practical.
+ *domega_in_dx *= 10;
+ *domega_in_dy *= 10;
+#endif
+ }
+ }
+ }
+ return LABEL_REFLECT|LABEL_GLOSSY;
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __BSDF_WARD_H__ */
+
diff --git a/intern/cycles/kernel/svm/bsdf_westin.h b/intern/cycles/kernel/svm/bsdf_westin.h
new file mode 100644
index 00000000000..7fe10f10dfc
--- /dev/null
+++ b/intern/cycles/kernel/svm/bsdf_westin.h
@@ -0,0 +1,212 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef __BSDF_WESTIN_H__
+#define __BSDF_WESTIN_H__
+
+CCL_NAMESPACE_BEGIN
+
+/* WESTIN BACKSCATTER */
+
+typedef struct BsdfWestinBackscatterClosure {
+ //float3 m_N;
+ float m_invroughness;
+} BsdfWestinBackscatterClosure;
+
+__device void bsdf_westin_backscatter_setup(ShaderData *sd, float3 N, float roughness)
+{
+ BsdfWestinBackscatterClosure *self = (BsdfWestinBackscatterClosure*)sd->svm_closure_data;
+
+ //self->m_N = N;
+ roughness = clamp(roughness, 1e-5f, 1.0f);
+ self->m_invroughness = 1.0f/roughness;
+
+ sd->svm_closure = CLOSURE_BSDF_WESTIN_BACKSCATTER_ID;
+ sd->flag |= SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY;
+}
+
+__device void bsdf_westin_backscatter_blur(ShaderData *sd, float roughness)
+{
+ BsdfWestinBackscatterClosure *self = (BsdfWestinBackscatterClosure*)sd->svm_closure_data;
+ self->m_invroughness = min(1.0f/roughness, self->m_invroughness);
+}
+
+__device float3 bsdf_westin_backscatter_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
+{
+ const BsdfWestinBackscatterClosure *self = (const BsdfWestinBackscatterClosure*)sd->svm_closure_data;
+ float3 m_N = sd->N;
+
+ // pdf is implicitly 0 (no indirect sampling)
+ float cosNO = dot(m_N, I);
+ float cosNI = dot(m_N, omega_in);
+ if(cosNO > 0 && cosNI > 0) {
+ float cosine = dot(I, omega_in);
+ *pdf = cosine > 0 ? (self->m_invroughness + 1) * powf(cosine, self->m_invroughness) : 0;
+ *pdf *= 0.5f * M_1_PI_F;
+ return make_float3 (*pdf, *pdf, *pdf);
+ }
+ return make_float3 (0, 0, 0);
+}
+
+__device float3 bsdf_westin_backscatter_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
+{
+ return make_float3(0.0f, 0.0f, 0.0f);
+}
+
+__device float bsdf_westin_backscatter_albedo(const ShaderData *sd, const float3 I)
+{
+ return 1.0f;
+}
+
+__device int bsdf_westin_backscatter_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
+{
+ const BsdfWestinBackscatterClosure *self = (const BsdfWestinBackscatterClosure*)sd->svm_closure_data;
+ float3 m_N = sd->N;
+
+ float cosNO = dot(m_N, sd->I);
+ if(cosNO > 0) {
+#ifdef __RAY_DIFFERENTIALS__
+ *domega_in_dx = sd->dI.dx;
+ *domega_in_dy = sd->dI.dy;
+#endif
+ float3 T, B;
+ make_orthonormals (sd->I, &T, &B);
+ float phi = 2 * M_PI_F * randu;
+ float cosTheta = powf(randv, 1 / (self->m_invroughness + 1));
+ float sinTheta2 = 1 - cosTheta * cosTheta;
+ float sinTheta = sinTheta2 > 0 ? sqrtf(sinTheta2) : 0;
+ *omega_in = (cosf(phi) * sinTheta) * T +
+ (sinf(phi) * sinTheta) * B +
+ (cosTheta) * sd->I;
+ if(dot(sd->Ng, *omega_in) > 0)
+ {
+ // common terms for pdf and eval
+ float cosNI = dot(m_N, *omega_in);
+ // make sure the direction we chose is still in the right hemisphere
+ if(cosNI > 0)
+ {
+ *pdf = 0.5f * M_1_PI_F * powf(cosTheta, self->m_invroughness);
+ *pdf = (self->m_invroughness + 1) * (*pdf);
+ *eval = make_float3(*pdf, *pdf, *pdf);
+#ifdef __RAY_DIFFERENTIALS__
+ // Since there is some blur to this reflection, make the
+ // derivatives a bit bigger. In theory this varies with the
+ // exponent but the exact relationship is complex and
+ // requires more ops than are practical.
+ *domega_in_dx *= 10;
+ *domega_in_dy *= 10;
+#endif
+ }
+ }
+ }
+ return LABEL_REFLECT|LABEL_GLOSSY;
+}
+
+/* WESTIN SHEEN */
+
+typedef struct BsdfWestinSheenClosure {
+ //float3 m_N;
+ float m_edginess;
+} BsdfWestinSheenClosure;
+
+__device void bsdf_westin_sheen_setup(ShaderData *sd, float3 N, float edginess)
+{
+ BsdfWestinSheenClosure *self = (BsdfWestinSheenClosure*)sd->svm_closure_data;
+
+ //self->m_N = N;
+ self->m_edginess = edginess;
+
+ sd->svm_closure = CLOSURE_BSDF_WESTIN_SHEEN_ID;
+ sd->flag |= SD_BSDF_HAS_EVAL|SD_BSDF_GLOSSY;
+}
+
+__device void bsdf_westin_sheen_blur(ShaderData *sd, float roughness)
+{
+}
+
+__device float3 bsdf_westin_sheen_eval_reflect(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
+{
+ const BsdfWestinSheenClosure *self = (const BsdfWestinSheenClosure*)sd->svm_closure_data;
+ float3 m_N = sd->N;
+
+ // pdf is implicitly 0 (no indirect sampling)
+ float cosNO = dot(m_N, I);
+ float cosNI = dot(m_N, omega_in);
+ if(cosNO > 0 && cosNI > 0) {
+ float sinNO2 = 1 - cosNO * cosNO;
+ *pdf = cosNI * M_1_PI_F;
+ float westin = sinNO2 > 0 ? powf(sinNO2, 0.5f * self->m_edginess) * (*pdf) : 0;
+ return make_float3 (westin, westin, westin);
+ }
+ return make_float3 (0, 0, 0);
+}
+
+__device float3 bsdf_westin_sheen_eval_transmit(const ShaderData *sd, const float3 I, const float3 omega_in, float *pdf)
+{
+ return make_float3(0.0f, 0.0f, 0.0f);
+}
+
+__device float bsdf_westin_sheen_albedo(const ShaderData *sd, const float3 I)
+{
+ return 1.0f;
+}
+
+__device int bsdf_westin_sheen_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, float3 *domega_in_dx, float3 *domega_in_dy, float *pdf)
+{
+ const BsdfWestinSheenClosure *self = (const BsdfWestinSheenClosure*)sd->svm_closure_data;
+ float3 m_N = sd->N;
+
+ // we are viewing the surface from the right side - send a ray out with cosine
+ // distribution over the hemisphere
+ sample_cos_hemisphere(m_N, randu, randv, omega_in, pdf);
+ if(dot(sd->Ng, *omega_in) > 0) {
+ // TODO: account for sheen when sampling
+ float cosNO = dot(m_N, sd->I);
+ float sinNO2 = 1 - cosNO * cosNO;
+ float westin = sinNO2 > 0 ? powf(sinNO2, 0.5f * self->m_edginess) * (*pdf) : 0;
+ *eval = make_float3(westin, westin, westin);
+#ifdef __RAY_DIFFERENTIALS__
+ // TODO: find a better approximation for the diffuse bounce
+ *domega_in_dx = (2 * dot(m_N, sd->dI.dx)) * m_N - sd->dI.dx;
+ *domega_in_dy = (2 * dot(m_N, sd->dI.dy)) * m_N - sd->dI.dy;
+ *domega_in_dx *= 125;
+ *domega_in_dy *= 125;
+#endif
+ } else
+ pdf = 0;
+ return LABEL_REFLECT|LABEL_DIFFUSE;
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __BSDF_WESTIN_H__ */
+
diff --git a/intern/cycles/kernel/svm/emissive.h b/intern/cycles/kernel/svm/emissive.h
new file mode 100644
index 00000000000..ed2b2e4aee8
--- /dev/null
+++ b/intern/cycles/kernel/svm/emissive.h
@@ -0,0 +1,83 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+CCL_NAMESPACE_BEGIN
+
+/* EMISSION CLOSURE */
+
+__device float3 emissive_eval(const float3 Ng, const float3 I)
+{
+ float cosNO = fabsf(dot(Ng, I));
+ float res = (cosNO > 0.0f)? M_1_PI_F: 0.0f;
+
+ return make_float3(res, res, res);
+}
+
+__device void emissive_sample(const float3 Ng, float randu, float randv, float3 *I, float *pdf)
+{
+ // We don't do anything sophisticated here for the step
+ // We just sample the whole cone uniformly to the cosine
+ float3 T, B;
+ make_orthonormals(Ng, &T, &B);
+ float phi = 2 * M_PI_F * randu;
+
+ float cosTheta = sqrtf(1.0f - 1.0f * randv);
+ float sinTheta = sqrtf(1.0f - cosTheta * cosTheta);
+ *I = (cosf(phi) * sinTheta) * T +
+ (sinf(phi) * sinTheta) * B +
+ cosTheta * Ng;
+
+ *pdf = M_1_PI_F;
+}
+
+/// Return the probability distribution function in the direction I,
+/// given the parameters and the light's surface normal. This MUST match
+/// the PDF computed by sample().
+__device float emissive_pdf(const float3 Ng, const float3 I)
+{
+ float cosNO = fabsf(dot(Ng, I));
+ return (cosNO > 0.0f)? M_1_PI_F: 0.0f;
+}
+
+__device float3 svm_emissive_eval(ShaderData *sd)
+{
+ return sd->svm_closure_weight*emissive_eval(sd->Ng, sd->I);
+}
+
+__device void svm_emissive_sample(ShaderData *sd, float randu, float randv, float3 *eval, float3 *I, float *pdf)
+{
+ *eval = sd->svm_closure_weight;
+ emissive_sample(sd->Ng, randu, randv, I, pdf);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h
new file mode 100644
index 00000000000..5bd076c9cab
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm.h
@@ -0,0 +1,271 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __SVM_H__
+#define __SVM_H__
+
+/* Shader Virtual Machine
+ *
+ * A shader is a list of nodes to be executed. These are simply read one after
+ * the other and executed, using an node counter. Each node and it's associated
+ * data is encoded as one or more uint4's in a 1D texture. If the data is larger
+ * than an uint4, the node can increase the node counter to compensate for this.
+ * Floats are encoded as int and then converted to float again.
+ *
+ * Nodes write their output into a stack. All stack data in the stack is
+ * floats, since it's all factors, colors and vectors. The stack will be stored
+ * in local memory on the GPU, as it would take too many register and indexes in
+ * ways not known at compile time. This seems the only solution even though it
+ * may be slow, with two positive factors. If the same shader is being executed,
+ * memory access will be coalesced, and on fermi cards, memory will actually be
+ * cached.
+ *
+ * The result of shader execution will be a single closure. This means the
+ * closure type, associated label, data and weight. Sampling from multiple
+ * closures is supported through the mix closure node, the logic for that is
+ * mostly taken care of in the SVM compiler.
+ */
+
+#include "svm_types.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Stack */
+
+__device float3 stack_load_float3(float *stack, uint a)
+{
+ kernel_assert(a+2 < SVM_STACK_SIZE);
+
+ return make_float3(stack[a+0], stack[a+1], stack[a+2]);
+}
+
+__device void stack_store_float3(float *stack, uint a, float3 f)
+{
+ kernel_assert(a+2 < SVM_STACK_SIZE);
+
+ stack[a+0] = f.x;
+ stack[a+1] = f.y;
+ stack[a+2] = f.z;
+}
+
+__device float stack_load_float(float *stack, uint a)
+{
+ kernel_assert(a < SVM_STACK_SIZE);
+
+ return stack[a];
+}
+
+__device float stack_load_float_default(float *stack, uint a, uint value)
+{
+ return (a == (uint)SVM_STACK_INVALID)? __int_as_float(value): stack_load_float(stack, a);
+}
+
+__device void stack_store_float(float *stack, uint a, float f)
+{
+ kernel_assert(a < SVM_STACK_SIZE);
+
+ stack[a] = f;
+}
+
+__device bool stack_valid(uint a)
+{
+ return a != (uint)SVM_STACK_INVALID;
+}
+
+/* Reading Nodes */
+
+__device uint4 read_node(KernelGlobals *kg, int *offset)
+{
+ uint4 node = kernel_tex_fetch(__svm_nodes, *offset);
+ (*offset)++;
+ return node;
+}
+
+__device float4 read_node_float(KernelGlobals *kg, int *offset)
+{
+ uint4 node = kernel_tex_fetch(__svm_nodes, *offset);
+ float4 f = make_float4(__int_as_float(node.x), __int_as_float(node.y), __int_as_float(node.z), __int_as_float(node.w));
+ (*offset)++;
+ return f;
+}
+
+__device void decode_node_uchar4(uint i, uint *x, uint *y, uint *z, uint *w)
+{
+ if(x) *x = (i & 0xFF);
+ if(y) *y = ((i >> 8) & 0xFF);
+ if(z) *z = ((i >> 16) & 0xFF);
+ if(w) *w = ((i >> 24) & 0xFF);
+}
+
+CCL_NAMESPACE_END
+
+/* Nodes */
+
+#include "svm_noise.h"
+#include "svm_texture.h"
+
+#include "svm_attribute.h"
+#include "svm_blend.h"
+#include "svm_closure.h"
+#include "svm_clouds.h"
+#include "svm_convert.h"
+#include "svm_displace.h"
+#include "svm_distorted_noise.h"
+#include "svm_fresnel.h"
+#include "svm_geometry.h"
+#include "svm_image.h"
+#include "svm_light_path.h"
+#include "svm_magic.h"
+#include "svm_mapping.h"
+#include "svm_marble.h"
+#include "svm_math.h"
+#include "svm_mix.h"
+#include "svm_musgrave.h"
+#include "svm_noisetex.h"
+#include "svm_sky.h"
+#include "svm_stucci.h"
+#include "svm_tex_coord.h"
+#include "svm_value.h"
+#include "svm_voronoi.h"
+#include "svm_wood.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Main Interpreter Loop */
+
+__device void svm_eval_nodes(KernelGlobals *kg, ShaderData *sd, ShaderType type, float randb, int path_flag)
+{
+ float stack[SVM_STACK_SIZE];
+ float closure_weight = 1.0f;
+ int offset = sd->shader;
+
+ sd->svm_closure = NBUILTIN_CLOSURES;
+ sd->svm_closure_weight = make_float3(0.0f, 0.0f, 0.0f);
+
+ while(1) {
+ uint4 node = read_node(kg, &offset);
+
+ if(node.x == NODE_SHADER_JUMP) {
+ if(type == SHADER_TYPE_SURFACE) offset = node.y;
+ else if(type == SHADER_TYPE_VOLUME) offset = node.z;
+ else if(type == SHADER_TYPE_DISPLACEMENT) offset = node.w;
+ else return;
+ }
+ else if(node.x == NODE_CLOSURE_BSDF)
+ svm_node_closure_bsdf(sd, node.y, node.z, node.w, randb);
+ else if(node.x == NODE_CLOSURE_EMISSION)
+ svm_node_closure_emission(sd);
+ else if(node.x == NODE_CLOSURE_BACKGROUND)
+ svm_node_closure_background(sd);
+ else if(node.x == NODE_CLOSURE_SET_WEIGHT)
+ svm_node_closure_set_weight(sd, node.y, node.z, node.w);
+ else if(node.x == NODE_CLOSURE_WEIGHT)
+ svm_node_closure_weight(sd, stack, node.y);
+ else if(node.x == NODE_EMISSION_WEIGHT)
+ svm_node_emission_weight(kg, sd, stack, node);
+ else if(node.x == NODE_MIX_CLOSURE)
+ svm_node_mix_closure(sd, stack, node.y, node.z, &offset, &randb);
+ else if(node.x == NODE_ADD_CLOSURE)
+ svm_node_add_closure(sd, stack, node.y, node.z, &offset, &randb, &closure_weight);
+ else if(node.x == NODE_JUMP)
+ offset = node.y;
+#ifdef __TEXTURES__
+ else if(node.x == NODE_TEX_NOISE_F)
+ svm_node_tex_noise_f(sd, stack, node.y, node.z);
+ else if(node.x == NODE_TEX_NOISE_V)
+ svm_node_tex_noise_v(sd, stack, node.y, node.z);
+ else if(node.x == NODE_TEX_IMAGE)
+ svm_node_tex_image(kg, sd, stack, node.y, node.z, node.w);
+ else if(node.x == NODE_TEX_ENVIRONMENT)
+ svm_node_tex_environment(kg, sd, stack, node.y, node.z, node.w);
+ else if(node.x == NODE_TEX_SKY)
+ svm_node_tex_sky(kg, sd, stack, node.y, node.z);
+ else if(node.x == NODE_TEX_BLEND)
+ svm_node_tex_blend(sd, stack, node);
+ else if(node.x == NODE_TEX_CLOUDS)
+ svm_node_tex_clouds(sd, stack, node);
+ else if(node.x == NODE_TEX_VORONOI)
+ svm_node_tex_voronoi(kg, sd, stack, node, &offset);
+ else if(node.x == NODE_TEX_MUSGRAVE)
+ svm_node_tex_musgrave(kg, sd, stack, node, &offset);
+ else if(node.x == NODE_TEX_MARBLE)
+ svm_node_tex_marble(kg, sd, stack, node, &offset);
+ else if(node.x == NODE_TEX_MAGIC)
+ svm_node_tex_magic(sd, stack, node);
+ else if(node.x == NODE_TEX_STUCCI)
+ svm_node_tex_stucci(kg, sd, stack, node, &offset);
+ else if(node.x == NODE_TEX_DISTORTED_NOISE)
+ svm_node_tex_distorted_noise(kg, sd, stack, node, &offset);
+ else if(node.x == NODE_TEX_WOOD)
+ svm_node_tex_wood(kg, sd, stack, node, &offset);
+#endif
+ else if(node.x == NODE_GEOMETRY)
+ svm_node_geometry(sd, stack, node.y, node.z);
+ else if(node.x == NODE_GEOMETRY_BUMP_DX)
+ svm_node_geometry_bump_dx(sd, stack, node.y, node.z);
+ else if(node.x == NODE_GEOMETRY_BUMP_DY)
+ svm_node_geometry_bump_dy(sd, stack, node.y, node.z);
+ else if(node.x == NODE_LIGHT_PATH)
+ svm_node_light_path(sd, stack, node.y, node.z, path_flag);
+ else if(node.x == NODE_CONVERT)
+ svm_node_convert(sd, stack, node.y, node.z, node.w);
+ else if(node.x == NODE_VALUE_F)
+ svm_node_value_f(kg, sd, stack, node.y, node.z);
+ else if(node.x == NODE_VALUE_V)
+ svm_node_value_v(kg, sd, stack, node.y, &offset);
+ else if(node.x == NODE_MIX)
+ svm_node_mix(kg, sd, stack, node.y, node.z, node.w, &offset);
+ else if(node.x == NODE_ATTR)
+ svm_node_attr(kg, sd, stack, node);
+ else if(node.x == NODE_ATTR_BUMP_DX)
+ svm_node_attr_bump_dx(kg, sd, stack, node);
+ else if(node.x == NODE_ATTR_BUMP_DY)
+ svm_node_attr_bump_dy(kg, sd, stack, node);
+ else if(node.x == NODE_FRESNEL)
+ svm_node_fresnel(sd, stack, node.y, node.z, node.w);
+ else if(node.x == NODE_SET_DISPLACEMENT)
+ svm_node_set_displacement(sd, stack, node.y);
+ else if(node.x == NODE_SET_BUMP)
+ svm_node_set_bump(sd, stack, node.y, node.z, node.w);
+ else if(node.x == NODE_MATH)
+ svm_node_math(kg, sd, stack, node.y, node.z, node.w, &offset);
+ else if(node.x == NODE_VECTOR_MATH)
+ svm_node_vector_math(kg, sd, stack, node.y, node.z, node.w, &offset);
+ else if(node.x == NODE_MAPPING)
+ svm_node_mapping(kg, sd, stack, node.y, node.z, &offset);
+ else if(node.x == NODE_TEX_COORD)
+ svm_node_tex_coord(kg, sd, stack, node.y, node.z);
+ else if(node.x == NODE_TEX_COORD_BUMP_DX)
+ svm_node_tex_coord_bump_dx(kg, sd, stack, node.y, node.z);
+ else if(node.x == NODE_TEX_COORD_BUMP_DY)
+ svm_node_tex_coord_bump_dy(kg, sd, stack, node.y, node.z);
+ else if(node.x == NODE_EMISSION_SET_WEIGHT_TOTAL)
+ svm_node_emission_set_weight_total(kg, sd, node.y, node.z, node.w);
+ else if(node.x == NODE_END)
+ break;
+ else
+ return;
+ }
+
+ sd->svm_closure_weight *= closure_weight;
+}
+
+CCL_NAMESPACE_END
+
+#endif /* __SVM_H__ */
+
diff --git a/intern/cycles/kernel/svm/svm_attribute.h b/intern/cycles/kernel/svm/svm_attribute.h
new file mode 100644
index 00000000000..3a94f08d42f
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_attribute.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Attribute Node */
+
+__device void svm_node_attr_init(KernelGlobals *kg, ShaderData *sd,
+ uint4 node, NodeAttributeType *type,
+ NodeAttributeType *mesh_type, AttributeElement *elem, uint *offset, uint *out_offset)
+{
+ if(sd->object != ~0) {
+ /* find attribute by unique id */
+ uint id = node.y;
+ uint attr_offset = sd->object*kernel_data.bvh.attributes_map_stride;
+ uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
+
+ while(attr_map.x != id)
+ attr_map = kernel_tex_fetch(__attributes_map, ++attr_offset);
+
+ /* return result */
+ *elem = (AttributeElement)attr_map.y;
+ *offset = attr_map.z;
+ *mesh_type = (NodeAttributeType)attr_map.w;
+ }
+ else {
+ /* background */
+ *elem = ATTR_ELEMENT_NONE;
+ *offset = 0;
+ *mesh_type = (NodeAttributeType)node.w;
+ }
+
+ *out_offset = node.z;
+ *type = (NodeAttributeType)node.w;
+}
+
+__device void svm_node_attr(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node)
+{
+ NodeAttributeType type, mesh_type;
+ AttributeElement elem;
+ uint offset, out_offset;
+
+ svm_node_attr_init(kg, sd, node, &type, &mesh_type, &elem, &offset, &out_offset);
+
+ /* fetch and store attribute */
+ if(type == NODE_ATTR_FLOAT) {
+ if(mesh_type == NODE_ATTR_FLOAT) {
+ float f = triangle_attribute_float(kg, sd, elem, offset, NULL, NULL);
+ stack_store_float(stack, out_offset, f);
+ }
+ else {
+ float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, NULL);
+ stack_store_float(stack, out_offset, average(f));
+ }
+ }
+ else {
+ if(mesh_type == NODE_ATTR_FLOAT3) {
+ float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, NULL);
+ stack_store_float3(stack, out_offset, f);
+ }
+ else {
+ float f = triangle_attribute_float(kg, sd, elem, offset, NULL, NULL);
+ stack_store_float3(stack, out_offset, make_float3(f, f, f));
+ }
+ }
+}
+
+__device void svm_node_attr_bump_dx(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node)
+{
+ NodeAttributeType type, mesh_type;
+ AttributeElement elem;
+ uint offset, out_offset;
+
+ svm_node_attr_init(kg, sd, node, &type, &mesh_type, &elem, &offset, &out_offset);
+
+ /* fetch and store attribute */
+ if(type == NODE_ATTR_FLOAT) {
+ if(mesh_type == NODE_ATTR_FLOAT) {
+ float dx;
+ float f = triangle_attribute_float(kg, sd, elem, offset, &dx, NULL);
+ stack_store_float(stack, out_offset, f+dx);
+ }
+ else {
+ float3 dx;
+ float3 f = triangle_attribute_float3(kg, sd, elem, offset, &dx, NULL);
+ stack_store_float(stack, out_offset, average(f+dx));
+ }
+ }
+ else {
+ if(mesh_type == NODE_ATTR_FLOAT3) {
+ float3 dx;
+ float3 f = triangle_attribute_float3(kg, sd, elem, offset, &dx, NULL);
+ stack_store_float3(stack, out_offset, f+dx);
+ }
+ else {
+ float dx;
+ float f = triangle_attribute_float(kg, sd, elem, offset, &dx, NULL);
+ stack_store_float3(stack, out_offset, make_float3(f+dx, f+dx, f+dx));
+ }
+ }
+}
+
+__device void svm_node_attr_bump_dy(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node)
+{
+ NodeAttributeType type, mesh_type;
+ AttributeElement elem;
+ uint offset, out_offset;
+
+ svm_node_attr_init(kg, sd, node, &type, &mesh_type, &elem, &offset, &out_offset);
+
+ /* fetch and store attribute */
+ if(type == NODE_ATTR_FLOAT) {
+ if(mesh_type == NODE_ATTR_FLOAT) {
+ float dy;
+ float f = triangle_attribute_float(kg, sd, elem, offset, NULL, &dy);
+ stack_store_float(stack, out_offset, f+dy);
+ }
+ else {
+ float3 dy;
+ float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, &dy);
+ stack_store_float(stack, out_offset, average(f+dy));
+ }
+ }
+ else {
+ if(mesh_type == NODE_ATTR_FLOAT3) {
+ float3 dy;
+ float3 f = triangle_attribute_float3(kg, sd, elem, offset, NULL, &dy);
+ stack_store_float3(stack, out_offset, f+dy);
+ }
+ else {
+ float dy;
+ float f = triangle_attribute_float(kg, sd, elem, offset, NULL, &dy);
+ stack_store_float3(stack, out_offset, make_float3(f+dy, f+dy, f+dy));
+ }
+ }
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_blend.h b/intern/cycles/kernel/svm/svm_blend.h
new file mode 100644
index 00000000000..b1be7b7f6bc
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_blend.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Blend */
+
+__device float svm_blend(float3 p, NodeBlendType type, NodeBlendAxis axis)
+{
+ float x, y;
+
+ if(axis == NODE_BLEND_VERTICAL) {
+ x= p.y;
+ y= p.x;
+ }
+ else {
+ x= p.x;
+ y= p.y;
+ }
+
+ if(type == NODE_BLEND_LINEAR) {
+ return (1.0f + x)/2.0f;
+ }
+ else if(type == NODE_BLEND_QUADRATIC) {
+ float r = fmaxf((1.0f + x)/2.0f, 0.0f);
+ return r*r;
+ }
+ else if(type == NODE_BLEND_EASING) {
+ float r = min(fmaxf((1.0f + x)/2.0f, 0.0f), 1.0f);
+ float t = r*r;
+
+ return (3.0f*t - 2.0f*t*r);
+ }
+ else if(type == NODE_BLEND_DIAGONAL) {
+ return (2.0f + x + y)/4.0f;
+ }
+ else if(type == NODE_BLEND_RADIAL) {
+ return atan2(y, x)/(2.0f*M_PI_F) + 0.5f;
+ }
+ else {
+ float r = fmaxf(1.0f - sqrtf(x*x + y*y + p.z*p.z), 0.0f);
+
+ if(type == NODE_BLEND_QUADRATIC_SPHERE)
+ return r*r;
+ else if(type == NODE_BLEND_SPHERICAL)
+ return r;
+ }
+
+ return 0.0f;
+}
+
+__device void svm_node_tex_blend(ShaderData *sd, float *stack, uint4 node)
+{
+ float3 co = stack_load_float3(stack, node.z);
+ uint type, axis;
+
+ decode_node_uchar4(node.y, &type, &axis, NULL, NULL);
+
+ float f = svm_blend(co, (NodeBlendType)type, (NodeBlendAxis)axis);
+ stack_store_float(stack, node.w, f);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_bsdf.h b/intern/cycles/kernel/svm/svm_bsdf.h
new file mode 100644
index 00000000000..f02dc786c6b
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_bsdf.h
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "bsdf_ashikhmin_velvet.h"
+#include "bsdf_diffuse.h"
+#include "bsdf_microfacet.h"
+#include "bsdf_reflection.h"
+#include "bsdf_refraction.h"
+#include "bsdf_transparent.h"
+#ifdef __DPDU__
+#include "bsdf_ward.h"
+#endif
+#include "bsdf_westin.h"
+
+CCL_NAMESPACE_BEGIN
+
+__device int svm_bsdf_sample(const ShaderData *sd, float randu, float randv, float3 *eval, float3 *omega_in, differential3 *domega_in, float *pdf)
+{
+ int label;
+
+ switch(sd->svm_closure) {
+ case CLOSURE_BSDF_DIFFUSE_ID:
+ label = bsdf_diffuse_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
+ break;
+ case CLOSURE_BSDF_TRANSLUCENT_ID:
+ label = bsdf_translucent_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
+ break;
+ case CLOSURE_BSDF_REFLECTION_ID:
+ label = bsdf_reflection_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
+ break;
+ case CLOSURE_BSDF_REFRACTION_ID:
+ label = bsdf_refraction_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
+ break;
+ case CLOSURE_BSDF_TRANSPARENT_ID:
+ label = bsdf_transparent_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
+ break;
+ case CLOSURE_BSDF_MICROFACET_GGX_ID:
+ case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
+ label = bsdf_microfacet_ggx_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
+ break;
+ case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
+ case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
+ label = bsdf_microfacet_beckmann_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
+ break;
+#ifdef __DPDU__
+ case CLOSURE_BSDF_WARD_ID:
+ label = bsdf_ward_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
+ break;
+#endif
+ case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID:
+ label = bsdf_ashikhmin_velvet_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
+ break;
+ case CLOSURE_BSDF_WESTIN_BACKSCATTER_ID:
+ label = bsdf_westin_backscatter_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
+ break;
+ case CLOSURE_BSDF_WESTIN_SHEEN_ID:
+ label = bsdf_westin_sheen_sample(sd, randu, randv, eval, omega_in, &domega_in->dx, &domega_in->dy, pdf);
+ break;
+ default:
+ label = LABEL_NONE;
+ break;
+ }
+
+ *eval *= sd->svm_closure_weight;
+
+ return label;
+}
+
+__device float3 svm_bsdf_eval(const ShaderData *sd, const float3 omega_in, float *pdf)
+{
+ float3 eval;
+
+ if(dot(sd->Ng, omega_in) >= 0.0f) {
+ switch(sd->svm_closure) {
+ case CLOSURE_BSDF_DIFFUSE_ID:
+ eval = bsdf_diffuse_eval_reflect(sd, sd->I, omega_in, pdf);
+ break;
+ case CLOSURE_BSDF_TRANSLUCENT_ID:
+ eval = bsdf_translucent_eval_reflect(sd, sd->I, omega_in, pdf);
+ break;
+ case CLOSURE_BSDF_REFLECTION_ID:
+ eval = bsdf_reflection_eval_reflect(sd, sd->I, omega_in, pdf);
+ break;
+ case CLOSURE_BSDF_REFRACTION_ID:
+ eval = bsdf_refraction_eval_reflect(sd, sd->I, omega_in, pdf);
+ break;
+ case CLOSURE_BSDF_TRANSPARENT_ID:
+ eval = bsdf_transparent_eval_reflect(sd, sd->I, omega_in, pdf);
+ break;
+ case CLOSURE_BSDF_MICROFACET_GGX_ID:
+ case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
+ eval = bsdf_microfacet_ggx_eval_reflect(sd, sd->I, omega_in, pdf);
+ break;
+ case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
+ case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
+ eval = bsdf_microfacet_beckmann_eval_reflect(sd, sd->I, omega_in, pdf);
+ break;
+#ifdef __DPDU__
+ case CLOSURE_BSDF_WARD_ID:
+ eval = bsdf_ward_eval_reflect(sd, sd->I, omega_in, pdf);
+ break;
+#endif
+ case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID:
+ eval = bsdf_ashikhmin_velvet_eval_reflect(sd, sd->I, omega_in, pdf);
+ break;
+ case CLOSURE_BSDF_WESTIN_BACKSCATTER_ID:
+ eval = bsdf_westin_backscatter_eval_reflect(sd, sd->I, omega_in, pdf);
+ break;
+ case CLOSURE_BSDF_WESTIN_SHEEN_ID:
+ eval = bsdf_westin_sheen_eval_reflect(sd, sd->I, omega_in, pdf);
+ break;
+ default:
+ eval = make_float3(0.0f, 0.0f, 0.0f);
+ break;
+ }
+ }
+ else {
+ switch(sd->svm_closure) {
+ case CLOSURE_BSDF_DIFFUSE_ID:
+ eval = bsdf_diffuse_eval_transmit(sd, sd->I, omega_in, pdf);
+ break;
+ case CLOSURE_BSDF_TRANSLUCENT_ID:
+ eval = bsdf_translucent_eval_transmit(sd, sd->I, omega_in, pdf);
+ break;
+ case CLOSURE_BSDF_REFLECTION_ID:
+ eval = bsdf_reflection_eval_transmit(sd, sd->I, omega_in, pdf);
+ break;
+ case CLOSURE_BSDF_REFRACTION_ID:
+ eval = bsdf_refraction_eval_transmit(sd, sd->I, omega_in, pdf);
+ break;
+ case CLOSURE_BSDF_TRANSPARENT_ID:
+ eval = bsdf_transparent_eval_transmit(sd, sd->I, omega_in, pdf);
+ break;
+ case CLOSURE_BSDF_MICROFACET_GGX_ID:
+ case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
+ eval = bsdf_microfacet_ggx_eval_transmit(sd, sd->I, omega_in, pdf);
+ break;
+ case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
+ case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
+ eval = bsdf_microfacet_beckmann_eval_transmit(sd, sd->I, omega_in, pdf);
+ break;
+#ifdef __DPDU__
+ case CLOSURE_BSDF_WARD_ID:
+ eval = bsdf_ward_eval_transmit(sd, sd->I, omega_in, pdf);
+ break;
+#endif
+ case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID:
+ eval = bsdf_ashikhmin_velvet_eval_transmit(sd, sd->I, omega_in, pdf);
+ break;
+ case CLOSURE_BSDF_WESTIN_BACKSCATTER_ID:
+ eval = bsdf_westin_backscatter_eval_transmit(sd, sd->I, omega_in, pdf);
+ break;
+ case CLOSURE_BSDF_WESTIN_SHEEN_ID:
+ eval = bsdf_westin_sheen_eval_transmit(sd, sd->I, omega_in, pdf);
+ break;
+ default:
+ eval = make_float3(0.0f, 0.0f, 0.0f);
+ break;
+ }
+ }
+
+ eval *= sd->svm_closure_weight;
+
+ return eval;
+}
+
+__device void svm_bsdf_blur(ShaderData *sd, float roughness)
+{
+ switch(sd->svm_closure) {
+ case CLOSURE_BSDF_DIFFUSE_ID:
+ bsdf_diffuse_blur(sd, roughness);
+ break;
+ case CLOSURE_BSDF_TRANSLUCENT_ID:
+ bsdf_translucent_blur(sd, roughness);
+ break;
+ case CLOSURE_BSDF_REFLECTION_ID:
+ bsdf_reflection_blur(sd, roughness);
+ break;
+ case CLOSURE_BSDF_REFRACTION_ID:
+ bsdf_refraction_blur(sd, roughness);
+ break;
+ case CLOSURE_BSDF_TRANSPARENT_ID:
+ bsdf_transparent_blur(sd, roughness);
+ break;
+ case CLOSURE_BSDF_MICROFACET_GGX_ID:
+ case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
+ bsdf_microfacet_ggx_blur(sd, roughness);
+ break;
+ case CLOSURE_BSDF_MICROFACET_BECKMANN_ID:
+ case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID:
+ bsdf_microfacet_beckmann_blur(sd, roughness);
+ break;
+#ifdef __DPDU__
+ case CLOSURE_BSDF_WARD_ID:
+ bsdf_ward_blur(sd, roughness);
+ break;
+#endif
+ case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID:
+ bsdf_ashikhmin_velvet_blur(sd, roughness);
+ break;
+ case CLOSURE_BSDF_WESTIN_BACKSCATTER_ID:
+ bsdf_westin_backscatter_blur(sd, roughness);
+ break;
+ case CLOSURE_BSDF_WESTIN_SHEEN_ID:
+ bsdf_westin_sheen_blur(sd, roughness);
+ break;
+ default:
+ break;
+ }
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_closure.h b/intern/cycles/kernel/svm/svm_closure.h
new file mode 100644
index 00000000000..fe9edc36e95
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_closure.h
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Closure Nodes */
+
+__device void svm_node_closure_bsdf(ShaderData *sd, uint type, int iparam1, int iparam2, float randb)
+{
+ float param1 = __int_as_float(iparam1);
+ float param2 = __int_as_float(iparam2);
+
+ switch(type) {
+ case CLOSURE_BSDF_DIFFUSE_ID:
+ bsdf_diffuse_setup(sd, sd->N);
+ break;
+ case CLOSURE_BSDF_TRANSLUCENT_ID:
+ bsdf_translucent_setup(sd, sd->N);
+ break;
+ case CLOSURE_BSDF_TRANSPARENT_ID:
+ bsdf_transparent_setup(sd);
+ break;
+ case CLOSURE_BSDF_REFLECTION_ID:
+ case CLOSURE_BSDF_MICROFACET_GGX_ID:
+ case CLOSURE_BSDF_MICROFACET_BECKMANN_ID: {
+ /* roughness */
+ /* index of refraction */
+ float eta = clamp(1.0f-param2, 1e-5f, 1.0f - 1e-5f);
+ eta = 1.0f/eta;
+
+ /* fresnel */
+ float cosNO = dot(sd->N, sd->I);
+ float fresnel = fresnel_dielectric_cos(cosNO, eta);
+
+ sd->svm_closure_weight *= fresnel;
+
+ /* setup bsdf */
+ if(type == CLOSURE_BSDF_REFLECTION_ID) {
+ bsdf_reflection_setup(sd, sd->N);
+ }
+ else if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_ID) {
+ float roughness = param1;
+ bsdf_microfacet_beckmann_setup(sd, sd->N, roughness, eta, false);
+ }
+ else {
+ float roughness = param1;
+ bsdf_microfacet_ggx_setup(sd, sd->N, roughness, eta, false);
+ }
+ break;
+ }
+ case CLOSURE_BSDF_REFRACTION_ID:
+ case CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID:
+ case CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID: {
+ /* index of refraction */
+ float eta = clamp(1.0f-param2, 1e-5f, 1.0f - 1e-5f);
+ eta = (sd->flag & SD_BACKFACING)? eta: 1.0f/eta;
+
+ /* fresnel */
+ float cosNO = dot(sd->N, sd->I);
+ float fresnel = fresnel_dielectric_cos(cosNO, eta);
+ bool refract = (fresnel < randb);
+
+ /* setup bsdf */
+ if(type == CLOSURE_BSDF_REFRACTION_ID) {
+ if(refract)
+ bsdf_refraction_setup(sd, sd->N, eta);
+ else
+ bsdf_reflection_setup(sd, sd->N);
+ }
+ else if(type == CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID) {
+ float roughness = param1;
+ bsdf_microfacet_beckmann_setup(sd, sd->N, roughness, eta, refract);
+ }
+ else {
+ float roughness = param1;
+ bsdf_microfacet_ggx_setup(sd, sd->N, roughness, eta, refract);
+ }
+ break;
+ }
+#ifdef __DPDU__
+ case CLOSURE_BSDF_WARD_ID: {
+ float roughness_u = param1;
+ float roughness_v = param2;
+ bsdf_ward_setup(sd, sd->N, normalize(sd->dPdu), roughness_u, roughness_v);
+ break;
+ }
+#endif
+ case CLOSURE_BSDF_ASHIKHMIN_VELVET_ID: {
+ /* sigma */
+ float sigma = clamp(param1, 0.0f, 1.0f);
+
+ /* index of refraction */
+ float eta = clamp(1.0f-param2, 1e-5f, 1.0f - 1e-5f);
+ eta = 1.0f/eta;
+
+ /* fresnel */
+ float cosNO = dot(sd->N, sd->I);
+ float fresnel = fresnel_dielectric_cos(cosNO, eta);
+
+ sd->svm_closure_weight *= fresnel;
+
+ bsdf_ashikhmin_velvet_setup(sd, sd->N, sigma);
+ break;
+ }
+ default:
+ return;
+ }
+}
+
+__device void svm_node_closure_emission(ShaderData *sd)
+{
+ sd->svm_closure = CLOSURE_EMISSION_ID;
+ sd->flag |= SD_EMISSION;
+}
+
+__device void svm_node_closure_background(ShaderData *sd)
+{
+ sd->svm_closure = CLOSURE_BACKGROUND_ID;
+}
+
+/* Closure Nodes */
+
+__device void svm_node_closure_set_weight(ShaderData *sd, uint r, uint g, uint b)
+{
+ sd->svm_closure_weight.x = __int_as_float(r);
+ sd->svm_closure_weight.y = __int_as_float(g);
+ sd->svm_closure_weight.z = __int_as_float(b);
+}
+
+__device void svm_node_emission_set_weight_total(KernelGlobals *kg, ShaderData *sd, uint r, uint g, uint b)
+{
+ sd->svm_closure_weight.x = __int_as_float(r);
+ sd->svm_closure_weight.y = __int_as_float(g);
+ sd->svm_closure_weight.z = __int_as_float(b);
+
+ if(sd->object != ~0)
+ sd->svm_closure_weight /= object_surface_area(kg, sd->object);
+}
+
+__device void svm_node_closure_weight(ShaderData *sd, float *stack, uint weight_offset)
+{
+ sd->svm_closure_weight = stack_load_float3(stack, weight_offset);
+}
+
+__device void svm_node_emission_weight(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node)
+{
+ uint color_offset = node.y;
+ uint strength_offset = node.z;
+ uint total_power = node.w;
+
+ sd->svm_closure_weight = stack_load_float3(stack, color_offset)*stack_load_float(stack, strength_offset);
+
+ if(total_power && sd->object != ~0)
+ sd->svm_closure_weight /= object_surface_area(kg, sd->object);
+}
+
+__device void svm_node_mix_closure(ShaderData *sd, float *stack,
+ uint weight_offset, uint node_jump, int *offset, float *randb)
+{
+ float weight = stack_load_float(stack, weight_offset);
+ weight = clamp(weight, 0.0f, 1.0f);
+
+ /* pick a closure and make the random number uniform over 0..1 again.
+ closure 1 starts on the next node, for closure 2 the start is at an
+ offset from the current node, so we jump */
+ if(*randb < weight) {
+ *offset += node_jump;
+ *randb = (*randb - weight)/(1.0f - weight);
+ }
+ else
+ *randb = *randb/weight;
+}
+
+__device void svm_node_add_closure(ShaderData *sd, float *stack, uint unused,
+ uint node_jump, int *offset, float *randb, float *closure_weight)
+{
+ float weight = 0.5f;
+
+ /* pick one of the two closures with probability 0.5. sampling quality
+ is not going to be great, for that we'd need to evaluate the weights
+ of the two closures being added */
+ if(*randb < weight) {
+ *offset += node_jump;
+ *randb = (*randb - weight)/(1.0f - weight);
+ }
+ else
+ *randb = *randb/weight;
+
+ *closure_weight *= 2.0f;
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_clouds.h b/intern/cycles/kernel/svm/svm_clouds.h
new file mode 100644
index 00000000000..e51af684ab9
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_clouds.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Clouds */
+
+__device void svm_clouds(NodeNoiseBasis basis, int hard, int depth, float size, float3 p, float *fac, float3 *color)
+{
+ p /= size;
+
+ *fac = noise_turbulence(p, basis, depth, hard);
+ *color = make_float3(*fac,
+ noise_turbulence(make_float3(p.y, p.x, p.z), basis, depth, hard),
+ noise_turbulence(make_float3(p.y, p.z, p.x), basis, depth, hard));
+}
+
+__device void svm_node_tex_clouds(ShaderData *sd, float *stack, uint4 node)
+{
+ uint basis, hard, depth;
+ uint size_offset, co_offset, fac_offset, color_offset;
+
+ decode_node_uchar4(node.y, &basis, &hard, &depth, NULL);
+ decode_node_uchar4(node.z, &size_offset, &co_offset, &fac_offset, &color_offset);
+
+ float3 co = stack_load_float3(stack, co_offset);
+ float size = stack_load_float_default(stack, size_offset, node.w);
+ size = nonzerof(size, 1e-5f);
+
+ float3 color;
+ float f;
+
+ svm_clouds((NodeNoiseBasis)basis, hard, depth, size, co, &f, &color);
+
+ if(stack_valid(fac_offset)) stack_store_float(stack, fac_offset, f);
+ if(stack_valid(color_offset)) stack_store_float3(stack, color_offset, color);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_convert.h b/intern/cycles/kernel/svm/svm_convert.h
new file mode 100644
index 00000000000..14925569bfb
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_convert.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Conversion Nodes */
+
+__device void svm_node_convert(ShaderData *sd, float *stack, uint type, uint from, uint to)
+{
+ switch(type) {
+ case NODE_CONVERT_FV: {
+ float f = stack_load_float(stack, from);
+ stack_store_float3(stack, to, make_float3(f, f, f));
+ break;
+ }
+ case NODE_CONVERT_CF: {
+ float3 f = stack_load_float3(stack, from);
+ float g = f.x*0.2126f + f.y*0.7152f + f.z*0.0722f;
+ stack_store_float(stack, to, g);
+ break;
+ }
+ case NODE_CONVERT_VF: {
+ float3 f = stack_load_float3(stack, from);
+ float g = (f.x + f.y + f.z)*(1.0f/3.0f);
+ stack_store_float(stack, to, g);
+ break;
+ }
+
+ }
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_displace.h b/intern/cycles/kernel/svm/svm_displace.h
new file mode 100644
index 00000000000..db8a8a13289
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_displace.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Bump Node */
+
+__device void svm_node_set_bump(ShaderData *sd, float *stack, uint c_offset, uint x_offset, uint y_offset)
+{
+#ifdef __RAY_DIFFERENTIALS__
+ float h_c = stack_load_float(stack, c_offset);
+ float h_x = stack_load_float(stack, x_offset);
+ float h_y = stack_load_float(stack, y_offset);
+
+ float3 Rx = cross(sd->dP.dy, sd->N);
+ float3 Ry = cross(sd->N, sd->dP.dx);
+
+ float det = dot(sd->dP.dx, Rx);
+ float3 surfgrad = (h_x - h_c)*Rx + (h_y - h_c)*Ry;
+
+ surfgrad *= 0.1f; /* todo: remove this factor */
+
+ sd->N = normalize(fabsf(det)*sd->N - signf(det)*surfgrad);
+#endif
+}
+
+/* Displacement Node */
+
+__device void svm_node_set_displacement(ShaderData *sd, float *stack, uint fac_offset)
+{
+ float d = stack_load_float(stack, fac_offset);
+ sd->P += sd->N*d*0.1f; /* todo: get rid of this factor */
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_distorted_noise.h b/intern/cycles/kernel/svm/svm_distorted_noise.h
new file mode 100644
index 00000000000..469313e377d
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_distorted_noise.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Distorted Noise (variable lacunarity noise) */
+
+__device float svm_distorted_noise(float3 p, float size, NodeNoiseBasis basis, NodeNoiseBasis distortion_basis, float distortion)
+{
+ float3 r;
+
+ p /= size;
+
+ r.x = noise_basis(p + make_float3(13.5f, 13.5f, 13.5f), basis) * distortion;
+ r.y = noise_basis(p, basis) * distortion;
+ r.z = noise_basis(p - make_float3(13.5f, 13.5f, 13.5f), basis) * distortion;
+
+ return noise_basis(p + r, distortion_basis); /* distorted-domain noise */
+}
+
+__device void svm_node_tex_distorted_noise(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
+{
+ uint4 node2 = read_node(kg, offset);
+
+ uint basis, distortion_basis;
+ uint size_offset, distortion_offset, co_offset, fac_offset;
+
+ decode_node_uchar4(node.y, &basis, &distortion_basis, NULL, NULL);
+ decode_node_uchar4(node.z, &size_offset, &distortion_offset, &co_offset, &fac_offset);
+
+ float3 co = stack_load_float3(stack, co_offset);
+ float size = stack_load_float_default(stack, size_offset, node2.x);
+ float distortion = stack_load_float_default(stack, distortion_offset, node2.y);
+ size = nonzerof(size, 1e-5f);
+
+ float f = svm_distorted_noise(co, size, (NodeNoiseBasis)basis,
+ (NodeNoiseBasis)distortion_basis, distortion);
+
+ stack_store_float(stack, fac_offset, f);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_fresnel.h b/intern/cycles/kernel/svm/svm_fresnel.h
new file mode 100644
index 00000000000..f6122fa3071
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_fresnel.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Fresnel Node */
+
+__device void svm_node_fresnel(ShaderData *sd, float *stack, uint fresnel_offset, uint fresnel_value, uint out_offset)
+{
+ float fresnel = (stack_valid(fresnel_offset))? stack_load_float(stack, fresnel_offset): __int_as_float(fresnel_value);
+ fresnel = fmaxf(1.0f - fresnel, 0.00001f);
+
+ float f = fresnel_dielectric_cos(dot(sd->I, sd->N), (sd->flag & SD_BACKFACING)? fresnel: 1.0f/fresnel);
+
+ stack_store_float(stack, out_offset, f);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_geometry.h b/intern/cycles/kernel/svm/svm_geometry.h
new file mode 100644
index 00000000000..77fe26c809e
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_geometry.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Geometry Node */
+
+__device void svm_node_geometry(ShaderData *sd, float *stack, uint type, uint out_offset)
+{
+ float3 data;
+
+ switch(type) {
+ case NODE_GEOM_P: data = sd->P; break;
+ case NODE_GEOM_N: data = sd->N; break;
+#ifdef __DPDU__
+ case NODE_GEOM_T: data = normalize(sd->dPdu); break;
+#endif
+ case NODE_GEOM_I: data = sd->I; break;
+ case NODE_GEOM_Ng: data = sd->Ng; break;
+#ifdef __UV__
+ case NODE_GEOM_uv: data = make_float3(sd->u, sd->v, 0.0f); break;
+#endif
+ }
+
+ stack_store_float3(stack, out_offset, data);
+}
+
+__device void svm_node_geometry_bump_dx(ShaderData *sd, float *stack, uint type, uint out_offset)
+{
+#ifdef __RAY_DIFFERENTIALS__
+ float3 data;
+
+ switch(type) {
+ case NODE_GEOM_P: data = sd->P + sd->dP.dx; break;
+ case NODE_GEOM_uv: data = make_float3(sd->u + sd->du.dx, sd->v + sd->dv.dx, 0.0f); break;
+ default: svm_node_geometry(sd, stack, type, out_offset); return;
+ }
+
+ stack_store_float3(stack, out_offset, data);
+#else
+ svm_node_geometry(sd, stack, type, out_offset);
+#endif
+}
+
+__device void svm_node_geometry_bump_dy(ShaderData *sd, float *stack, uint type, uint out_offset)
+{
+#ifdef __RAY_DIFFERENTIALS__
+ float3 data;
+
+ switch(type) {
+ case NODE_GEOM_P: data = sd->P + sd->dP.dy; break;
+ case NODE_GEOM_uv: data = make_float3(sd->u + sd->du.dy, sd->v + sd->dv.dy, 0.0f); break;
+ default: svm_node_geometry(sd, stack, type, out_offset); return;
+ }
+
+ stack_store_float3(stack, out_offset, data);
+#else
+ svm_node_geometry(sd, stack, type, out_offset);
+#endif
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_image.h b/intern/cycles/kernel/svm/svm_image.h
new file mode 100644
index 00000000000..c2020b1f69c
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_image.h
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+__device float4 svm_image_texture(KernelGlobals *kg, int id, float x, float y)
+{
+ float4 r;
+
+ /* not particularly proud of this massive switch, what are the
+ alternatives?
+ - use a single big 1D texture, and do our own lookup/filtering
+ - group by size and use a 3d texture, performance impact
+ - group into larger texture with some padding for correct lerp
+
+ also note that cuda has 128 textures limit, we use 100 now, since
+ we still need some for other storage */
+
+ switch(id) {
+ case 0: r = kernel_tex_image_interp(__tex_image_000, x, y); break;
+ case 1: r = kernel_tex_image_interp(__tex_image_001, x, y); break;
+ case 2: r = kernel_tex_image_interp(__tex_image_002, x, y); break;
+ case 3: r = kernel_tex_image_interp(__tex_image_003, x, y); break;
+ case 4: r = kernel_tex_image_interp(__tex_image_004, x, y); break;
+ case 5: r = kernel_tex_image_interp(__tex_image_005, x, y); break;
+ case 6: r = kernel_tex_image_interp(__tex_image_006, x, y); break;
+ case 7: r = kernel_tex_image_interp(__tex_image_007, x, y); break;
+ case 8: r = kernel_tex_image_interp(__tex_image_008, x, y); break;
+ case 9: r = kernel_tex_image_interp(__tex_image_009, x, y); break;
+ case 10: r = kernel_tex_image_interp(__tex_image_010, x, y); break;
+ case 11: r = kernel_tex_image_interp(__tex_image_011, x, y); break;
+ case 12: r = kernel_tex_image_interp(__tex_image_012, x, y); break;
+ case 13: r = kernel_tex_image_interp(__tex_image_013, x, y); break;
+ case 14: r = kernel_tex_image_interp(__tex_image_014, x, y); break;
+ case 15: r = kernel_tex_image_interp(__tex_image_015, x, y); break;
+ case 16: r = kernel_tex_image_interp(__tex_image_016, x, y); break;
+ case 17: r = kernel_tex_image_interp(__tex_image_017, x, y); break;
+ case 18: r = kernel_tex_image_interp(__tex_image_018, x, y); break;
+ case 19: r = kernel_tex_image_interp(__tex_image_019, x, y); break;
+ case 20: r = kernel_tex_image_interp(__tex_image_020, x, y); break;
+ case 21: r = kernel_tex_image_interp(__tex_image_021, x, y); break;
+ case 22: r = kernel_tex_image_interp(__tex_image_022, x, y); break;
+ case 23: r = kernel_tex_image_interp(__tex_image_023, x, y); break;
+ case 24: r = kernel_tex_image_interp(__tex_image_024, x, y); break;
+ case 25: r = kernel_tex_image_interp(__tex_image_025, x, y); break;
+ case 26: r = kernel_tex_image_interp(__tex_image_026, x, y); break;
+ case 27: r = kernel_tex_image_interp(__tex_image_027, x, y); break;
+ case 28: r = kernel_tex_image_interp(__tex_image_028, x, y); break;
+ case 29: r = kernel_tex_image_interp(__tex_image_029, x, y); break;
+ case 30: r = kernel_tex_image_interp(__tex_image_030, x, y); break;
+ case 31: r = kernel_tex_image_interp(__tex_image_031, x, y); break;
+ case 32: r = kernel_tex_image_interp(__tex_image_032, x, y); break;
+ case 33: r = kernel_tex_image_interp(__tex_image_033, x, y); break;
+ case 34: r = kernel_tex_image_interp(__tex_image_034, x, y); break;
+ case 35: r = kernel_tex_image_interp(__tex_image_035, x, y); break;
+ case 36: r = kernel_tex_image_interp(__tex_image_036, x, y); break;
+ case 37: r = kernel_tex_image_interp(__tex_image_037, x, y); break;
+ case 38: r = kernel_tex_image_interp(__tex_image_038, x, y); break;
+ case 39: r = kernel_tex_image_interp(__tex_image_039, x, y); break;
+ case 40: r = kernel_tex_image_interp(__tex_image_040, x, y); break;
+ case 41: r = kernel_tex_image_interp(__tex_image_041, x, y); break;
+ case 42: r = kernel_tex_image_interp(__tex_image_042, x, y); break;
+ case 43: r = kernel_tex_image_interp(__tex_image_043, x, y); break;
+ case 44: r = kernel_tex_image_interp(__tex_image_044, x, y); break;
+ case 45: r = kernel_tex_image_interp(__tex_image_045, x, y); break;
+ case 46: r = kernel_tex_image_interp(__tex_image_046, x, y); break;
+ case 47: r = kernel_tex_image_interp(__tex_image_047, x, y); break;
+ case 48: r = kernel_tex_image_interp(__tex_image_048, x, y); break;
+ case 49: r = kernel_tex_image_interp(__tex_image_049, x, y); break;
+ case 50: r = kernel_tex_image_interp(__tex_image_050, x, y); break;
+ case 51: r = kernel_tex_image_interp(__tex_image_051, x, y); break;
+ case 52: r = kernel_tex_image_interp(__tex_image_052, x, y); break;
+ case 53: r = kernel_tex_image_interp(__tex_image_053, x, y); break;
+ case 54: r = kernel_tex_image_interp(__tex_image_054, x, y); break;
+ case 55: r = kernel_tex_image_interp(__tex_image_055, x, y); break;
+ case 56: r = kernel_tex_image_interp(__tex_image_056, x, y); break;
+ case 57: r = kernel_tex_image_interp(__tex_image_057, x, y); break;
+ case 58: r = kernel_tex_image_interp(__tex_image_058, x, y); break;
+ case 59: r = kernel_tex_image_interp(__tex_image_059, x, y); break;
+ case 60: r = kernel_tex_image_interp(__tex_image_060, x, y); break;
+ case 61: r = kernel_tex_image_interp(__tex_image_061, x, y); break;
+ case 62: r = kernel_tex_image_interp(__tex_image_062, x, y); break;
+ case 63: r = kernel_tex_image_interp(__tex_image_063, x, y); break;
+ case 64: r = kernel_tex_image_interp(__tex_image_064, x, y); break;
+ case 65: r = kernel_tex_image_interp(__tex_image_065, x, y); break;
+ case 66: r = kernel_tex_image_interp(__tex_image_066, x, y); break;
+ case 67: r = kernel_tex_image_interp(__tex_image_067, x, y); break;
+ case 68: r = kernel_tex_image_interp(__tex_image_068, x, y); break;
+ case 69: r = kernel_tex_image_interp(__tex_image_069, x, y); break;
+ case 70: r = kernel_tex_image_interp(__tex_image_070, x, y); break;
+ case 71: r = kernel_tex_image_interp(__tex_image_071, x, y); break;
+ case 72: r = kernel_tex_image_interp(__tex_image_072, x, y); break;
+ case 73: r = kernel_tex_image_interp(__tex_image_073, x, y); break;
+ case 74: r = kernel_tex_image_interp(__tex_image_074, x, y); break;
+ case 75: r = kernel_tex_image_interp(__tex_image_075, x, y); break;
+ case 76: r = kernel_tex_image_interp(__tex_image_076, x, y); break;
+ case 77: r = kernel_tex_image_interp(__tex_image_077, x, y); break;
+ case 78: r = kernel_tex_image_interp(__tex_image_078, x, y); break;
+ case 79: r = kernel_tex_image_interp(__tex_image_079, x, y); break;
+ case 80: r = kernel_tex_image_interp(__tex_image_080, x, y); break;
+ case 81: r = kernel_tex_image_interp(__tex_image_081, x, y); break;
+ case 82: r = kernel_tex_image_interp(__tex_image_082, x, y); break;
+ case 83: r = kernel_tex_image_interp(__tex_image_083, x, y); break;
+ case 84: r = kernel_tex_image_interp(__tex_image_084, x, y); break;
+ case 85: r = kernel_tex_image_interp(__tex_image_085, x, y); break;
+ case 86: r = kernel_tex_image_interp(__tex_image_086, x, y); break;
+ case 87: r = kernel_tex_image_interp(__tex_image_087, x, y); break;
+ case 88: r = kernel_tex_image_interp(__tex_image_088, x, y); break;
+ case 89: r = kernel_tex_image_interp(__tex_image_089, x, y); break;
+ case 90: r = kernel_tex_image_interp(__tex_image_090, x, y); break;
+ case 91: r = kernel_tex_image_interp(__tex_image_091, x, y); break;
+ case 92: r = kernel_tex_image_interp(__tex_image_092, x, y); break;
+ case 93: r = kernel_tex_image_interp(__tex_image_093, x, y); break;
+ case 94: r = kernel_tex_image_interp(__tex_image_094, x, y); break;
+ case 95: r = kernel_tex_image_interp(__tex_image_095, x, y); break;
+ case 96: r = kernel_tex_image_interp(__tex_image_096, x, y); break;
+ case 97: r = kernel_tex_image_interp(__tex_image_097, x, y); break;
+ case 98: r = kernel_tex_image_interp(__tex_image_098, x, y); break;
+ case 99: r = kernel_tex_image_interp(__tex_image_099, x, y); break;
+ default:
+ kernel_assert(0);
+ return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
+ }
+
+ return r;
+}
+
+__device void svm_node_tex_image(KernelGlobals *kg, ShaderData *sd, float *stack, uint id, uint co_offset, uint out_offset)
+{
+ float3 co = stack_load_float3(stack, co_offset);
+ float4 f = svm_image_texture(kg, id, co.x, co.y);
+
+ stack_store_float3(stack, out_offset, make_float3(f.x, f.y, f.z));
+}
+
+__device void svm_node_tex_environment(KernelGlobals *kg, ShaderData *sd, float *stack, uint id, uint co_offset, uint out_offset)
+{
+ float3 co = stack_load_float3(stack, co_offset);
+ float u = (atan2f(co.y, co.x) + M_PI_F)/(2*M_PI_F);
+ float v = atan2f(co.z, hypotf(co.x, co.y))/M_PI_F + 0.5f;
+ float4 f = svm_image_texture(kg, id, u, v);
+
+ stack_store_float3(stack, out_offset, make_float3(f.x, f.y, f.z));
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_light_path.h b/intern/cycles/kernel/svm/svm_light_path.h
new file mode 100644
index 00000000000..a4a461f9590
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_light_path.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Light Path Node */
+
+__device void svm_node_light_path(ShaderData *sd, float *stack, uint type, uint out_offset, int path_flag)
+{
+ float info = 0.0f;
+
+ switch(type) {
+ case NODE_LP_camera: info = (path_flag & PATH_RAY_CAMERA)? 1.0f: 0.0f; break;
+ case NODE_LP_shadow: info = (path_flag & PATH_RAY_SHADOW)? 1.0f: 0.0f; break;
+ case NODE_LP_diffuse: info = (path_flag & PATH_RAY_DIFFUSE)? 1.0f: 0.0f; break;
+ case NODE_LP_glossy: info = (path_flag & PATH_RAY_GLOSSY)? 1.0f: 0.0f; break;
+ case NODE_LP_reflection: info = (path_flag & PATH_RAY_REFLECT)? 1.0f: 0.0f; break;
+ case NODE_LP_transmission: info = (path_flag & PATH_RAY_TRANSMIT)? 1.0f: 0.0f; break;
+ case NODE_LP_backfacing: info = (sd->flag & SD_BACKFACING)? 1.0f: 0.0f; break;
+ }
+
+ stack_store_float(stack, out_offset, info? 1.0f: 0.0f);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_magic.h b/intern/cycles/kernel/svm/svm_magic.h
new file mode 100644
index 00000000000..608ca4bbd2f
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_magic.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Magic */
+
+__device float3 svm_magic(float3 p, int n, float turbulence)
+{
+ float turb = turbulence/5.0f;
+
+ float x = sinf((p.x + p.y + p.z)*5.0f);
+ float y = cosf((-p.x + p.y - p.z)*5.0f);
+ float z = -cosf((-p.x - p.y + p.z)*5.0f);
+
+ if(n > 0) {
+ x *= turb;
+ y *= turb;
+ z *= turb;
+ y = -cosf(x-y+z);
+ y *= turb;
+
+ if(n > 1) {
+ x= cosf(x-y-z);
+ x *= turb;
+
+ if(n > 2) {
+ z= sinf(-x-y-z);
+ z *= turb;
+
+ if(n > 3) {
+ x= -cosf(-x+y-z);
+ x *= turb;
+
+ if(n > 4) {
+ y= -sinf(-x+y+z);
+ y *= turb;
+
+ if(n > 5) {
+ y= -cosf(-x+y+z);
+ y *= turb;
+
+ if(n > 6) {
+ x= cosf(x+y+z);
+ x *= turb;
+
+ if(n > 7) {
+ z= sinf(x+y-z);
+ z *= turb;
+
+ if(n > 8) {
+ x= -cosf(-x-y+z);
+ x *= turb;
+
+ if(n > 9) {
+ y= -sinf(x-y+z);
+ y *= turb;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if(turb != 0.0f) {
+ turb *= 2.0f;
+ x /= turb;
+ y /= turb;
+ z /= turb;
+ }
+
+ return make_float3(0.5f - x, 0.5f - y, 0.5f - z);
+}
+
+__device void svm_node_tex_magic(ShaderData *sd, float *stack, uint4 node)
+{
+ uint depth, turbulence_offset, co_offset, color_offset;
+
+ decode_node_uchar4(node.y, &depth, &turbulence_offset, &co_offset, &color_offset);
+
+ float3 co = stack_load_float3(stack, co_offset);
+ float turbulence = stack_load_float_default(stack, turbulence_offset, node.z);
+
+ float3 color = svm_magic(co, depth, turbulence);
+ stack_store_float3(stack, color_offset, color);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_mapping.h b/intern/cycles/kernel/svm/svm_mapping.h
new file mode 100644
index 00000000000..7633c3e783b
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_mapping.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Mapping Node */
+
+__device void svm_node_mapping(KernelGlobals *kg, ShaderData *sd, float *stack, uint vec_offset, uint out_offset, int *offset)
+{
+ float3 v = stack_load_float3(stack, vec_offset);
+
+ Transform tfm;
+ tfm.x = read_node_float(kg, offset);
+ tfm.y = read_node_float(kg, offset);
+ tfm.z = read_node_float(kg, offset);
+ tfm.w = read_node_float(kg, offset);
+
+ float3 r = transform(&tfm, v);
+ stack_store_float3(stack, out_offset, r);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_marble.h b/intern/cycles/kernel/svm/svm_marble.h
new file mode 100644
index 00000000000..4284688afb8
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_marble.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Marble */
+
+__device float svm_marble(float3 p, float size, NodeMarbleType type, NodeWaveType wave, NodeNoiseBasis basis, int hard, float turb, int depth)
+{
+ float x = p.x;
+ float y = p.y;
+ float z = p.z;
+
+ float n = 5.0f * (x + y + z);
+
+ float mi = n + turb * noise_turbulence(p/size, basis, depth, hard);
+
+ mi = noise_wave(wave, mi);
+
+ if(type == NODE_MARBLE_SHARP)
+ mi = sqrt(mi);
+ else if(type == NODE_MARBLE_SHARPER)
+ mi = sqrt(sqrt(mi));
+
+ return mi;
+}
+
+__device void svm_node_tex_marble(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
+{
+ uint4 node2 = read_node(kg, offset);
+
+ uint type, wave, basis, hard;
+ uint depth;
+ uint size_offset, turbulence_offset, co_offset, fac_offset;
+
+ decode_node_uchar4(node.y, &type, &wave, &basis, &hard);
+ decode_node_uchar4(node.z, &depth, NULL, NULL, NULL);
+ decode_node_uchar4(node.w, &size_offset, &turbulence_offset, &co_offset, &fac_offset);
+
+ float3 co = stack_load_float3(stack, co_offset);
+ float size = stack_load_float_default(stack, size_offset, node2.x);
+ float turbulence = stack_load_float_default(stack, turbulence_offset, node2.y);
+ size = nonzerof(size, 1e-5f);
+
+ float f = svm_marble(co, size, (NodeMarbleType)type, (NodeWaveType)wave,
+ (NodeNoiseBasis)basis, hard, turbulence, depth);
+
+ stack_store_float(stack, fac_offset, f);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_math.h b/intern/cycles/kernel/svm/svm_math.h
new file mode 100644
index 00000000000..6650a10a4d9
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_math.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+__device float safe_asinf(float a)
+{
+ if(a <= -1.0f)
+ return -M_PI_2;
+ else if(a >= 1.0f)
+ return M_PI_2_F;
+
+ return asinf(a);
+}
+
+__device float safe_acosf(float a)
+{
+ if(a <= -1.0f)
+ return M_PI_F;
+ else if(a >= 1.0f)
+ return 0.0f;
+
+ return acosf(a);
+}
+
+__device float safe_powf(float a, float b)
+{
+ if(b == 0.0f)
+ return 1.0f;
+ if(a == 0.0f)
+ return 0.0f;
+ if(a < 0.0f && b != (int)b)
+ return 0.0f;
+
+ return powf(a, b);
+}
+
+__device float safe_logf(float a, float b)
+{
+ if(a < 0.0f || b < 0.0f)
+ return 0.0f;
+
+ return logf(a)/logf(b);
+}
+
+__device float safe_divide(float a, float b)
+{
+ float result;
+
+ if(b == 0.0f)
+ result = 0.0f;
+ else
+ result = a/b;
+
+ return result;
+}
+
+__device float svm_math(NodeMath type, float Fac1, float Fac2)
+{
+ float Fac;
+
+ if(type == NODE_MATH_ADD)
+ Fac = Fac1 + Fac2;
+ else if(type == NODE_MATH_SUBTRACT)
+ Fac = Fac1 - Fac2;
+ else if(type == NODE_MATH_MULTIPLY)
+ Fac = Fac1*Fac2;
+ else if(type == NODE_MATH_DIVIDE)
+ Fac = safe_divide(Fac1, Fac2);
+ else if(type == NODE_MATH_SINE)
+ Fac = sinf(Fac1);
+ else if(type == NODE_MATH_COSINE)
+ Fac = cosf(Fac1);
+ else if(type == NODE_MATH_TANGENT)
+ Fac = tanf(Fac1);
+ else if(type == NODE_MATH_ARCSINE)
+ Fac = safe_asinf(Fac1);
+ else if(type == NODE_MATH_ARCCOSINE)
+ Fac = safe_acosf(Fac1);
+ else if(type == NODE_MATH_ARCTANGENT)
+ Fac = atanf(Fac1);
+ else if(type == NODE_MATH_POWER)
+ Fac = safe_powf(Fac1, Fac2);
+ else if(type == NODE_MATH_LOGARITHM)
+ Fac = safe_logf(Fac1, Fac2);
+ else if(type == NODE_MATH_MINIMUM)
+ Fac = fminf(Fac1, Fac2);
+ else if(type == NODE_MATH_MAXIMUM)
+ Fac = fmaxf(Fac1, Fac2);
+ else if(type == NODE_MATH_ROUND)
+ Fac = floorf(Fac1 + 0.5f);
+ else if(type == NODE_MATH_LESS_THAN)
+ Fac = Fac1 < Fac2;
+ else if(type == NODE_MATH_GREATER_THAN)
+ Fac = Fac1 > Fac2;
+ else
+ Fac = 0.0f;
+
+ return Fac;
+}
+
+__device void svm_vector_math(float *Fac, float3 *Vector, NodeVectorMath type, float3 Vector1, float3 Vector2)
+{
+ if(type == NODE_VECTOR_MATH_ADD) {
+ *Vector = Vector1 + Vector2;
+ *Fac = (fabsf(Vector->x) + fabsf(Vector->y) + fabsf(Vector->z))/3.0f;
+ }
+ else if(type == NODE_VECTOR_MATH_SUBTRACT) {
+ *Vector = Vector1 + Vector2;
+ *Fac = (fabsf(Vector->x) + fabsf(Vector->y) + fabsf(Vector->z))/3.0f;
+ }
+ else if(type == NODE_VECTOR_MATH_AVERAGE) {
+ *Fac = len(Vector1 + Vector2);
+ *Vector = normalize(Vector1 + Vector2);
+ }
+ else if(type == NODE_VECTOR_MATH_DOT_PRODUCT) {
+ *Fac = dot(Vector1, Vector2);
+ *Vector = make_float3(0.0f, 0.0f, 0.0f);
+ }
+ else if(type == NODE_VECTOR_MATH_CROSS_PRODUCT) {
+ float3 c = cross(Vector1, Vector2);
+ *Fac = len(c);
+ *Vector = normalize(c);
+ }
+ else if(type == NODE_VECTOR_MATH_NORMALIZE) {
+ *Fac = len(Vector1);
+ *Vector = normalize(Vector1);
+ }
+ else {
+ *Fac = 0.0f;
+ *Vector = make_float3(0.0f, 0.0f, 0.0f);
+ }
+}
+
+/* Nodes */
+
+__device void svm_node_math(KernelGlobals *kg, ShaderData *sd, float *stack, uint itype, uint f1_offset, uint f2_offset, int *offset)
+{
+ NodeMath type = (NodeMath)itype;
+ float f1 = stack_load_float(stack, f1_offset);
+ float f2 = stack_load_float(stack, f2_offset);
+ float f = svm_math(type, f1, f2);
+
+ uint4 node1 = read_node(kg, offset);
+
+ stack_store_float(stack, node1.y, f);
+}
+
+__device void svm_node_vector_math(KernelGlobals *kg, ShaderData *sd, float *stack, uint itype, uint v1_offset, uint v2_offset, int *offset)
+{
+ NodeVectorMath type = (NodeVectorMath)itype;
+ float3 v1 = stack_load_float3(stack, v1_offset);
+ float3 v2 = stack_load_float3(stack, v2_offset);
+ float f;
+ float3 v;
+
+ svm_vector_math(&f, &v, type, v1, v2);
+
+ uint4 node1 = read_node(kg, offset);
+
+ if(stack_valid(node1.y)) stack_store_float(stack, node1.y, f);
+ if(stack_valid(node1.z)) stack_store_float3(stack, node1.z, v);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_mix.h b/intern/cycles/kernel/svm/svm_mix.h
new file mode 100644
index 00000000000..5a8ca2f76dd
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_mix.h
@@ -0,0 +1,387 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+__device float3 rgb_to_hsv(float3 rgb)
+{
+ float cmax, cmin, h, s, v, cdelta;
+ float3 c;
+
+ cmax = fmaxf(rgb.x, fmaxf(rgb.y, rgb.z));
+ cmin = min(rgb.x, min(rgb.y, rgb.z));
+ cdelta = cmax - cmin;
+
+ v = cmax;
+
+ if(cmax != 0.0f) {
+ s = cdelta/cmax;
+ }
+ else {
+ s = 0.0f;
+ h = 0.0f;
+ }
+
+ if(s == 0.0f) {
+ h = 0.0f;
+ }
+ else {
+ c = (make_float3(cmax, cmax, cmax) - rgb)/cdelta;
+
+ if(rgb.x == cmax) h = c.z - c.y;
+ else if(rgb.y == cmax) h = 2.0f + c.x - c.z;
+ else h = 4.0f + c.y - c.x;
+
+ h /= 6.0f;
+
+ if(h < 0.0f)
+ h += 1.0f;
+ }
+
+ return make_float3(h, s, v);
+}
+
+__device float3 hsv_to_rgb(float3 hsv)
+{
+ float i, f, p, q, t, h, s, v;
+ float3 rgb;
+
+ h = hsv.x;
+ s = hsv.y;
+ v = hsv.z;
+
+ if(s==0.0f) {
+ rgb = make_float3(v, v, v);
+ }
+ else {
+ if(h==1.0f)
+ h = 0.0f;
+
+ h *= 6.0f;
+ i = floor(h);
+ f = h - i;
+ rgb = make_float3(f, f, f);
+ p = v*(1.0f-s);
+ q = v*(1.0f-(s*f));
+ t = v*(1.0f-(s*(1.0f-f)));
+
+ if(i == 0.0f) rgb = make_float3(v, t, p);
+ else if(i == 1.0f) rgb = make_float3(q, v, p);
+ else if(i == 2.0f) rgb = make_float3(p, v, t);
+ else if(i == 3.0f) rgb = make_float3(p, q, v);
+ else if(i == 4.0f) rgb = make_float3(t, p, v);
+ else rgb = make_float3(v, p, q);
+ }
+
+ return rgb;
+}
+
+__device float3 svm_mix_blend(float t, float3 col1, float3 col2)
+{
+ return lerp(col1, col2, t);
+}
+
+__device float3 svm_mix_add(float t, float3 col1, float3 col2)
+{
+ return lerp(col1, col1 + col2, t);
+}
+
+__device float3 svm_mix_mul(float t, float3 col1, float3 col2)
+{
+ return lerp(col1, col1 * col2, t);
+}
+
+__device float3 svm_mix_screen(float t, float3 col1, float3 col2)
+{
+ float tm = 1.0f - t;
+
+ return make_float3(1.0f, 1.0f, 1.0f) - (make_float3(tm, tm, tm) + t*(make_float3(1.0f, 1.0f, 1.0f) - col2))*(make_float3(1.0f, 1.0f, 1.0f) - col1);
+}
+
+__device float3 svm_mix_overlay(float t, float3 col1, float3 col2)
+{
+ float tm = 1.0f - t;
+
+ float3 outcol = col1;
+
+ if(outcol.x < 0.5f)
+ outcol.x *= tm + 2.0f*t*col2.x;
+ else
+ outcol.x = 1.0f - (tm + 2.0f*t*(1.0f - col2.x))*(1.0f - outcol.x);
+
+ if(outcol.y < 0.5f)
+ outcol.y *= tm + 2.0f*t*col2.y;
+ else
+ outcol.y = 1.0f - (tm + 2.0f*t*(1.0f - col2.y))*(1.0f - outcol.y);
+
+ if(outcol.z < 0.5f)
+ outcol.z *= tm + 2.0f*t*col2.z;
+ else
+ outcol.z = 1.0f - (tm + 2.0f*t*(1.0f - col2.z))*(1.0f - outcol.z);
+
+ return outcol;
+}
+
+__device float3 svm_mix_sub(float t, float3 col1, float3 col2)
+{
+ return lerp(col1, col1 - col2, t);
+}
+
+__device float3 svm_mix_div(float t, float3 col1, float3 col2)
+{
+ float tm = 1.0f - t;
+
+ float3 outcol = col1;
+
+ if(col2.x != 0.0f) outcol.x = tm*outcol.x + t*outcol.x/col2.x;
+ if(col2.y != 0.0f) outcol.y = tm*outcol.y + t*outcol.y/col2.y;
+ if(col2.z != 0.0f) outcol.z = tm*outcol.z + t*outcol.z/col2.z;
+
+ return outcol;
+}
+
+__device float3 svm_mix_diff(float t, float3 col1, float3 col2)
+{
+ return lerp(col1, fabs(col1 - col2), t);
+}
+
+__device float3 svm_mix_dark(float t, float3 col1, float3 col2)
+{
+ return min(col1, col2*t);
+}
+
+__device float3 svm_mix_light(float t, float3 col1, float3 col2)
+{
+ return max(col1, col2*t);
+}
+
+__device float3 svm_mix_dodge(float t, float3 col1, float3 col2)
+{
+ float3 outcol = col1;
+
+ if(outcol.x != 0.0f) {
+ float tmp = 1.0f - t*col2.x;
+ if(tmp <= 0.0f)
+ outcol.x = 1.0f;
+ else if((tmp = outcol.x/tmp) > 1.0f)
+ outcol.x = 1.0f;
+ else
+ outcol.x = tmp;
+ }
+ if(outcol.y != 0.0f) {
+ float tmp = 1.0f - t*col2.y;
+ if(tmp <= 0.0f)
+ outcol.y = 1.0f;
+ else if((tmp = outcol.y/tmp) > 1.0f)
+ outcol.y = 1.0f;
+ else
+ outcol.y = tmp;
+ }
+ if(outcol.z != 0.0f) {
+ float tmp = 1.0f - t*col2.z;
+ if(tmp <= 0.0f)
+ outcol.z = 1.0f;
+ else if((tmp = outcol.z/tmp) > 1.0f)
+ outcol.z = 1.0f;
+ else
+ outcol.z = tmp;
+ }
+
+ return outcol;
+}
+
+__device float3 svm_mix_burn(float t, float3 col1, float3 col2)
+{
+ float tmp, tm = 1.0f - t;
+
+ float3 outcol = col1;
+
+ tmp = tm + t*col2.x;
+ if(tmp <= 0.0f)
+ outcol.x = 0.0f;
+ else if((tmp = (1.0f - (1.0f - outcol.x)/tmp)) < 0.0f)
+ outcol.x = 0.0f;
+ else if(tmp > 1.0f)
+ outcol.x = 1.0f;
+ else
+ outcol.x = tmp;
+
+ tmp = tm + t*col2.y;
+ if(tmp <= 0.0f)
+ outcol.y = 0.0f;
+ else if((tmp = (1.0f - (1.0f - outcol.y)/tmp)) < 0.0f)
+ outcol.y = 0.0f;
+ else if(tmp > 1.0f)
+ outcol.y = 1.0f;
+ else
+ outcol.y = tmp;
+
+ tmp = tm + t*col2.z;
+ if(tmp <= 0.0f)
+ outcol.z = 0.0f;
+ else if((tmp = (1.0f - (1.0f - outcol.z)/tmp)) < 0.0f)
+ outcol.z = 0.0f;
+ else if(tmp > 1.0f)
+ outcol.z = 1.0f;
+ else
+ outcol.z = tmp;
+
+ return outcol;
+}
+
+__device float3 svm_mix_hue(float t, float3 col1, float3 col2)
+{
+ float3 outcol = col1;
+
+ float3 hsv2 = rgb_to_hsv(col2);
+
+ if(hsv2.y != 0.0f) {
+ float3 hsv = rgb_to_hsv(outcol);
+ hsv.x = hsv2.x;
+ float3 tmp = hsv_to_rgb(hsv);
+
+ outcol = lerp(outcol, tmp, t);
+ }
+
+ return outcol;
+}
+
+__device float3 svm_mix_sat(float t, float3 col1, float3 col2)
+{
+ float tm = 1.0f - t;
+
+ float3 outcol = col1;
+
+ float3 hsv = rgb_to_hsv(outcol);
+
+ if(hsv.y != 0.0f) {
+ float3 hsv2 = rgb_to_hsv(col2);
+
+ hsv.y = tm*hsv.y + t*hsv2.y;
+ outcol = hsv_to_rgb(hsv);
+ }
+
+ return outcol;
+}
+
+__device float3 svm_mix_val(float t, float3 col1, float3 col2)
+{
+ float tm = 1.0f - t;
+
+ float3 hsv = rgb_to_hsv(col1);
+ float3 hsv2 = rgb_to_hsv(col2);
+
+ hsv.z = tm*hsv.z + t*hsv2.z;
+
+ return hsv_to_rgb(hsv);
+}
+
+__device float3 svm_mix_color(float t, float3 col1, float3 col2)
+{
+ float3 outcol = col1;
+ float3 hsv2 = rgb_to_hsv(col2);
+
+ if(hsv2.y != 0.0f) {
+ float3 hsv = rgb_to_hsv(outcol);
+ hsv.x = hsv2.x;
+ hsv.y = hsv2.y;
+ float3 tmp = hsv_to_rgb(hsv);
+
+ outcol = lerp(outcol, tmp, t);
+ }
+
+ return outcol;
+}
+
+__device float3 svm_mix_soft(float t, float3 col1, float3 col2)
+{
+ float tm = 1.0f - t;
+
+ float3 one= make_float3(1.0f, 1.0f, 1.0f);
+ float3 scr= one - (one - col2)*(one - col1);
+
+ return tm*col1 + t*((one - col1)*col2*col1 + col1*scr);
+}
+
+__device float3 svm_mix_linear(float t, float3 col1, float3 col2)
+{
+ float3 outcol = col1;
+
+ if(col2.x > 0.5f)
+ outcol.x= col1.x + t*(2.0f*(col2.x - 0.5f));
+ else
+ outcol.x= col1.x + t*(2.0f*(col2.x) - 1.0f);
+
+ if(col2.y > 0.5f)
+ outcol.y= col1.y + t*(2.0f*(col2.y - 0.5f));
+ else
+ outcol.y= col1.y + t*(2.0f*(col2.y) - 1.0f);
+
+ if(col2.z > 0.5f)
+ outcol.z= col1.z + t*(2.0f*(col2.z - 0.5f));
+ else
+ outcol.z= col1.z + t*(2.0f*(col2.z) - 1.0f);
+
+ return outcol;
+}
+
+__device float3 svm_mix(NodeMix type, float fac, float3 c1, float3 c2)
+{
+ float t = clamp(fac, 0.0f, 1.0f);
+
+ switch(type) {
+ case NODE_MIX_BLEND: return svm_mix_blend(t, c1, c2);
+ case NODE_MIX_ADD: return svm_mix_add(t, c1, c2);
+ case NODE_MIX_MUL: return svm_mix_mul(t, c1, c2);
+ case NODE_MIX_SCREEN: return svm_mix_screen(t, c1, c2);
+ case NODE_MIX_OVERLAY: return svm_mix_overlay(t, c1, c2);
+ case NODE_MIX_SUB: return svm_mix_sub(t, c1, c2);
+ case NODE_MIX_DIV: return svm_mix_div(t, c1, c2);
+ case NODE_MIX_DIFF: return svm_mix_diff(t, c1, c2);
+ case NODE_MIX_DARK: return svm_mix_dark(t, c1, c2);
+ case NODE_MIX_LIGHT: return svm_mix_light(t, c1, c2);
+ case NODE_MIX_DODGE: return svm_mix_dodge(t, c1, c2);
+ case NODE_MIX_BURN: return svm_mix_burn(t, c1, c2);
+ case NODE_MIX_HUE: return svm_mix_hue(t, c1, c2);
+ case NODE_MIX_SAT: return svm_mix_sat(t, c1, c2);
+ case NODE_MIX_VAL: return svm_mix_val (t, c1, c2);
+ case NODE_MIX_COLOR: return svm_mix_color(t, c1, c2);
+ case NODE_MIX_SOFT: return svm_mix_soft(t, c1, c2);
+ case NODE_MIX_LINEAR: return svm_mix_linear(t, c1, c2);
+ }
+
+ return make_float3(0.0f, 0.0f, 0.0f);
+}
+
+/* Node */
+
+__device void svm_node_mix(KernelGlobals *kg, ShaderData *sd, float *stack, uint fac_offset, uint c1_offset, uint c2_offset, int *offset)
+{
+ /* read extra data */
+ uint4 node1 = read_node(kg, offset);
+
+ float fac = stack_load_float(stack, fac_offset);
+ float3 c1 = stack_load_float3(stack, c1_offset);
+ float3 c2 = stack_load_float3(stack, c2_offset);
+ float3 result = svm_mix((NodeMix)node1.y, fac, c1, c2);
+
+ stack_store_float3(stack, node1.z, result);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_musgrave.h b/intern/cycles/kernel/svm/svm_musgrave.h
new file mode 100644
index 00000000000..5163b9f2ced
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_musgrave.h
@@ -0,0 +1,237 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Musgrave fBm
+ *
+ * H: fractal increment parameter
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ *
+ * from "Texturing and Modelling: A procedural approach"
+ */
+
+__device float noise_musgrave_fBm(float3 p, NodeNoiseBasis basis, float H, float lacunarity, float octaves)
+{
+ float rmd;
+ float value = 0.0f;
+ float pwr = 1.0f;
+ float pwHL = pow(lacunarity, -H);
+ int i;
+
+ for(i = 0; i < (int)octaves; i++) {
+ value += noise_basis(p, basis) * pwr;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if(rmd != 0.0f)
+ value += rmd * noise_basis(p, basis) * pwr;
+
+ return value;
+}
+
+/* Musgrave Multifractal
+ *
+ * H: highest fractal dimension
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ */
+
+__device float noise_musgrave_multi_fractal(float3 p, NodeNoiseBasis basis, float H, float lacunarity, float octaves)
+{
+ float rmd;
+ float value = 1.0f;
+ float pwr = 1.0f;
+ float pwHL = pow(lacunarity, -H);
+ int i;
+
+ for(i = 0; i < (int)octaves; i++) {
+ value *= (pwr * noise_basis(p, basis) + 1.0f);
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if(rmd != 0.0f)
+ value *= (rmd * pwr * noise_basis(p, basis) + 1.0f); /* correct? */
+
+ return value;
+}
+
+/* Musgrave Heterogeneous Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+__device float noise_musgrave_hetero_terrain(float3 p, NodeNoiseBasis basis, float H, float lacunarity, float octaves, float offset)
+{
+ float value, increment, rmd;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+ int i;
+
+ /* first unscaled octave of function; later octaves are scaled */
+ value = offset + noise_basis(p, basis);
+ p *= lacunarity;
+
+ for(i = 1; i < (int)octaves; i++) {
+ increment = (noise_basis(p, basis) + offset) * pwr * value;
+ value += increment;
+ pwr *= pwHL;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if(rmd != 0.0f) {
+ increment = (noise_basis(p, basis) + offset) * pwr * value;
+ value += rmd * increment;
+ }
+
+ return value;
+}
+
+/* Hybrid Additive/Multiplicative Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+__device float noise_musgrave_hybrid_multi_fractal(float3 p, NodeNoiseBasis basis, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float result, signal, weight, rmd;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+ int i;
+
+ result = noise_basis(p, basis) + offset;
+ weight = gain * result;
+ p *= lacunarity;
+
+ for(i = 1; (weight > 0.001f) && (i < (int)octaves); i++) {
+ if(weight > 1.0f)
+ weight = 1.0f;
+
+ signal = (noise_basis(p, basis) + offset) * pwr;
+ pwr *= pwHL;
+ result += weight * signal;
+ weight *= gain * signal;
+ p *= lacunarity;
+ }
+
+ rmd = octaves - floor(octaves);
+ if(rmd != 0.0f)
+ result += rmd * ((noise_basis(p, basis) + offset) * pwr);
+
+ return result;
+}
+
+/* Ridged Multifractal Terrain
+ *
+ * H: fractal dimension of the roughest area
+ * lacunarity: gap between successive frequencies
+ * octaves: number of frequencies in the fBm
+ * offset: raises the terrain from `sea level'
+ */
+
+__device float noise_musgrave_ridged_multi_fractal(float3 p, NodeNoiseBasis basis, float H, float lacunarity, float octaves, float offset, float gain)
+{
+ float result, signal, weight;
+ float pwHL = pow(lacunarity, -H);
+ float pwr = pwHL;
+ int i;
+
+ signal = offset - fabsf(noise_basis(p, basis));
+ signal *= signal;
+ result = signal;
+ weight = 1.0f;
+
+ for(i = 1; i < (int)octaves; i++) {
+ p *= lacunarity;
+ weight = clamp(signal * gain, 0.0f, 1.0f);
+ signal = offset - fabsf(noise_basis(p, basis));
+ signal *= signal;
+ signal *= weight;
+ result += signal * pwr;
+ pwr *= pwHL;
+ }
+
+ return result;
+}
+
+/* Shader */
+
+__device float svm_musgrave(NodeMusgraveType type, NodeNoiseBasis basis, float dimension, float lacunarity, float octaves, float offset, float intensity, float gain, float size, float3 p)
+{
+ p /= size;
+
+ if(type == NODE_MUSGRAVE_MULTIFRACTAL)
+ return intensity*noise_musgrave_multi_fractal(p, basis, dimension, lacunarity, octaves);
+ else if(type == NODE_MUSGRAVE_FBM)
+ return intensity*noise_musgrave_fBm(p, basis, dimension, lacunarity, octaves);
+ else if(type == NODE_MUSGRAVE_HYBRID_MULTIFRACTAL)
+ return intensity*noise_musgrave_hybrid_multi_fractal(p, basis, dimension, lacunarity, octaves, offset, gain);
+ else if(type == NODE_MUSGRAVE_RIDGED_MULTIFRACTAL)
+ return intensity*noise_musgrave_ridged_multi_fractal(p, basis, dimension, lacunarity, octaves, offset, gain);
+ else if(type == NODE_MUSGRAVE_HETERO_TERRAIN)
+ return intensity*noise_musgrave_hetero_terrain(p, basis, dimension, lacunarity, octaves, offset);
+
+ return 0.0f;
+}
+
+__device void svm_node_tex_musgrave(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
+{
+ uint4 node2 = read_node(kg, offset);
+ uint4 node3 = read_node(kg, offset);
+
+ uint type, basis, co_offset, fac_offset;
+ uint dimension_offset, lacunarity_offset, octaves_offset, offset_offset;
+ uint gain_offset, size_offset;
+
+ decode_node_uchar4(node.y, &type, &basis, &co_offset, &fac_offset);
+ decode_node_uchar4(node.z, &dimension_offset, &lacunarity_offset, &octaves_offset, &offset_offset);
+ decode_node_uchar4(node.z, &gain_offset, &size_offset, NULL, NULL);
+
+ float3 co = stack_load_float3(stack, co_offset);
+ float dimension = stack_load_float_default(stack, dimension_offset, node2.x);
+ float lacunarity = stack_load_float_default(stack, lacunarity_offset, node2.y);
+ float octaves = stack_load_float_default(stack, octaves_offset, node2.z);
+ float foffset = stack_load_float_default(stack, offset_offset, node2.w);
+ float gain = stack_load_float_default(stack, gain_offset, node3.x);
+ float size = stack_load_float_default(stack, size_offset, node3.y);
+
+ dimension = fmaxf(dimension, 0.0f);
+ octaves = fmaxf(octaves, 0.0f);
+ lacunarity = fmaxf(lacunarity, 1e-5f);
+ size = nonzerof(size, 1e-5f);
+
+ float f = svm_musgrave((NodeMusgraveType)type, (NodeNoiseBasis)basis,
+ dimension, lacunarity, octaves, foffset, 1.0f, gain, size, co);
+
+ stack_store_float(stack, fac_offset, f);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_noise.h b/intern/cycles/kernel/svm/svm_noise.h
new file mode 100644
index 00000000000..745744e142c
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_noise.h
@@ -0,0 +1,230 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+CCL_NAMESPACE_BEGIN
+
+__device int quick_floor(float x)
+{
+ return (int)x - ((x < 0) ? 1 : 0);
+}
+
+__device float bits_to_01(uint bits)
+{
+ return bits * (1.0f/(float)0xFFFFFFFF);
+}
+
+__device uint hash(uint kx, uint ky, uint kz)
+{
+ // define some handy macros
+#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
+#define final(a,b,c) \
+{ \
+ c ^= b; c -= rot(b,14); \
+ a ^= c; a -= rot(c,11); \
+ b ^= a; b -= rot(a,25); \
+ c ^= b; c -= rot(b,16); \
+ a ^= c; a -= rot(c,4); \
+ b ^= a; b -= rot(a,14); \
+ c ^= b; c -= rot(b,24); \
+}
+ // now hash the data!
+ uint a, b, c, len = 3;
+ a = b = c = 0xdeadbeef + (len << 2) + 13;
+
+ c += kz;
+ b += ky;
+ a += kx;
+ final(a, b, c);
+
+ return c;
+ // macros not needed anymore
+#undef rot
+#undef final
+}
+
+__device int imod(int a, int b)
+{
+ a %= b;
+ return a < 0 ? a + b : a;
+}
+
+__device uint phash(int kx, int ky, int kz, int3 p)
+{
+ return hash(imod(kx, p.x), imod(ky, p.y), imod(kz, p.z));
+}
+
+__device float floorfrac(float x, int* i)
+{
+ *i = quick_floor(x);
+ return x - *i;
+}
+
+__device float fade(float t)
+{
+ return t * t * t * (t * (t * 6.0f - 15.0f) + 10.0f);
+}
+
+__device float nerp(float t, float a, float b)
+{
+ return (1.0f - t) * a + t * b;
+}
+
+__device float grad(int hash, float x, float y, float z)
+{
+ // use vectors pointing to the edges of the cube
+ int h = hash & 15;
+ float u = h<8 ? x : y;
+ float v = h<4 ? y : h==12||h==14 ? x : z;
+ return ((h&1) ? -u : u) + ((h&2) ? -v : v);
+}
+
+__device float scale3(float result)
+{
+ return 0.9820f * result;
+}
+
+__device float perlin(float x, float y, float z)
+{
+ int X; float fx = floorfrac(x, &X);
+ int Y; float fy = floorfrac(y, &Y);
+ int Z; float fz = floorfrac(z, &Z);
+
+ float u = fade(fx);
+ float v = fade(fy);
+ float w = fade(fz);
+
+ float result;
+
+ result = nerp (w, nerp (v, nerp (u, grad (hash (X , Y , Z ), fx , fy , fz ),
+ grad (hash (X+1, Y , Z ), fx-1.0f, fy , fz )),
+ nerp (u, grad (hash (X , Y+1, Z ), fx , fy-1.0f, fz ),
+ grad (hash (X+1, Y+1, Z ), fx-1.0f, fy-1.0f, fz ))),
+ nerp (v, nerp (u, grad (hash (X , Y , Z+1), fx , fy , fz-1.0f ),
+ grad (hash (X+1, Y , Z+1), fx-1.0f, fy , fz-1.0f )),
+ nerp (u, grad (hash (X , Y+1, Z+1), fx , fy-1.0f, fz-1.0f ),
+ grad (hash (X+1, Y+1, Z+1), fx-1.0f, fy-1.0f, fz-1.0f ))));
+ return scale3(result);
+}
+
+__device float perlin_periodic(float x, float y, float z, float3 pperiod)
+{
+ int X; float fx = floorfrac(x, &X);
+ int Y; float fy = floorfrac(y, &Y);
+ int Z; float fz = floorfrac(z, &Z);
+
+ int3 p;
+
+ p.x = fmaxf(quick_floor(pperiod.x), 1);
+ p.y = fmaxf(quick_floor(pperiod.y), 1);
+ p.z = fmaxf(quick_floor(pperiod.z), 1);
+
+ float u = fade(fx);
+ float v = fade(fy);
+ float w = fade(fz);
+
+ float result;
+
+ result = nerp (w, nerp (v, nerp (u, grad (phash (X , Y , Z , p), fx , fy , fz ),
+ grad (phash (X+1, Y , Z , p), fx-1.0f, fy , fz )),
+ nerp (u, grad (phash (X , Y+1, Z , p), fx , fy-1.0f, fz ),
+ grad (phash (X+1, Y+1, Z , p), fx-1.0f, fy-1.0f, fz ))),
+ nerp (v, nerp (u, grad (phash (X , Y , Z+1, p), fx , fy , fz-1.0f ),
+ grad (phash (X+1, Y , Z+1, p), fx-1.0f, fy , fz-1.0f )),
+ nerp (u, grad (phash (X , Y+1, Z+1, p), fx , fy-1.0f, fz-1.0f ),
+ grad (phash (X+1, Y+1, Z+1, p), fx-1.0f, fy-1.0f, fz-1.0f ))));
+ return scale3(result);
+}
+
+/* perlin noise in range 0..1 */
+__device float noise(float3 p)
+{
+ float r = perlin(p.x, p.y, p.z);
+ return 0.5f*r + 0.5f;
+}
+
+/* perlin noise in range -1..1 */
+__device float snoise(float3 p)
+{
+ return perlin(p.x, p.y, p.z);
+}
+
+/* cell noise */
+__device float cellnoise(float3 p)
+{
+ uint ix = quick_floor(p.x);
+ uint iy = quick_floor(p.y);
+ uint iz = quick_floor(p.z);
+
+ return bits_to_01(hash(ix, iy, iz));
+}
+
+__device float3 cellnoise_color(float3 p)
+{
+ float r = cellnoise(p);
+ float g = cellnoise(make_float3(p.y, p.x, p.z));
+ float b = cellnoise(make_float3(p.y, p.z, p.x));
+
+ return make_float3(r, g, b);
+}
+
+/* periodic perlin noise in range 0..1 */
+__device float pnoise(float3 p, float3 pperiod)
+{
+ float r = perlin_periodic(p.x, p.y, p.z, pperiod);
+ return 0.5f*r + 0.5f;
+}
+
+/* periodic perlin noise in range -1..1 */
+__device float psnoise(float3 p, float3 pperiod)
+{
+ return perlin_periodic(p.x, p.y, p.z, pperiod);
+}
+
+/* turbulence */
+__device float turbulence(float3 P, int oct, bool hard)
+{
+ float amp = 1.0f, fscale = 1.0f, sum = 0.0f;
+ int i;
+
+ for(i=0; i<=oct; i++, amp *= 0.5f, fscale *= 2.0f) {
+ float t = noise(fscale*P);
+ if(hard) t = fabsf(2.0f*t - 1.0f);
+ sum += t * amp;
+ }
+
+ sum *= ((float)(1<<oct)/(float)((1<<(oct+1))-1));
+
+ return sum;
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_noisetex.h b/intern/cycles/kernel/svm/svm_noisetex.h
new file mode 100644
index 00000000000..38b249a80fe
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_noisetex.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+__device float svm_noise_texture_value(float3 p)
+{
+ return cellnoise(p*1e8f);
+}
+
+__device float3 svm_noise_texture_color(float3 p)
+{
+ return cellnoise_color(p*1e8f);
+}
+
+__device void svm_node_tex_noise_f(ShaderData *sd, float *stack, uint co_offset, uint out_offset)
+{
+ float3 co = stack_load_float3(stack, co_offset);
+ float f = svm_noise_texture_value(co);
+
+ stack_store_float(stack, out_offset, f);
+}
+
+__device void svm_node_tex_noise_v(ShaderData *sd, float *stack, uint co_offset, uint out_offset)
+{
+ float3 co = stack_load_float3(stack, co_offset);
+ float3 f = svm_noise_texture_color(co);
+
+ stack_store_float3(stack, out_offset, f);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_sky.h b/intern/cycles/kernel/svm/svm_sky.h
new file mode 100644
index 00000000000..dd02cb64cd7
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_sky.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+__device float3 xyY_to_xyz(float x, float y, float Y)
+{
+ float X, Z;
+
+ if(y != 0.0f) X = (x / y) * Y;
+ else X = 0.0f;
+
+ if(y != 0.0f && Y != 0.0f) Z = (1.0f - x - y) / y * Y;
+ else Z = 0.0f;
+
+ return make_float3(X, Y, Z);
+}
+
+__device float3 xyz_to_rgb(float x, float y, float z)
+{
+ return make_float3(3.240479f * x + -1.537150f * y + -0.498535f * z,
+ -0.969256f * x + 1.875991f * y + 0.041556f * z,
+ 0.055648f * x + -0.204043f * y + 1.057311f * z);
+}
+
+/*
+ * "A Practical Analytic Model for Daylight"
+ * A. J. Preetham, Peter Shirley, Brian Smits
+ */
+
+__device float sky_angle_between(float thetav, float phiv, float theta, float phi)
+{
+ float cospsi = sinf(thetav)*sinf(theta)*cosf(phi - phiv) + cosf(thetav)*cosf(theta);
+ return safe_acosf(cospsi);
+}
+
+__device float sky_perez_function(float lam[5], float theta, float gamma)
+{
+ float ctheta = cosf(theta);
+ float cgamma = cosf(gamma);
+
+ return (1.0f + lam[0]*expf(lam[1]/ctheta)) * (1.0f + lam[2]*expf(lam[3]*gamma) + lam[4]*cgamma*cgamma);
+}
+
+__device float3 sky_radiance(KernelGlobals *kg, float3 dir)
+{
+ /* convert vector to spherical coordinates */
+ float2 spherical = direction_to_spherical(dir);
+ float theta = spherical.x;
+ float phi = spherical.y;
+
+ /* angle between sun direction and dir */
+ float gamma = sky_angle_between(theta, phi, kernel_data.sunsky.theta, kernel_data.sunsky.phi);
+
+ /* clamp theta to horizon */
+ theta = min(theta, M_PI_2_F - 0.001f);
+
+ /* compute xyY color space values */
+ float x = kernel_data.sunsky.zenith_x * sky_perez_function(kernel_data.sunsky.perez_x, theta, gamma);
+ float y = kernel_data.sunsky.zenith_y * sky_perez_function(kernel_data.sunsky.perez_y, theta, gamma);
+ float Y = kernel_data.sunsky.zenith_Y * sky_perez_function(kernel_data.sunsky.perez_Y, theta, gamma);
+
+ /* convert to RGB */
+ float3 xyz = xyY_to_xyz(x, y, Y);
+ return xyz_to_rgb(xyz.x, xyz.y, xyz.z);
+}
+
+__device void svm_node_tex_sky(KernelGlobals *kg, ShaderData *sd, float *stack, uint dir_offset, uint out_offset)
+{
+ float3 dir = stack_load_float3(stack, dir_offset);
+ float3 f = sky_radiance(kg, dir);
+
+ stack_store_float3(stack, out_offset, f);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_stucci.h b/intern/cycles/kernel/svm/svm_stucci.h
new file mode 100644
index 00000000000..be8883b6388
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_stucci.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Stucci */
+
+__device float svm_stucci(NodeStucciType type, NodeNoiseBasis basis, int hard, float turbulence, float size, float3 p)
+{
+ p /= size;
+
+ float b2 = noise_basis_hard(p, basis, hard);
+ float ofs = turbulence/200.0f;
+
+ if(type != NODE_STUCCI_PLASTIC)
+ ofs *= b2*b2;
+
+ float r = noise_basis_hard(make_float3(p.x, p.y, p.z+ofs), basis, hard);
+
+ if(type == NODE_STUCCI_WALL_OUT)
+ r = 1.0f - r;
+
+ return fmaxf(r, 0.0f);
+}
+
+__device void svm_node_tex_stucci(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
+{
+ uint4 node2 = read_node(kg, offset);
+
+ uint type, basis, hard;
+ uint size_offset, turbulence_offset, co_offset, fac_offset;
+
+ decode_node_uchar4(node.y, &type, &basis, &hard, NULL);
+ decode_node_uchar4(node.z, &size_offset, &turbulence_offset, &co_offset, &fac_offset);
+
+ float3 co = stack_load_float3(stack, co_offset);
+ float size = stack_load_float_default(stack, size_offset, node2.x);
+ float turbulence = stack_load_float_default(stack, turbulence_offset, node2.y);
+ size = nonzerof(size, 1e-5f);
+
+ float f = svm_stucci((NodeStucciType)type, (NodeNoiseBasis)basis, hard,
+ turbulence, size, co);
+
+ stack_store_float(stack, fac_offset, f);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_tex_coord.h b/intern/cycles/kernel/svm/svm_tex_coord.h
new file mode 100644
index 00000000000..bcf3716ae57
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_tex_coord.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Texture Coordinate Node */
+
+__device float3 svm_background_offset(KernelGlobals *kg)
+{
+ Transform cameratoworld = kernel_data.cam.cameratoworld;
+ return make_float3(cameratoworld.x.w, cameratoworld.y.w, cameratoworld.z.w);
+}
+
+__device void svm_node_tex_coord(KernelGlobals *kg, ShaderData *sd, float *stack, uint type, uint out_offset)
+{
+ float3 data;
+
+ switch(type) {
+ case NODE_TEXCO_OBJECT: {
+ if(sd->object != ~0) {
+ Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM);
+ data = transform(&tfm, sd->P);
+ }
+ else
+ data = sd->P;
+ break;
+ }
+ case NODE_TEXCO_CAMERA: {
+ Transform tfm = kernel_data.cam.worldtocamera;
+
+ if(sd->object != ~0)
+ data = transform(&tfm, sd->P);
+ else
+ data = transform(&tfm, sd->P + svm_background_offset(kg));
+ break;
+ }
+ case NODE_TEXCO_WINDOW: {
+ Transform tfm = kernel_data.cam.worldtondc;
+
+ if(sd->object != ~0)
+ data = transform(&tfm, sd->P);
+ else
+ data = transform(&tfm, sd->P + svm_background_offset(kg));
+ break;
+ }
+ case NODE_TEXCO_REFLECTION: {
+ if(sd->object != ~0)
+ data = sd->I - 2.0f*dot(sd->N, sd->I)*sd->N;
+ else
+ data = sd->I;
+ break;
+ }
+ }
+
+ stack_store_float3(stack, out_offset, data);
+}
+
+__device void svm_node_tex_coord_bump_dx(KernelGlobals *kg, ShaderData *sd, float *stack, uint type, uint out_offset)
+{
+#ifdef __RAY_DIFFERENTIALS__
+ float3 data;
+
+ switch(type) {
+ case NODE_TEXCO_OBJECT: {
+ if(sd->object != ~0) {
+ Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM);
+ data = transform(&tfm, sd->P + sd->dP.dx);
+ }
+ else
+ data = sd->P + sd->dP.dx;
+ break;
+ }
+ case NODE_TEXCO_CAMERA: {
+ Transform tfm = kernel_data.cam.worldtocamera;
+
+ if(sd->object != ~0)
+ data = transform(&tfm, sd->P + sd->dP.dx);
+ else
+ data = transform(&tfm, sd->P + sd->dP.dx + svm_background_offset(kg));
+ break;
+ }
+ case NODE_TEXCO_WINDOW: {
+ Transform tfm = kernel_data.cam.worldtondc;
+
+ if(sd->object != ~0)
+ data = transform(&tfm, sd->P + sd->dP.dx);
+ else
+ data = transform(&tfm, sd->P + sd->dP.dx + svm_background_offset(kg));
+ break;
+ }
+ case NODE_TEXCO_REFLECTION: {
+ if(sd->object != ~0)
+ data = sd->I - 2.0f*dot(sd->N, sd->I)*sd->N;
+ else
+ data = sd->I;
+ break;
+ }
+ }
+
+ stack_store_float3(stack, out_offset, data);
+#else
+ svm_node_tex_coord(kg, sd, stack, type, out_offset);
+#endif
+}
+
+__device void svm_node_tex_coord_bump_dy(KernelGlobals *kg, ShaderData *sd, float *stack, uint type, uint out_offset)
+{
+#ifdef __RAY_DIFFERENTIALS__
+ float3 data;
+
+ switch(type) {
+ case NODE_TEXCO_OBJECT: {
+ if(sd->object != ~0) {
+ Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM);
+ data = transform(&tfm, sd->P + sd->dP.dy);
+ }
+ else
+ data = sd->P + sd->dP.dy;
+ break;
+ }
+ case NODE_TEXCO_CAMERA: {
+ Transform tfm = kernel_data.cam.worldtocamera;
+
+ if(sd->object != ~0)
+ data = transform(&tfm, sd->P + sd->dP.dy);
+ else
+ data = transform(&tfm, sd->P + sd->dP.dy + svm_background_offset(kg));
+ break;
+ }
+ case NODE_TEXCO_WINDOW: {
+ Transform tfm = kernel_data.cam.worldtondc;
+
+ if(sd->object != ~0)
+ data = transform(&tfm, sd->P + sd->dP.dy);
+ else
+ data = transform(&tfm, sd->P + sd->dP.dy + svm_background_offset(kg));
+ break;
+ }
+ case NODE_TEXCO_REFLECTION: {
+ if(sd->object != ~0)
+ data = sd->I - 2.0f*dot(sd->N, sd->I)*sd->N;
+ else
+ data = sd->I;
+ break;
+ }
+ }
+
+ stack_store_float3(stack, out_offset, data);
+#else
+ svm_node_tex_coord(kg, sd, stack, type, out_offset);
+#endif
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_texture.h b/intern/cycles/kernel/svm/svm_texture.h
new file mode 100644
index 00000000000..c5f71c0d5bd
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_texture.h
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Voronoi Distances */
+
+__device float voronoi_distance(NodeDistanceMetric distance_metric, float3 d, float e)
+{
+ if(distance_metric == NODE_VORONOI_DISTANCE_SQUARED)
+ return dot(d, d);
+ if(distance_metric == NODE_VORONOI_ACTUAL_DISTANCE)
+ return len(d);
+ if(distance_metric == NODE_VORONOI_MANHATTAN)
+ return fabsf(d.x) + fabsf(d.y) + fabsf(d.z);
+ if(distance_metric == NODE_VORONOI_CHEBYCHEV)
+ return fmaxf(fabsf(d.x), fmaxf(fabsf(d.y), fabsf(d.z)));
+ if(distance_metric == NODE_VORONOI_MINKOVSKY_H)
+ return sqrtf(fabsf(d.x)) + sqrtf(fabsf(d.y)) + sqrtf(fabsf(d.y));
+ if(distance_metric == NODE_VORONOI_MINKOVSKY_4)
+ return sqrtf(sqrtf(dot(d*d, d*d)));
+ if(distance_metric == NODE_VORONOI_MINKOVSKY)
+ return powf(powf(fabsf(d.x), e) + powf(fabsf(d.y), e) + powf(fabsf(d.z), e), 1.0f/e);
+
+ return 0.0f;
+}
+
+/* Voronoi / Worley like */
+
+__device void voronoi(float3 p, NodeDistanceMetric distance_metric, float e, float da[4], float3 pa[4])
+{
+ /* returns distances in da and point coords in pa */
+ int xx, yy, zz, xi, yi, zi;
+
+ xi = (int)floorf(p.x);
+ yi = (int)floorf(p.y);
+ zi = (int)floorf(p.z);
+
+ da[0] = 1e10f;
+ da[1] = 1e10f;
+ da[2] = 1e10f;
+ da[3] = 1e10f;
+
+ pa[0] = make_float3(0.0f, 0.0f, 0.0f);
+ pa[1] = make_float3(0.0f, 0.0f, 0.0f);
+ pa[2] = make_float3(0.0f, 0.0f, 0.0f);
+ pa[3] = make_float3(0.0f, 0.0f, 0.0f);
+
+ for(xx = xi-1; xx <= xi+1; xx++) {
+ for(yy = yi-1; yy <= yi+1; yy++) {
+ for(zz = zi-1; zz <= zi+1; zz++) {
+ float3 ip = make_float3(xx, yy, zz);
+ float3 vp = cellnoise_color(ip);
+ float3 pd = p - (vp + ip);
+ float d = voronoi_distance(distance_metric, pd, e);
+
+ vp += make_float3(xx, yy, zz);
+
+ if(d < da[0]) {
+ da[3] = da[2];
+ da[2] = da[1];
+ da[1] = da[0];
+ da[0] = d;
+
+ pa[3] = pa[2];
+ pa[2] = pa[1];
+ pa[1] = pa[0];
+ pa[0] = vp;
+ }
+ else if(d < da[1]) {
+ da[3] = da[2];
+ da[2] = da[1];
+ da[1] = d;
+
+ pa[3] = pa[2];
+ pa[2] = pa[1];
+ pa[1] = vp;
+ }
+ else if(d < da[2]) {
+ da[3] = da[2];
+ da[2] = d;
+
+ pa[3] = pa[2];
+ pa[2] = vp;
+ }
+ else if(d < da[3]) {
+ da[3] = d;
+ pa[3] = vp;
+ }
+ }
+ }
+ }
+}
+
+__device float voronoi_Fn(float3 p, int n)
+{
+ float da[4];
+ float3 pa[4];
+
+ voronoi(p, NODE_VORONOI_DISTANCE_SQUARED, 0, da, pa);
+
+ return da[n];
+}
+
+__device float voronoi_FnFn(float3 p, int n1, int n2)
+{
+ float da[4];
+ float3 pa[4];
+
+ voronoi(p, NODE_VORONOI_DISTANCE_SQUARED, 0, da, pa);
+
+ return da[n2] - da[n1];
+}
+
+__device float voronoi_F1(float3 p) { return voronoi_Fn(p, 0); }
+__device float voronoi_F2(float3 p) { return voronoi_Fn(p, 1); }
+__device float voronoi_F3(float3 p) { return voronoi_Fn(p, 2); }
+__device float voronoi_F4(float3 p) { return voronoi_Fn(p, 3); }
+__device float voronoi_F1F2(float3 p) { return voronoi_FnFn(p, 0, 1); }
+
+__device float voronoi_Cr(float3 p)
+{
+ /* crackle type pattern, just a scale/clamp of F2-F1 */
+ float t = 10.0f*voronoi_F1F2(p);
+ return (t > 1.0f)? 1.0f: t;
+}
+
+__device float voronoi_F1S(float3 p) { return 2.0f*voronoi_F1(p) - 1.0f; }
+__device float voronoi_F2S(float3 p) { return 2.0f*voronoi_F2(p) - 1.0f; }
+__device float voronoi_F3S(float3 p) { return 2.0f*voronoi_F3(p) - 1.0f; }
+__device float voronoi_F4S(float3 p) { return 2.0f*voronoi_F4(p) - 1.0f; }
+__device float voronoi_F1F2S(float3 p) { return 2.0f*voronoi_F1F2(p) - 1.0f; }
+__device float voronoi_CrS(float3 p) { return 2.0f*voronoi_Cr(p) - 1.0f; }
+
+/* Noise Bases */
+
+__device float noise_basis(float3 p, NodeNoiseBasis basis)
+{
+ /* Only Perlin enabled for now, others break CUDA compile by making kernel
+ too big, with compile using > 4GB, due to everything being inlined. */
+
+#if 0
+ if(basis == NODE_NOISE_PERLIN)
+#endif
+ return noise(p);
+#if 0
+ if(basis == NODE_NOISE_VORONOI_F1)
+ return voronoi_F1S(p);
+ if(basis == NODE_NOISE_VORONOI_F2)
+ return voronoi_F2S(p);
+ if(basis == NODE_NOISE_VORONOI_F3)
+ return voronoi_F3S(p);
+ if(basis == NODE_NOISE_VORONOI_F4)
+ return voronoi_F4S(p);
+ if(basis == NODE_NOISE_VORONOI_F2_F1)
+ return voronoi_F1F2S(p);
+ if(basis == NODE_NOISE_VORONOI_CRACKLE)
+ return voronoi_CrS(p);
+ if(basis == NODE_NOISE_CELL_NOISE)
+ return cellnoise(p);
+
+ return 0.0f;
+#endif
+}
+
+/* Soft/Hard Noise */
+
+__device float noise_basis_hard(float3 p, NodeNoiseBasis basis, int hard)
+{
+ float t = noise_basis(p, basis);
+ return (hard)? fabsf(2.0f*t - 1.0f): t;
+}
+
+/* Waves */
+
+__device float noise_wave(NodeWaveType wave, float a)
+{
+ if(wave == NODE_WAVE_SINE) {
+ return 0.5f + 0.5f*sin(a);
+ }
+ else if(wave == NODE_WAVE_SAW) {
+ float b = 2*M_PI;
+ int n = (int)(a / b);
+ a -= n*b;
+ if(a < 0) a += b;
+
+ return a / b;
+ }
+ else if(wave == NODE_WAVE_TRI) {
+ float b = 2*M_PI;
+ float rmax = 1.0f;
+
+ return rmax - 2.0f*fabsf(floorf((a*(1.0f/b))+0.5f) - (a*(1.0f/b)));
+ }
+
+ return 0.0f;
+}
+
+/* Turbulence */
+
+__device float noise_turbulence(float3 p, NodeNoiseBasis basis, int octaves, int hard)
+{
+ float fscale = 1.0f;
+ float amp = 1.0f;
+ float sum = 0.0f;
+ int i;
+
+ for(i = 0; i <= octaves; i++) {
+ float t = noise_basis(fscale*p, basis);
+
+ if(hard)
+ t = fabsf(2.0f*t - 1.0f);
+
+ sum += t*amp;
+ amp *= 0.5f;
+ fscale *= 2.0f;
+ }
+
+ sum *= ((float)(1 << octaves)/(float)((1 << (octaves+1)) - 1));
+
+ return sum;
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_types.h b/intern/cycles/kernel/svm/svm_types.h
new file mode 100644
index 00000000000..aa58aba79c9
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_types.h
@@ -0,0 +1,286 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __SVM_TYPES_H__
+#define __SVM_TYPES_H__
+
+CCL_NAMESPACE_BEGIN
+
+/* Stack */
+
+/* SVM stack has a fixed size */
+#define SVM_STACK_SIZE 64
+/* SVM stack offsets with this value indicate that it's not on the stack */
+#define SVM_STACK_INVALID 255
+
+/* Nodes */
+
+/* note that we do not simply use 0, 1, 2, .. as values for these. this works
+ * around an obscure CUDA bug that happens when compiling for fermi. why it
+ * happens i have no idea, but consecutive values are problematic, maybe it
+ * generates an incorrect jump table. */
+
+enum NodeType {
+ NODE_END = 0,
+ NODE_CLOSURE_BSDF = 100,
+ NODE_CLOSURE_EMISSION = 200,
+ NODE_CLOSURE_BACKGROUND = 300,
+ NODE_CLOSURE_SET_WEIGHT = 400,
+ NODE_CLOSURE_WEIGHT = 500,
+ NODE_MIX_CLOSURE = 600,
+ NODE_JUMP = 700,
+ NODE_TEX_NOISE_F = 800,
+ NODE_TEX_NOISE_V = 900,
+ NODE_TEX_IMAGE = 1000,
+ NODE_TEX_SKY = 1100,
+ NODE_GEOMETRY = 1200,
+ NODE_LIGHT_PATH = 1300,
+ NODE_VALUE_F = 1400,
+ NODE_VALUE_V = 1500,
+ NODE_MIX = 1600,
+ NODE_ATTR = 1700,
+ NODE_CONVERT = 1900,
+ NODE_FRESNEL = 2000,
+ NODE_EMISSION_WEIGHT = 2100,
+ NODE_TEX_BLEND = 2200,
+ NODE_TEX_VORONOI = 2300,
+ NODE_TEX_MUSGRAVE = 2400,
+ NODE_TEX_MARBLE = 2500,
+ NODE_TEX_MAGIC = 2600,
+ NODE_TEX_STUCCI = 2700,
+ NODE_TEX_DISTORTED_NOISE = 2800,
+ NODE_TEX_WOOD = 2900,
+ NODE_TEX_CLOUDS = 3000,
+ NODE_SHADER_JUMP = 3100,
+ NODE_SET_DISPLACEMENT = 3200,
+ NODE_GEOMETRY_BUMP_DX = 3300,
+ NODE_GEOMETRY_BUMP_DY = 3400,
+ NODE_SET_BUMP = 3500,
+ NODE_MATH = 3600,
+ NODE_VECTOR_MATH = 3700,
+ NODE_MAPPING = 3800,
+ NODE_TEX_COORD = 3900,
+ NODE_TEX_COORD_BUMP_DX = 4000,
+ NODE_TEX_COORD_BUMP_DY = 4100,
+ NODE_ADD_CLOSURE = 4200,
+ NODE_EMISSION_SET_WEIGHT_TOTAL = 4300,
+ NODE_ATTR_BUMP_DX = 4400,
+ NODE_ATTR_BUMP_DY = 4500,
+ NODE_TEX_ENVIRONMENT = 4600
+};
+
+enum NodeAttributeType {
+ NODE_ATTR_FLOAT = 0,
+ NODE_ATTR_FLOAT3
+};
+
+enum NodeGeometry {
+ NODE_GEOM_P = 0,
+ NODE_GEOM_N,
+ NODE_GEOM_T,
+ NODE_GEOM_I,
+ NODE_GEOM_Ng,
+ NODE_GEOM_uv
+};
+
+enum NodeLightPath {
+ NODE_LP_camera = 0,
+ NODE_LP_shadow,
+ NODE_LP_diffuse,
+ NODE_LP_glossy,
+ NODE_LP_reflection,
+ NODE_LP_transmission,
+ NODE_LP_backfacing
+};
+
+enum NodeTexCoord {
+ NODE_TEXCO_OBJECT,
+ NODE_TEXCO_CAMERA,
+ NODE_TEXCO_WINDOW,
+ NODE_TEXCO_REFLECTION
+};
+
+enum NodeMix {
+ NODE_MIX_BLEND = 0,
+ NODE_MIX_ADD,
+ NODE_MIX_MUL,
+ NODE_MIX_SCREEN,
+ NODE_MIX_OVERLAY,
+ NODE_MIX_SUB,
+ NODE_MIX_DIV,
+ NODE_MIX_DIFF,
+ NODE_MIX_DARK,
+ NODE_MIX_LIGHT,
+ NODE_MIX_DODGE,
+ NODE_MIX_BURN,
+ NODE_MIX_HUE,
+ NODE_MIX_SAT,
+ NODE_MIX_VAL,
+ NODE_MIX_COLOR,
+ NODE_MIX_SOFT,
+ NODE_MIX_LINEAR
+};
+
+enum NodeMath {
+ NODE_MATH_ADD,
+ NODE_MATH_SUBTRACT,
+ NODE_MATH_MULTIPLY,
+ NODE_MATH_DIVIDE,
+ NODE_MATH_SINE,
+ NODE_MATH_COSINE,
+ NODE_MATH_TANGENT,
+ NODE_MATH_ARCSINE,
+ NODE_MATH_ARCCOSINE,
+ NODE_MATH_ARCTANGENT,
+ NODE_MATH_POWER,
+ NODE_MATH_LOGARITHM,
+ NODE_MATH_MINIMUM,
+ NODE_MATH_MAXIMUM,
+ NODE_MATH_ROUND,
+ NODE_MATH_LESS_THAN,
+ NODE_MATH_GREATER_THAN
+};
+
+enum NodeVectorMath {
+ NODE_VECTOR_MATH_ADD,
+ NODE_VECTOR_MATH_SUBTRACT,
+ NODE_VECTOR_MATH_AVERAGE,
+ NODE_VECTOR_MATH_DOT_PRODUCT,
+ NODE_VECTOR_MATH_CROSS_PRODUCT,
+ NODE_VECTOR_MATH_NORMALIZE
+};
+
+enum NodeConvert {
+ NODE_CONVERT_FV,
+ NODE_CONVERT_CF,
+ NODE_CONVERT_VF
+};
+
+enum NodeDistanceMetric {
+ NODE_VORONOI_DISTANCE_SQUARED,
+ NODE_VORONOI_ACTUAL_DISTANCE,
+ NODE_VORONOI_MANHATTAN,
+ NODE_VORONOI_CHEBYCHEV,
+ NODE_VORONOI_MINKOVSKY_H,
+ NODE_VORONOI_MINKOVSKY_4,
+ NODE_VORONOI_MINKOVSKY
+};
+
+enum NodeNoiseBasis {
+ NODE_NOISE_PERLIN,
+ NODE_NOISE_VORONOI_F1,
+ NODE_NOISE_VORONOI_F2,
+ NODE_NOISE_VORONOI_F3,
+ NODE_NOISE_VORONOI_F4,
+ NODE_NOISE_VORONOI_F2_F1,
+ NODE_NOISE_VORONOI_CRACKLE,
+ NODE_NOISE_CELL_NOISE
+};
+
+enum NodeWaveType {
+ NODE_WAVE_SINE,
+ NODE_WAVE_SAW,
+ NODE_WAVE_TRI
+};
+
+enum NodeMusgraveType {
+ NODE_MUSGRAVE_MULTIFRACTAL,
+ NODE_MUSGRAVE_FBM,
+ NODE_MUSGRAVE_HYBRID_MULTIFRACTAL,
+ NODE_MUSGRAVE_RIDGED_MULTIFRACTAL,
+ NODE_MUSGRAVE_HETERO_TERRAIN
+};
+
+enum NodeWoodType {
+ NODE_WOOD_BANDS,
+ NODE_WOOD_RINGS,
+ NODE_WOOD_BAND_NOISE,
+ NODE_WOOD_RING_NOISE
+};
+
+enum NodeBlendType {
+ NODE_BLEND_LINEAR,
+ NODE_BLEND_QUADRATIC,
+ NODE_BLEND_EASING,
+ NODE_BLEND_DIAGONAL,
+ NODE_BLEND_RADIAL,
+ NODE_BLEND_QUADRATIC_SPHERE,
+ NODE_BLEND_SPHERICAL
+};
+
+enum NodeBlendAxis {
+ NODE_BLEND_HORIZONTAL,
+ NODE_BLEND_VERTICAL
+};
+
+enum NodeMarbleType {
+ NODE_MARBLE_SOFT,
+ NODE_MARBLE_SHARP,
+ NODE_MARBLE_SHARPER
+};
+
+enum NodeStucciType {
+ NODE_STUCCI_PLASTIC,
+ NODE_STUCCI_WALL_IN,
+ NODE_STUCCI_WALL_OUT
+};
+
+enum NodeVoronoiColoring {
+ NODE_VORONOI_INTENSITY,
+ NODE_VORONOI_POSITION,
+ NODE_VORONOI_POSITION_OUTLINE,
+ NODE_VORONOI_POSITION_OUTLINE_INTENSITY
+};
+
+enum ShaderType {
+ SHADER_TYPE_SURFACE,
+ SHADER_TYPE_VOLUME,
+ SHADER_TYPE_DISPLACEMENT
+};
+
+/* Closure */
+
+typedef enum ClosureType {
+ CLOSURE_BSDF_DIFFUSE_ID,
+ CLOSURE_BSDF_TRANSLUCENT_ID,
+ CLOSURE_BSDF_REFLECTION_ID,
+ CLOSURE_BSDF_REFRACTION_ID,
+ CLOSURE_BSDF_GLASS_ID,
+ CLOSURE_BSDF_TRANSPARENT_ID,
+ CLOSURE_BSDF_MICROFACET_GGX_ID,
+ CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID,
+ CLOSURE_BSDF_MICROFACET_BECKMANN_ID,
+ CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID,
+ CLOSURE_BSDF_WARD_ID,
+ CLOSURE_BSDF_ASHIKHMIN_VELVET_ID,
+ CLOSURE_BSDF_WESTIN_BACKSCATTER_ID,
+ CLOSURE_BSDF_WESTIN_SHEEN_ID,
+ CLOSURE_BSSRDF_CUBIC_ID,
+ CLOSURE_EMISSION_ID,
+ CLOSURE_DEBUG_ID,
+ CLOSURE_BACKGROUND_ID,
+ CLOSURE_HOLDOUT_ID,
+ CLOSURE_SUBSURFACE_ID,
+
+ NBUILTIN_CLOSURES
+} ClosureType;
+
+CCL_NAMESPACE_END
+
+#endif /* __SVM_TYPES_H__ */
+
diff --git a/intern/cycles/kernel/svm/svm_value.h b/intern/cycles/kernel/svm/svm_value.h
new file mode 100644
index 00000000000..80cb285f80c
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_value.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Value Nodes */
+
+__device void svm_node_value_f(KernelGlobals *kg, ShaderData *sd, float *stack, uint ivalue, uint out_offset)
+{
+ stack_store_float(stack, out_offset, __int_as_float(ivalue));
+}
+
+__device void svm_node_value_v(KernelGlobals *kg, ShaderData *sd, float *stack, uint out_offset, int *offset)
+{
+ /* read extra data */
+ uint4 node1 = read_node(kg, offset);
+ float3 p = make_float3(__int_as_float(node1.y), __int_as_float(node1.z), __int_as_float(node1.w));
+
+ stack_store_float3(stack, out_offset, p);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_voronoi.h b/intern/cycles/kernel/svm/svm_voronoi.h
new file mode 100644
index 00000000000..df37b8faca8
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_voronoi.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Voronoi */
+
+__device float svm_voronoi(NodeDistanceMetric distance_metric, NodeVoronoiColoring coloring,
+ float weight1, float weight2, float weight3, float weight4,
+ float exponent, float intensity, float size, float3 p, float3 *color)
+{
+ float aw1 = fabsf(weight1);
+ float aw2 = fabsf(weight2);
+ float aw3 = fabsf(weight3);
+ float aw4 = fabsf(weight4);
+ float sc = (aw1 + aw2 + aw3 + aw4);
+
+ if(sc != 0.0f)
+ sc = intensity/sc;
+
+ /* compute distance and point coordinate of 4 nearest neighbours */
+ float da[4];
+ float3 pa[4];
+
+ voronoi(p/size, distance_metric, exponent, da, pa);
+
+ /* Scalar output */
+ float fac = sc * fabsf(weight1*da[0] + weight2*da[1] + weight3*da[2] + weight4*da[3]);
+
+ /* colored output */
+ if(coloring == NODE_VORONOI_INTENSITY) {
+ *color = make_float3(fac, fac, fac);
+ }
+ else {
+ *color = aw1*cellnoise_color(pa[0]);
+ *color += aw2*cellnoise_color(pa[1]);
+ *color += aw3*cellnoise_color(pa[2]);
+ *color += aw4*cellnoise_color(pa[3]);
+
+ if(coloring != NODE_VORONOI_POSITION) {
+ float t1 = min((da[1] - da[0])*10.0f, 1.0f);
+
+ if(coloring == NODE_VORONOI_POSITION_OUTLINE_INTENSITY)
+ *color *= t1*fac;
+ else if(coloring == NODE_VORONOI_POSITION_OUTLINE)
+ *color *= t1*sc;
+ }
+ else {
+ *color *= sc;
+ }
+ }
+
+ return fac;
+}
+
+__device void svm_node_tex_voronoi(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
+{
+ uint4 node2 = read_node(kg, offset);
+ uint4 node3 = read_node(kg, offset);
+
+ uint distance_metric, coloring, exponent_offset;
+ uint size_offset, co_offset, fac_offset, color_offset;
+ uint weight1_offset, weight2_offset, weight3_offset, weight4_offset;
+
+ decode_node_uchar4(node.y, &distance_metric, &coloring, &exponent_offset, NULL);
+ decode_node_uchar4(node.z, &size_offset, &co_offset, &fac_offset, &color_offset);
+ decode_node_uchar4(node.w, &weight1_offset, &weight2_offset, &weight3_offset, &weight4_offset);
+
+ float3 co = stack_load_float3(stack, co_offset);
+ float weight1 = stack_load_float_default(stack, weight1_offset, node2.x);
+ float weight2 = stack_load_float_default(stack, weight2_offset, node2.y);
+ float weight3 = stack_load_float_default(stack, weight3_offset, node2.z);
+ float weight4 = stack_load_float_default(stack, weight4_offset, node2.w);
+ float exponent = stack_load_float_default(stack, exponent_offset, node3.x);
+ float size = stack_load_float_default(stack, size_offset, node3.y);
+
+ exponent = fmaxf(exponent, 1e-5f);
+ size = nonzerof(size, 1e-5f);
+
+ float3 color;
+ float f = svm_voronoi((NodeDistanceMetric)distance_metric,
+ (NodeVoronoiColoring)coloring,
+ weight1, weight2, weight3, weight4, exponent, 1.0f, size, co, &color);
+
+ if(stack_valid(fac_offset)) stack_store_float(stack, fac_offset, f);
+ if(stack_valid(color_offset)) stack_store_float3(stack, color_offset, color);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/svm_wood.h b/intern/cycles/kernel/svm/svm_wood.h
new file mode 100644
index 00000000000..5c94a9fa3a2
--- /dev/null
+++ b/intern/cycles/kernel/svm/svm_wood.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2011, Blender Foundation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+CCL_NAMESPACE_BEGIN
+
+/* Wood */
+
+__device float svm_wood(float3 p, float size, NodeWoodType type, NodeWaveType wave, NodeNoiseBasis basis, uint hard, float turb)
+{
+ float x = p.x;
+ float y = p.y;
+ float z = p.z;
+
+ if(type == NODE_WOOD_BANDS) {
+ return noise_wave(wave, (x + y + z)*10.0f);
+ }
+ else if(type == NODE_WOOD_RINGS) {
+ return noise_wave(wave, sqrt(x*x + y*y + z*z)*20.0f);
+ }
+ else if (type == NODE_WOOD_BAND_NOISE) {
+ float wi = turb*noise_basis_hard(p/size, basis, hard);
+ return noise_wave(wave, (x + y + z)*10.0f + wi);
+ }
+ else if (type == NODE_WOOD_RING_NOISE) {
+ float wi = turb*noise_basis_hard(p/size, basis, hard);
+ return noise_wave(wave, sqrt(x*x + y*y + z*z)*20.0f + wi);
+ }
+
+ return 0.0f;
+}
+
+__device void svm_node_tex_wood(KernelGlobals *kg, ShaderData *sd, float *stack, uint4 node, int *offset)
+{
+ uint4 node2 = read_node(kg, offset);
+
+ uint type, wave, basis, hard;
+ uint co_offset, size_offset, turbulence_offset, fac_offset;
+
+ decode_node_uchar4(node.y, &type, &wave, &basis, &hard);
+ decode_node_uchar4(node.z, &co_offset, &size_offset, &turbulence_offset, &fac_offset);
+
+ float3 co = stack_load_float3(stack, co_offset);
+ float size = stack_load_float_default(stack, size_offset, node2.y);
+ float turbulence = stack_load_float_default(stack, turbulence_offset, node2.z);
+ size = nonzerof(size, 1e-5f);
+
+ float f = svm_wood(co, size, (NodeWoodType)type, (NodeWaveType)wave,
+ (NodeNoiseBasis)basis, hard, turbulence);
+
+ stack_store_float(stack, fac_offset, f);
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/kernel/svm/volume.h b/intern/cycles/kernel/svm/volume.h
new file mode 100644
index 00000000000..32e0601ee00
--- /dev/null
+++ b/intern/cycles/kernel/svm/volume.h
@@ -0,0 +1,43 @@
+/*
+ * Adapted from Open Shading Language with this license:
+ *
+ * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
+ * All Rights Reserved.
+ *
+ * Modifications Copyright 2011, Blender Foundation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of Sony Pictures Imageworks nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+CCL_NAMESPACE_BEGIN
+
+/* VOLUME CLOSURE */
+
+__device float3 volume_eval_phase(ShaderData *sd, const float3 omega_in, const float3 omega_out)
+{
+ return make_float3(1.0f, 1.0f, 1.0f);
+}
+
+CCL_NAMESPACE_END
+