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:
authorTon Roosendaal <ton@blender.org>2011-04-27 15:58:34 +0400
committerTon Roosendaal <ton@blender.org>2011-04-27 15:58:34 +0400
commitda376e0237517543aa21740ee2363234ee1c20ae (patch)
tree014a513ed8d0eccc5e54fef42347781e85bae56a /intern/cycles/kernel/svm
parent693780074388111e7b9ef1c3825e462f398dc6c4 (diff)
Cycles render engine, initial commit. This is the engine itself, blender modifications and build instructions will follow later.
Cycles uses code from some great open source projects, many thanks them: * BVH building and traversal code from NVidia's "Understanding the Efficiency of Ray Traversal on GPUs": http://code.google.com/p/understanding-the-efficiency-of-ray-traversal-on-gpus/ * Open Shading Language for a large part of the shading system: http://code.google.com/p/openshadinglanguage/ * Blender for procedural textures and a few other nodes. * Approximate Catmull Clark subdivision from NVidia Mesh tools: http://code.google.com/p/nvidia-mesh-tools/ * Sobol direction vectors from: http://web.maths.unsw.edu.au/~fkuo/sobol/ * Film response functions from: http://www.cs.columbia.edu/CAVE/software/softlib/dorf.php
Diffstat (limited to 'intern/cycles/kernel/svm')
-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
40 files changed, 5590 insertions, 0 deletions
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
+