diff options
Diffstat (limited to 'intern/cycles/render/nodes.cpp')
-rw-r--r-- | intern/cycles/render/nodes.cpp | 1914 |
1 files changed, 1914 insertions, 0 deletions
diff --git a/intern/cycles/render/nodes.cpp b/intern/cycles/render/nodes.cpp new file mode 100644 index 00000000000..d783c3699ea --- /dev/null +++ b/intern/cycles/render/nodes.cpp @@ -0,0 +1,1914 @@ +/* + * 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 "image.h" +#include "nodes.h" +#include "svm.h" +#include "osl.h" + +#include "util_transform.h" + +CCL_NAMESPACE_BEGIN + +/* Image Texture */ + +ImageTextureNode::ImageTextureNode() +: ShaderNode("image_texture") +{ + image_manager = NULL; + slot = -1; + filename = ""; + + add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_COORDINATE); + add_output("Color", SHADER_SOCKET_COLOR); +} + +ImageTextureNode::~ImageTextureNode() +{ + if(image_manager && slot != -1) + image_manager->remove_image(slot); +} + +ShaderNode *ImageTextureNode::clone() const +{ + ImageTextureNode *node = new ImageTextureNode(*this); + node->image_manager = NULL; + node->slot = -1; + return node; +} + +void ImageTextureNode::compile(SVMCompiler& compiler) +{ + ShaderInput *vector_in = input("Vector"); + ShaderOutput *color_out = output("Color"); + + image_manager = compiler.image_manager; + if(slot == -1) + slot = image_manager->add_image(filename); + + compiler.stack_assign(color_out); + + if(slot != -1) { + compiler.stack_assign(vector_in); + compiler.add_node(NODE_TEX_IMAGE, slot, vector_in->stack_offset, color_out->stack_offset); + } + else { + /* image not found */ + compiler.add_node(NODE_VALUE_V, color_out->stack_offset); + compiler.add_node(NODE_VALUE_V, make_float3(0, 0, 0)); + } +} + +void ImageTextureNode::compile(OSLCompiler& compiler) +{ + compiler.parameter("filename", filename.c_str()); + compiler.add(this, "node_image_texture"); +} + +/* Environment Texture */ + +EnvironmentTextureNode::EnvironmentTextureNode() +: ShaderNode("environment_texture") +{ + image_manager = NULL; + slot = -1; + filename = ""; + + add_input("Vector", SHADER_SOCKET_VECTOR, ShaderInput::POSITION); + add_output("Color", SHADER_SOCKET_COLOR); +} + +EnvironmentTextureNode::~EnvironmentTextureNode() +{ + if(image_manager && slot != -1) + image_manager->remove_image(slot); +} + +ShaderNode *EnvironmentTextureNode::clone() const +{ + EnvironmentTextureNode *node = new EnvironmentTextureNode(*this); + node->image_manager = NULL; + node->slot = -1; + return node; +} + +void EnvironmentTextureNode::compile(SVMCompiler& compiler) +{ + ShaderInput *vector_in = input("Vector"); + ShaderOutput *color_out = output("Color"); + + image_manager = compiler.image_manager; + if(slot == -1) + slot = image_manager->add_image(filename); + + compiler.stack_assign(color_out); + + if(slot != -1) { + compiler.stack_assign(vector_in); + compiler.add_node(NODE_TEX_ENVIRONMENT, slot, vector_in->stack_offset, color_out->stack_offset); + } + else { + /* image not found */ + compiler.add_node(NODE_VALUE_V, color_out->stack_offset); + compiler.add_node(NODE_VALUE_V, make_float3(0, 0, 0)); + } +} + +void EnvironmentTextureNode::compile(OSLCompiler& compiler) +{ + compiler.parameter("filename", filename.c_str()); + compiler.add(this, "node_environment_texture"); +} + +/* Sky Texture */ + +static float2 sky_spherical_coordinates(float3 dir) +{ + return make_float2(acosf(dir.z), atan2f(dir.x, dir.y)); +} + +static float sky_perez_function(float lam[6], float theta, float gamma) +{ + return (1.f + lam[0]*expf(lam[1]/cosf(theta))) * (1.f + lam[2]*expf(lam[3]*gamma) + lam[4]*cosf(gamma)*cosf(gamma)); +} + +static void sky_texture_precompute(KernelSunSky *ksunsky, float3 dir, float turbidity) +{ + float2 spherical = sky_spherical_coordinates(dir); + float theta = spherical.x; + float phi = spherical.y; + + ksunsky->theta = theta; + ksunsky->phi = phi; + ksunsky->dir = dir; + + float theta2 = theta*theta; + float theta3 = theta*theta*theta; + float T = turbidity; + float T2 = T * T; + + float chi = (4.0f / 9.0f - T / 120.0f) * (M_PI_F - 2.0f * theta); + ksunsky->zenith_Y = (4.0453f * T - 4.9710f) * tan(chi) - 0.2155f * T + 2.4192f; + ksunsky->zenith_Y *= 0.06f; + + ksunsky->zenith_x = + (0.00166f * theta3 - 0.00375f * theta2 + 0.00209f * theta) * T2 + + (-0.02903f * theta3 + 0.06377f * theta2 - 0.03202f * theta + 0.00394f) * T + + (0.11693f * theta3 - 0.21196f * theta2 + 0.06052f * theta + 0.25886f); + + ksunsky->zenith_y = + (0.00275f * theta3 - 0.00610f * theta2 + 0.00317f * theta) * T2 + + (-0.04214f * theta3 + 0.08970f * theta2 - 0.04153f * theta + 0.00516f) * T + + (0.15346f * theta3 - 0.26756f * theta2 + 0.06670f * theta + 0.26688f); + + ksunsky->perez_Y[0] = (0.1787f * T - 1.4630f); + ksunsky->perez_Y[1] = (-0.3554f * T + 0.4275f); + ksunsky->perez_Y[2] = (-0.0227f * T + 5.3251f); + ksunsky->perez_Y[3] = (0.1206f * T - 2.5771f); + ksunsky->perez_Y[4] = (-0.0670f * T + 0.3703f); + + ksunsky->perez_x[0] = (-0.0193f * T - 0.2592f); + ksunsky->perez_x[1] = (-0.0665f * T + 0.0008f); + ksunsky->perez_x[2] = (-0.0004f * T + 0.2125f); + ksunsky->perez_x[3] = (-0.0641f * T - 0.8989f); + ksunsky->perez_x[4] = (-0.0033f * T + 0.0452f); + + ksunsky->perez_y[0] = (-0.0167f * T - 0.2608f); + ksunsky->perez_y[1] = (-0.0950f * T + 0.0092f); + ksunsky->perez_y[2] = (-0.0079f * T + 0.2102f); + ksunsky->perez_y[3] = (-0.0441f * T - 1.6537f); + ksunsky->perez_y[4] = (-0.0109f * T + 0.0529f); + + ksunsky->zenith_Y /= sky_perez_function(ksunsky->perez_Y, 0, theta); + ksunsky->zenith_x /= sky_perez_function(ksunsky->perez_x, 0, theta); + ksunsky->zenith_y /= sky_perez_function(ksunsky->perez_y, 0, theta); +} + +SkyTextureNode::SkyTextureNode() +: ShaderNode("sky_texture") +{ + sun_direction = make_float3(0.0f, 0.0f, 1.0f); + turbidity = 2.2f; + + add_input("Vector", SHADER_SOCKET_VECTOR, ShaderInput::POSITION); + add_output("Color", SHADER_SOCKET_COLOR); +} + +void SkyTextureNode::compile(SVMCompiler& compiler) +{ + ShaderInput *vector_in = input("Vector"); + ShaderOutput *color_out = output("Color"); + + if(compiler.sunsky) { + sky_texture_precompute(compiler.sunsky, sun_direction, turbidity); + compiler.sunsky = NULL; + } + + if(vector_in->link) + compiler.stack_assign(vector_in); + compiler.stack_assign(color_out); + compiler.add_node(NODE_TEX_SKY, vector_in->stack_offset, color_out->stack_offset); +} + +void SkyTextureNode::compile(OSLCompiler& compiler) +{ + compiler.parameter_vector("sun_direction", sun_direction); + compiler.parameter("turbidity", turbidity); + compiler.add(this, "node_sky_texture"); +} + +/* Noise Texture */ + +NoiseTextureNode::NoiseTextureNode() +: ShaderNode("noise_texture") +{ + add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_COORDINATE); + add_output("Color", SHADER_SOCKET_COLOR); + add_output("Fac", SHADER_SOCKET_FLOAT); +} + +void NoiseTextureNode::compile(SVMCompiler& compiler) +{ + ShaderInput *vector_in = input("Vector"); + ShaderOutput *color_out = output("Color"); + ShaderOutput *fac_out = output("Fac"); + + if(!color_out->links.empty()) { + compiler.stack_assign(vector_in); + compiler.stack_assign(color_out); + compiler.add_node(NODE_TEX_NOISE_V, vector_in->stack_offset, color_out->stack_offset); + } + + if(!fac_out->links.empty()) { + compiler.stack_assign(vector_in); + compiler.stack_assign(fac_out); + compiler.add_node(NODE_TEX_NOISE_F, vector_in->stack_offset, fac_out->stack_offset); + } +} + +void NoiseTextureNode::compile(OSLCompiler& compiler) +{ + compiler.add(this, "node_noise_texture"); +} + +/* Blend Texture */ + +static ShaderEnum blend_progression_init() +{ + ShaderEnum enm; + + enm.insert("Linear", NODE_BLEND_LINEAR); + enm.insert("Quadratic", NODE_BLEND_QUADRATIC); + enm.insert("Easing", NODE_BLEND_EASING); + enm.insert("Diagonal", NODE_BLEND_DIAGONAL); + enm.insert("Radial", NODE_BLEND_RADIAL); + enm.insert("Quadratic Sphere", NODE_BLEND_QUADRATIC_SPHERE); + enm.insert("Spherical", NODE_BLEND_SPHERICAL); + + return enm; +} + +static ShaderEnum blend_axis_init() +{ + ShaderEnum enm; + + enm.insert("Horizontal", NODE_BLEND_HORIZONTAL); + enm.insert("Vertical", NODE_BLEND_VERTICAL); + + return enm; +} + +ShaderEnum BlendTextureNode::progression_enum = blend_progression_init(); +ShaderEnum BlendTextureNode::axis_enum = blend_axis_init(); + +BlendTextureNode::BlendTextureNode() +: ShaderNode("blend_texture") +{ + progression = ustring("Linear"); + axis = ustring("Horizontal"); + + add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_COORDINATE); + add_output("Fac", SHADER_SOCKET_FLOAT); +} + +void BlendTextureNode::compile(SVMCompiler& compiler) +{ + ShaderInput *vector_in = input("Vector"); + ShaderOutput *fac_out = output("Fac"); + + if(vector_in->link) compiler.stack_assign(vector_in); + + compiler.stack_assign(fac_out); + compiler.add_node(NODE_TEX_BLEND, + compiler.encode_uchar4(progression_enum[progression], axis_enum[axis]), + vector_in->stack_offset, fac_out->stack_offset); +} + +void BlendTextureNode::compile(OSLCompiler& compiler) +{ + compiler.parameter("Progression", progression); + compiler.parameter("Axis", axis); + compiler.add(this, "node_blend_texture"); +} + +/* Clouds Texture */ + +static ShaderEnum noise_basis_init() +{ + ShaderEnum enm; + + enm.insert("Perlin", NODE_NOISE_PERLIN); + enm.insert("Voronoi F1", NODE_NOISE_VORONOI_F1); + enm.insert("Voronoi F2", NODE_NOISE_VORONOI_F2); + enm.insert("Voronoi F3", NODE_NOISE_VORONOI_F3); + enm.insert("Voronoi F4", NODE_NOISE_VORONOI_F4); + enm.insert("Voronoi F2-F1", NODE_NOISE_VORONOI_F2_F1); + enm.insert("Voronoi Crackle", NODE_NOISE_VORONOI_CRACKLE); + enm.insert("Cell Noise", NODE_NOISE_CELL_NOISE); + + return enm; +} + +ShaderEnum CloudsTextureNode::basis_enum = noise_basis_init(); + +CloudsTextureNode::CloudsTextureNode() +: ShaderNode("clouds_texture") +{ + basis = ustring("Perlin"); + hard = false; + depth = 2; + + add_input("Size", SHADER_SOCKET_FLOAT, 0.25f); + add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_COORDINATE); + + add_output("Color", SHADER_SOCKET_COLOR); + add_output("Fac", SHADER_SOCKET_FLOAT); +} + +void CloudsTextureNode::compile(SVMCompiler& compiler) +{ + ShaderInput *size_in = input("Size"); + ShaderInput *vector_in = input("Vector"); + ShaderOutput *color_out = output("Color"); + ShaderOutput *fac_out = output("Fac"); + + if(vector_in->link) compiler.stack_assign(vector_in); + if(size_in->link) compiler.stack_assign(size_in); + + compiler.stack_assign(color_out); + compiler.stack_assign(fac_out); + + compiler.add_node(NODE_TEX_CLOUDS, + compiler.encode_uchar4(basis_enum[basis], hard, depth), + compiler.encode_uchar4(size_in->stack_offset, vector_in->stack_offset, fac_out->stack_offset, color_out->stack_offset), + __float_as_int(size_in->value.x)); +} + +void CloudsTextureNode::compile(OSLCompiler& compiler) +{ + compiler.parameter("Hard", (hard)? 1: 0); + compiler.parameter("Depth", depth); + compiler.parameter("Basis", basis); + compiler.add(this, "node_clouds_texture"); +} + +/* Voronoi Texture */ + +static ShaderEnum distance_metric_init() +{ + ShaderEnum enm; + + enm.insert("Distance Squared", NODE_VORONOI_DISTANCE_SQUARED); + enm.insert("Actual Distance", NODE_VORONOI_ACTUAL_DISTANCE); + enm.insert("Manhattan", NODE_VORONOI_MANHATTAN); + enm.insert("Chebychev", NODE_VORONOI_CHEBYCHEV); + enm.insert("Minkovsky 1/2", NODE_VORONOI_MINKOVSKY_H); + enm.insert("Minkovsky 4", NODE_VORONOI_MINKOVSKY_4); + enm.insert("Minkovsky", NODE_VORONOI_MINKOVSKY); + + return enm; +} + +static ShaderEnum voronoi_coloring_init() +{ + ShaderEnum enm; + + enm.insert("Intensity", NODE_VORONOI_INTENSITY); + enm.insert("Position", NODE_VORONOI_POSITION); + enm.insert("Position and Outline", NODE_VORONOI_POSITION_OUTLINE); + enm.insert("Position, Outline, and Intensity", NODE_VORONOI_POSITION_OUTLINE_INTENSITY); + + return enm; +} + +ShaderEnum VoronoiTextureNode::distance_metric_enum = distance_metric_init(); +ShaderEnum VoronoiTextureNode::coloring_enum = voronoi_coloring_init(); + +VoronoiTextureNode::VoronoiTextureNode() +: ShaderNode("voronoi_texture") +{ + distance_metric = ustring("Actual Distance"); + coloring = ustring("Intensity"); + + add_input("Size", SHADER_SOCKET_FLOAT, 0.25f); + add_input("Weight1", SHADER_SOCKET_FLOAT, 1.0f); + add_input("Weight2", SHADER_SOCKET_FLOAT, 0.0f); + add_input("Weight3", SHADER_SOCKET_FLOAT, 0.0f); + add_input("Weight4", SHADER_SOCKET_FLOAT, 0.0f); + add_input("Exponent", SHADER_SOCKET_FLOAT, 2.5f); + add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_COORDINATE); + + add_output("Color", SHADER_SOCKET_COLOR); + add_output("Fac", SHADER_SOCKET_FLOAT); +} + +void VoronoiTextureNode::compile(SVMCompiler& compiler) +{ + ShaderInput *weight1_in = input("Weight1"); + ShaderInput *weight2_in = input("Weight2"); + ShaderInput *weight3_in = input("Weight3"); + ShaderInput *weight4_in = input("Weight4"); + ShaderInput *exponent_in = input("Exponent"); + ShaderInput *size_in = input("Size"); + ShaderInput *vector_in = input("Vector"); + ShaderOutput *color_out = output("Color"); + ShaderOutput *fac_out = output("Fac"); + + if(weight1_in->link) compiler.stack_assign(weight1_in); + if(weight2_in->link) compiler.stack_assign(weight2_in); + if(weight3_in->link) compiler.stack_assign(weight3_in); + if(weight4_in->link) compiler.stack_assign(weight4_in); + if(exponent_in->link) compiler.stack_assign(exponent_in); + if(vector_in->link) compiler.stack_assign(vector_in); + if(size_in->link) compiler.stack_assign(size_in); + + compiler.stack_assign(color_out); + compiler.stack_assign(fac_out); + + compiler.add_node(NODE_TEX_VORONOI, + compiler.encode_uchar4(distance_metric_enum[distance_metric], coloring_enum[coloring], exponent_in->stack_offset), + compiler.encode_uchar4(size_in->stack_offset, vector_in->stack_offset, fac_out->stack_offset, color_out->stack_offset), + compiler.encode_uchar4(weight1_in->stack_offset, weight2_in->stack_offset, weight3_in->stack_offset, weight4_in->stack_offset)); + compiler.add_node(__float_as_int(weight1_in->value.x), + __float_as_int(weight2_in->value.x), + __float_as_int(weight3_in->value.x), + __float_as_int(weight4_in->value.x)); + compiler.add_node(__float_as_int(exponent_in->value.x), + __float_as_int(size_in->value.x)); +} + +void VoronoiTextureNode::compile(OSLCompiler& compiler) +{ + compiler.parameter("DistanceMetric", distance_metric); + compiler.parameter("Coloring", coloring); + compiler.add(this, "node_voronoi_texture"); +} + +/* Musgrave Texture */ + +static ShaderEnum musgrave_type_init() +{ + ShaderEnum enm; + + enm.insert("Multifractal", NODE_MUSGRAVE_MULTIFRACTAL); + enm.insert("fBM", NODE_MUSGRAVE_FBM); + enm.insert("Hybrid Multifractal", NODE_MUSGRAVE_HYBRID_MULTIFRACTAL); + enm.insert("Ridged Multifractal", NODE_MUSGRAVE_RIDGED_MULTIFRACTAL); + enm.insert("Hetero Terrain", NODE_MUSGRAVE_HETERO_TERRAIN); + + return enm; +} + +ShaderEnum MusgraveTextureNode::type_enum = musgrave_type_init(); +ShaderEnum MusgraveTextureNode::basis_enum = noise_basis_init(); + +MusgraveTextureNode::MusgraveTextureNode() +: ShaderNode("musgrave_texture") +{ + type = ustring("fBM"); + basis = ustring("Perlin"); + + add_input("Dimension", SHADER_SOCKET_FLOAT, 2.0f); + add_input("Lacunarity", SHADER_SOCKET_FLOAT, 1.0f); + add_input("Octaves", SHADER_SOCKET_FLOAT, 2.0f); + add_input("Offset", SHADER_SOCKET_FLOAT, 0.0f); + add_input("Gain", SHADER_SOCKET_FLOAT, 1.0f); + add_input("Size", SHADER_SOCKET_FLOAT, 0.25f); + add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_COORDINATE); + + add_output("Fac", SHADER_SOCKET_FLOAT); +} + +void MusgraveTextureNode::compile(SVMCompiler& compiler) +{ + ShaderInput *vector_in = input("Vector"); + ShaderInput *dimension_in = input("Dimension"); + ShaderInput *lacunarity_in = input("Lacunarity"); + ShaderInput *octaves_in = input("Octaves"); + ShaderInput *offset_in = input("Offset"); + ShaderInput *gain_in = input("Gain"); + ShaderInput *size_in = input("Size"); + ShaderOutput *fac_out = output("Fac"); + + if(vector_in->link) compiler.stack_assign(vector_in); + if(dimension_in->link) compiler.stack_assign(dimension_in); + if(lacunarity_in->link) compiler.stack_assign(lacunarity_in); + if(octaves_in->link) compiler.stack_assign(octaves_in); + if(offset_in->link) compiler.stack_assign(offset_in); + if(gain_in->link) compiler.stack_assign(gain_in); + if(size_in->link) compiler.stack_assign(size_in); + + compiler.stack_assign(fac_out); + compiler.add_node(NODE_TEX_MUSGRAVE, + compiler.encode_uchar4(type_enum[type], basis_enum[basis], vector_in->stack_offset, fac_out->stack_offset), + compiler.encode_uchar4(dimension_in->stack_offset, lacunarity_in->stack_offset, octaves_in->stack_offset, offset_in->stack_offset), + compiler.encode_uchar4(gain_in->stack_offset, size_in->stack_offset)); + compiler.add_node(__float_as_int(dimension_in->value.x), + __float_as_int(lacunarity_in->value.x), + __float_as_int(octaves_in->value.x), + __float_as_int(offset_in->value.x)); + compiler.add_node(__float_as_int(gain_in->value.x), + __float_as_int(size_in->value.x)); +} + +void MusgraveTextureNode::compile(OSLCompiler& compiler) +{ + compiler.parameter("Type", type); + compiler.parameter("Basis", basis); + + compiler.add(this, "node_musgrave_texture"); +} + +/* Marble Texture */ + +static ShaderEnum marble_type_init() +{ + ShaderEnum enm; + + enm.insert("Soft", NODE_MARBLE_SOFT); + enm.insert("Sharp", NODE_MARBLE_SHARP); + enm.insert("Sharper", NODE_MARBLE_SHARPER); + + return enm; +} + +static ShaderEnum noise_wave_init() +{ + ShaderEnum enm; + + enm.insert("Sine", NODE_WAVE_SINE); + enm.insert("Saw", NODE_WAVE_SAW); + enm.insert("Tri", NODE_WAVE_TRI); + + return enm; +} + +ShaderEnum MarbleTextureNode::type_enum = marble_type_init(); +ShaderEnum MarbleTextureNode::wave_enum = noise_wave_init(); +ShaderEnum MarbleTextureNode::basis_enum = noise_basis_init(); + +MarbleTextureNode::MarbleTextureNode() +: ShaderNode("marble_texture") +{ + type = ustring("Soft"); + wave = ustring("Sine"); + basis = ustring("Perlin"); + hard = false; + depth = 2; + + add_input("Size", SHADER_SOCKET_FLOAT, 0.25f); + add_input("Turbulence", SHADER_SOCKET_FLOAT, 5.0f); + add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_COORDINATE); + + add_output("Fac", SHADER_SOCKET_FLOAT); +} + +void MarbleTextureNode::compile(SVMCompiler& compiler) +{ + ShaderInput *size_in = input("Size"); + ShaderInput *turbulence_in = input("Turbulence"); + ShaderInput *vector_in = input("Vector"); + ShaderOutput *fac_out = output("Fac"); + + if(size_in->link) compiler.stack_assign(size_in); + if(turbulence_in->link) compiler.stack_assign(turbulence_in); + if(vector_in->link) compiler.stack_assign(vector_in); + + compiler.stack_assign(fac_out); + compiler.add_node(NODE_TEX_MARBLE, + compiler.encode_uchar4(type_enum[type], wave_enum[wave], basis_enum[basis], hard), + compiler.encode_uchar4(depth), + compiler.encode_uchar4(size_in->stack_offset, turbulence_in->stack_offset, vector_in->stack_offset, fac_out->stack_offset)); + compiler.add_node(__float_as_int(size_in->value.x), __float_as_int(turbulence_in->value.x)); +} + +void MarbleTextureNode::compile(OSLCompiler& compiler) +{ + compiler.parameter("Type", type); + compiler.parameter("Wave", wave); + compiler.parameter("Basis", basis); + compiler.parameter("Hard", (hard)? 1: 0); + compiler.parameter("Depth", depth); + + compiler.add(this, "node_marble_texture"); +} + +/* Magic Texture */ + +MagicTextureNode::MagicTextureNode() +: ShaderNode("magic_texture") +{ + depth = 2; + + add_input("Turbulence", SHADER_SOCKET_FLOAT, 5.0f); + add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_COORDINATE); + add_output("Color", SHADER_SOCKET_COLOR); +} + +void MagicTextureNode::compile(SVMCompiler& compiler) +{ + ShaderInput *vector_in = input("Vector"); + ShaderInput *turbulence_in = input("Turbulence"); + ShaderOutput *color_out = output("Color"); + + if(vector_in->link) compiler.stack_assign(vector_in); + if(turbulence_in->link) compiler.stack_assign(turbulence_in); + + compiler.stack_assign(color_out); + compiler.add_node(NODE_TEX_MAGIC, + compiler.encode_uchar4(depth, turbulence_in->stack_offset, vector_in->stack_offset, color_out->stack_offset), + __float_as_int(turbulence_in->value.x)); +} + +void MagicTextureNode::compile(OSLCompiler& compiler) +{ + compiler.parameter("Depth", depth); + compiler.add(this, "node_magic_texture"); +} + +/* Stucci Texture */ + +static ShaderEnum stucci_type_init() +{ + ShaderEnum enm; + + enm.insert("Plastic", NODE_STUCCI_PLASTIC); + enm.insert("Wall In", NODE_STUCCI_WALL_IN); + enm.insert("Wall Out", NODE_STUCCI_WALL_OUT); + + return enm; +} + +ShaderEnum StucciTextureNode::type_enum = stucci_type_init(); +ShaderEnum StucciTextureNode::basis_enum = noise_basis_init(); + +StucciTextureNode::StucciTextureNode() +: ShaderNode("stucci_texture") +{ + type = ustring("Plastic"); + basis = ustring("Perlin"); + hard = false; + + add_input("Size", SHADER_SOCKET_FLOAT, 1.0f); + add_input("Turbulence", SHADER_SOCKET_FLOAT, 1.0f); + add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_COORDINATE); + + add_output("Fac", SHADER_SOCKET_FLOAT); +} + +void StucciTextureNode::compile(SVMCompiler& compiler) +{ + ShaderInput *size_in = input("Size"); + ShaderInput *turbulence_in = input("Turbulence"); + ShaderInput *vector_in = input("Vector"); + ShaderOutput *fac_out = output("Fac"); + + if(size_in->link) compiler.stack_assign(size_in); + if(turbulence_in->link) compiler.stack_assign(turbulence_in); + if(vector_in->link) compiler.stack_assign(vector_in); + + compiler.stack_assign(fac_out); + + compiler.add_node(NODE_TEX_STUCCI, + compiler.encode_uchar4(type_enum[type], basis_enum[basis], hard), + compiler.encode_uchar4(size_in->stack_offset, turbulence_in->stack_offset, + vector_in->stack_offset, fac_out->stack_offset)); + compiler.add_node(__float_as_int(size_in->value.x), + __float_as_int(turbulence_in->value.x)); +} + +void StucciTextureNode::compile(OSLCompiler& compiler) +{ + compiler.parameter("Type", type); + compiler.parameter("Basis", basis); + compiler.parameter("Hard", (hard)? 1: 0); + compiler.add(this, "node_stucci_texture"); +} + +/* Distorted Noise Texture */ + +ShaderEnum DistortedNoiseTextureNode::basis_enum = noise_basis_init(); + +DistortedNoiseTextureNode::DistortedNoiseTextureNode() +: ShaderNode("distorted_noise_texture") +{ + basis = ustring("Perlin"); + distortion_basis = ustring("Perlin"); + + add_input("Size", SHADER_SOCKET_FLOAT, 0.25f); + add_input("Distortion", SHADER_SOCKET_FLOAT, 1.0f); + add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_COORDINATE); + + add_output("Fac", SHADER_SOCKET_FLOAT); +} + +void DistortedNoiseTextureNode::compile(SVMCompiler& compiler) +{ + ShaderInput *size_in = input("Size"); + ShaderInput *distortion_in = input("Distortion"); + ShaderInput *vector_in = input("Vector"); + ShaderOutput *fac_out = output("Fac"); + + if(size_in->link) compiler.stack_assign(size_in); + if(distortion_in->link) compiler.stack_assign(distortion_in); + if(vector_in->link) compiler.stack_assign(vector_in); + + compiler.stack_assign(fac_out); + + compiler.add_node(NODE_TEX_DISTORTED_NOISE, + compiler.encode_uchar4(basis_enum[basis], basis_enum[distortion_basis]), + compiler.encode_uchar4(size_in->stack_offset, distortion_in->stack_offset, vector_in->stack_offset, fac_out->stack_offset)); + compiler.add_node(__float_as_int(size_in->value.x), + __float_as_int(distortion_in->value.x)); +} + +void DistortedNoiseTextureNode::compile(OSLCompiler& compiler) +{ + compiler.parameter("Basis", basis); + compiler.parameter("DistortionBasis", distortion_basis); + compiler.add(this, "node_distorted_noise_texture"); +} + +/* Wood Texture */ + +static ShaderEnum wood_type_init() +{ + ShaderEnum enm; + + enm.insert("Bands", NODE_WOOD_BANDS); + enm.insert("Rings", NODE_WOOD_RINGS); + enm.insert("Band Noise", NODE_WOOD_BAND_NOISE); + enm.insert("Ring Noise", NODE_WOOD_RING_NOISE); + + return enm; +} + +ShaderEnum WoodTextureNode::type_enum = wood_type_init(); +ShaderEnum WoodTextureNode::wave_enum = noise_wave_init(); +ShaderEnum WoodTextureNode::basis_enum = noise_basis_init(); + +WoodTextureNode::WoodTextureNode() +: ShaderNode("wood_texture") +{ + type = ustring("Bands"); + wave = ustring("Sine"); + basis = ustring("Perlin"); + hard = false; + + add_input("Size", SHADER_SOCKET_FLOAT, 0.25f); + add_input("Turbulence", SHADER_SOCKET_FLOAT, 5.0f); + add_input("Vector", SHADER_SOCKET_POINT, ShaderInput::TEXTURE_COORDINATE); + + add_output("Fac", SHADER_SOCKET_FLOAT); +} + +void WoodTextureNode::compile(SVMCompiler& compiler) +{ + ShaderInput *vector_in = input("Vector"); + ShaderInput *size_in = input("Size"); + ShaderInput *turbulence_in = input("Turbulence"); + ShaderOutput *fac_out = output("Fac"); + + if(vector_in->link) compiler.stack_assign(vector_in); + if(size_in->link) compiler.stack_assign(size_in); + if(turbulence_in->link) compiler.stack_assign(turbulence_in); + + compiler.stack_assign(fac_out); + compiler.add_node(NODE_TEX_WOOD, + compiler.encode_uchar4(type_enum[type], wave_enum[wave], basis_enum[basis], hard), + compiler.encode_uchar4(vector_in->stack_offset, size_in->stack_offset, turbulence_in->stack_offset, fac_out->stack_offset)); + compiler.add_node(NODE_TEX_WOOD, make_float3(size_in->value.x, turbulence_in->value.x, 0.0f)); +} + +void WoodTextureNode::compile(OSLCompiler& compiler) +{ + compiler.parameter("Type", type); + compiler.parameter("Wave", wave); + compiler.parameter("Basis", basis); + compiler.parameter("Hard", (hard)? 1: 0); + compiler.add(this, "node_wood_texture"); +} + +/* Mapping */ + +MappingNode::MappingNode() +: ShaderNode("mapping") +{ + add_input("Vector", SHADER_SOCKET_POINT); + add_output("Vector", SHADER_SOCKET_POINT); + + translation = make_float3(0.0f, 0.0f, 0.0f); + rotation = make_float3(0.0f, 0.0f, 0.0f); + scale = make_float3(1.0f, 1.0f, 1.0f); +} + +Transform MappingNode::compute_transform() +{ + Transform smat = transform_scale(scale); + Transform rmat = transform_euler(rotation); + Transform tmat = transform_translate(translation); + + return tmat*rmat*smat; +} + +void MappingNode::compile(SVMCompiler& compiler) +{ + ShaderInput *vector_in = input("Vector"); + ShaderOutput *vector_out = output("Vector"); + + compiler.stack_assign(vector_in); + compiler.stack_assign(vector_out); + + compiler.add_node(NODE_MAPPING, vector_in->stack_offset, vector_out->stack_offset); + + Transform tfm = compute_transform(); + compiler.add_node(tfm.x); + compiler.add_node(tfm.y); + compiler.add_node(tfm.z); + compiler.add_node(tfm.w); +} + +void MappingNode::compile(OSLCompiler& compiler) +{ + Transform tfm = transform_transpose(compute_transform()); + compiler.parameter("Matrix", tfm); + + compiler.add(this, "node_mapping"); +} + +/* Convert */ + +ConvertNode::ConvertNode(ShaderSocketType from_, ShaderSocketType to_) +: ShaderNode("convert") +{ + from = from_; + to = to_; + + assert(from != to); + + if(from == SHADER_SOCKET_FLOAT) + add_input("Val", SHADER_SOCKET_FLOAT); + else if(from == SHADER_SOCKET_COLOR) + add_input("Color", SHADER_SOCKET_COLOR); + else if(from == SHADER_SOCKET_VECTOR) + add_input("Vector", SHADER_SOCKET_VECTOR); + else if(from == SHADER_SOCKET_POINT) + add_input("Point", SHADER_SOCKET_POINT); + else if(from == SHADER_SOCKET_NORMAL) + add_input("Normal", SHADER_SOCKET_NORMAL); + else + assert(0); + + if(to == SHADER_SOCKET_FLOAT) + add_output("Val", SHADER_SOCKET_FLOAT); + else if(to == SHADER_SOCKET_COLOR) + add_output("Color", SHADER_SOCKET_COLOR); + else if(to == SHADER_SOCKET_VECTOR) + add_output("Vector", SHADER_SOCKET_VECTOR); + else if(to == SHADER_SOCKET_POINT) + add_output("Point", SHADER_SOCKET_POINT); + else if(to == SHADER_SOCKET_NORMAL) + add_output("Normal", SHADER_SOCKET_NORMAL); + else + assert(0); +} + +void ConvertNode::compile(SVMCompiler& compiler) +{ + ShaderInput *in = inputs[0]; + ShaderOutput *out = outputs[0]; + + if(to == SHADER_SOCKET_FLOAT) { + compiler.stack_assign(in); + compiler.stack_assign(out); + + if(from == SHADER_SOCKET_COLOR) + /* color to float */ + compiler.add_node(NODE_CONVERT, NODE_CONVERT_CF, in->stack_offset, out->stack_offset); + else + /* vector/point/normal to float */ + compiler.add_node(NODE_CONVERT, NODE_CONVERT_VF, in->stack_offset, out->stack_offset); + } + else if(from == SHADER_SOCKET_FLOAT) { + compiler.stack_assign(in); + compiler.stack_assign(out); + + /* float to float3 */ + compiler.add_node(NODE_CONVERT, NODE_CONVERT_FV, in->stack_offset, out->stack_offset); + } + else { + /* float3 to float3 */ + if(in->link) { + /* no op in SVM */ + compiler.stack_link(in, out); + } + else { + /* set 0,0,0 value */ + compiler.stack_assign(in); + compiler.stack_assign(out); + + compiler.add_node(NODE_VALUE_V, in->stack_offset); + compiler.add_node(NODE_VALUE_V, in->value); + } + } +} + +void ConvertNode::compile(OSLCompiler& compiler) +{ + if(from == SHADER_SOCKET_FLOAT) + compiler.add(this, "node_convert_from_float"); + else if(from == SHADER_SOCKET_COLOR) + compiler.add(this, "node_convert_from_color"); + else if(from == SHADER_SOCKET_VECTOR) + compiler.add(this, "node_convert_from_vector"); + else if(from == SHADER_SOCKET_POINT) + compiler.add(this, "node_convert_from_point"); + else if(from == SHADER_SOCKET_NORMAL) + compiler.add(this, "node_convert_from_normal"); + else + assert(0); +} + +/* BSDF Closure */ + +BsdfNode::BsdfNode() +: ShaderNode("bsdf") +{ + closure = ccl::CLOSURE_BSDF_DIFFUSE_ID; + + add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f)); + add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, true); + + add_output("BSDF", SHADER_SOCKET_CLOSURE); +} + +void BsdfNode::compile(SVMCompiler& compiler, ShaderInput *param1, ShaderInput *param2) +{ + ShaderInput *color_in = input("Color"); + + if(color_in->link) { + compiler.stack_assign(color_in); + compiler.add_node(NODE_CLOSURE_WEIGHT, color_in->stack_offset); + } + else + compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value); + + compiler.add_node(NODE_CLOSURE_BSDF, + closure, + (param1)? __float_as_int(param1->value.x): 0.0f, + (param2)? __float_as_int(param2->value.x): 0.0f); +} + +void BsdfNode::compile(SVMCompiler& compiler) +{ + compile(compiler, NULL, NULL); +} + +void BsdfNode::compile(OSLCompiler& compiler) +{ + assert(0); +} + +/* Ward BSDF Closure */ + +WardBsdfNode::WardBsdfNode() +{ + closure = CLOSURE_BSDF_WARD_ID; + + add_input("Roughness U", SHADER_SOCKET_FLOAT, 0.2f); + add_input("Roughness V", SHADER_SOCKET_FLOAT, 0.2f); +} + +void WardBsdfNode::compile(SVMCompiler& compiler) +{ + BsdfNode::compile(compiler, input("Roughness U"), input("Roughness V")); +} + +void WardBsdfNode::compile(OSLCompiler& compiler) +{ + compiler.add(this, "node_ward_bsdf"); +} + +/* Glossy BSDF Closure */ + +static ShaderEnum glossy_distribution_init() +{ + ShaderEnum enm; + + enm.insert("Sharp", CLOSURE_BSDF_REFLECTION_ID); + enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID); + enm.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ID); + + return enm; +} + +ShaderEnum GlossyBsdfNode::distribution_enum = glossy_distribution_init(); + +GlossyBsdfNode::GlossyBsdfNode() +{ + distribution = ustring("Beckmann"); + + add_input("Roughness", SHADER_SOCKET_FLOAT, 0.2f); + add_input("Fresnel", SHADER_SOCKET_FLOAT, 1.0f); +} + +void GlossyBsdfNode::compile(SVMCompiler& compiler) +{ + closure = (ClosureType)distribution_enum[distribution]; + + if(closure == CLOSURE_BSDF_REFLECTION_ID) + BsdfNode::compile(compiler, NULL, input("Fresnel")); + else + BsdfNode::compile(compiler, input("Roughness"), input("Fresnel")); +} + +void GlossyBsdfNode::compile(OSLCompiler& compiler) +{ + compiler.parameter("distribution", distribution); + compiler.add(this, "node_glossy_bsdf"); +} + +/* Glass BSDF Closure */ + +static ShaderEnum glass_distribution_init() +{ + ShaderEnum enm; + + enm.insert("Sharp", CLOSURE_BSDF_REFRACTION_ID); + enm.insert("Beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID); + enm.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID); + + return enm; +} + +ShaderEnum GlassBsdfNode::distribution_enum = glass_distribution_init(); + +GlassBsdfNode::GlassBsdfNode() +{ + distribution = ustring("Sharp"); + + add_input("Roughness", SHADER_SOCKET_FLOAT, 0.2f); + add_input("Fresnel", SHADER_SOCKET_FLOAT, 0.3f); +} + +void GlassBsdfNode::compile(SVMCompiler& compiler) +{ + closure = (ClosureType)distribution_enum[distribution]; + + if(closure == CLOSURE_BSDF_REFRACTION_ID) + BsdfNode::compile(compiler, NULL, input("Fresnel")); + else + BsdfNode::compile(compiler, input("Roughness"), input("Fresnel")); +} + +void GlassBsdfNode::compile(OSLCompiler& compiler) +{ + compiler.parameter("distribution", distribution); + compiler.add(this, "node_glass_bsdf"); +} + +/* Velvet BSDF Closure */ + +VelvetBsdfNode::VelvetBsdfNode() +{ + closure = CLOSURE_BSDF_ASHIKHMIN_VELVET_ID; + + add_input("Sigma", SHADER_SOCKET_FLOAT, 1.0f); + add_input("Fresnel", SHADER_SOCKET_FLOAT, 1.0f); +} + +void VelvetBsdfNode::compile(SVMCompiler& compiler) +{ + BsdfNode::compile(compiler, input("Sigma"), input("Fresnel")); +} + +void VelvetBsdfNode::compile(OSLCompiler& compiler) +{ + compiler.add(this, "node_velvet_bsdf"); +} + +/* Diffuse BSDF Closure */ + +DiffuseBsdfNode::DiffuseBsdfNode() +{ + closure = CLOSURE_BSDF_DIFFUSE_ID; +} + +void DiffuseBsdfNode::compile(SVMCompiler& compiler) +{ + BsdfNode::compile(compiler, NULL, NULL); +} + +void DiffuseBsdfNode::compile(OSLCompiler& compiler) +{ + compiler.add(this, "node_diffuse_bsdf"); +} + +/* Translucent BSDF Closure */ + +TranslucentBsdfNode::TranslucentBsdfNode() +{ + closure = CLOSURE_BSDF_TRANSLUCENT_ID; +} + +void TranslucentBsdfNode::compile(SVMCompiler& compiler) +{ + BsdfNode::compile(compiler, NULL, NULL); +} + +void TranslucentBsdfNode::compile(OSLCompiler& compiler) +{ + compiler.add(this, "node_translucent_bsdf"); +} + +/* Transparent BSDF Closure */ + +TransparentBsdfNode::TransparentBsdfNode() +{ + closure = CLOSURE_BSDF_TRANSPARENT_ID; +} + +void TransparentBsdfNode::compile(SVMCompiler& compiler) +{ + BsdfNode::compile(compiler, NULL, NULL); +} + +void TransparentBsdfNode::compile(OSLCompiler& compiler) +{ + compiler.add(this, "node_transparent_bsdf"); +} + +/* Emissive Closure */ + +EmissionNode::EmissionNode() +: ShaderNode("emission") +{ + total_power = false; + + add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f)); + add_input("Strength", SHADER_SOCKET_FLOAT, 10.0f); + add_output("Emission", SHADER_SOCKET_CLOSURE); +} + +void EmissionNode::compile(SVMCompiler& compiler) +{ + compiler.add_node(NODE_CLOSURE_EMISSION, CLOSURE_EMISSION_ID); + + ShaderInput *color_in = input("Color"); + ShaderInput *strength_in = input("Strength"); + + if(color_in->link || strength_in->link) { + compiler.stack_assign(color_in); + compiler.stack_assign(strength_in); + compiler.add_node(NODE_EMISSION_WEIGHT, color_in->stack_offset, strength_in->stack_offset, total_power? 1: 0); + } + else if(total_power) + compiler.add_node(NODE_EMISSION_SET_WEIGHT_TOTAL, color_in->value * strength_in->value.x); + else + compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value * strength_in->value.x); +} + +void EmissionNode::compile(OSLCompiler& compiler) +{ + compiler.parameter("TotalPower", (total_power)? 1: 0); + compiler.add(this, "node_emission"); +} + +/* Background Closure */ + +BackgroundNode::BackgroundNode() +: ShaderNode("background") +{ + add_input("Color", SHADER_SOCKET_COLOR, make_float3(0.8f, 0.8f, 0.8f)); + add_input("Strength", SHADER_SOCKET_FLOAT, 1.0f); + add_output("Background", SHADER_SOCKET_CLOSURE); +} + +void BackgroundNode::compile(SVMCompiler& compiler) +{ + compiler.add_node(NODE_CLOSURE_BACKGROUND, CLOSURE_BACKGROUND_ID); + + ShaderInput *color_in = input("Color"); + ShaderInput *strength_in = input("Strength"); + + if(color_in->link || strength_in->link) { + compiler.stack_assign(color_in); + compiler.stack_assign(strength_in); + compiler.add_node(NODE_EMISSION_WEIGHT, color_in->stack_offset, strength_in->stack_offset); + } + else + compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color_in->value*strength_in->value.x); +} + +void BackgroundNode::compile(OSLCompiler& compiler) +{ + compiler.add(this, "node_background"); +} + +/* Geometry */ + +GeometryNode::GeometryNode() +: ShaderNode("geometry") +{ + add_input("NormalIn", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, true); + add_output("Position", SHADER_SOCKET_POINT); + add_output("Normal", SHADER_SOCKET_NORMAL); + add_output("Tangent", SHADER_SOCKET_NORMAL); + add_output("True Normal", SHADER_SOCKET_NORMAL); + add_output("Incoming", SHADER_SOCKET_VECTOR); + add_output("UV", SHADER_SOCKET_POINT); + add_output("Backfacing", SHADER_SOCKET_FLOAT); +} + +void GeometryNode::compile(SVMCompiler& compiler) +{ + ShaderOutput *out; + NodeType geom_node = NODE_GEOMETRY; + + if(bump == SHADER_BUMP_DX) + geom_node = NODE_GEOMETRY_BUMP_DX; + else if(bump == SHADER_BUMP_DY) + geom_node = NODE_GEOMETRY_BUMP_DY; + + out = output("Position"); + if(!out->links.empty()) { + compiler.stack_assign(out); + compiler.add_node(geom_node, NODE_GEOM_P, out->stack_offset); + } + + out = output("Normal"); + if(!out->links.empty()) { + compiler.stack_assign(out); + compiler.add_node(geom_node, NODE_GEOM_N, out->stack_offset); + } + + out = output("Tangent"); + if(!out->links.empty()) { + compiler.stack_assign(out); + compiler.add_node(geom_node, NODE_GEOM_T, out->stack_offset); + } + + out = output("True Normal"); + if(!out->links.empty()) { + compiler.stack_assign(out); + compiler.add_node(geom_node, NODE_GEOM_Ng, out->stack_offset); + } + + out = output("Incoming"); + if(!out->links.empty()) { + compiler.stack_assign(out); + compiler.add_node(geom_node, NODE_GEOM_I, out->stack_offset); + } + + out = output("UV"); + if(!out->links.empty()) { + compiler.stack_assign(out); + compiler.add_node(geom_node, NODE_GEOM_uv, out->stack_offset); + } + + out = output("Backfacing"); + if(!out->links.empty()) { + compiler.stack_assign(out); + compiler.add_node(NODE_LIGHT_PATH, NODE_LP_backfacing, out->stack_offset); + } +} + +void GeometryNode::compile(OSLCompiler& compiler) +{ + if(bump == SHADER_BUMP_DX) + compiler.parameter("bump_offset", "dx"); + else if(bump == SHADER_BUMP_DY) + compiler.parameter("bump_offset", "dy"); + else + compiler.parameter("bump_offset", "center"); + + compiler.add(this, "node_geometry"); +} + +/* TextureCoordinate */ + +TextureCoordinateNode::TextureCoordinateNode() +: ShaderNode("texture_coordinate") +{ + add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, true); + add_output("Generated", SHADER_SOCKET_POINT); + add_output("UV", SHADER_SOCKET_POINT); + add_output("Object", SHADER_SOCKET_POINT); + add_output("Camera", SHADER_SOCKET_POINT); + add_output("Window", SHADER_SOCKET_POINT); + add_output("Reflection", SHADER_SOCKET_NORMAL); +} + +void TextureCoordinateNode::attributes(AttributeRequestSet *attributes) +{ + if(!output("Generated")->links.empty()) + attributes->add(Attribute::STD_GENERATED); + if(!output("UV")->links.empty()) + attributes->add(Attribute::STD_UV); + + ShaderNode::attributes(attributes); +} + +void TextureCoordinateNode::compile(SVMCompiler& compiler) +{ + ShaderOutput *out; + NodeType texco_node = NODE_TEX_COORD; + NodeType attr_node = NODE_ATTR; + NodeType geom_node = NODE_GEOMETRY; + + if(bump == SHADER_BUMP_DX) { + texco_node = NODE_TEX_COORD_BUMP_DX; + attr_node = NODE_ATTR_BUMP_DX; + geom_node = NODE_GEOMETRY_BUMP_DX; + } + else if(bump == SHADER_BUMP_DY) { + texco_node = NODE_TEX_COORD_BUMP_DY; + attr_node = NODE_ATTR_BUMP_DY; + geom_node = NODE_GEOMETRY_BUMP_DY; + } + + out = output("Generated"); + if(!out->links.empty()) { + if(compiler.background) { + compiler.stack_assign(out); + compiler.add_node(geom_node, NODE_GEOM_P, out->stack_offset); + } + else { + int attr = compiler.attribute(Attribute::STD_GENERATED); + compiler.stack_assign(out); + compiler.add_node(attr_node, attr, out->stack_offset, NODE_ATTR_FLOAT3); + } + } + + out = output("UV"); + if(!out->links.empty()) { + int attr = compiler.attribute(Attribute::STD_UV); + compiler.stack_assign(out); + compiler.add_node(attr_node, attr, out->stack_offset, NODE_ATTR_FLOAT3); + } + + out = output("Object"); + if(!out->links.empty()) { + compiler.stack_assign(out); + compiler.add_node(texco_node, NODE_TEXCO_OBJECT, out->stack_offset); + } + + out = output("Camera"); + if(!out->links.empty()) { + compiler.stack_assign(out); + compiler.add_node(texco_node, NODE_TEXCO_CAMERA, out->stack_offset); + } + + out = output("Window"); + if(!out->links.empty()) { + compiler.stack_assign(out); + compiler.add_node(texco_node, NODE_TEXCO_WINDOW, out->stack_offset); + } + + out = output("Reflection"); + if(!out->links.empty()) { + if(compiler.background) { + compiler.stack_assign(out); + compiler.add_node(geom_node, NODE_GEOM_I, out->stack_offset); + } + else { + compiler.stack_assign(out); + compiler.add_node(texco_node, NODE_TEXCO_REFLECTION, out->stack_offset); + } + } +} + +void TextureCoordinateNode::compile(OSLCompiler& compiler) +{ + if(bump == SHADER_BUMP_DX) + compiler.parameter("bump_offset", "dx"); + else if(bump == SHADER_BUMP_DY) + compiler.parameter("bump_offset", "dy"); + else + compiler.parameter("bump_offset", "center"); + + if(compiler.background) + compiler.parameter("is_background", true); + + compiler.add(this, "node_texture_coordinate"); +} + +/* Light Path */ + +LightPathNode::LightPathNode() +: ShaderNode("light_path") +{ + add_output("Is Camera Ray", SHADER_SOCKET_FLOAT); + add_output("Is Shadow Ray", SHADER_SOCKET_FLOAT); + add_output("Is Diffuse Ray", SHADER_SOCKET_FLOAT); + add_output("Is Glossy Ray", SHADER_SOCKET_FLOAT); + add_output("Is Reflection Ray", SHADER_SOCKET_FLOAT); + add_output("Is Transmission Ray", SHADER_SOCKET_FLOAT); +} + +void LightPathNode::compile(SVMCompiler& compiler) +{ + ShaderOutput *out; + + out = output("Is Camera Ray"); + if(!out->links.empty()) { + compiler.stack_assign(out); + compiler.add_node(NODE_LIGHT_PATH, NODE_LP_camera, out->stack_offset); + } + + out = output("Is Shadow Ray"); + if(!out->links.empty()) { + compiler.stack_assign(out); + compiler.add_node(NODE_LIGHT_PATH, NODE_LP_shadow, out->stack_offset); + } + + out = output("Is Diffuse Ray"); + if(!out->links.empty()) { + compiler.stack_assign(out); + compiler.add_node(NODE_LIGHT_PATH, NODE_LP_diffuse, out->stack_offset); + } + + out = output("Is Glossy Ray"); + if(!out->links.empty()) { + compiler.stack_assign(out); + compiler.add_node(NODE_LIGHT_PATH, NODE_LP_glossy, out->stack_offset); + } + + out = output("Is Reflection Ray"); + if(!out->links.empty()) { + compiler.stack_assign(out); + compiler.add_node(NODE_LIGHT_PATH, NODE_LP_reflection, out->stack_offset); + } + + out = output("Is Transmission Ray"); + if(!out->links.empty()) { + compiler.stack_assign(out); + compiler.add_node(NODE_LIGHT_PATH, NODE_LP_transmission, out->stack_offset); + } +} + +void LightPathNode::compile(OSLCompiler& compiler) +{ + compiler.add(this, "node_light_path"); +} + +/* Value */ + +ValueNode::ValueNode() +: ShaderNode("value") +{ + value = 0.0f; + + add_output("Value", SHADER_SOCKET_FLOAT); +} + +void ValueNode::compile(SVMCompiler& compiler) +{ + ShaderOutput *val_out = output("Value"); + + compiler.stack_assign(val_out); + compiler.add_node(NODE_VALUE_F, __float_as_int(value), val_out->stack_offset); +} + +void ValueNode::compile(OSLCompiler& compiler) +{ + compiler.parameter("value_value", value); + compiler.add(this, "node_value"); +} + +/* Color */ + +ColorNode::ColorNode() +: ShaderNode("color") +{ + value = make_float3(0.0f, 0.0f, 0.0f); + + add_output("Color", SHADER_SOCKET_COLOR); +} + +void ColorNode::compile(SVMCompiler& compiler) +{ + ShaderOutput *color_out = output("Color"); + + if(color_out && !color_out->links.empty()) { + compiler.stack_assign(color_out); + compiler.add_node(NODE_VALUE_V, color_out->stack_offset); + compiler.add_node(NODE_VALUE_V, value); + } +} + +void ColorNode::compile(OSLCompiler& compiler) +{ + compiler.parameter_color("color_value", value); + + compiler.add(this, "node_value"); +} + +/* Add Closure */ + +AddClosureNode::AddClosureNode() +: ShaderNode("add_closure") +{ + add_input("Closure1", SHADER_SOCKET_CLOSURE); + add_input("Closure2", SHADER_SOCKET_CLOSURE); + add_output("Closure", SHADER_SOCKET_CLOSURE); +} + +void AddClosureNode::compile(SVMCompiler& compiler) +{ + /* handled in the SVM compiler */ +} + +void AddClosureNode::compile(OSLCompiler& compiler) +{ + compiler.add(this, "node_add_closure"); +} + +/* Mix Closure */ + +MixClosureNode::MixClosureNode() +: ShaderNode("mix_closure") +{ + add_input("Fac", SHADER_SOCKET_FLOAT, 0.5f); + add_input("Closure1", SHADER_SOCKET_CLOSURE); + add_input("Closure2", SHADER_SOCKET_CLOSURE); + add_output("Closure", SHADER_SOCKET_CLOSURE); +} + +void MixClosureNode::compile(SVMCompiler& compiler) +{ + /* handled in the SVM compiler */ +} + +void MixClosureNode::compile(OSLCompiler& compiler) +{ + compiler.add(this, "node_mix_closure"); +} + +/* Mix */ + +MixNode::MixNode() +: ShaderNode("mix") +{ + type = ustring("Mix"); + + add_input("Fac", SHADER_SOCKET_FLOAT, 0.5f); + add_input("Color1", SHADER_SOCKET_COLOR); + add_input("Color2", SHADER_SOCKET_COLOR); + add_output("Color", SHADER_SOCKET_COLOR); +} + +static ShaderEnum mix_type_init() +{ + ShaderEnum enm; + + enm.insert("Mix", NODE_MIX_BLEND); + enm.insert("Add", NODE_MIX_ADD); + enm.insert("Multiply", NODE_MIX_MUL); + enm.insert("Screen", NODE_MIX_SCREEN); + enm.insert("Overlay", NODE_MIX_OVERLAY); + enm.insert("Subtract", NODE_MIX_SUB); + enm.insert("Divide", NODE_MIX_DIV); + enm.insert("Difference", NODE_MIX_DIFF); + enm.insert("Darken", NODE_MIX_DARK); + enm.insert("Lighten", NODE_MIX_LIGHT); + enm.insert("Dodge", NODE_MIX_DODGE); + enm.insert("Burn", NODE_MIX_BURN); + enm.insert("Hue", NODE_MIX_HUE); + enm.insert("Saturation", NODE_MIX_SAT); + enm.insert("Value", NODE_MIX_VAL ); + enm.insert("Color", NODE_MIX_COLOR); + enm.insert("Soft Light", NODE_MIX_SOFT); + enm.insert("Linear Light", NODE_MIX_LINEAR); + + return enm; +} + +ShaderEnum MixNode::type_enum = mix_type_init(); + +void MixNode::compile(SVMCompiler& compiler) +{ + ShaderInput *fac_in = input("Fac"); + ShaderInput *color1_in = input("Color1"); + ShaderInput *color2_in = input("Color2"); + ShaderOutput *color_out = output("Color"); + + compiler.stack_assign(fac_in); + compiler.stack_assign(color1_in); + compiler.stack_assign(color2_in); + compiler.stack_assign(color_out); + + compiler.add_node(NODE_MIX, fac_in->stack_offset, color1_in->stack_offset, color2_in->stack_offset); + compiler.add_node(NODE_MIX, type_enum[type], color_out->stack_offset); +} + +void MixNode::compile(OSLCompiler& compiler) +{ + compiler.parameter("type", type); + compiler.add(this, "node_mix"); +} + +/* Attribute */ + +AttributeNode::AttributeNode() +: ShaderNode("attribute") +{ + attribute = ""; + + add_output("Color", SHADER_SOCKET_COLOR); + add_output("Vector", SHADER_SOCKET_VECTOR); + add_output("Fac", SHADER_SOCKET_FLOAT); +} + +void AttributeNode::attributes(AttributeRequestSet *attributes) +{ + ShaderOutput *color_out = output("Color"); + ShaderOutput *vector_out = output("Vector"); + ShaderOutput *fac_out = output("Fac"); + + if(!color_out->links.empty() || !vector_out->links.empty() || !fac_out->links.empty()) + attributes->add(attribute); + + ShaderNode::attributes(attributes); +} + +void AttributeNode::compile(SVMCompiler& compiler) +{ + ShaderOutput *color_out = output("Color"); + ShaderOutput *vector_out = output("Vector"); + ShaderOutput *fac_out = output("Fac"); + NodeType attr_node = NODE_ATTR; + + if(bump == SHADER_BUMP_DX) + attr_node = NODE_ATTR_BUMP_DX; + else if(bump == SHADER_BUMP_DY) + attr_node = NODE_ATTR_BUMP_DY; + + if(!color_out->links.empty() || !vector_out->links.empty()) { + int attr = compiler.attribute(attribute); + + if(!color_out->links.empty()) { + compiler.stack_assign(color_out); + compiler.add_node(attr_node, attr, color_out->stack_offset, NODE_ATTR_FLOAT3); + } + if(!vector_out->links.empty()) { + compiler.stack_assign(vector_out); + compiler.add_node(attr_node, attr, vector_out->stack_offset, NODE_ATTR_FLOAT3); + } + } + + if(!fac_out->links.empty()) { + int attr = compiler.attribute(attribute); + + compiler.stack_assign(fac_out); + compiler.add_node(attr_node, attr, fac_out->stack_offset, NODE_ATTR_FLOAT); + } +} + +void AttributeNode::compile(OSLCompiler& compiler) +{ + if(bump == SHADER_BUMP_DX) + compiler.parameter("bump_offset", "dx"); + else if(bump == SHADER_BUMP_DY) + compiler.parameter("bump_offset", "dy"); + else + compiler.parameter("bump_offset", "center"); + + compiler.parameter("name", attribute.c_str()); + compiler.add(this, "node_attribute"); +} + +/* Fresnel */ + +FresnelNode::FresnelNode() +: ShaderNode("Fresnel") +{ + add_input("Normal", SHADER_SOCKET_NORMAL, ShaderInput::NORMAL, true); + add_input("Fresnel", SHADER_SOCKET_FLOAT, 0.3f); + add_output("Fac", SHADER_SOCKET_FLOAT); +} + +void FresnelNode::compile(SVMCompiler& compiler) +{ + ShaderInput *fresnel_in = input("Fresnel"); + ShaderOutput *fac_out = output("Fac"); + + compiler.stack_assign(fresnel_in); + compiler.stack_assign(fac_out); + compiler.add_node(NODE_FRESNEL, fresnel_in->stack_offset, __float_as_int(fresnel_in->value.x), fac_out->stack_offset); +} + +void FresnelNode::compile(OSLCompiler& compiler) +{ + compiler.add(this, "node_fresnel"); +} + +/* Output */ + +OutputNode::OutputNode() +: ShaderNode("output") +{ + add_input("Surface", SHADER_SOCKET_CLOSURE); + add_input("Volume", SHADER_SOCKET_CLOSURE); + add_input("Displacement", SHADER_SOCKET_FLOAT); +} + +void OutputNode::compile(SVMCompiler& compiler) +{ + if(compiler.output_type() == SHADER_TYPE_DISPLACEMENT) { + ShaderInput *displacement_in = input("Displacement"); + + if(displacement_in->link) { + compiler.stack_assign(displacement_in); + compiler.add_node(NODE_SET_DISPLACEMENT, displacement_in->stack_offset); + } + } +} + +void OutputNode::compile(OSLCompiler& compiler) +{ + if(compiler.output_type() == SHADER_TYPE_SURFACE) + compiler.add(this, "node_output_surface"); + else if(compiler.output_type() == SHADER_TYPE_VOLUME) + compiler.add(this, "node_output_volume"); + else if(compiler.output_type() == SHADER_TYPE_DISPLACEMENT) + compiler.add(this, "node_output_displacement"); +} + +/* Math */ + +MathNode::MathNode() +: ShaderNode("math") +{ + type = ustring("Add"); + + add_input("Value1", SHADER_SOCKET_FLOAT); + add_input("Value2", SHADER_SOCKET_FLOAT); + add_output("Value", SHADER_SOCKET_FLOAT); +} + +static ShaderEnum math_type_init() +{ + ShaderEnum enm; + + enm.insert("Add", NODE_MATH_ADD); + enm.insert("Subtract", NODE_MATH_SUBTRACT); + enm.insert("Multiply", NODE_MATH_MULTIPLY); + enm.insert("Divide", NODE_MATH_DIVIDE); + enm.insert("Sine", NODE_MATH_SINE); + enm.insert("Cosine", NODE_MATH_COSINE); + enm.insert("Tangent", NODE_MATH_TANGENT); + enm.insert("Arcsine", NODE_MATH_ARCSINE); + enm.insert("Arccosine", NODE_MATH_ARCCOSINE); + enm.insert("Arctangent", NODE_MATH_ARCTANGENT); + enm.insert("Power", NODE_MATH_POWER); + enm.insert("Logarithm", NODE_MATH_LOGARITHM); + enm.insert("Minimum", NODE_MATH_MINIMUM); + enm.insert("Maximum", NODE_MATH_MAXIMUM); + enm.insert("Round", NODE_MATH_ROUND); + enm.insert("Less Than", NODE_MATH_LESS_THAN); + enm.insert("Greater Than", NODE_MATH_GREATER_THAN); + + return enm; +} + +ShaderEnum MathNode::type_enum = math_type_init(); + +void MathNode::compile(SVMCompiler& compiler) +{ + ShaderInput *value1_in = input("Value1"); + ShaderInput *value2_in = input("Value2"); + ShaderOutput *value_out = output("Value"); + + compiler.stack_assign(value1_in); + compiler.stack_assign(value2_in); + compiler.stack_assign(value_out); + + compiler.add_node(NODE_MATH, type_enum[type], value1_in->stack_offset, value2_in->stack_offset); + compiler.add_node(NODE_MATH, value_out->stack_offset); +} + +void MathNode::compile(OSLCompiler& compiler) +{ + compiler.parameter("type", type); + compiler.add(this, "node_math"); +} + +/* VectorMath */ + +VectorMathNode::VectorMathNode() +: ShaderNode("vector_math") +{ + type = ustring("Add"); + + add_input("Vector1", SHADER_SOCKET_VECTOR); + add_input("Vector2", SHADER_SOCKET_VECTOR); + add_output("Fac", SHADER_SOCKET_FLOAT); + add_output("Vector", SHADER_SOCKET_VECTOR); +} + +static ShaderEnum vector_math_type_init() +{ + ShaderEnum enm; + + enm.insert("Add", NODE_VECTOR_MATH_ADD); + enm.insert("Subtract", NODE_VECTOR_MATH_SUBTRACT); + enm.insert("Average", NODE_VECTOR_MATH_AVERAGE); + enm.insert("Dot Product", NODE_VECTOR_MATH_DOT_PRODUCT); + enm.insert("Cross Product", NODE_VECTOR_MATH_CROSS_PRODUCT); + enm.insert("Normalize", NODE_VECTOR_MATH_NORMALIZE); + + return enm; +} + +ShaderEnum VectorMathNode::type_enum = vector_math_type_init(); + +void VectorMathNode::compile(SVMCompiler& compiler) +{ + ShaderInput *vector1_in = input("Vector1"); + ShaderInput *vector2_in = input("Vector2"); + ShaderOutput *fac_out = output("Fac"); + ShaderOutput *vector_out = output("Vector"); + + compiler.stack_assign(vector1_in); + compiler.stack_assign(vector2_in); + compiler.stack_assign(fac_out); + compiler.stack_assign(vector_out); + + compiler.add_node(NODE_VECTOR_MATH, type_enum[type], vector1_in->stack_offset, vector2_in->stack_offset); + compiler.add_node(NODE_VECTOR_MATH, fac_out->stack_offset, vector_out->stack_offset); +} + +void VectorMathNode::compile(OSLCompiler& compiler) +{ + compiler.parameter("type", type); + compiler.add(this, "node_vector_math"); +} + +/* BumpNode */ + +BumpNode::BumpNode() +: ShaderNode("bump") +{ + add_input("SampleCenter", SHADER_SOCKET_FLOAT); + add_input("SampleX", SHADER_SOCKET_FLOAT); + add_input("SampleY", SHADER_SOCKET_FLOAT); + + add_output("Normal", SHADER_SOCKET_NORMAL); +} + +void BumpNode::compile(SVMCompiler& compiler) +{ + ShaderInput *center_in = input("SampleCenter"); + ShaderInput *dx_in = input("SampleX"); + ShaderInput *dy_in = input("SampleY"); + + compiler.stack_assign(center_in); + compiler.stack_assign(dx_in); + compiler.stack_assign(dy_in); + + compiler.add_node(NODE_SET_BUMP, center_in->stack_offset, dx_in->stack_offset, dy_in->stack_offset); +} + +void BumpNode::compile(OSLCompiler& compiler) +{ + compiler.add(this, "node_bump"); +} + +CCL_NAMESPACE_END + |