7064 lines
		
	
	
		
			216 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			7064 lines
		
	
	
		
			216 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/*
 | 
						|
 * Copyright 2011-2013 Blender Foundation
 | 
						|
 *
 | 
						|
 * Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
 * you may not use this file except in compliance with the License.
 | 
						|
 * You may obtain a copy of the License at
 | 
						|
 *
 | 
						|
 * http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
 *
 | 
						|
 * Unless required by applicable law or agreed to in writing, software
 | 
						|
 * distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
 * See the License for the specific language governing permissions and
 | 
						|
 * limitations under the License.
 | 
						|
 */
 | 
						|
 | 
						|
#include "render/nodes.h"
 | 
						|
#include "render/colorspace.h"
 | 
						|
#include "render/constant_fold.h"
 | 
						|
#include "render/film.h"
 | 
						|
#include "render/image.h"
 | 
						|
#include "render/image_sky.h"
 | 
						|
#include "render/integrator.h"
 | 
						|
#include "render/light.h"
 | 
						|
#include "render/mesh.h"
 | 
						|
#include "render/osl.h"
 | 
						|
#include "render/scene.h"
 | 
						|
#include "render/svm.h"
 | 
						|
 | 
						|
#include "sky_model.h"
 | 
						|
 | 
						|
#include "util/util_foreach.h"
 | 
						|
#include "util/util_logging.h"
 | 
						|
#include "util/util_transform.h"
 | 
						|
 | 
						|
#include "kernel/svm/svm_color_util.h"
 | 
						|
#include "kernel/svm/svm_mapping_util.h"
 | 
						|
#include "kernel/svm/svm_math_util.h"
 | 
						|
#include "kernel/svm/svm_ramp_util.h"
 | 
						|
 | 
						|
CCL_NAMESPACE_BEGIN
 | 
						|
 | 
						|
/* Texture Mapping */
 | 
						|
 | 
						|
#define TEXTURE_MAPPING_DEFINE(TextureNode) \
 | 
						|
  SOCKET_POINT(tex_mapping.translation, "Translation", make_float3(0.0f, 0.0f, 0.0f)); \
 | 
						|
  SOCKET_VECTOR(tex_mapping.rotation, "Rotation", make_float3(0.0f, 0.0f, 0.0f)); \
 | 
						|
  SOCKET_VECTOR(tex_mapping.scale, "Scale", make_float3(1.0f, 1.0f, 1.0f)); \
 | 
						|
\
 | 
						|
  SOCKET_VECTOR(tex_mapping.min, "Min", make_float3(-FLT_MAX, -FLT_MAX, -FLT_MAX)); \
 | 
						|
  SOCKET_VECTOR(tex_mapping.max, "Max", make_float3(FLT_MAX, FLT_MAX, FLT_MAX)); \
 | 
						|
  SOCKET_BOOLEAN(tex_mapping.use_minmax, "Use Min Max", false); \
 | 
						|
\
 | 
						|
  static NodeEnum mapping_axis_enum; \
 | 
						|
  mapping_axis_enum.insert("none", TextureMapping::NONE); \
 | 
						|
  mapping_axis_enum.insert("x", TextureMapping::X); \
 | 
						|
  mapping_axis_enum.insert("y", TextureMapping::Y); \
 | 
						|
  mapping_axis_enum.insert("z", TextureMapping::Z); \
 | 
						|
  SOCKET_ENUM(tex_mapping.x_mapping, "x_mapping", mapping_axis_enum, TextureMapping::X); \
 | 
						|
  SOCKET_ENUM(tex_mapping.y_mapping, "y_mapping", mapping_axis_enum, TextureMapping::Y); \
 | 
						|
  SOCKET_ENUM(tex_mapping.z_mapping, "z_mapping", mapping_axis_enum, TextureMapping::Z); \
 | 
						|
\
 | 
						|
  static NodeEnum mapping_type_enum; \
 | 
						|
  mapping_type_enum.insert("point", TextureMapping::POINT); \
 | 
						|
  mapping_type_enum.insert("texture", TextureMapping::TEXTURE); \
 | 
						|
  mapping_type_enum.insert("vector", TextureMapping::VECTOR); \
 | 
						|
  mapping_type_enum.insert("normal", TextureMapping::NORMAL); \
 | 
						|
  SOCKET_ENUM(tex_mapping.type, "Type", mapping_type_enum, TextureMapping::TEXTURE); \
 | 
						|
\
 | 
						|
  static NodeEnum mapping_projection_enum; \
 | 
						|
  mapping_projection_enum.insert("flat", TextureMapping::FLAT); \
 | 
						|
  mapping_projection_enum.insert("cube", TextureMapping::CUBE); \
 | 
						|
  mapping_projection_enum.insert("tube", TextureMapping::TUBE); \
 | 
						|
  mapping_projection_enum.insert("sphere", TextureMapping::SPHERE); \
 | 
						|
  SOCKET_ENUM(tex_mapping.projection, "Projection", mapping_projection_enum, TextureMapping::FLAT);
 | 
						|
 | 
						|
TextureMapping::TextureMapping()
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
Transform TextureMapping::compute_transform()
 | 
						|
{
 | 
						|
  Transform mmat = transform_scale(make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
 | 
						|
  if (x_mapping != NONE)
 | 
						|
    mmat[0][x_mapping - 1] = 1.0f;
 | 
						|
  if (y_mapping != NONE)
 | 
						|
    mmat[1][y_mapping - 1] = 1.0f;
 | 
						|
  if (z_mapping != NONE)
 | 
						|
    mmat[2][z_mapping - 1] = 1.0f;
 | 
						|
 | 
						|
  float3 scale_clamped = scale;
 | 
						|
 | 
						|
  if (type == TEXTURE || type == NORMAL) {
 | 
						|
    /* keep matrix invertible */
 | 
						|
    if (fabsf(scale.x) < 1e-5f)
 | 
						|
      scale_clamped.x = signf(scale.x) * 1e-5f;
 | 
						|
    if (fabsf(scale.y) < 1e-5f)
 | 
						|
      scale_clamped.y = signf(scale.y) * 1e-5f;
 | 
						|
    if (fabsf(scale.z) < 1e-5f)
 | 
						|
      scale_clamped.z = signf(scale.z) * 1e-5f;
 | 
						|
  }
 | 
						|
 | 
						|
  Transform smat = transform_scale(scale_clamped);
 | 
						|
  Transform rmat = transform_euler(rotation);
 | 
						|
  Transform tmat = transform_translate(translation);
 | 
						|
 | 
						|
  Transform mat;
 | 
						|
 | 
						|
  switch (type) {
 | 
						|
    case TEXTURE:
 | 
						|
      /* inverse transform on texture coordinate gives
 | 
						|
       * forward transform on texture */
 | 
						|
      mat = tmat * rmat * smat;
 | 
						|
      mat = transform_inverse(mat);
 | 
						|
      break;
 | 
						|
    case POINT:
 | 
						|
      /* full transform */
 | 
						|
      mat = tmat * rmat * smat;
 | 
						|
      break;
 | 
						|
    case VECTOR:
 | 
						|
      /* no translation for vectors */
 | 
						|
      mat = rmat * smat;
 | 
						|
      break;
 | 
						|
    case NORMAL:
 | 
						|
      /* no translation for normals, and inverse transpose */
 | 
						|
      mat = rmat * smat;
 | 
						|
      mat = transform_transposed_inverse(mat);
 | 
						|
      break;
 | 
						|
  }
 | 
						|
 | 
						|
  /* projection last */
 | 
						|
  mat = mat * mmat;
 | 
						|
 | 
						|
  return mat;
 | 
						|
}
 | 
						|
 | 
						|
bool TextureMapping::skip()
 | 
						|
{
 | 
						|
  if (translation != make_float3(0.0f, 0.0f, 0.0f))
 | 
						|
    return false;
 | 
						|
  if (rotation != make_float3(0.0f, 0.0f, 0.0f))
 | 
						|
    return false;
 | 
						|
  if (scale != make_float3(1.0f, 1.0f, 1.0f))
 | 
						|
    return false;
 | 
						|
 | 
						|
  if (x_mapping != X || y_mapping != Y || z_mapping != Z)
 | 
						|
    return false;
 | 
						|
  if (use_minmax)
 | 
						|
    return false;
 | 
						|
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
void TextureMapping::compile(SVMCompiler &compiler, int offset_in, int offset_out)
 | 
						|
{
 | 
						|
  compiler.add_node(NODE_TEXTURE_MAPPING, offset_in, offset_out);
 | 
						|
 | 
						|
  Transform tfm = compute_transform();
 | 
						|
  compiler.add_node(tfm.x);
 | 
						|
  compiler.add_node(tfm.y);
 | 
						|
  compiler.add_node(tfm.z);
 | 
						|
 | 
						|
  if (use_minmax) {
 | 
						|
    compiler.add_node(NODE_MIN_MAX, offset_out, offset_out);
 | 
						|
    compiler.add_node(float3_to_float4(min));
 | 
						|
    compiler.add_node(float3_to_float4(max));
 | 
						|
  }
 | 
						|
 | 
						|
  if (type == NORMAL) {
 | 
						|
    compiler.add_node(NODE_VECTOR_MATH,
 | 
						|
                      NODE_VECTOR_MATH_NORMALIZE,
 | 
						|
                      compiler.encode_uchar4(offset_out, offset_out, offset_out),
 | 
						|
                      compiler.encode_uchar4(SVM_STACK_INVALID, offset_out));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* Convenience function for texture nodes, allocating stack space to output
 | 
						|
 * a modified vector and returning its offset */
 | 
						|
int TextureMapping::compile_begin(SVMCompiler &compiler, ShaderInput *vector_in)
 | 
						|
{
 | 
						|
  if (!skip()) {
 | 
						|
    int offset_in = compiler.stack_assign(vector_in);
 | 
						|
    int offset_out = compiler.stack_find_offset(SocketType::VECTOR);
 | 
						|
 | 
						|
    compile(compiler, offset_in, offset_out);
 | 
						|
 | 
						|
    return offset_out;
 | 
						|
  }
 | 
						|
 | 
						|
  return compiler.stack_assign(vector_in);
 | 
						|
}
 | 
						|
 | 
						|
void TextureMapping::compile_end(SVMCompiler &compiler, ShaderInput *vector_in, int vector_offset)
 | 
						|
{
 | 
						|
  if (!skip()) {
 | 
						|
    compiler.stack_clear_offset(vector_in->type(), vector_offset);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void TextureMapping::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  if (!skip()) {
 | 
						|
    compiler.parameter("mapping", compute_transform());
 | 
						|
    compiler.parameter("use_mapping", 1);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* Image Texture */
 | 
						|
 | 
						|
NODE_DEFINE(ImageTextureNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("image_texture", create, NodeType::SHADER);
 | 
						|
 | 
						|
  TEXTURE_MAPPING_DEFINE(ImageTextureNode);
 | 
						|
 | 
						|
  SOCKET_STRING(filename, "Filename", ustring());
 | 
						|
  SOCKET_STRING(colorspace, "Colorspace", u_colorspace_auto);
 | 
						|
 | 
						|
  static NodeEnum alpha_type_enum;
 | 
						|
  alpha_type_enum.insert("auto", IMAGE_ALPHA_AUTO);
 | 
						|
  alpha_type_enum.insert("unassociated", IMAGE_ALPHA_UNASSOCIATED);
 | 
						|
  alpha_type_enum.insert("associated", IMAGE_ALPHA_ASSOCIATED);
 | 
						|
  alpha_type_enum.insert("channel_packed", IMAGE_ALPHA_CHANNEL_PACKED);
 | 
						|
  alpha_type_enum.insert("ignore", IMAGE_ALPHA_IGNORE);
 | 
						|
  SOCKET_ENUM(alpha_type, "Alpha Type", alpha_type_enum, IMAGE_ALPHA_AUTO);
 | 
						|
 | 
						|
  static NodeEnum interpolation_enum;
 | 
						|
  interpolation_enum.insert("closest", INTERPOLATION_CLOSEST);
 | 
						|
  interpolation_enum.insert("linear", INTERPOLATION_LINEAR);
 | 
						|
  interpolation_enum.insert("cubic", INTERPOLATION_CUBIC);
 | 
						|
  interpolation_enum.insert("smart", INTERPOLATION_SMART);
 | 
						|
  SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR);
 | 
						|
 | 
						|
  static NodeEnum extension_enum;
 | 
						|
  extension_enum.insert("periodic", EXTENSION_REPEAT);
 | 
						|
  extension_enum.insert("clamp", EXTENSION_EXTEND);
 | 
						|
  extension_enum.insert("black", EXTENSION_CLIP);
 | 
						|
  SOCKET_ENUM(extension, "Extension", extension_enum, EXTENSION_REPEAT);
 | 
						|
 | 
						|
  static NodeEnum projection_enum;
 | 
						|
  projection_enum.insert("flat", NODE_IMAGE_PROJ_FLAT);
 | 
						|
  projection_enum.insert("box", NODE_IMAGE_PROJ_BOX);
 | 
						|
  projection_enum.insert("sphere", NODE_IMAGE_PROJ_SPHERE);
 | 
						|
  projection_enum.insert("tube", NODE_IMAGE_PROJ_TUBE);
 | 
						|
  SOCKET_ENUM(projection, "Projection", projection_enum, NODE_IMAGE_PROJ_FLAT);
 | 
						|
 | 
						|
  SOCKET_FLOAT(projection_blend, "Projection Blend", 0.0f);
 | 
						|
 | 
						|
  SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_UV);
 | 
						|
 | 
						|
  SOCKET_OUT_COLOR(color, "Color");
 | 
						|
  SOCKET_OUT_FLOAT(alpha, "Alpha");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
ImageTextureNode::ImageTextureNode() : ImageSlotTextureNode(node_type)
 | 
						|
{
 | 
						|
  colorspace = u_colorspace_raw;
 | 
						|
  animated = false;
 | 
						|
  tiles.push_back(1001);
 | 
						|
}
 | 
						|
 | 
						|
ShaderNode *ImageTextureNode::clone() const
 | 
						|
{
 | 
						|
  ImageTextureNode *node = new ImageTextureNode(*this);
 | 
						|
  node->handle = handle;
 | 
						|
  return node;
 | 
						|
}
 | 
						|
 | 
						|
ImageParams ImageTextureNode::image_params() const
 | 
						|
{
 | 
						|
  ImageParams params;
 | 
						|
  params.animated = animated;
 | 
						|
  params.interpolation = interpolation;
 | 
						|
  params.extension = extension;
 | 
						|
  params.alpha_type = alpha_type;
 | 
						|
  params.colorspace = colorspace;
 | 
						|
  return params;
 | 
						|
}
 | 
						|
 | 
						|
void ImageTextureNode::cull_tiles(Scene *scene, ShaderGraph *graph)
 | 
						|
{
 | 
						|
  /* Box projection computes its own UVs that always lie in the
 | 
						|
   * 1001 tile, so there's no point in loading any others. */
 | 
						|
  if (projection == NODE_IMAGE_PROJ_BOX) {
 | 
						|
    tiles.clear();
 | 
						|
    tiles.push_back(1001);
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!scene->params.background) {
 | 
						|
    /* During interactive renders, all tiles are loaded.
 | 
						|
     * While we could support updating this when UVs change, that could lead
 | 
						|
     * to annoying interruptions when loading images while editing UVs. */
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  /* Only check UVs for tile culling if there are multiple tiles. */
 | 
						|
  if (tiles.size() < 2) {
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  ShaderInput *vector_in = input("Vector");
 | 
						|
  ustring attribute;
 | 
						|
  if (vector_in->link) {
 | 
						|
    ShaderNode *node = vector_in->link->parent;
 | 
						|
    if (node->type == UVMapNode::node_type) {
 | 
						|
      UVMapNode *uvmap = (UVMapNode *)node;
 | 
						|
      attribute = uvmap->attribute;
 | 
						|
    }
 | 
						|
    else if (node->type == TextureCoordinateNode::node_type) {
 | 
						|
      if (vector_in->link != node->output("UV")) {
 | 
						|
        return;
 | 
						|
      }
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  unordered_set<int> used_tiles;
 | 
						|
  /* TODO(lukas): This is quite inefficient. A fairly simple improvement would
 | 
						|
   * be to have a cache in each mesh that is indexed by attribute.
 | 
						|
   * Additionally, building a graph-to-meshes list once could help. */
 | 
						|
  foreach (Geometry *geom, scene->geometry) {
 | 
						|
    foreach (Shader *shader, geom->used_shaders) {
 | 
						|
      if (shader->graph == graph) {
 | 
						|
        geom->get_uv_tiles(attribute, used_tiles);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  ccl::vector<int> new_tiles;
 | 
						|
  foreach (int tile, tiles) {
 | 
						|
    if (used_tiles.count(tile)) {
 | 
						|
      new_tiles.push_back(tile);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  tiles.swap(new_tiles);
 | 
						|
}
 | 
						|
 | 
						|
void ImageTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 | 
						|
{
 | 
						|
#ifdef WITH_PTEX
 | 
						|
  /* todo: avoid loading other texture coordinates when using ptex,
 | 
						|
   * and hide texture coordinate socket in the UI */
 | 
						|
  if (shader->has_surface && string_endswith(filename, ".ptx")) {
 | 
						|
    /* ptex */
 | 
						|
    attributes->add(ATTR_STD_PTEX_FACE_ID);
 | 
						|
    attributes->add(ATTR_STD_PTEX_UV);
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  ShaderNode::attributes(shader, attributes);
 | 
						|
}
 | 
						|
 | 
						|
void ImageTextureNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *vector_in = input("Vector");
 | 
						|
  ShaderOutput *color_out = output("Color");
 | 
						|
  ShaderOutput *alpha_out = output("Alpha");
 | 
						|
 | 
						|
  if (handle.empty()) {
 | 
						|
    cull_tiles(compiler.scene, compiler.current_graph);
 | 
						|
    ImageManager *image_manager = compiler.scene->image_manager;
 | 
						|
    handle = image_manager->add_image(filename.string(), image_params(), tiles);
 | 
						|
  }
 | 
						|
 | 
						|
  /* All tiles have the same metadata. */
 | 
						|
  const ImageMetaData metadata = handle.metadata();
 | 
						|
  const bool compress_as_srgb = metadata.compress_as_srgb;
 | 
						|
  const ustring known_colorspace = metadata.colorspace;
 | 
						|
 | 
						|
  int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
 | 
						|
  uint flags = 0;
 | 
						|
 | 
						|
  if (compress_as_srgb) {
 | 
						|
    flags |= NODE_IMAGE_COMPRESS_AS_SRGB;
 | 
						|
  }
 | 
						|
  if (!alpha_out->links.empty()) {
 | 
						|
    const bool unassociate_alpha = !(ColorSpaceManager::colorspace_is_data(colorspace) ||
 | 
						|
                                     alpha_type == IMAGE_ALPHA_CHANNEL_PACKED ||
 | 
						|
                                     alpha_type == IMAGE_ALPHA_IGNORE);
 | 
						|
 | 
						|
    if (unassociate_alpha) {
 | 
						|
      flags |= NODE_IMAGE_ALPHA_UNASSOCIATE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (projection != NODE_IMAGE_PROJ_BOX) {
 | 
						|
    /* If there only is one image (a very common case), we encode it as a negative value. */
 | 
						|
    int num_nodes;
 | 
						|
    if (handle.num_tiles() == 1) {
 | 
						|
      num_nodes = -handle.svm_slot();
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      num_nodes = divide_up(handle.num_tiles(), 2);
 | 
						|
    }
 | 
						|
 | 
						|
    compiler.add_node(NODE_TEX_IMAGE,
 | 
						|
                      num_nodes,
 | 
						|
                      compiler.encode_uchar4(vector_offset,
 | 
						|
                                             compiler.stack_assign_if_linked(color_out),
 | 
						|
                                             compiler.stack_assign_if_linked(alpha_out),
 | 
						|
                                             flags),
 | 
						|
                      projection);
 | 
						|
 | 
						|
    if (num_nodes > 0) {
 | 
						|
      for (int i = 0; i < num_nodes; i++) {
 | 
						|
        int4 node;
 | 
						|
        node.x = tiles[2 * i];
 | 
						|
        node.y = handle.svm_slot(2 * i);
 | 
						|
        if (2 * i + 1 < tiles.size()) {
 | 
						|
          node.z = tiles[2 * i + 1];
 | 
						|
          node.w = handle.svm_slot(2 * i + 1);
 | 
						|
        }
 | 
						|
        else {
 | 
						|
          node.z = -1;
 | 
						|
          node.w = -1;
 | 
						|
        }
 | 
						|
        compiler.add_node(node.x, node.y, node.z, node.w);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    assert(handle.num_tiles() == 1);
 | 
						|
    compiler.add_node(NODE_TEX_IMAGE_BOX,
 | 
						|
                      handle.svm_slot(),
 | 
						|
                      compiler.encode_uchar4(vector_offset,
 | 
						|
                                             compiler.stack_assign_if_linked(color_out),
 | 
						|
                                             compiler.stack_assign_if_linked(alpha_out),
 | 
						|
                                             flags),
 | 
						|
                      __float_as_int(projection_blend));
 | 
						|
  }
 | 
						|
 | 
						|
  tex_mapping.compile_end(compiler, vector_in, vector_offset);
 | 
						|
}
 | 
						|
 | 
						|
void ImageTextureNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderOutput *alpha_out = output("Alpha");
 | 
						|
 | 
						|
  tex_mapping.compile(compiler);
 | 
						|
 | 
						|
  if (handle.empty()) {
 | 
						|
    ImageManager *image_manager = compiler.scene->image_manager;
 | 
						|
    handle = image_manager->add_image(filename.string(), image_params());
 | 
						|
  }
 | 
						|
 | 
						|
  const ImageMetaData metadata = handle.metadata();
 | 
						|
  const bool is_float = metadata.is_float();
 | 
						|
  const bool compress_as_srgb = metadata.compress_as_srgb;
 | 
						|
  const ustring known_colorspace = metadata.colorspace;
 | 
						|
 | 
						|
  if (handle.svm_slot() == -1) {
 | 
						|
    compiler.parameter_texture(
 | 
						|
        "filename", filename, compress_as_srgb ? u_colorspace_raw : known_colorspace);
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    compiler.parameter_texture("filename", handle.svm_slot());
 | 
						|
  }
 | 
						|
 | 
						|
  const bool unassociate_alpha = !(ColorSpaceManager::colorspace_is_data(colorspace) ||
 | 
						|
                                   alpha_type == IMAGE_ALPHA_CHANNEL_PACKED ||
 | 
						|
                                   alpha_type == IMAGE_ALPHA_IGNORE);
 | 
						|
  const bool is_tiled = (filename.find("<UDIM>") != string::npos);
 | 
						|
 | 
						|
  compiler.parameter(this, "projection");
 | 
						|
  compiler.parameter(this, "projection_blend");
 | 
						|
  compiler.parameter("compress_as_srgb", compress_as_srgb);
 | 
						|
  compiler.parameter("ignore_alpha", alpha_type == IMAGE_ALPHA_IGNORE);
 | 
						|
  compiler.parameter("unassociate_alpha", !alpha_out->links.empty() && unassociate_alpha);
 | 
						|
  compiler.parameter("is_float", is_float);
 | 
						|
  compiler.parameter("is_tiled", is_tiled);
 | 
						|
  compiler.parameter(this, "interpolation");
 | 
						|
  compiler.parameter(this, "extension");
 | 
						|
 | 
						|
  compiler.add(this, "node_image_texture");
 | 
						|
}
 | 
						|
 | 
						|
/* Environment Texture */
 | 
						|
 | 
						|
NODE_DEFINE(EnvironmentTextureNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("environment_texture", create, NodeType::SHADER);
 | 
						|
 | 
						|
  TEXTURE_MAPPING_DEFINE(EnvironmentTextureNode);
 | 
						|
 | 
						|
  SOCKET_STRING(filename, "Filename", ustring());
 | 
						|
  SOCKET_STRING(colorspace, "Colorspace", u_colorspace_auto);
 | 
						|
 | 
						|
  static NodeEnum alpha_type_enum;
 | 
						|
  alpha_type_enum.insert("auto", IMAGE_ALPHA_AUTO);
 | 
						|
  alpha_type_enum.insert("unassociated", IMAGE_ALPHA_UNASSOCIATED);
 | 
						|
  alpha_type_enum.insert("associated", IMAGE_ALPHA_ASSOCIATED);
 | 
						|
  alpha_type_enum.insert("channel_packed", IMAGE_ALPHA_CHANNEL_PACKED);
 | 
						|
  alpha_type_enum.insert("ignore", IMAGE_ALPHA_IGNORE);
 | 
						|
  SOCKET_ENUM(alpha_type, "Alpha Type", alpha_type_enum, IMAGE_ALPHA_AUTO);
 | 
						|
 | 
						|
  static NodeEnum interpolation_enum;
 | 
						|
  interpolation_enum.insert("closest", INTERPOLATION_CLOSEST);
 | 
						|
  interpolation_enum.insert("linear", INTERPOLATION_LINEAR);
 | 
						|
  interpolation_enum.insert("cubic", INTERPOLATION_CUBIC);
 | 
						|
  interpolation_enum.insert("smart", INTERPOLATION_SMART);
 | 
						|
  SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR);
 | 
						|
 | 
						|
  static NodeEnum projection_enum;
 | 
						|
  projection_enum.insert("equirectangular", NODE_ENVIRONMENT_EQUIRECTANGULAR);
 | 
						|
  projection_enum.insert("mirror_ball", NODE_ENVIRONMENT_MIRROR_BALL);
 | 
						|
  SOCKET_ENUM(projection, "Projection", projection_enum, NODE_ENVIRONMENT_EQUIRECTANGULAR);
 | 
						|
 | 
						|
  SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_POSITION);
 | 
						|
 | 
						|
  SOCKET_OUT_COLOR(color, "Color");
 | 
						|
  SOCKET_OUT_FLOAT(alpha, "Alpha");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
EnvironmentTextureNode::EnvironmentTextureNode() : ImageSlotTextureNode(node_type)
 | 
						|
{
 | 
						|
  colorspace = u_colorspace_raw;
 | 
						|
  animated = false;
 | 
						|
}
 | 
						|
 | 
						|
ShaderNode *EnvironmentTextureNode::clone() const
 | 
						|
{
 | 
						|
  EnvironmentTextureNode *node = new EnvironmentTextureNode(*this);
 | 
						|
  node->handle = handle;
 | 
						|
  return node;
 | 
						|
}
 | 
						|
 | 
						|
ImageParams EnvironmentTextureNode::image_params() const
 | 
						|
{
 | 
						|
  ImageParams params;
 | 
						|
  params.animated = animated;
 | 
						|
  params.interpolation = interpolation;
 | 
						|
  params.extension = EXTENSION_REPEAT;
 | 
						|
  params.alpha_type = alpha_type;
 | 
						|
  params.colorspace = colorspace;
 | 
						|
  return params;
 | 
						|
}
 | 
						|
 | 
						|
void EnvironmentTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 | 
						|
{
 | 
						|
#ifdef WITH_PTEX
 | 
						|
  if (shader->has_surface && string_endswith(filename, ".ptx")) {
 | 
						|
    /* ptex */
 | 
						|
    attributes->add(ATTR_STD_PTEX_FACE_ID);
 | 
						|
    attributes->add(ATTR_STD_PTEX_UV);
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  ShaderNode::attributes(shader, attributes);
 | 
						|
}
 | 
						|
 | 
						|
void EnvironmentTextureNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *vector_in = input("Vector");
 | 
						|
  ShaderOutput *color_out = output("Color");
 | 
						|
  ShaderOutput *alpha_out = output("Alpha");
 | 
						|
 | 
						|
  if (handle.empty()) {
 | 
						|
    ImageManager *image_manager = compiler.scene->image_manager;
 | 
						|
    handle = image_manager->add_image(filename.string(), image_params());
 | 
						|
  }
 | 
						|
 | 
						|
  const ImageMetaData metadata = handle.metadata();
 | 
						|
  const bool compress_as_srgb = metadata.compress_as_srgb;
 | 
						|
  const ustring known_colorspace = metadata.colorspace;
 | 
						|
 | 
						|
  int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
 | 
						|
  uint flags = 0;
 | 
						|
 | 
						|
  if (compress_as_srgb) {
 | 
						|
    flags |= NODE_IMAGE_COMPRESS_AS_SRGB;
 | 
						|
  }
 | 
						|
 | 
						|
  compiler.add_node(NODE_TEX_ENVIRONMENT,
 | 
						|
                    handle.svm_slot(),
 | 
						|
                    compiler.encode_uchar4(vector_offset,
 | 
						|
                                           compiler.stack_assign_if_linked(color_out),
 | 
						|
                                           compiler.stack_assign_if_linked(alpha_out),
 | 
						|
                                           flags),
 | 
						|
                    projection);
 | 
						|
 | 
						|
  tex_mapping.compile_end(compiler, vector_in, vector_offset);
 | 
						|
}
 | 
						|
 | 
						|
void EnvironmentTextureNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  if (handle.empty()) {
 | 
						|
    ImageManager *image_manager = compiler.scene->image_manager;
 | 
						|
    handle = image_manager->add_image(filename.string(), image_params());
 | 
						|
  }
 | 
						|
 | 
						|
  tex_mapping.compile(compiler);
 | 
						|
 | 
						|
  const ImageMetaData metadata = handle.metadata();
 | 
						|
  const bool is_float = metadata.is_float();
 | 
						|
  const bool compress_as_srgb = metadata.compress_as_srgb;
 | 
						|
  const ustring known_colorspace = metadata.colorspace;
 | 
						|
 | 
						|
  if (handle.svm_slot() == -1) {
 | 
						|
    compiler.parameter_texture(
 | 
						|
        "filename", filename, compress_as_srgb ? u_colorspace_raw : known_colorspace);
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    compiler.parameter_texture("filename", handle.svm_slot());
 | 
						|
  }
 | 
						|
 | 
						|
  compiler.parameter(this, "projection");
 | 
						|
  compiler.parameter(this, "interpolation");
 | 
						|
  compiler.parameter("compress_as_srgb", compress_as_srgb);
 | 
						|
  compiler.parameter("ignore_alpha", alpha_type == IMAGE_ALPHA_IGNORE);
 | 
						|
  compiler.parameter("is_float", is_float);
 | 
						|
  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));
 | 
						|
}
 | 
						|
 | 
						|
typedef struct SunSky {
 | 
						|
  /* sun direction in spherical and cartesian */
 | 
						|
  float theta, phi;
 | 
						|
 | 
						|
  /* Parameter */
 | 
						|
  float radiance_x, radiance_y, radiance_z;
 | 
						|
  float config_x[9], config_y[9], config_z[9], nishita_data[10];
 | 
						|
} SunSky;
 | 
						|
 | 
						|
/* Preetham model */
 | 
						|
static float sky_perez_function(float lam[6], float theta, float gamma)
 | 
						|
{
 | 
						|
  return (1.0f + lam[0] * expf(lam[1] / cosf(theta))) *
 | 
						|
         (1.0f + lam[2] * expf(lam[3] * gamma) + lam[4] * cosf(gamma) * cosf(gamma));
 | 
						|
}
 | 
						|
 | 
						|
static void sky_texture_precompute_preetham(SunSky *sunsky, float3 dir, float turbidity)
 | 
						|
{
 | 
						|
  /*
 | 
						|
   * We re-use the SunSky struct of the new model, to avoid extra variables
 | 
						|
   * zenith_Y/x/y is now radiance_x/y/z
 | 
						|
   * perez_Y/x/y is now config_x/y/z
 | 
						|
   */
 | 
						|
 | 
						|
  float2 spherical = sky_spherical_coordinates(dir);
 | 
						|
  float theta = spherical.x;
 | 
						|
  float phi = spherical.y;
 | 
						|
 | 
						|
  sunsky->theta = theta;
 | 
						|
  sunsky->phi = phi;
 | 
						|
 | 
						|
  float theta2 = theta * theta;
 | 
						|
  float theta3 = theta2 * theta;
 | 
						|
  float T = turbidity;
 | 
						|
  float T2 = T * T;
 | 
						|
 | 
						|
  float chi = (4.0f / 9.0f - T / 120.0f) * (M_PI_F - 2.0f * theta);
 | 
						|
  sunsky->radiance_x = (4.0453f * T - 4.9710f) * tanf(chi) - 0.2155f * T + 2.4192f;
 | 
						|
  sunsky->radiance_x *= 0.06f;
 | 
						|
 | 
						|
  sunsky->radiance_y = (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);
 | 
						|
 | 
						|
  sunsky->radiance_z = (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);
 | 
						|
 | 
						|
  sunsky->config_x[0] = (0.1787f * T - 1.4630f);
 | 
						|
  sunsky->config_x[1] = (-0.3554f * T + 0.4275f);
 | 
						|
  sunsky->config_x[2] = (-0.0227f * T + 5.3251f);
 | 
						|
  sunsky->config_x[3] = (0.1206f * T - 2.5771f);
 | 
						|
  sunsky->config_x[4] = (-0.0670f * T + 0.3703f);
 | 
						|
 | 
						|
  sunsky->config_y[0] = (-0.0193f * T - 0.2592f);
 | 
						|
  sunsky->config_y[1] = (-0.0665f * T + 0.0008f);
 | 
						|
  sunsky->config_y[2] = (-0.0004f * T + 0.2125f);
 | 
						|
  sunsky->config_y[3] = (-0.0641f * T - 0.8989f);
 | 
						|
  sunsky->config_y[4] = (-0.0033f * T + 0.0452f);
 | 
						|
 | 
						|
  sunsky->config_z[0] = (-0.0167f * T - 0.2608f);
 | 
						|
  sunsky->config_z[1] = (-0.0950f * T + 0.0092f);
 | 
						|
  sunsky->config_z[2] = (-0.0079f * T + 0.2102f);
 | 
						|
  sunsky->config_z[3] = (-0.0441f * T - 1.6537f);
 | 
						|
  sunsky->config_z[4] = (-0.0109f * T + 0.0529f);
 | 
						|
 | 
						|
  /* unused for old sky model */
 | 
						|
  for (int i = 5; i < 9; i++) {
 | 
						|
    sunsky->config_x[i] = 0.0f;
 | 
						|
    sunsky->config_y[i] = 0.0f;
 | 
						|
    sunsky->config_z[i] = 0.0f;
 | 
						|
  }
 | 
						|
 | 
						|
  sunsky->radiance_x /= sky_perez_function(sunsky->config_x, 0, theta);
 | 
						|
  sunsky->radiance_y /= sky_perez_function(sunsky->config_y, 0, theta);
 | 
						|
  sunsky->radiance_z /= sky_perez_function(sunsky->config_z, 0, theta);
 | 
						|
}
 | 
						|
 | 
						|
/* Hosek / Wilkie */
 | 
						|
static void sky_texture_precompute_hosek(SunSky *sunsky,
 | 
						|
                                         float3 dir,
 | 
						|
                                         float turbidity,
 | 
						|
                                         float ground_albedo)
 | 
						|
{
 | 
						|
  /* Calculate Sun Direction and save coordinates */
 | 
						|
  float2 spherical = sky_spherical_coordinates(dir);
 | 
						|
  float theta = spherical.x;
 | 
						|
  float phi = spherical.y;
 | 
						|
 | 
						|
  /* Clamp Turbidity */
 | 
						|
  turbidity = clamp(turbidity, 0.0f, 10.0f);
 | 
						|
 | 
						|
  /* Clamp to Horizon */
 | 
						|
  theta = clamp(theta, 0.0f, M_PI_2_F);
 | 
						|
 | 
						|
  sunsky->theta = theta;
 | 
						|
  sunsky->phi = phi;
 | 
						|
 | 
						|
  float solarElevation = M_PI_2_F - theta;
 | 
						|
 | 
						|
  /* Initialize Sky Model */
 | 
						|
  SKY_ArHosekSkyModelState *sky_state;
 | 
						|
  sky_state = SKY_arhosek_xyz_skymodelstate_alloc_init(
 | 
						|
      (double)turbidity, (double)ground_albedo, (double)solarElevation);
 | 
						|
 | 
						|
  /* Copy values from sky_state to SunSky */
 | 
						|
  for (int i = 0; i < 9; ++i) {
 | 
						|
    sunsky->config_x[i] = (float)sky_state->configs[0][i];
 | 
						|
    sunsky->config_y[i] = (float)sky_state->configs[1][i];
 | 
						|
    sunsky->config_z[i] = (float)sky_state->configs[2][i];
 | 
						|
  }
 | 
						|
  sunsky->radiance_x = (float)sky_state->radiances[0];
 | 
						|
  sunsky->radiance_y = (float)sky_state->radiances[1];
 | 
						|
  sunsky->radiance_z = (float)sky_state->radiances[2];
 | 
						|
 | 
						|
  /* Free sky_state */
 | 
						|
  SKY_arhosekskymodelstate_free(sky_state);
 | 
						|
}
 | 
						|
 | 
						|
/* Nishita improved */
 | 
						|
static void sky_texture_precompute_nishita(SunSky *sunsky,
 | 
						|
                                           bool sun_disc,
 | 
						|
                                           float sun_size,
 | 
						|
                                           float sun_intensity,
 | 
						|
                                           float sun_elevation,
 | 
						|
                                           float sun_rotation,
 | 
						|
                                           float altitude,
 | 
						|
                                           float air_density,
 | 
						|
                                           float dust_density)
 | 
						|
{
 | 
						|
  /* sample 2 sun pixels */
 | 
						|
  float pixel_bottom[3];
 | 
						|
  float pixel_top[3];
 | 
						|
  SKY_nishita_skymodel_precompute_sun(
 | 
						|
      sun_elevation, sun_size, altitude, air_density, dust_density, pixel_bottom, pixel_top);
 | 
						|
  /* limit sun rotation between 0 and 360 degrees */
 | 
						|
  sun_rotation = fmodf(sun_rotation, M_2PI_F);
 | 
						|
  if (sun_rotation < 0.0f) {
 | 
						|
    sun_rotation += M_2PI_F;
 | 
						|
  }
 | 
						|
  sun_rotation = M_2PI_F - sun_rotation;
 | 
						|
  /* send data to svm_sky */
 | 
						|
  sunsky->nishita_data[0] = pixel_bottom[0];
 | 
						|
  sunsky->nishita_data[1] = pixel_bottom[1];
 | 
						|
  sunsky->nishita_data[2] = pixel_bottom[2];
 | 
						|
  sunsky->nishita_data[3] = pixel_top[0];
 | 
						|
  sunsky->nishita_data[4] = pixel_top[1];
 | 
						|
  sunsky->nishita_data[5] = pixel_top[2];
 | 
						|
  sunsky->nishita_data[6] = sun_elevation;
 | 
						|
  sunsky->nishita_data[7] = sun_rotation;
 | 
						|
  sunsky->nishita_data[8] = sun_disc ? sun_size : 0.0f;
 | 
						|
  sunsky->nishita_data[9] = sun_intensity;
 | 
						|
}
 | 
						|
 | 
						|
NODE_DEFINE(SkyTextureNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("sky_texture", create, NodeType::SHADER);
 | 
						|
 | 
						|
  TEXTURE_MAPPING_DEFINE(SkyTextureNode);
 | 
						|
 | 
						|
  static NodeEnum type_enum;
 | 
						|
  type_enum.insert("preetham", NODE_SKY_PREETHAM);
 | 
						|
  type_enum.insert("hosek_wilkie", NODE_SKY_HOSEK);
 | 
						|
  type_enum.insert("nishita_improved", NODE_SKY_NISHITA);
 | 
						|
  SOCKET_ENUM(type, "Type", type_enum, NODE_SKY_NISHITA);
 | 
						|
 | 
						|
  SOCKET_VECTOR(sun_direction, "Sun Direction", make_float3(0.0f, 0.0f, 1.0f));
 | 
						|
  SOCKET_FLOAT(turbidity, "Turbidity", 2.2f);
 | 
						|
  SOCKET_FLOAT(ground_albedo, "Ground Albedo", 0.3f);
 | 
						|
  SOCKET_BOOLEAN(sun_disc, "Sun Disc", true);
 | 
						|
  SOCKET_FLOAT(sun_size, "Sun Size", 0.009512f);
 | 
						|
  SOCKET_FLOAT(sun_intensity, "Sun Intensity", 1.0f);
 | 
						|
  SOCKET_FLOAT(sun_elevation, "Sun Elevation", M_PI_2_F);
 | 
						|
  SOCKET_FLOAT(sun_rotation, "Sun Rotation", 0.0f);
 | 
						|
  SOCKET_FLOAT(altitude, "Altitude", 1.0f);
 | 
						|
  SOCKET_FLOAT(air_density, "Air", 1.0f);
 | 
						|
  SOCKET_FLOAT(dust_density, "Dust", 1.0f);
 | 
						|
  SOCKET_FLOAT(ozone_density, "Ozone", 1.0f);
 | 
						|
 | 
						|
  SOCKET_IN_POINT(
 | 
						|
      vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
 | 
						|
 | 
						|
  SOCKET_OUT_COLOR(color, "Color");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
SkyTextureNode::SkyTextureNode() : TextureNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void SkyTextureNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *vector_in = input("Vector");
 | 
						|
  ShaderOutput *color_out = output("Color");
 | 
						|
 | 
						|
  SunSky sunsky;
 | 
						|
  if (type == NODE_SKY_PREETHAM)
 | 
						|
    sky_texture_precompute_preetham(&sunsky, sun_direction, turbidity);
 | 
						|
  else if (type == NODE_SKY_HOSEK)
 | 
						|
    sky_texture_precompute_hosek(&sunsky, sun_direction, turbidity, ground_albedo);
 | 
						|
  else if (type == NODE_SKY_NISHITA) {
 | 
						|
    /* Clamp altitude to reasonable values.
 | 
						|
     * Below 1m causes numerical issues and above 60km is space. */
 | 
						|
    float clamped_altitude = clamp(altitude, 1.0f, 59999.0f);
 | 
						|
 | 
						|
    sky_texture_precompute_nishita(&sunsky,
 | 
						|
                                   sun_disc,
 | 
						|
                                   sun_size,
 | 
						|
                                   sun_intensity,
 | 
						|
                                   sun_elevation,
 | 
						|
                                   sun_rotation,
 | 
						|
                                   clamped_altitude,
 | 
						|
                                   air_density,
 | 
						|
                                   dust_density);
 | 
						|
    /* precomputed texture image parameters */
 | 
						|
    ImageManager *image_manager = compiler.scene->image_manager;
 | 
						|
    ImageParams impar;
 | 
						|
    impar.interpolation = INTERPOLATION_LINEAR;
 | 
						|
    impar.extension = EXTENSION_EXTEND;
 | 
						|
 | 
						|
    /* precompute sky texture */
 | 
						|
    if (handle.empty()) {
 | 
						|
      SkyLoader *loader = new SkyLoader(
 | 
						|
          sun_elevation, clamped_altitude, air_density, dust_density, ozone_density);
 | 
						|
      handle = image_manager->add_image(loader, impar);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else
 | 
						|
    assert(false);
 | 
						|
 | 
						|
  int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
 | 
						|
 | 
						|
  compiler.stack_assign(color_out);
 | 
						|
  compiler.add_node(NODE_TEX_SKY, vector_offset, compiler.stack_assign(color_out), type);
 | 
						|
  /* nishita doesn't need this data */
 | 
						|
  if (type != NODE_SKY_NISHITA) {
 | 
						|
    compiler.add_node(__float_as_uint(sunsky.phi),
 | 
						|
                      __float_as_uint(sunsky.theta),
 | 
						|
                      __float_as_uint(sunsky.radiance_x),
 | 
						|
                      __float_as_uint(sunsky.radiance_y));
 | 
						|
    compiler.add_node(__float_as_uint(sunsky.radiance_z),
 | 
						|
                      __float_as_uint(sunsky.config_x[0]),
 | 
						|
                      __float_as_uint(sunsky.config_x[1]),
 | 
						|
                      __float_as_uint(sunsky.config_x[2]));
 | 
						|
    compiler.add_node(__float_as_uint(sunsky.config_x[3]),
 | 
						|
                      __float_as_uint(sunsky.config_x[4]),
 | 
						|
                      __float_as_uint(sunsky.config_x[5]),
 | 
						|
                      __float_as_uint(sunsky.config_x[6]));
 | 
						|
    compiler.add_node(__float_as_uint(sunsky.config_x[7]),
 | 
						|
                      __float_as_uint(sunsky.config_x[8]),
 | 
						|
                      __float_as_uint(sunsky.config_y[0]),
 | 
						|
                      __float_as_uint(sunsky.config_y[1]));
 | 
						|
    compiler.add_node(__float_as_uint(sunsky.config_y[2]),
 | 
						|
                      __float_as_uint(sunsky.config_y[3]),
 | 
						|
                      __float_as_uint(sunsky.config_y[4]),
 | 
						|
                      __float_as_uint(sunsky.config_y[5]));
 | 
						|
    compiler.add_node(__float_as_uint(sunsky.config_y[6]),
 | 
						|
                      __float_as_uint(sunsky.config_y[7]),
 | 
						|
                      __float_as_uint(sunsky.config_y[8]),
 | 
						|
                      __float_as_uint(sunsky.config_z[0]));
 | 
						|
    compiler.add_node(__float_as_uint(sunsky.config_z[1]),
 | 
						|
                      __float_as_uint(sunsky.config_z[2]),
 | 
						|
                      __float_as_uint(sunsky.config_z[3]),
 | 
						|
                      __float_as_uint(sunsky.config_z[4]));
 | 
						|
    compiler.add_node(__float_as_uint(sunsky.config_z[5]),
 | 
						|
                      __float_as_uint(sunsky.config_z[6]),
 | 
						|
                      __float_as_uint(sunsky.config_z[7]),
 | 
						|
                      __float_as_uint(sunsky.config_z[8]));
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    compiler.add_node(__float_as_uint(sunsky.nishita_data[0]),
 | 
						|
                      __float_as_uint(sunsky.nishita_data[1]),
 | 
						|
                      __float_as_uint(sunsky.nishita_data[2]),
 | 
						|
                      __float_as_uint(sunsky.nishita_data[3]));
 | 
						|
    compiler.add_node(__float_as_uint(sunsky.nishita_data[4]),
 | 
						|
                      __float_as_uint(sunsky.nishita_data[5]),
 | 
						|
                      __float_as_uint(sunsky.nishita_data[6]),
 | 
						|
                      __float_as_uint(sunsky.nishita_data[7]));
 | 
						|
    compiler.add_node(__float_as_uint(sunsky.nishita_data[8]),
 | 
						|
                      __float_as_uint(sunsky.nishita_data[9]),
 | 
						|
                      handle.svm_slot(),
 | 
						|
                      0);
 | 
						|
  }
 | 
						|
 | 
						|
  tex_mapping.compile_end(compiler, vector_in, vector_offset);
 | 
						|
}
 | 
						|
 | 
						|
void SkyTextureNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  tex_mapping.compile(compiler);
 | 
						|
 | 
						|
  SunSky sunsky;
 | 
						|
  if (type == NODE_SKY_PREETHAM)
 | 
						|
    sky_texture_precompute_preetham(&sunsky, sun_direction, turbidity);
 | 
						|
  else if (type == NODE_SKY_HOSEK)
 | 
						|
    sky_texture_precompute_hosek(&sunsky, sun_direction, turbidity, ground_albedo);
 | 
						|
  else if (type == NODE_SKY_NISHITA) {
 | 
						|
    /* Clamp altitude to reasonable values.
 | 
						|
     * Below 1m causes numerical issues and above 60km is space. */
 | 
						|
    float clamped_altitude = clamp(altitude, 1.0f, 59999.0f);
 | 
						|
 | 
						|
    sky_texture_precompute_nishita(&sunsky,
 | 
						|
                                   sun_disc,
 | 
						|
                                   sun_size,
 | 
						|
                                   sun_intensity,
 | 
						|
                                   sun_elevation,
 | 
						|
                                   sun_rotation,
 | 
						|
                                   clamped_altitude,
 | 
						|
                                   air_density,
 | 
						|
                                   dust_density);
 | 
						|
    /* precomputed texture image parameters */
 | 
						|
    ImageManager *image_manager = compiler.scene->image_manager;
 | 
						|
    ImageParams impar;
 | 
						|
    impar.interpolation = INTERPOLATION_LINEAR;
 | 
						|
    impar.extension = EXTENSION_EXTEND;
 | 
						|
 | 
						|
    /* precompute sky texture */
 | 
						|
    if (handle.empty()) {
 | 
						|
      SkyLoader *loader = new SkyLoader(
 | 
						|
          sun_elevation, clamped_altitude, air_density, dust_density, ozone_density);
 | 
						|
      handle = image_manager->add_image(loader, impar);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else
 | 
						|
    assert(false);
 | 
						|
 | 
						|
  compiler.parameter(this, "type");
 | 
						|
  compiler.parameter("theta", sunsky.theta);
 | 
						|
  compiler.parameter("phi", sunsky.phi);
 | 
						|
  compiler.parameter_color("radiance",
 | 
						|
                           make_float3(sunsky.radiance_x, sunsky.radiance_y, sunsky.radiance_z));
 | 
						|
  compiler.parameter_array("config_x", sunsky.config_x, 9);
 | 
						|
  compiler.parameter_array("config_y", sunsky.config_y, 9);
 | 
						|
  compiler.parameter_array("config_z", sunsky.config_z, 9);
 | 
						|
  compiler.parameter_array("nishita_data", sunsky.nishita_data, 10);
 | 
						|
  /* nishita texture */
 | 
						|
  if (type == NODE_SKY_NISHITA) {
 | 
						|
    compiler.parameter_texture("filename", handle.svm_slot());
 | 
						|
  }
 | 
						|
  compiler.add(this, "node_sky_texture");
 | 
						|
}
 | 
						|
 | 
						|
/* Gradient Texture */
 | 
						|
 | 
						|
NODE_DEFINE(GradientTextureNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("gradient_texture", create, NodeType::SHADER);
 | 
						|
 | 
						|
  TEXTURE_MAPPING_DEFINE(GradientTextureNode);
 | 
						|
 | 
						|
  static NodeEnum type_enum;
 | 
						|
  type_enum.insert("linear", NODE_BLEND_LINEAR);
 | 
						|
  type_enum.insert("quadratic", NODE_BLEND_QUADRATIC);
 | 
						|
  type_enum.insert("easing", NODE_BLEND_EASING);
 | 
						|
  type_enum.insert("diagonal", NODE_BLEND_DIAGONAL);
 | 
						|
  type_enum.insert("radial", NODE_BLEND_RADIAL);
 | 
						|
  type_enum.insert("quadratic_sphere", NODE_BLEND_QUADRATIC_SPHERE);
 | 
						|
  type_enum.insert("spherical", NODE_BLEND_SPHERICAL);
 | 
						|
  SOCKET_ENUM(type, "Type", type_enum, NODE_BLEND_LINEAR);
 | 
						|
 | 
						|
  SOCKET_IN_POINT(
 | 
						|
      vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
 | 
						|
 | 
						|
  SOCKET_OUT_COLOR(color, "Color");
 | 
						|
  SOCKET_OUT_FLOAT(fac, "Fac");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
GradientTextureNode::GradientTextureNode() : TextureNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void GradientTextureNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *vector_in = input("Vector");
 | 
						|
  ShaderOutput *color_out = output("Color");
 | 
						|
  ShaderOutput *fac_out = output("Fac");
 | 
						|
 | 
						|
  int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
 | 
						|
 | 
						|
  compiler.add_node(NODE_TEX_GRADIENT,
 | 
						|
                    compiler.encode_uchar4(type,
 | 
						|
                                           vector_offset,
 | 
						|
                                           compiler.stack_assign_if_linked(fac_out),
 | 
						|
                                           compiler.stack_assign_if_linked(color_out)));
 | 
						|
 | 
						|
  tex_mapping.compile_end(compiler, vector_in, vector_offset);
 | 
						|
}
 | 
						|
 | 
						|
void GradientTextureNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  tex_mapping.compile(compiler);
 | 
						|
 | 
						|
  compiler.parameter(this, "type");
 | 
						|
  compiler.add(this, "node_gradient_texture");
 | 
						|
}
 | 
						|
 | 
						|
/* Noise Texture */
 | 
						|
 | 
						|
NODE_DEFINE(NoiseTextureNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("noise_texture", create, NodeType::SHADER);
 | 
						|
 | 
						|
  TEXTURE_MAPPING_DEFINE(NoiseTextureNode);
 | 
						|
 | 
						|
  static NodeEnum dimensions_enum;
 | 
						|
  dimensions_enum.insert("1D", 1);
 | 
						|
  dimensions_enum.insert("2D", 2);
 | 
						|
  dimensions_enum.insert("3D", 3);
 | 
						|
  dimensions_enum.insert("4D", 4);
 | 
						|
  SOCKET_ENUM(dimensions, "Dimensions", dimensions_enum, 3);
 | 
						|
 | 
						|
  SOCKET_IN_POINT(
 | 
						|
      vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
 | 
						|
  SOCKET_IN_FLOAT(w, "W", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
 | 
						|
  SOCKET_IN_FLOAT(detail, "Detail", 2.0f);
 | 
						|
  SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f);
 | 
						|
  SOCKET_IN_FLOAT(distortion, "Distortion", 0.0f);
 | 
						|
 | 
						|
  SOCKET_OUT_FLOAT(fac, "Fac");
 | 
						|
  SOCKET_OUT_COLOR(color, "Color");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
NoiseTextureNode::NoiseTextureNode() : TextureNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void NoiseTextureNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *vector_in = input("Vector");
 | 
						|
  ShaderInput *w_in = input("W");
 | 
						|
  ShaderInput *scale_in = input("Scale");
 | 
						|
  ShaderInput *detail_in = input("Detail");
 | 
						|
  ShaderInput *roughness_in = input("Roughness");
 | 
						|
  ShaderInput *distortion_in = input("Distortion");
 | 
						|
  ShaderOutput *fac_out = output("Fac");
 | 
						|
  ShaderOutput *color_out = output("Color");
 | 
						|
 | 
						|
  int vector_stack_offset = tex_mapping.compile_begin(compiler, vector_in);
 | 
						|
  int w_stack_offset = compiler.stack_assign_if_linked(w_in);
 | 
						|
  int scale_stack_offset = compiler.stack_assign_if_linked(scale_in);
 | 
						|
  int detail_stack_offset = compiler.stack_assign_if_linked(detail_in);
 | 
						|
  int roughness_stack_offset = compiler.stack_assign_if_linked(roughness_in);
 | 
						|
  int distortion_stack_offset = compiler.stack_assign_if_linked(distortion_in);
 | 
						|
  int fac_stack_offset = compiler.stack_assign_if_linked(fac_out);
 | 
						|
  int color_stack_offset = compiler.stack_assign_if_linked(color_out);
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      NODE_TEX_NOISE,
 | 
						|
      dimensions,
 | 
						|
      compiler.encode_uchar4(
 | 
						|
          vector_stack_offset, w_stack_offset, scale_stack_offset, detail_stack_offset),
 | 
						|
      compiler.encode_uchar4(
 | 
						|
          roughness_stack_offset, distortion_stack_offset, fac_stack_offset, color_stack_offset));
 | 
						|
  compiler.add_node(
 | 
						|
      __float_as_int(w), __float_as_int(scale), __float_as_int(detail), __float_as_int(roughness));
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      __float_as_int(distortion), SVM_STACK_INVALID, SVM_STACK_INVALID, SVM_STACK_INVALID);
 | 
						|
 | 
						|
  tex_mapping.compile_end(compiler, vector_in, vector_stack_offset);
 | 
						|
}
 | 
						|
 | 
						|
void NoiseTextureNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  tex_mapping.compile(compiler);
 | 
						|
  compiler.parameter(this, "dimensions");
 | 
						|
  compiler.add(this, "node_noise_texture");
 | 
						|
}
 | 
						|
 | 
						|
/* Voronoi Texture */
 | 
						|
 | 
						|
NODE_DEFINE(VoronoiTextureNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("voronoi_texture", create, NodeType::SHADER);
 | 
						|
 | 
						|
  TEXTURE_MAPPING_DEFINE(VoronoiTextureNode);
 | 
						|
 | 
						|
  static NodeEnum dimensions_enum;
 | 
						|
  dimensions_enum.insert("1D", 1);
 | 
						|
  dimensions_enum.insert("2D", 2);
 | 
						|
  dimensions_enum.insert("3D", 3);
 | 
						|
  dimensions_enum.insert("4D", 4);
 | 
						|
  SOCKET_ENUM(dimensions, "Dimensions", dimensions_enum, 3);
 | 
						|
 | 
						|
  static NodeEnum metric_enum;
 | 
						|
  metric_enum.insert("euclidean", NODE_VORONOI_EUCLIDEAN);
 | 
						|
  metric_enum.insert("manhattan", NODE_VORONOI_MANHATTAN);
 | 
						|
  metric_enum.insert("chebychev", NODE_VORONOI_CHEBYCHEV);
 | 
						|
  metric_enum.insert("minkowski", NODE_VORONOI_MINKOWSKI);
 | 
						|
  SOCKET_ENUM(metric, "Distance Metric", metric_enum, NODE_VORONOI_EUCLIDEAN);
 | 
						|
 | 
						|
  static NodeEnum feature_enum;
 | 
						|
  feature_enum.insert("f1", NODE_VORONOI_F1);
 | 
						|
  feature_enum.insert("f2", NODE_VORONOI_F2);
 | 
						|
  feature_enum.insert("smooth_f1", NODE_VORONOI_SMOOTH_F1);
 | 
						|
  feature_enum.insert("distance_to_edge", NODE_VORONOI_DISTANCE_TO_EDGE);
 | 
						|
  feature_enum.insert("n_sphere_radius", NODE_VORONOI_N_SPHERE_RADIUS);
 | 
						|
  SOCKET_ENUM(feature, "Feature", feature_enum, NODE_VORONOI_F1);
 | 
						|
 | 
						|
  SOCKET_IN_POINT(
 | 
						|
      vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
 | 
						|
  SOCKET_IN_FLOAT(w, "W", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(scale, "Scale", 5.0f);
 | 
						|
  SOCKET_IN_FLOAT(smoothness, "Smoothness", 5.0f);
 | 
						|
  SOCKET_IN_FLOAT(exponent, "Exponent", 0.5f);
 | 
						|
  SOCKET_IN_FLOAT(randomness, "Randomness", 1.0f);
 | 
						|
 | 
						|
  SOCKET_OUT_FLOAT(distance, "Distance");
 | 
						|
  SOCKET_OUT_COLOR(color, "Color");
 | 
						|
  SOCKET_OUT_POINT(position, "Position");
 | 
						|
  SOCKET_OUT_FLOAT(w, "W");
 | 
						|
  SOCKET_OUT_FLOAT(radius, "Radius");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
VoronoiTextureNode::VoronoiTextureNode() : TextureNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void VoronoiTextureNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *vector_in = input("Vector");
 | 
						|
  ShaderInput *w_in = input("W");
 | 
						|
  ShaderInput *scale_in = input("Scale");
 | 
						|
  ShaderInput *smoothness_in = input("Smoothness");
 | 
						|
  ShaderInput *exponent_in = input("Exponent");
 | 
						|
  ShaderInput *randomness_in = input("Randomness");
 | 
						|
 | 
						|
  ShaderOutput *distance_out = output("Distance");
 | 
						|
  ShaderOutput *color_out = output("Color");
 | 
						|
  ShaderOutput *position_out = output("Position");
 | 
						|
  ShaderOutput *w_out = output("W");
 | 
						|
  ShaderOutput *radius_out = output("Radius");
 | 
						|
 | 
						|
  int vector_stack_offset = tex_mapping.compile_begin(compiler, vector_in);
 | 
						|
  int w_in_stack_offset = compiler.stack_assign_if_linked(w_in);
 | 
						|
  int scale_stack_offset = compiler.stack_assign_if_linked(scale_in);
 | 
						|
  int smoothness_stack_offset = compiler.stack_assign_if_linked(smoothness_in);
 | 
						|
  int exponent_stack_offset = compiler.stack_assign_if_linked(exponent_in);
 | 
						|
  int randomness_stack_offset = compiler.stack_assign_if_linked(randomness_in);
 | 
						|
  int distance_stack_offset = compiler.stack_assign_if_linked(distance_out);
 | 
						|
  int color_stack_offset = compiler.stack_assign_if_linked(color_out);
 | 
						|
  int position_stack_offset = compiler.stack_assign_if_linked(position_out);
 | 
						|
  int w_out_stack_offset = compiler.stack_assign_if_linked(w_out);
 | 
						|
  int radius_stack_offset = compiler.stack_assign_if_linked(radius_out);
 | 
						|
 | 
						|
  compiler.add_node(NODE_TEX_VORONOI, dimensions, feature, metric);
 | 
						|
  compiler.add_node(
 | 
						|
      compiler.encode_uchar4(
 | 
						|
          vector_stack_offset, w_in_stack_offset, scale_stack_offset, smoothness_stack_offset),
 | 
						|
      compiler.encode_uchar4(exponent_stack_offset,
 | 
						|
                             randomness_stack_offset,
 | 
						|
                             distance_stack_offset,
 | 
						|
                             color_stack_offset),
 | 
						|
      compiler.encode_uchar4(position_stack_offset, w_out_stack_offset, radius_stack_offset),
 | 
						|
      __float_as_int(w));
 | 
						|
 | 
						|
  compiler.add_node(__float_as_int(scale),
 | 
						|
                    __float_as_int(smoothness),
 | 
						|
                    __float_as_int(exponent),
 | 
						|
                    __float_as_int(randomness));
 | 
						|
 | 
						|
  tex_mapping.compile_end(compiler, vector_in, vector_stack_offset);
 | 
						|
}
 | 
						|
 | 
						|
void VoronoiTextureNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  tex_mapping.compile(compiler);
 | 
						|
 | 
						|
  compiler.parameter(this, "dimensions");
 | 
						|
  compiler.parameter(this, "feature");
 | 
						|
  compiler.parameter(this, "metric");
 | 
						|
  compiler.add(this, "node_voronoi_texture");
 | 
						|
}
 | 
						|
 | 
						|
/* IES Light */
 | 
						|
 | 
						|
NODE_DEFINE(IESLightNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("ies_light", create, NodeType::SHADER);
 | 
						|
 | 
						|
  TEXTURE_MAPPING_DEFINE(IESLightNode);
 | 
						|
 | 
						|
  SOCKET_STRING(ies, "IES", ustring());
 | 
						|
  SOCKET_STRING(filename, "File Name", ustring());
 | 
						|
 | 
						|
  SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
 | 
						|
  SOCKET_IN_POINT(
 | 
						|
      vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_NORMAL);
 | 
						|
 | 
						|
  SOCKET_OUT_FLOAT(fac, "Fac");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
IESLightNode::IESLightNode() : TextureNode(node_type)
 | 
						|
{
 | 
						|
  light_manager = NULL;
 | 
						|
  slot = -1;
 | 
						|
}
 | 
						|
 | 
						|
ShaderNode *IESLightNode::clone() const
 | 
						|
{
 | 
						|
  IESLightNode *node = new IESLightNode(*this);
 | 
						|
 | 
						|
  node->light_manager = NULL;
 | 
						|
  node->slot = -1;
 | 
						|
 | 
						|
  return node;
 | 
						|
}
 | 
						|
 | 
						|
IESLightNode::~IESLightNode()
 | 
						|
{
 | 
						|
  if (light_manager) {
 | 
						|
    light_manager->remove_ies(slot);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void IESLightNode::get_slot()
 | 
						|
{
 | 
						|
  assert(light_manager);
 | 
						|
 | 
						|
  if (slot == -1) {
 | 
						|
    if (ies.empty()) {
 | 
						|
      slot = light_manager->add_ies_from_file(filename.string());
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      slot = light_manager->add_ies(ies.string());
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void IESLightNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  light_manager = compiler.scene->light_manager;
 | 
						|
  get_slot();
 | 
						|
 | 
						|
  ShaderInput *strength_in = input("Strength");
 | 
						|
  ShaderInput *vector_in = input("Vector");
 | 
						|
  ShaderOutput *fac_out = output("Fac");
 | 
						|
 | 
						|
  int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
 | 
						|
 | 
						|
  compiler.add_node(NODE_IES,
 | 
						|
                    compiler.encode_uchar4(compiler.stack_assign_if_linked(strength_in),
 | 
						|
                                           vector_offset,
 | 
						|
                                           compiler.stack_assign(fac_out),
 | 
						|
                                           0),
 | 
						|
                    slot,
 | 
						|
                    __float_as_int(strength));
 | 
						|
 | 
						|
  tex_mapping.compile_end(compiler, vector_in, vector_offset);
 | 
						|
}
 | 
						|
 | 
						|
void IESLightNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  light_manager = compiler.scene->light_manager;
 | 
						|
  get_slot();
 | 
						|
 | 
						|
  tex_mapping.compile(compiler);
 | 
						|
 | 
						|
  compiler.parameter_texture_ies("filename", slot);
 | 
						|
  compiler.add(this, "node_ies_light");
 | 
						|
}
 | 
						|
 | 
						|
/* White Noise Texture */
 | 
						|
 | 
						|
NODE_DEFINE(WhiteNoiseTextureNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("white_noise_texture", create, NodeType::SHADER);
 | 
						|
 | 
						|
  static NodeEnum dimensions_enum;
 | 
						|
  dimensions_enum.insert("1D", 1);
 | 
						|
  dimensions_enum.insert("2D", 2);
 | 
						|
  dimensions_enum.insert("3D", 3);
 | 
						|
  dimensions_enum.insert("4D", 4);
 | 
						|
  SOCKET_ENUM(dimensions, "Dimensions", dimensions_enum, 3);
 | 
						|
 | 
						|
  SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
  SOCKET_IN_FLOAT(w, "W", 0.0f);
 | 
						|
 | 
						|
  SOCKET_OUT_FLOAT(value, "Value");
 | 
						|
  SOCKET_OUT_COLOR(color, "Color");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
WhiteNoiseTextureNode::WhiteNoiseTextureNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void WhiteNoiseTextureNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *vector_in = input("Vector");
 | 
						|
  ShaderInput *w_in = input("W");
 | 
						|
  ShaderOutput *value_out = output("Value");
 | 
						|
  ShaderOutput *color_out = output("Color");
 | 
						|
 | 
						|
  int vector_stack_offset = compiler.stack_assign(vector_in);
 | 
						|
  int w_stack_offset = compiler.stack_assign(w_in);
 | 
						|
  int value_stack_offset = compiler.stack_assign(value_out);
 | 
						|
  int color_stack_offset = compiler.stack_assign(color_out);
 | 
						|
 | 
						|
  compiler.add_node(NODE_TEX_WHITE_NOISE,
 | 
						|
                    dimensions,
 | 
						|
                    compiler.encode_uchar4(vector_stack_offset, w_stack_offset),
 | 
						|
                    compiler.encode_uchar4(value_stack_offset, color_stack_offset));
 | 
						|
}
 | 
						|
 | 
						|
void WhiteNoiseTextureNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.parameter(this, "dimensions");
 | 
						|
  compiler.add(this, "node_white_noise_texture");
 | 
						|
}
 | 
						|
 | 
						|
/* Musgrave Texture */
 | 
						|
 | 
						|
NODE_DEFINE(MusgraveTextureNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("musgrave_texture", create, NodeType::SHADER);
 | 
						|
 | 
						|
  TEXTURE_MAPPING_DEFINE(MusgraveTextureNode);
 | 
						|
 | 
						|
  static NodeEnum dimensions_enum;
 | 
						|
  dimensions_enum.insert("1D", 1);
 | 
						|
  dimensions_enum.insert("2D", 2);
 | 
						|
  dimensions_enum.insert("3D", 3);
 | 
						|
  dimensions_enum.insert("4D", 4);
 | 
						|
  SOCKET_ENUM(dimensions, "Dimensions", dimensions_enum, 3);
 | 
						|
 | 
						|
  static NodeEnum type_enum;
 | 
						|
  type_enum.insert("multifractal", NODE_MUSGRAVE_MULTIFRACTAL);
 | 
						|
  type_enum.insert("fBM", NODE_MUSGRAVE_FBM);
 | 
						|
  type_enum.insert("hybrid_multifractal", NODE_MUSGRAVE_HYBRID_MULTIFRACTAL);
 | 
						|
  type_enum.insert("ridged_multifractal", NODE_MUSGRAVE_RIDGED_MULTIFRACTAL);
 | 
						|
  type_enum.insert("hetero_terrain", NODE_MUSGRAVE_HETERO_TERRAIN);
 | 
						|
  SOCKET_ENUM(type, "Type", type_enum, NODE_MUSGRAVE_FBM);
 | 
						|
 | 
						|
  SOCKET_IN_POINT(
 | 
						|
      vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
 | 
						|
  SOCKET_IN_FLOAT(w, "W", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
 | 
						|
  SOCKET_IN_FLOAT(detail, "Detail", 2.0f);
 | 
						|
  SOCKET_IN_FLOAT(dimension, "Dimension", 2.0f);
 | 
						|
  SOCKET_IN_FLOAT(lacunarity, "Lacunarity", 2.0f);
 | 
						|
  SOCKET_IN_FLOAT(offset, "Offset", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(gain, "Gain", 1.0f);
 | 
						|
 | 
						|
  SOCKET_OUT_FLOAT(fac, "Fac");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
MusgraveTextureNode::MusgraveTextureNode() : TextureNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void MusgraveTextureNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *vector_in = input("Vector");
 | 
						|
  ShaderInput *w_in = input("W");
 | 
						|
  ShaderInput *scale_in = input("Scale");
 | 
						|
  ShaderInput *detail_in = input("Detail");
 | 
						|
  ShaderInput *dimension_in = input("Dimension");
 | 
						|
  ShaderInput *lacunarity_in = input("Lacunarity");
 | 
						|
  ShaderInput *offset_in = input("Offset");
 | 
						|
  ShaderInput *gain_in = input("Gain");
 | 
						|
  ShaderOutput *fac_out = output("Fac");
 | 
						|
 | 
						|
  int vector_stack_offset = tex_mapping.compile_begin(compiler, vector_in);
 | 
						|
  int w_stack_offset = compiler.stack_assign_if_linked(w_in);
 | 
						|
  int scale_stack_offset = compiler.stack_assign_if_linked(scale_in);
 | 
						|
  int detail_stack_offset = compiler.stack_assign_if_linked(detail_in);
 | 
						|
  int dimension_stack_offset = compiler.stack_assign_if_linked(dimension_in);
 | 
						|
  int lacunarity_stack_offset = compiler.stack_assign_if_linked(lacunarity_in);
 | 
						|
  int offset_stack_offset = compiler.stack_assign_if_linked(offset_in);
 | 
						|
  int gain_stack_offset = compiler.stack_assign_if_linked(gain_in);
 | 
						|
  int fac_stack_offset = compiler.stack_assign(fac_out);
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      NODE_TEX_MUSGRAVE,
 | 
						|
      compiler.encode_uchar4(type, dimensions, vector_stack_offset, w_stack_offset),
 | 
						|
      compiler.encode_uchar4(scale_stack_offset,
 | 
						|
                             detail_stack_offset,
 | 
						|
                             dimension_stack_offset,
 | 
						|
                             lacunarity_stack_offset),
 | 
						|
      compiler.encode_uchar4(offset_stack_offset, gain_stack_offset, fac_stack_offset));
 | 
						|
  compiler.add_node(
 | 
						|
      __float_as_int(w), __float_as_int(scale), __float_as_int(detail), __float_as_int(dimension));
 | 
						|
  compiler.add_node(__float_as_int(lacunarity), __float_as_int(offset), __float_as_int(gain));
 | 
						|
 | 
						|
  tex_mapping.compile_end(compiler, vector_in, vector_stack_offset);
 | 
						|
}
 | 
						|
 | 
						|
void MusgraveTextureNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  tex_mapping.compile(compiler);
 | 
						|
 | 
						|
  compiler.parameter(this, "type");
 | 
						|
  compiler.parameter(this, "dimensions");
 | 
						|
  compiler.add(this, "node_musgrave_texture");
 | 
						|
}
 | 
						|
 | 
						|
/* Wave Texture */
 | 
						|
 | 
						|
NODE_DEFINE(WaveTextureNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("wave_texture", create, NodeType::SHADER);
 | 
						|
 | 
						|
  TEXTURE_MAPPING_DEFINE(WaveTextureNode);
 | 
						|
 | 
						|
  static NodeEnum type_enum;
 | 
						|
  type_enum.insert("bands", NODE_WAVE_BANDS);
 | 
						|
  type_enum.insert("rings", NODE_WAVE_RINGS);
 | 
						|
  SOCKET_ENUM(type, "Type", type_enum, NODE_WAVE_BANDS);
 | 
						|
 | 
						|
  static NodeEnum bands_direction_enum;
 | 
						|
  bands_direction_enum.insert("x", NODE_WAVE_BANDS_DIRECTION_X);
 | 
						|
  bands_direction_enum.insert("y", NODE_WAVE_BANDS_DIRECTION_Y);
 | 
						|
  bands_direction_enum.insert("z", NODE_WAVE_BANDS_DIRECTION_Z);
 | 
						|
  bands_direction_enum.insert("diagonal", NODE_WAVE_BANDS_DIRECTION_DIAGONAL);
 | 
						|
  SOCKET_ENUM(
 | 
						|
      bands_direction, "Bands Direction", bands_direction_enum, NODE_WAVE_BANDS_DIRECTION_X);
 | 
						|
 | 
						|
  static NodeEnum rings_direction_enum;
 | 
						|
  rings_direction_enum.insert("x", NODE_WAVE_RINGS_DIRECTION_X);
 | 
						|
  rings_direction_enum.insert("y", NODE_WAVE_RINGS_DIRECTION_Y);
 | 
						|
  rings_direction_enum.insert("z", NODE_WAVE_RINGS_DIRECTION_Z);
 | 
						|
  rings_direction_enum.insert("spherical", NODE_WAVE_RINGS_DIRECTION_SPHERICAL);
 | 
						|
  SOCKET_ENUM(
 | 
						|
      rings_direction, "Rings Direction", rings_direction_enum, NODE_WAVE_BANDS_DIRECTION_X);
 | 
						|
 | 
						|
  static NodeEnum profile_enum;
 | 
						|
  profile_enum.insert("sine", NODE_WAVE_PROFILE_SIN);
 | 
						|
  profile_enum.insert("saw", NODE_WAVE_PROFILE_SAW);
 | 
						|
  profile_enum.insert("tri", NODE_WAVE_PROFILE_TRI);
 | 
						|
  SOCKET_ENUM(profile, "Profile", profile_enum, NODE_WAVE_PROFILE_SIN);
 | 
						|
 | 
						|
  SOCKET_IN_POINT(
 | 
						|
      vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
 | 
						|
  SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
 | 
						|
  SOCKET_IN_FLOAT(distortion, "Distortion", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(detail, "Detail", 2.0f);
 | 
						|
  SOCKET_IN_FLOAT(detail_scale, "Detail Scale", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(detail_roughness, "Detail Roughness", 0.5f);
 | 
						|
  SOCKET_IN_FLOAT(phase, "Phase Offset", 0.0f);
 | 
						|
  SOCKET_OUT_COLOR(color, "Color");
 | 
						|
  SOCKET_OUT_FLOAT(fac, "Fac");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
WaveTextureNode::WaveTextureNode() : TextureNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void WaveTextureNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *vector_in = input("Vector");
 | 
						|
  ShaderInput *scale_in = input("Scale");
 | 
						|
  ShaderInput *distortion_in = input("Distortion");
 | 
						|
  ShaderInput *detail_in = input("Detail");
 | 
						|
  ShaderInput *dscale_in = input("Detail Scale");
 | 
						|
  ShaderInput *droughness_in = input("Detail Roughness");
 | 
						|
  ShaderInput *phase_in = input("Phase Offset");
 | 
						|
  ShaderOutput *color_out = output("Color");
 | 
						|
  ShaderOutput *fac_out = output("Fac");
 | 
						|
 | 
						|
  int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
 | 
						|
 | 
						|
  compiler.add_node(NODE_TEX_WAVE,
 | 
						|
                    compiler.encode_uchar4(type, bands_direction, rings_direction, profile),
 | 
						|
                    compiler.encode_uchar4(vector_offset,
 | 
						|
                                           compiler.stack_assign_if_linked(scale_in),
 | 
						|
                                           compiler.stack_assign_if_linked(distortion_in)),
 | 
						|
                    compiler.encode_uchar4(compiler.stack_assign_if_linked(detail_in),
 | 
						|
                                           compiler.stack_assign_if_linked(dscale_in),
 | 
						|
                                           compiler.stack_assign_if_linked(droughness_in),
 | 
						|
                                           compiler.stack_assign_if_linked(phase_in)));
 | 
						|
 | 
						|
  compiler.add_node(compiler.encode_uchar4(compiler.stack_assign_if_linked(color_out),
 | 
						|
                                           compiler.stack_assign_if_linked(fac_out)),
 | 
						|
                    __float_as_int(scale),
 | 
						|
                    __float_as_int(distortion),
 | 
						|
                    __float_as_int(detail));
 | 
						|
 | 
						|
  compiler.add_node(__float_as_int(detail_scale),
 | 
						|
                    __float_as_int(detail_roughness),
 | 
						|
                    __float_as_int(phase),
 | 
						|
                    SVM_STACK_INVALID);
 | 
						|
 | 
						|
  tex_mapping.compile_end(compiler, vector_in, vector_offset);
 | 
						|
}
 | 
						|
 | 
						|
void WaveTextureNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  tex_mapping.compile(compiler);
 | 
						|
 | 
						|
  compiler.parameter(this, "type");
 | 
						|
  compiler.parameter(this, "bands_direction");
 | 
						|
  compiler.parameter(this, "rings_direction");
 | 
						|
  compiler.parameter(this, "profile");
 | 
						|
 | 
						|
  compiler.add(this, "node_wave_texture");
 | 
						|
}
 | 
						|
 | 
						|
/* Magic Texture */
 | 
						|
 | 
						|
NODE_DEFINE(MagicTextureNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("magic_texture", create, NodeType::SHADER);
 | 
						|
 | 
						|
  TEXTURE_MAPPING_DEFINE(MagicTextureNode);
 | 
						|
 | 
						|
  SOCKET_INT(depth, "Depth", 2);
 | 
						|
 | 
						|
  SOCKET_IN_POINT(
 | 
						|
      vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
 | 
						|
  SOCKET_IN_FLOAT(scale, "Scale", 5.0f);
 | 
						|
  SOCKET_IN_FLOAT(distortion, "Distortion", 1.0f);
 | 
						|
 | 
						|
  SOCKET_OUT_COLOR(color, "Color");
 | 
						|
  SOCKET_OUT_FLOAT(fac, "Fac");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
MagicTextureNode::MagicTextureNode() : TextureNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void MagicTextureNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *vector_in = input("Vector");
 | 
						|
  ShaderInput *scale_in = input("Scale");
 | 
						|
  ShaderInput *distortion_in = input("Distortion");
 | 
						|
  ShaderOutput *color_out = output("Color");
 | 
						|
  ShaderOutput *fac_out = output("Fac");
 | 
						|
 | 
						|
  int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
 | 
						|
 | 
						|
  compiler.add_node(NODE_TEX_MAGIC,
 | 
						|
                    compiler.encode_uchar4(depth,
 | 
						|
                                           compiler.stack_assign_if_linked(color_out),
 | 
						|
                                           compiler.stack_assign_if_linked(fac_out)),
 | 
						|
                    compiler.encode_uchar4(vector_offset,
 | 
						|
                                           compiler.stack_assign_if_linked(scale_in),
 | 
						|
                                           compiler.stack_assign_if_linked(distortion_in)));
 | 
						|
  compiler.add_node(__float_as_int(scale), __float_as_int(distortion));
 | 
						|
 | 
						|
  tex_mapping.compile_end(compiler, vector_in, vector_offset);
 | 
						|
}
 | 
						|
 | 
						|
void MagicTextureNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  tex_mapping.compile(compiler);
 | 
						|
 | 
						|
  compiler.parameter(this, "depth");
 | 
						|
  compiler.add(this, "node_magic_texture");
 | 
						|
}
 | 
						|
 | 
						|
/* Checker Texture */
 | 
						|
 | 
						|
NODE_DEFINE(CheckerTextureNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("checker_texture", create, NodeType::SHADER);
 | 
						|
 | 
						|
  TEXTURE_MAPPING_DEFINE(CheckerTextureNode);
 | 
						|
 | 
						|
  SOCKET_IN_POINT(
 | 
						|
      vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
 | 
						|
  SOCKET_IN_COLOR(color1, "Color1", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
  SOCKET_IN_COLOR(color2, "Color2", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
  SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
 | 
						|
 | 
						|
  SOCKET_OUT_COLOR(color, "Color");
 | 
						|
  SOCKET_OUT_FLOAT(fac, "Fac");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
CheckerTextureNode::CheckerTextureNode() : TextureNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void CheckerTextureNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *vector_in = input("Vector");
 | 
						|
  ShaderInput *color1_in = input("Color1");
 | 
						|
  ShaderInput *color2_in = input("Color2");
 | 
						|
  ShaderInput *scale_in = input("Scale");
 | 
						|
 | 
						|
  ShaderOutput *color_out = output("Color");
 | 
						|
  ShaderOutput *fac_out = output("Fac");
 | 
						|
 | 
						|
  int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
 | 
						|
 | 
						|
  compiler.add_node(NODE_TEX_CHECKER,
 | 
						|
                    compiler.encode_uchar4(vector_offset,
 | 
						|
                                           compiler.stack_assign(color1_in),
 | 
						|
                                           compiler.stack_assign(color2_in),
 | 
						|
                                           compiler.stack_assign_if_linked(scale_in)),
 | 
						|
                    compiler.encode_uchar4(compiler.stack_assign_if_linked(color_out),
 | 
						|
                                           compiler.stack_assign_if_linked(fac_out)),
 | 
						|
                    __float_as_int(scale));
 | 
						|
 | 
						|
  tex_mapping.compile_end(compiler, vector_in, vector_offset);
 | 
						|
}
 | 
						|
 | 
						|
void CheckerTextureNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  tex_mapping.compile(compiler);
 | 
						|
 | 
						|
  compiler.add(this, "node_checker_texture");
 | 
						|
}
 | 
						|
 | 
						|
/* Brick Texture */
 | 
						|
 | 
						|
NODE_DEFINE(BrickTextureNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("brick_texture", create, NodeType::SHADER);
 | 
						|
 | 
						|
  TEXTURE_MAPPING_DEFINE(BrickTextureNode);
 | 
						|
 | 
						|
  SOCKET_FLOAT(offset, "Offset", 0.5f);
 | 
						|
  SOCKET_INT(offset_frequency, "Offset Frequency", 2);
 | 
						|
  SOCKET_FLOAT(squash, "Squash", 1.0f);
 | 
						|
  SOCKET_INT(squash_frequency, "Squash Frequency", 2);
 | 
						|
 | 
						|
  SOCKET_IN_POINT(
 | 
						|
      vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TEXTURE_GENERATED);
 | 
						|
 | 
						|
  SOCKET_IN_COLOR(color1, "Color1", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
  SOCKET_IN_COLOR(color2, "Color2", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
  SOCKET_IN_COLOR(mortar, "Mortar", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
  SOCKET_IN_FLOAT(scale, "Scale", 5.0f);
 | 
						|
  SOCKET_IN_FLOAT(mortar_size, "Mortar Size", 0.02f);
 | 
						|
  SOCKET_IN_FLOAT(mortar_smooth, "Mortar Smooth", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(bias, "Bias", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(brick_width, "Brick Width", 0.5f);
 | 
						|
  SOCKET_IN_FLOAT(row_height, "Row Height", 0.25f);
 | 
						|
 | 
						|
  SOCKET_OUT_COLOR(color, "Color");
 | 
						|
  SOCKET_OUT_FLOAT(fac, "Fac");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
BrickTextureNode::BrickTextureNode() : TextureNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void BrickTextureNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *vector_in = input("Vector");
 | 
						|
  ShaderInput *color1_in = input("Color1");
 | 
						|
  ShaderInput *color2_in = input("Color2");
 | 
						|
  ShaderInput *mortar_in = input("Mortar");
 | 
						|
  ShaderInput *scale_in = input("Scale");
 | 
						|
  ShaderInput *mortar_size_in = input("Mortar Size");
 | 
						|
  ShaderInput *mortar_smooth_in = input("Mortar Smooth");
 | 
						|
  ShaderInput *bias_in = input("Bias");
 | 
						|
  ShaderInput *brick_width_in = input("Brick Width");
 | 
						|
  ShaderInput *row_height_in = input("Row Height");
 | 
						|
 | 
						|
  ShaderOutput *color_out = output("Color");
 | 
						|
  ShaderOutput *fac_out = output("Fac");
 | 
						|
 | 
						|
  int vector_offset = tex_mapping.compile_begin(compiler, vector_in);
 | 
						|
 | 
						|
  compiler.add_node(NODE_TEX_BRICK,
 | 
						|
                    compiler.encode_uchar4(vector_offset,
 | 
						|
                                           compiler.stack_assign(color1_in),
 | 
						|
                                           compiler.stack_assign(color2_in),
 | 
						|
                                           compiler.stack_assign(mortar_in)),
 | 
						|
                    compiler.encode_uchar4(compiler.stack_assign_if_linked(scale_in),
 | 
						|
                                           compiler.stack_assign_if_linked(mortar_size_in),
 | 
						|
                                           compiler.stack_assign_if_linked(bias_in),
 | 
						|
                                           compiler.stack_assign_if_linked(brick_width_in)),
 | 
						|
                    compiler.encode_uchar4(compiler.stack_assign_if_linked(row_height_in),
 | 
						|
                                           compiler.stack_assign_if_linked(color_out),
 | 
						|
                                           compiler.stack_assign_if_linked(fac_out),
 | 
						|
                                           compiler.stack_assign_if_linked(mortar_smooth_in)));
 | 
						|
 | 
						|
  compiler.add_node(compiler.encode_uchar4(offset_frequency, squash_frequency),
 | 
						|
                    __float_as_int(scale),
 | 
						|
                    __float_as_int(mortar_size),
 | 
						|
                    __float_as_int(bias));
 | 
						|
 | 
						|
  compiler.add_node(__float_as_int(brick_width),
 | 
						|
                    __float_as_int(row_height),
 | 
						|
                    __float_as_int(offset),
 | 
						|
                    __float_as_int(squash));
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      __float_as_int(mortar_smooth), SVM_STACK_INVALID, SVM_STACK_INVALID, SVM_STACK_INVALID);
 | 
						|
 | 
						|
  tex_mapping.compile_end(compiler, vector_in, vector_offset);
 | 
						|
}
 | 
						|
 | 
						|
void BrickTextureNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  tex_mapping.compile(compiler);
 | 
						|
 | 
						|
  compiler.parameter(this, "offset");
 | 
						|
  compiler.parameter(this, "offset_frequency");
 | 
						|
  compiler.parameter(this, "squash");
 | 
						|
  compiler.parameter(this, "squash_frequency");
 | 
						|
  compiler.add(this, "node_brick_texture");
 | 
						|
}
 | 
						|
 | 
						|
/* Point Density Texture */
 | 
						|
 | 
						|
NODE_DEFINE(PointDensityTextureNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("point_density_texture", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_STRING(filename, "Filename", ustring());
 | 
						|
 | 
						|
  static NodeEnum space_enum;
 | 
						|
  space_enum.insert("object", NODE_TEX_VOXEL_SPACE_OBJECT);
 | 
						|
  space_enum.insert("world", NODE_TEX_VOXEL_SPACE_WORLD);
 | 
						|
  SOCKET_ENUM(space, "Space", space_enum, NODE_TEX_VOXEL_SPACE_OBJECT);
 | 
						|
 | 
						|
  static NodeEnum interpolation_enum;
 | 
						|
  interpolation_enum.insert("closest", INTERPOLATION_CLOSEST);
 | 
						|
  interpolation_enum.insert("linear", INTERPOLATION_LINEAR);
 | 
						|
  interpolation_enum.insert("cubic", INTERPOLATION_CUBIC);
 | 
						|
  interpolation_enum.insert("smart", INTERPOLATION_SMART);
 | 
						|
  SOCKET_ENUM(interpolation, "Interpolation", interpolation_enum, INTERPOLATION_LINEAR);
 | 
						|
 | 
						|
  SOCKET_TRANSFORM(tfm, "Transform", transform_identity());
 | 
						|
 | 
						|
  SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_POSITION);
 | 
						|
 | 
						|
  SOCKET_OUT_FLOAT(density, "Density");
 | 
						|
  SOCKET_OUT_COLOR(color, "Color");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
PointDensityTextureNode::PointDensityTextureNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
PointDensityTextureNode::~PointDensityTextureNode()
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
ShaderNode *PointDensityTextureNode::clone() const
 | 
						|
{
 | 
						|
  /* Increase image user count for new node. We need to ensure to not call
 | 
						|
   * add_image again, to work around access of freed data on the Blender
 | 
						|
   * side. A better solution should be found to avoid this. */
 | 
						|
  PointDensityTextureNode *node = new PointDensityTextureNode(*this);
 | 
						|
  node->handle = handle; /* TODO: not needed? */
 | 
						|
  return node;
 | 
						|
}
 | 
						|
 | 
						|
void PointDensityTextureNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 | 
						|
{
 | 
						|
  if (shader->has_volume)
 | 
						|
    attributes->add(ATTR_STD_GENERATED_TRANSFORM);
 | 
						|
 | 
						|
  ShaderNode::attributes(shader, attributes);
 | 
						|
}
 | 
						|
 | 
						|
ImageParams PointDensityTextureNode::image_params() const
 | 
						|
{
 | 
						|
  ImageParams params;
 | 
						|
  params.interpolation = interpolation;
 | 
						|
  return params;
 | 
						|
}
 | 
						|
 | 
						|
void PointDensityTextureNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *vector_in = input("Vector");
 | 
						|
  ShaderOutput *density_out = output("Density");
 | 
						|
  ShaderOutput *color_out = output("Color");
 | 
						|
 | 
						|
  const bool use_density = !density_out->links.empty();
 | 
						|
  const bool use_color = !color_out->links.empty();
 | 
						|
 | 
						|
  if (use_density || use_color) {
 | 
						|
    if (handle.empty()) {
 | 
						|
      ImageManager *image_manager = compiler.scene->image_manager;
 | 
						|
      handle = image_manager->add_image(filename.string(), image_params());
 | 
						|
    }
 | 
						|
 | 
						|
    const int slot = handle.svm_slot();
 | 
						|
    if (slot != -1) {
 | 
						|
      compiler.stack_assign(vector_in);
 | 
						|
      compiler.add_node(NODE_TEX_VOXEL,
 | 
						|
                        slot,
 | 
						|
                        compiler.encode_uchar4(compiler.stack_assign(vector_in),
 | 
						|
                                               compiler.stack_assign_if_linked(density_out),
 | 
						|
                                               compiler.stack_assign_if_linked(color_out),
 | 
						|
                                               space));
 | 
						|
      if (space == NODE_TEX_VOXEL_SPACE_WORLD) {
 | 
						|
        compiler.add_node(tfm.x);
 | 
						|
        compiler.add_node(tfm.y);
 | 
						|
        compiler.add_node(tfm.z);
 | 
						|
      }
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      if (use_density) {
 | 
						|
        compiler.add_node(NODE_VALUE_F, __float_as_int(0.0f), compiler.stack_assign(density_out));
 | 
						|
      }
 | 
						|
      if (use_color) {
 | 
						|
        compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out));
 | 
						|
        compiler.add_node(
 | 
						|
            NODE_VALUE_V,
 | 
						|
            make_float3(TEX_IMAGE_MISSING_R, TEX_IMAGE_MISSING_G, TEX_IMAGE_MISSING_B));
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void PointDensityTextureNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderOutput *density_out = output("Density");
 | 
						|
  ShaderOutput *color_out = output("Color");
 | 
						|
 | 
						|
  const bool use_density = !density_out->links.empty();
 | 
						|
  const bool use_color = !color_out->links.empty();
 | 
						|
 | 
						|
  if (use_density || use_color) {
 | 
						|
    if (handle.empty()) {
 | 
						|
      ImageManager *image_manager = compiler.scene->image_manager;
 | 
						|
      handle = image_manager->add_image(filename.string(), image_params());
 | 
						|
    }
 | 
						|
 | 
						|
    compiler.parameter_texture("filename", handle.svm_slot());
 | 
						|
    if (space == NODE_TEX_VOXEL_SPACE_WORLD) {
 | 
						|
      compiler.parameter("mapping", tfm);
 | 
						|
      compiler.parameter("use_mapping", 1);
 | 
						|
    }
 | 
						|
    compiler.parameter(this, "interpolation");
 | 
						|
    compiler.add(this, "node_voxel_texture");
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* Normal */
 | 
						|
 | 
						|
NODE_DEFINE(NormalNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("normal", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_VECTOR(direction, "direction", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
 | 
						|
  SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
 | 
						|
  SOCKET_OUT_NORMAL(normal, "Normal");
 | 
						|
  SOCKET_OUT_FLOAT(dot, "Dot");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
NormalNode::NormalNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void NormalNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *normal_in = input("Normal");
 | 
						|
  ShaderOutput *normal_out = output("Normal");
 | 
						|
  ShaderOutput *dot_out = output("Dot");
 | 
						|
 | 
						|
  compiler.add_node(NODE_NORMAL,
 | 
						|
                    compiler.stack_assign(normal_in),
 | 
						|
                    compiler.stack_assign(normal_out),
 | 
						|
                    compiler.stack_assign(dot_out));
 | 
						|
  compiler.add_node(
 | 
						|
      __float_as_int(direction.x), __float_as_int(direction.y), __float_as_int(direction.z));
 | 
						|
}
 | 
						|
 | 
						|
void NormalNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.parameter(this, "direction");
 | 
						|
  compiler.add(this, "node_normal");
 | 
						|
}
 | 
						|
 | 
						|
/* Mapping */
 | 
						|
 | 
						|
NODE_DEFINE(MappingNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("mapping", create, NodeType::SHADER);
 | 
						|
 | 
						|
  static NodeEnum type_enum;
 | 
						|
  type_enum.insert("point", NODE_MAPPING_TYPE_POINT);
 | 
						|
  type_enum.insert("texture", NODE_MAPPING_TYPE_TEXTURE);
 | 
						|
  type_enum.insert("vector", NODE_MAPPING_TYPE_VECTOR);
 | 
						|
  type_enum.insert("normal", NODE_MAPPING_TYPE_NORMAL);
 | 
						|
  SOCKET_ENUM(type, "Type", type_enum, NODE_MAPPING_TYPE_POINT);
 | 
						|
 | 
						|
  SOCKET_IN_POINT(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
  SOCKET_IN_POINT(location, "Location", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
  SOCKET_IN_POINT(rotation, "Rotation", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
  SOCKET_IN_POINT(scale, "Scale", make_float3(1.0f, 1.0f, 1.0f));
 | 
						|
 | 
						|
  SOCKET_OUT_POINT(vector, "Vector");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
MappingNode::MappingNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void MappingNode::constant_fold(const ConstantFolder &folder)
 | 
						|
{
 | 
						|
  if (folder.all_inputs_constant()) {
 | 
						|
    float3 result = svm_mapping((NodeMappingType)type, vector, location, rotation, scale);
 | 
						|
    folder.make_constant(result);
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    folder.fold_mapping((NodeMappingType)type);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void MappingNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *vector_in = input("Vector");
 | 
						|
  ShaderInput *location_in = input("Location");
 | 
						|
  ShaderInput *rotation_in = input("Rotation");
 | 
						|
  ShaderInput *scale_in = input("Scale");
 | 
						|
  ShaderOutput *vector_out = output("Vector");
 | 
						|
 | 
						|
  int vector_stack_offset = compiler.stack_assign(vector_in);
 | 
						|
  int location_stack_offset = compiler.stack_assign(location_in);
 | 
						|
  int rotation_stack_offset = compiler.stack_assign(rotation_in);
 | 
						|
  int scale_stack_offset = compiler.stack_assign(scale_in);
 | 
						|
  int result_stack_offset = compiler.stack_assign(vector_out);
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      NODE_MAPPING,
 | 
						|
      type,
 | 
						|
      compiler.encode_uchar4(
 | 
						|
          vector_stack_offset, location_stack_offset, rotation_stack_offset, scale_stack_offset),
 | 
						|
      result_stack_offset);
 | 
						|
}
 | 
						|
 | 
						|
void MappingNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.parameter(this, "type");
 | 
						|
  compiler.add(this, "node_mapping");
 | 
						|
}
 | 
						|
 | 
						|
/* RGBToBW */
 | 
						|
 | 
						|
NODE_DEFINE(RGBToBWNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("rgb_to_bw", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
  SOCKET_OUT_FLOAT(val, "Val");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
RGBToBWNode::RGBToBWNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void RGBToBWNode::constant_fold(const ConstantFolder &folder)
 | 
						|
{
 | 
						|
  if (folder.all_inputs_constant()) {
 | 
						|
    float val = folder.scene->shader_manager->linear_rgb_to_gray(color);
 | 
						|
    folder.make_constant(val);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void RGBToBWNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add_node(NODE_CONVERT,
 | 
						|
                    NODE_CONVERT_CF,
 | 
						|
                    compiler.stack_assign(inputs[0]),
 | 
						|
                    compiler.stack_assign(outputs[0]));
 | 
						|
}
 | 
						|
 | 
						|
void RGBToBWNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_rgb_to_bw");
 | 
						|
}
 | 
						|
 | 
						|
/* Convert */
 | 
						|
 | 
						|
const NodeType *ConvertNode::node_types[ConvertNode::MAX_TYPE][ConvertNode::MAX_TYPE];
 | 
						|
bool ConvertNode::initialized = ConvertNode::register_types();
 | 
						|
 | 
						|
Node *ConvertNode::create(const NodeType *type)
 | 
						|
{
 | 
						|
  return new ConvertNode(type->inputs[0].type, type->outputs[0].type);
 | 
						|
}
 | 
						|
 | 
						|
bool ConvertNode::register_types()
 | 
						|
{
 | 
						|
  const int num_types = 8;
 | 
						|
  SocketType::Type types[num_types] = {SocketType::FLOAT,
 | 
						|
                                       SocketType::INT,
 | 
						|
                                       SocketType::COLOR,
 | 
						|
                                       SocketType::VECTOR,
 | 
						|
                                       SocketType::POINT,
 | 
						|
                                       SocketType::NORMAL,
 | 
						|
                                       SocketType::STRING,
 | 
						|
                                       SocketType::CLOSURE};
 | 
						|
 | 
						|
  for (size_t i = 0; i < num_types; i++) {
 | 
						|
    SocketType::Type from = types[i];
 | 
						|
    ustring from_name(SocketType::type_name(from));
 | 
						|
    ustring from_value_name("value_" + from_name.string());
 | 
						|
 | 
						|
    for (size_t j = 0; j < num_types; j++) {
 | 
						|
      SocketType::Type to = types[j];
 | 
						|
      ustring to_name(SocketType::type_name(to));
 | 
						|
      ustring to_value_name("value_" + to_name.string());
 | 
						|
 | 
						|
      string node_name = "convert_" + from_name.string() + "_to_" + to_name.string();
 | 
						|
      NodeType *type = NodeType::add(node_name.c_str(), create, NodeType::SHADER);
 | 
						|
 | 
						|
      type->register_input(from_value_name,
 | 
						|
                           from_value_name,
 | 
						|
                           from,
 | 
						|
                           SOCKET_OFFSETOF(ConvertNode, value_float),
 | 
						|
                           SocketType::zero_default_value(),
 | 
						|
                           NULL,
 | 
						|
                           NULL,
 | 
						|
                           SocketType::LINKABLE);
 | 
						|
      type->register_output(to_value_name, to_value_name, to);
 | 
						|
 | 
						|
      assert(from < MAX_TYPE);
 | 
						|
      assert(to < MAX_TYPE);
 | 
						|
 | 
						|
      node_types[from][to] = type;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return true;
 | 
						|
}
 | 
						|
 | 
						|
ConvertNode::ConvertNode(SocketType::Type from_, SocketType::Type to_, bool autoconvert)
 | 
						|
    : ShaderNode(node_types[from_][to_])
 | 
						|
{
 | 
						|
  from = from_;
 | 
						|
  to = to_;
 | 
						|
 | 
						|
  if (from == to)
 | 
						|
    special_type = SHADER_SPECIAL_TYPE_PROXY;
 | 
						|
  else if (autoconvert)
 | 
						|
    special_type = SHADER_SPECIAL_TYPE_AUTOCONVERT;
 | 
						|
}
 | 
						|
 | 
						|
void ConvertNode::constant_fold(const ConstantFolder &folder)
 | 
						|
{
 | 
						|
  /* proxy nodes should have been removed at this point */
 | 
						|
  assert(special_type != SHADER_SPECIAL_TYPE_PROXY);
 | 
						|
 | 
						|
  /* TODO(DingTo): conversion from/to int is not supported yet, don't fold in that case */
 | 
						|
 | 
						|
  if (folder.all_inputs_constant()) {
 | 
						|
    if (from == SocketType::FLOAT) {
 | 
						|
      if (SocketType::is_float3(to)) {
 | 
						|
        folder.make_constant(make_float3(value_float, value_float, value_float));
 | 
						|
      }
 | 
						|
    }
 | 
						|
    else if (SocketType::is_float3(from)) {
 | 
						|
      if (to == SocketType::FLOAT) {
 | 
						|
        if (from == SocketType::COLOR) {
 | 
						|
          /* color to float */
 | 
						|
          float val = folder.scene->shader_manager->linear_rgb_to_gray(value_color);
 | 
						|
          folder.make_constant(val);
 | 
						|
        }
 | 
						|
        else {
 | 
						|
          /* vector/point/normal to float */
 | 
						|
          folder.make_constant(average(value_vector));
 | 
						|
        }
 | 
						|
      }
 | 
						|
      else if (SocketType::is_float3(to)) {
 | 
						|
        folder.make_constant(value_color);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    ShaderInput *in = inputs[0];
 | 
						|
    ShaderNode *prev = in->link->parent;
 | 
						|
 | 
						|
    /* no-op conversion of A to B to A */
 | 
						|
    if (prev->type == node_types[to][from]) {
 | 
						|
      ShaderInput *prev_in = prev->inputs[0];
 | 
						|
 | 
						|
      if (SocketType::is_float3(from) && (to == SocketType::FLOAT || SocketType::is_float3(to)) &&
 | 
						|
          prev_in->link) {
 | 
						|
        folder.bypass(prev_in->link);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ConvertNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  /* proxy nodes should have been removed at this point */
 | 
						|
  assert(special_type != SHADER_SPECIAL_TYPE_PROXY);
 | 
						|
 | 
						|
  ShaderInput *in = inputs[0];
 | 
						|
  ShaderOutput *out = outputs[0];
 | 
						|
 | 
						|
  if (from == SocketType::FLOAT) {
 | 
						|
    if (to == SocketType::INT)
 | 
						|
      /* float to int */
 | 
						|
      compiler.add_node(
 | 
						|
          NODE_CONVERT, NODE_CONVERT_FI, compiler.stack_assign(in), compiler.stack_assign(out));
 | 
						|
    else
 | 
						|
      /* float to float3 */
 | 
						|
      compiler.add_node(
 | 
						|
          NODE_CONVERT, NODE_CONVERT_FV, compiler.stack_assign(in), compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
  else if (from == SocketType::INT) {
 | 
						|
    if (to == SocketType::FLOAT)
 | 
						|
      /* int to float */
 | 
						|
      compiler.add_node(
 | 
						|
          NODE_CONVERT, NODE_CONVERT_IF, compiler.stack_assign(in), compiler.stack_assign(out));
 | 
						|
    else
 | 
						|
      /* int to vector/point/normal */
 | 
						|
      compiler.add_node(
 | 
						|
          NODE_CONVERT, NODE_CONVERT_IV, compiler.stack_assign(in), compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
  else if (to == SocketType::FLOAT) {
 | 
						|
    if (from == SocketType::COLOR)
 | 
						|
      /* color to float */
 | 
						|
      compiler.add_node(
 | 
						|
          NODE_CONVERT, NODE_CONVERT_CF, compiler.stack_assign(in), compiler.stack_assign(out));
 | 
						|
    else
 | 
						|
      /* vector/point/normal to float */
 | 
						|
      compiler.add_node(
 | 
						|
          NODE_CONVERT, NODE_CONVERT_VF, compiler.stack_assign(in), compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
  else if (to == SocketType::INT) {
 | 
						|
    if (from == SocketType::COLOR)
 | 
						|
      /* color to int */
 | 
						|
      compiler.add_node(
 | 
						|
          NODE_CONVERT, NODE_CONVERT_CI, compiler.stack_assign(in), compiler.stack_assign(out));
 | 
						|
    else
 | 
						|
      /* vector/point/normal to int */
 | 
						|
      compiler.add_node(
 | 
						|
          NODE_CONVERT, NODE_CONVERT_VI, compiler.stack_assign(in), compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    /* float3 to float3 */
 | 
						|
    if (in->link) {
 | 
						|
      /* no op in SVM */
 | 
						|
      compiler.stack_link(in, out);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      /* set 0,0,0 value */
 | 
						|
      compiler.add_node(NODE_VALUE_V, compiler.stack_assign(out));
 | 
						|
      compiler.add_node(NODE_VALUE_V, value_color);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ConvertNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  /* proxy nodes should have been removed at this point */
 | 
						|
  assert(special_type != SHADER_SPECIAL_TYPE_PROXY);
 | 
						|
 | 
						|
  if (from == SocketType::FLOAT)
 | 
						|
    compiler.add(this, "node_convert_from_float");
 | 
						|
  else if (from == SocketType::INT)
 | 
						|
    compiler.add(this, "node_convert_from_int");
 | 
						|
  else if (from == SocketType::COLOR)
 | 
						|
    compiler.add(this, "node_convert_from_color");
 | 
						|
  else if (from == SocketType::VECTOR)
 | 
						|
    compiler.add(this, "node_convert_from_vector");
 | 
						|
  else if (from == SocketType::POINT)
 | 
						|
    compiler.add(this, "node_convert_from_point");
 | 
						|
  else if (from == SocketType::NORMAL)
 | 
						|
    compiler.add(this, "node_convert_from_normal");
 | 
						|
  else
 | 
						|
    assert(0);
 | 
						|
}
 | 
						|
 | 
						|
/* Base type for all closure-type nodes */
 | 
						|
 | 
						|
BsdfBaseNode::BsdfBaseNode(const NodeType *node_type) : ShaderNode(node_type)
 | 
						|
{
 | 
						|
  special_type = SHADER_SPECIAL_TYPE_CLOSURE;
 | 
						|
}
 | 
						|
 | 
						|
bool BsdfBaseNode::has_bump()
 | 
						|
{
 | 
						|
  /* detect if anything is plugged into the normal input besides the default */
 | 
						|
  ShaderInput *normal_in = input("Normal");
 | 
						|
  return (normal_in && normal_in->link &&
 | 
						|
          normal_in->link->parent->special_type != SHADER_SPECIAL_TYPE_GEOMETRY);
 | 
						|
}
 | 
						|
 | 
						|
/* BSDF Closure */
 | 
						|
 | 
						|
BsdfNode::BsdfNode(const NodeType *node_type) : BsdfBaseNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void BsdfNode::compile(SVMCompiler &compiler,
 | 
						|
                       ShaderInput *param1,
 | 
						|
                       ShaderInput *param2,
 | 
						|
                       ShaderInput *param3,
 | 
						|
                       ShaderInput *param4)
 | 
						|
{
 | 
						|
  ShaderInput *color_in = input("Color");
 | 
						|
  ShaderInput *normal_in = input("Normal");
 | 
						|
  ShaderInput *tangent_in = input("Tangent");
 | 
						|
 | 
						|
  if (color_in->link)
 | 
						|
    compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
 | 
						|
  else
 | 
						|
    compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color);
 | 
						|
 | 
						|
  int normal_offset = (normal_in) ? compiler.stack_assign_if_linked(normal_in) : SVM_STACK_INVALID;
 | 
						|
  int tangent_offset = (tangent_in) ? compiler.stack_assign_if_linked(tangent_in) :
 | 
						|
                                      SVM_STACK_INVALID;
 | 
						|
  int param3_offset = (param3) ? compiler.stack_assign(param3) : SVM_STACK_INVALID;
 | 
						|
  int param4_offset = (param4) ? compiler.stack_assign(param4) : SVM_STACK_INVALID;
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      NODE_CLOSURE_BSDF,
 | 
						|
      compiler.encode_uchar4(closure,
 | 
						|
                             (param1) ? compiler.stack_assign(param1) : SVM_STACK_INVALID,
 | 
						|
                             (param2) ? compiler.stack_assign(param2) : SVM_STACK_INVALID,
 | 
						|
                             compiler.closure_mix_weight_offset()),
 | 
						|
      __float_as_int((param1) ? get_float(param1->socket_type) : 0.0f),
 | 
						|
      __float_as_int((param2) ? get_float(param2->socket_type) : 0.0f));
 | 
						|
 | 
						|
  compiler.add_node(normal_offset, tangent_offset, param3_offset, param4_offset);
 | 
						|
}
 | 
						|
 | 
						|
void BsdfNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  compile(compiler, NULL, NULL);
 | 
						|
}
 | 
						|
 | 
						|
void BsdfNode::compile(OSLCompiler & /*compiler*/)
 | 
						|
{
 | 
						|
  assert(0);
 | 
						|
}
 | 
						|
 | 
						|
/* Anisotropic BSDF Closure */
 | 
						|
 | 
						|
NODE_DEFINE(AnisotropicBsdfNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("anisotropic_bsdf", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
 | 
						|
  SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
 | 
						|
  SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
 | 
						|
 | 
						|
  static NodeEnum distribution_enum;
 | 
						|
  distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
 | 
						|
  distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ID);
 | 
						|
  distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
 | 
						|
  distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
 | 
						|
  SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ID);
 | 
						|
 | 
						|
  SOCKET_IN_VECTOR(tangent, "Tangent", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TANGENT);
 | 
						|
 | 
						|
  SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f);
 | 
						|
  SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.5f);
 | 
						|
  SOCKET_IN_FLOAT(rotation, "Rotation", 0.0f);
 | 
						|
 | 
						|
  SOCKET_OUT_CLOSURE(BSDF, "BSDF");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
AnisotropicBsdfNode::AnisotropicBsdfNode() : BsdfNode(node_type)
 | 
						|
{
 | 
						|
  closure = CLOSURE_BSDF_MICROFACET_GGX_ID;
 | 
						|
}
 | 
						|
 | 
						|
void AnisotropicBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 | 
						|
{
 | 
						|
  if (shader->has_surface) {
 | 
						|
    ShaderInput *tangent_in = input("Tangent");
 | 
						|
 | 
						|
    if (!tangent_in->link)
 | 
						|
      attributes->add(ATTR_STD_GENERATED);
 | 
						|
  }
 | 
						|
 | 
						|
  ShaderNode::attributes(shader, attributes);
 | 
						|
}
 | 
						|
 | 
						|
void AnisotropicBsdfNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  closure = distribution;
 | 
						|
 | 
						|
  if (closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID)
 | 
						|
    BsdfNode::compile(
 | 
						|
        compiler, input("Roughness"), input("Anisotropy"), input("Rotation"), input("Color"));
 | 
						|
  else
 | 
						|
    BsdfNode::compile(compiler, input("Roughness"), input("Anisotropy"), input("Rotation"));
 | 
						|
}
 | 
						|
 | 
						|
void AnisotropicBsdfNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.parameter(this, "distribution");
 | 
						|
  compiler.add(this, "node_anisotropic_bsdf");
 | 
						|
}
 | 
						|
 | 
						|
/* Glossy BSDF Closure */
 | 
						|
 | 
						|
NODE_DEFINE(GlossyBsdfNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("glossy_bsdf", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
 | 
						|
  SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
 | 
						|
  SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
 | 
						|
 | 
						|
  static NodeEnum distribution_enum;
 | 
						|
  distribution_enum.insert("sharp", CLOSURE_BSDF_REFLECTION_ID);
 | 
						|
  distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_ID);
 | 
						|
  distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_ID);
 | 
						|
  distribution_enum.insert("ashikhmin_shirley", CLOSURE_BSDF_ASHIKHMIN_SHIRLEY_ID);
 | 
						|
  distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID);
 | 
						|
  SOCKET_ENUM(distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_ID);
 | 
						|
  SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f);
 | 
						|
 | 
						|
  SOCKET_OUT_CLOSURE(BSDF, "BSDF");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
GlossyBsdfNode::GlossyBsdfNode() : BsdfNode(node_type)
 | 
						|
{
 | 
						|
  closure = CLOSURE_BSDF_MICROFACET_GGX_ID;
 | 
						|
  distribution_orig = NBUILTIN_CLOSURES;
 | 
						|
}
 | 
						|
 | 
						|
void GlossyBsdfNode::simplify_settings(Scene *scene)
 | 
						|
{
 | 
						|
  if (distribution_orig == NBUILTIN_CLOSURES) {
 | 
						|
    roughness_orig = roughness;
 | 
						|
    distribution_orig = distribution;
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    /* By default we use original values, so we don't worry about restoring
 | 
						|
     * defaults later one and can only do override when needed.
 | 
						|
     */
 | 
						|
    roughness = roughness_orig;
 | 
						|
    distribution = distribution_orig;
 | 
						|
  }
 | 
						|
  Integrator *integrator = scene->integrator;
 | 
						|
  ShaderInput *roughness_input = input("Roughness");
 | 
						|
  if (integrator->filter_glossy == 0.0f) {
 | 
						|
    /* Fallback to Sharp closure for Roughness close to 0.
 | 
						|
     * Note: Keep the epsilon in sync with kernel!
 | 
						|
     */
 | 
						|
    if (!roughness_input->link && roughness <= 1e-4f) {
 | 
						|
      VLOG(1) << "Using sharp glossy BSDF.";
 | 
						|
      distribution = CLOSURE_BSDF_REFLECTION_ID;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    /* If filter glossy is used we replace Sharp glossy with GGX so we can
 | 
						|
     * benefit from closure blur to remove unwanted noise.
 | 
						|
     */
 | 
						|
    if (roughness_input->link == NULL && distribution == CLOSURE_BSDF_REFLECTION_ID) {
 | 
						|
      VLOG(1) << "Using GGX glossy with filter glossy.";
 | 
						|
      distribution = CLOSURE_BSDF_MICROFACET_GGX_ID;
 | 
						|
      roughness = 0.0f;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  closure = distribution;
 | 
						|
}
 | 
						|
 | 
						|
bool GlossyBsdfNode::has_integrator_dependency()
 | 
						|
{
 | 
						|
  ShaderInput *roughness_input = input("Roughness");
 | 
						|
  return !roughness_input->link &&
 | 
						|
         (distribution == CLOSURE_BSDF_REFLECTION_ID || roughness <= 1e-4f);
 | 
						|
}
 | 
						|
 | 
						|
void GlossyBsdfNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  closure = distribution;
 | 
						|
 | 
						|
  if (closure == CLOSURE_BSDF_REFLECTION_ID)
 | 
						|
    BsdfNode::compile(compiler, NULL, NULL);
 | 
						|
  else if (closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_ID)
 | 
						|
    BsdfNode::compile(compiler, input("Roughness"), NULL, NULL, input("Color"));
 | 
						|
  else
 | 
						|
    BsdfNode::compile(compiler, input("Roughness"), NULL);
 | 
						|
}
 | 
						|
 | 
						|
void GlossyBsdfNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.parameter(this, "distribution");
 | 
						|
  compiler.add(this, "node_glossy_bsdf");
 | 
						|
}
 | 
						|
 | 
						|
/* Glass BSDF Closure */
 | 
						|
 | 
						|
NODE_DEFINE(GlassBsdfNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("glass_bsdf", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
 | 
						|
  SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
 | 
						|
  SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
 | 
						|
 | 
						|
  static NodeEnum distribution_enum;
 | 
						|
  distribution_enum.insert("sharp", CLOSURE_BSDF_SHARP_GLASS_ID);
 | 
						|
  distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_GLASS_ID);
 | 
						|
  distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
 | 
						|
  distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
 | 
						|
  SOCKET_ENUM(
 | 
						|
      distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
 | 
						|
  SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(IOR, "IOR", 0.3f);
 | 
						|
 | 
						|
  SOCKET_OUT_CLOSURE(BSDF, "BSDF");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
GlassBsdfNode::GlassBsdfNode() : BsdfNode(node_type)
 | 
						|
{
 | 
						|
  closure = CLOSURE_BSDF_SHARP_GLASS_ID;
 | 
						|
  distribution_orig = NBUILTIN_CLOSURES;
 | 
						|
}
 | 
						|
 | 
						|
void GlassBsdfNode::simplify_settings(Scene *scene)
 | 
						|
{
 | 
						|
  if (distribution_orig == NBUILTIN_CLOSURES) {
 | 
						|
    roughness_orig = roughness;
 | 
						|
    distribution_orig = distribution;
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    /* By default we use original values, so we don't worry about restoring
 | 
						|
     * defaults later one and can only do override when needed.
 | 
						|
     */
 | 
						|
    roughness = roughness_orig;
 | 
						|
    distribution = distribution_orig;
 | 
						|
  }
 | 
						|
  Integrator *integrator = scene->integrator;
 | 
						|
  ShaderInput *roughness_input = input("Roughness");
 | 
						|
  if (integrator->filter_glossy == 0.0f) {
 | 
						|
    /* Fallback to Sharp closure for Roughness close to 0.
 | 
						|
     * Note: Keep the epsilon in sync with kernel!
 | 
						|
     */
 | 
						|
    if (!roughness_input->link && roughness <= 1e-4f) {
 | 
						|
      VLOG(1) << "Using sharp glass BSDF.";
 | 
						|
      distribution = CLOSURE_BSDF_SHARP_GLASS_ID;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    /* If filter glossy is used we replace Sharp glossy with GGX so we can
 | 
						|
     * benefit from closure blur to remove unwanted noise.
 | 
						|
     */
 | 
						|
    if (roughness_input->link == NULL && distribution == CLOSURE_BSDF_SHARP_GLASS_ID) {
 | 
						|
      VLOG(1) << "Using GGX glass with filter glossy.";
 | 
						|
      distribution = CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID;
 | 
						|
      roughness = 0.0f;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  closure = distribution;
 | 
						|
}
 | 
						|
 | 
						|
bool GlassBsdfNode::has_integrator_dependency()
 | 
						|
{
 | 
						|
  ShaderInput *roughness_input = input("Roughness");
 | 
						|
  return !roughness_input->link &&
 | 
						|
         (distribution == CLOSURE_BSDF_SHARP_GLASS_ID || roughness <= 1e-4f);
 | 
						|
}
 | 
						|
 | 
						|
void GlassBsdfNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  closure = distribution;
 | 
						|
 | 
						|
  if (closure == CLOSURE_BSDF_SHARP_GLASS_ID)
 | 
						|
    BsdfNode::compile(compiler, NULL, input("IOR"));
 | 
						|
  else if (closure == CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID)
 | 
						|
    BsdfNode::compile(compiler, input("Roughness"), input("IOR"), input("Color"));
 | 
						|
  else
 | 
						|
    BsdfNode::compile(compiler, input("Roughness"), input("IOR"));
 | 
						|
}
 | 
						|
 | 
						|
void GlassBsdfNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.parameter(this, "distribution");
 | 
						|
  compiler.add(this, "node_glass_bsdf");
 | 
						|
}
 | 
						|
 | 
						|
/* Refraction BSDF Closure */
 | 
						|
 | 
						|
NODE_DEFINE(RefractionBsdfNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("refraction_bsdf", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
 | 
						|
  SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
 | 
						|
  SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
 | 
						|
 | 
						|
  static NodeEnum distribution_enum;
 | 
						|
  distribution_enum.insert("sharp", CLOSURE_BSDF_REFRACTION_ID);
 | 
						|
  distribution_enum.insert("beckmann", CLOSURE_BSDF_MICROFACET_BECKMANN_REFRACTION_ID);
 | 
						|
  distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
 | 
						|
  SOCKET_ENUM(
 | 
						|
      distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID);
 | 
						|
 | 
						|
  SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(IOR, "IOR", 0.3f);
 | 
						|
 | 
						|
  SOCKET_OUT_CLOSURE(BSDF, "BSDF");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
RefractionBsdfNode::RefractionBsdfNode() : BsdfNode(node_type)
 | 
						|
{
 | 
						|
  closure = CLOSURE_BSDF_REFRACTION_ID;
 | 
						|
  distribution_orig = NBUILTIN_CLOSURES;
 | 
						|
}
 | 
						|
 | 
						|
void RefractionBsdfNode::simplify_settings(Scene *scene)
 | 
						|
{
 | 
						|
  if (distribution_orig == NBUILTIN_CLOSURES) {
 | 
						|
    roughness_orig = roughness;
 | 
						|
    distribution_orig = distribution;
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    /* By default we use original values, so we don't worry about restoring
 | 
						|
     * defaults later one and can only do override when needed.
 | 
						|
     */
 | 
						|
    roughness = roughness_orig;
 | 
						|
    distribution = distribution_orig;
 | 
						|
  }
 | 
						|
  Integrator *integrator = scene->integrator;
 | 
						|
  ShaderInput *roughness_input = input("Roughness");
 | 
						|
  if (integrator->filter_glossy == 0.0f) {
 | 
						|
    /* Fallback to Sharp closure for Roughness close to 0.
 | 
						|
     * Note: Keep the epsilon in sync with kernel!
 | 
						|
     */
 | 
						|
    if (!roughness_input->link && roughness <= 1e-4f) {
 | 
						|
      VLOG(1) << "Using sharp refraction BSDF.";
 | 
						|
      distribution = CLOSURE_BSDF_REFRACTION_ID;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    /* If filter glossy is used we replace Sharp glossy with GGX so we can
 | 
						|
     * benefit from closure blur to remove unwanted noise.
 | 
						|
     */
 | 
						|
    if (roughness_input->link == NULL && distribution == CLOSURE_BSDF_REFRACTION_ID) {
 | 
						|
      VLOG(1) << "Using GGX refraction with filter glossy.";
 | 
						|
      distribution = CLOSURE_BSDF_MICROFACET_GGX_REFRACTION_ID;
 | 
						|
      roughness = 0.0f;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  closure = distribution;
 | 
						|
}
 | 
						|
 | 
						|
bool RefractionBsdfNode::has_integrator_dependency()
 | 
						|
{
 | 
						|
  ShaderInput *roughness_input = input("Roughness");
 | 
						|
  return !roughness_input->link &&
 | 
						|
         (distribution == CLOSURE_BSDF_REFRACTION_ID || roughness <= 1e-4f);
 | 
						|
}
 | 
						|
 | 
						|
void RefractionBsdfNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  closure = distribution;
 | 
						|
 | 
						|
  if (closure == CLOSURE_BSDF_REFRACTION_ID)
 | 
						|
    BsdfNode::compile(compiler, NULL, input("IOR"));
 | 
						|
  else
 | 
						|
    BsdfNode::compile(compiler, input("Roughness"), input("IOR"));
 | 
						|
}
 | 
						|
 | 
						|
void RefractionBsdfNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.parameter(this, "distribution");
 | 
						|
  compiler.add(this, "node_refraction_bsdf");
 | 
						|
}
 | 
						|
 | 
						|
/* Toon BSDF Closure */
 | 
						|
 | 
						|
NODE_DEFINE(ToonBsdfNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("toon_bsdf", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
 | 
						|
  SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
 | 
						|
  SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
 | 
						|
 | 
						|
  static NodeEnum component_enum;
 | 
						|
  component_enum.insert("diffuse", CLOSURE_BSDF_DIFFUSE_TOON_ID);
 | 
						|
  component_enum.insert("glossy", CLOSURE_BSDF_GLOSSY_TOON_ID);
 | 
						|
  SOCKET_ENUM(component, "Component", component_enum, CLOSURE_BSDF_DIFFUSE_TOON_ID);
 | 
						|
  SOCKET_IN_FLOAT(size, "Size", 0.5f);
 | 
						|
  SOCKET_IN_FLOAT(smooth, "Smooth", 0.0f);
 | 
						|
 | 
						|
  SOCKET_OUT_CLOSURE(BSDF, "BSDF");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
ToonBsdfNode::ToonBsdfNode() : BsdfNode(node_type)
 | 
						|
{
 | 
						|
  closure = CLOSURE_BSDF_DIFFUSE_TOON_ID;
 | 
						|
}
 | 
						|
 | 
						|
void ToonBsdfNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  closure = component;
 | 
						|
 | 
						|
  BsdfNode::compile(compiler, input("Size"), input("Smooth"));
 | 
						|
}
 | 
						|
 | 
						|
void ToonBsdfNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.parameter(this, "component");
 | 
						|
  compiler.add(this, "node_toon_bsdf");
 | 
						|
}
 | 
						|
 | 
						|
/* Velvet BSDF Closure */
 | 
						|
 | 
						|
NODE_DEFINE(VelvetBsdfNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("velvet_bsdf", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
 | 
						|
  SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
 | 
						|
  SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
 | 
						|
  SOCKET_IN_FLOAT(sigma, "Sigma", 1.0f);
 | 
						|
 | 
						|
  SOCKET_OUT_CLOSURE(BSDF, "BSDF");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
VelvetBsdfNode::VelvetBsdfNode() : BsdfNode(node_type)
 | 
						|
{
 | 
						|
  closure = CLOSURE_BSDF_ASHIKHMIN_VELVET_ID;
 | 
						|
}
 | 
						|
 | 
						|
void VelvetBsdfNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  BsdfNode::compile(compiler, input("Sigma"), NULL);
 | 
						|
}
 | 
						|
 | 
						|
void VelvetBsdfNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_velvet_bsdf");
 | 
						|
}
 | 
						|
 | 
						|
/* Diffuse BSDF Closure */
 | 
						|
 | 
						|
NODE_DEFINE(DiffuseBsdfNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("diffuse_bsdf", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
 | 
						|
  SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
 | 
						|
  SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
 | 
						|
  SOCKET_IN_FLOAT(roughness, "Roughness", 0.0f);
 | 
						|
 | 
						|
  SOCKET_OUT_CLOSURE(BSDF, "BSDF");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
DiffuseBsdfNode::DiffuseBsdfNode() : BsdfNode(node_type)
 | 
						|
{
 | 
						|
  closure = CLOSURE_BSDF_DIFFUSE_ID;
 | 
						|
}
 | 
						|
 | 
						|
void DiffuseBsdfNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  BsdfNode::compile(compiler, input("Roughness"), NULL);
 | 
						|
}
 | 
						|
 | 
						|
void DiffuseBsdfNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_diffuse_bsdf");
 | 
						|
}
 | 
						|
 | 
						|
/* Disney principled BSDF Closure */
 | 
						|
NODE_DEFINE(PrincipledBsdfNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("principled_bsdf", create, NodeType::SHADER);
 | 
						|
 | 
						|
  static NodeEnum distribution_enum;
 | 
						|
  distribution_enum.insert("GGX", CLOSURE_BSDF_MICROFACET_GGX_GLASS_ID);
 | 
						|
  distribution_enum.insert("Multiscatter GGX", CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
 | 
						|
  SOCKET_ENUM(
 | 
						|
      distribution, "Distribution", distribution_enum, CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID);
 | 
						|
 | 
						|
  static NodeEnum subsurface_method_enum;
 | 
						|
  subsurface_method_enum.insert("burley", CLOSURE_BSSRDF_PRINCIPLED_ID);
 | 
						|
  subsurface_method_enum.insert("random_walk", CLOSURE_BSSRDF_PRINCIPLED_RANDOM_WALK_ID);
 | 
						|
  SOCKET_ENUM(subsurface_method,
 | 
						|
              "Subsurface Method",
 | 
						|
              subsurface_method_enum,
 | 
						|
              CLOSURE_BSSRDF_PRINCIPLED_ID);
 | 
						|
 | 
						|
  SOCKET_IN_COLOR(base_color, "Base Color", make_float3(0.8f, 0.8f, 0.8f));
 | 
						|
  SOCKET_IN_COLOR(subsurface_color, "Subsurface Color", make_float3(0.8f, 0.8f, 0.8f));
 | 
						|
  SOCKET_IN_FLOAT(metallic, "Metallic", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(subsurface, "Subsurface", 0.0f);
 | 
						|
  SOCKET_IN_VECTOR(subsurface_radius, "Subsurface Radius", make_float3(0.1f, 0.1f, 0.1f));
 | 
						|
  SOCKET_IN_FLOAT(specular, "Specular", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(roughness, "Roughness", 0.5f);
 | 
						|
  SOCKET_IN_FLOAT(specular_tint, "Specular Tint", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(anisotropic, "Anisotropic", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(sheen, "Sheen", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(sheen_tint, "Sheen Tint", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(clearcoat, "Clearcoat", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(clearcoat_roughness, "Clearcoat Roughness", 0.03f);
 | 
						|
  SOCKET_IN_FLOAT(ior, "IOR", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(transmission, "Transmission", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(transmission_roughness, "Transmission Roughness", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(anisotropic_rotation, "Anisotropic Rotation", 0.0f);
 | 
						|
  SOCKET_IN_COLOR(emission, "Emission", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
  SOCKET_IN_FLOAT(alpha, "Alpha", 1.0f);
 | 
						|
  SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
 | 
						|
  SOCKET_IN_NORMAL(clearcoat_normal,
 | 
						|
                   "Clearcoat Normal",
 | 
						|
                   make_float3(0.0f, 0.0f, 0.0f),
 | 
						|
                   SocketType::LINK_NORMAL);
 | 
						|
  SOCKET_IN_NORMAL(tangent, "Tangent", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_TANGENT);
 | 
						|
  SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
 | 
						|
 | 
						|
  SOCKET_OUT_CLOSURE(BSDF, "BSDF");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
PrincipledBsdfNode::PrincipledBsdfNode() : BsdfBaseNode(node_type)
 | 
						|
{
 | 
						|
  closure = CLOSURE_BSDF_PRINCIPLED_ID;
 | 
						|
  distribution = CLOSURE_BSDF_MICROFACET_MULTI_GGX_GLASS_ID;
 | 
						|
  distribution_orig = NBUILTIN_CLOSURES;
 | 
						|
}
 | 
						|
 | 
						|
void PrincipledBsdfNode::expand(ShaderGraph *graph)
 | 
						|
{
 | 
						|
  ShaderOutput *principled_out = output("BSDF");
 | 
						|
 | 
						|
  ShaderInput *emission_in = input("Emission");
 | 
						|
  if (emission_in->link || emission != make_float3(0.0f, 0.0f, 0.0f)) {
 | 
						|
    /* Create add closure and emission. */
 | 
						|
    AddClosureNode *add = new AddClosureNode();
 | 
						|
    EmissionNode *emission_node = new EmissionNode();
 | 
						|
    ShaderOutput *new_out = add->output("Closure");
 | 
						|
 | 
						|
    graph->add(add);
 | 
						|
    graph->add(emission_node);
 | 
						|
 | 
						|
    emission_node->strength = 1.0f;
 | 
						|
    graph->relink(emission_in, emission_node->input("Color"));
 | 
						|
    graph->relink(principled_out, new_out);
 | 
						|
    graph->connect(emission_node->output("Emission"), add->input("Closure1"));
 | 
						|
    graph->connect(principled_out, add->input("Closure2"));
 | 
						|
 | 
						|
    principled_out = new_out;
 | 
						|
  }
 | 
						|
 | 
						|
  ShaderInput *alpha_in = input("Alpha");
 | 
						|
  if (alpha_in->link || alpha != 1.0f) {
 | 
						|
    /* Create mix and transparent BSDF for alpha transparency. */
 | 
						|
    MixClosureNode *mix = new MixClosureNode();
 | 
						|
    TransparentBsdfNode *transparent = new TransparentBsdfNode();
 | 
						|
 | 
						|
    graph->add(mix);
 | 
						|
    graph->add(transparent);
 | 
						|
 | 
						|
    graph->relink(alpha_in, mix->input("Fac"));
 | 
						|
    graph->relink(principled_out, mix->output("Closure"));
 | 
						|
    graph->connect(transparent->output("BSDF"), mix->input("Closure1"));
 | 
						|
    graph->connect(principled_out, mix->input("Closure2"));
 | 
						|
  }
 | 
						|
 | 
						|
  remove_input(emission_in);
 | 
						|
  remove_input(alpha_in);
 | 
						|
}
 | 
						|
 | 
						|
bool PrincipledBsdfNode::has_surface_bssrdf()
 | 
						|
{
 | 
						|
  ShaderInput *subsurface_in = input("Subsurface");
 | 
						|
  return (subsurface_in->link != NULL || subsurface > CLOSURE_WEIGHT_CUTOFF);
 | 
						|
}
 | 
						|
 | 
						|
void PrincipledBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 | 
						|
{
 | 
						|
  if (shader->has_surface) {
 | 
						|
    ShaderInput *tangent_in = input("Tangent");
 | 
						|
 | 
						|
    if (!tangent_in->link)
 | 
						|
      attributes->add(ATTR_STD_GENERATED);
 | 
						|
  }
 | 
						|
 | 
						|
  ShaderNode::attributes(shader, attributes);
 | 
						|
}
 | 
						|
 | 
						|
void PrincipledBsdfNode::compile(SVMCompiler &compiler,
 | 
						|
                                 ShaderInput *p_metallic,
 | 
						|
                                 ShaderInput *p_subsurface,
 | 
						|
                                 ShaderInput *p_subsurface_radius,
 | 
						|
                                 ShaderInput *p_specular,
 | 
						|
                                 ShaderInput *p_roughness,
 | 
						|
                                 ShaderInput *p_specular_tint,
 | 
						|
                                 ShaderInput *p_anisotropic,
 | 
						|
                                 ShaderInput *p_sheen,
 | 
						|
                                 ShaderInput *p_sheen_tint,
 | 
						|
                                 ShaderInput *p_clearcoat,
 | 
						|
                                 ShaderInput *p_clearcoat_roughness,
 | 
						|
                                 ShaderInput *p_ior,
 | 
						|
                                 ShaderInput *p_transmission,
 | 
						|
                                 ShaderInput *p_anisotropic_rotation,
 | 
						|
                                 ShaderInput *p_transmission_roughness)
 | 
						|
{
 | 
						|
  ShaderInput *base_color_in = input("Base Color");
 | 
						|
  ShaderInput *subsurface_color_in = input("Subsurface Color");
 | 
						|
  ShaderInput *normal_in = input("Normal");
 | 
						|
  ShaderInput *clearcoat_normal_in = input("Clearcoat Normal");
 | 
						|
  ShaderInput *tangent_in = input("Tangent");
 | 
						|
 | 
						|
  float3 weight = make_float3(1.0f, 1.0f, 1.0f);
 | 
						|
 | 
						|
  compiler.add_node(NODE_CLOSURE_SET_WEIGHT, weight);
 | 
						|
 | 
						|
  int normal_offset = compiler.stack_assign_if_linked(normal_in);
 | 
						|
  int clearcoat_normal_offset = compiler.stack_assign_if_linked(clearcoat_normal_in);
 | 
						|
  int tangent_offset = compiler.stack_assign_if_linked(tangent_in);
 | 
						|
  int specular_offset = compiler.stack_assign(p_specular);
 | 
						|
  int roughness_offset = compiler.stack_assign(p_roughness);
 | 
						|
  int specular_tint_offset = compiler.stack_assign(p_specular_tint);
 | 
						|
  int anisotropic_offset = compiler.stack_assign(p_anisotropic);
 | 
						|
  int sheen_offset = compiler.stack_assign(p_sheen);
 | 
						|
  int sheen_tint_offset = compiler.stack_assign(p_sheen_tint);
 | 
						|
  int clearcoat_offset = compiler.stack_assign(p_clearcoat);
 | 
						|
  int clearcoat_roughness_offset = compiler.stack_assign(p_clearcoat_roughness);
 | 
						|
  int ior_offset = compiler.stack_assign(p_ior);
 | 
						|
  int transmission_offset = compiler.stack_assign(p_transmission);
 | 
						|
  int transmission_roughness_offset = compiler.stack_assign(p_transmission_roughness);
 | 
						|
  int anisotropic_rotation_offset = compiler.stack_assign(p_anisotropic_rotation);
 | 
						|
  int subsurface_radius_offset = compiler.stack_assign(p_subsurface_radius);
 | 
						|
 | 
						|
  compiler.add_node(NODE_CLOSURE_BSDF,
 | 
						|
                    compiler.encode_uchar4(closure,
 | 
						|
                                           compiler.stack_assign(p_metallic),
 | 
						|
                                           compiler.stack_assign(p_subsurface),
 | 
						|
                                           compiler.closure_mix_weight_offset()),
 | 
						|
                    __float_as_int((p_metallic) ? get_float(p_metallic->socket_type) : 0.0f),
 | 
						|
                    __float_as_int((p_subsurface) ? get_float(p_subsurface->socket_type) : 0.0f));
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      normal_offset,
 | 
						|
      tangent_offset,
 | 
						|
      compiler.encode_uchar4(
 | 
						|
          specular_offset, roughness_offset, specular_tint_offset, anisotropic_offset),
 | 
						|
      compiler.encode_uchar4(
 | 
						|
          sheen_offset, sheen_tint_offset, clearcoat_offset, clearcoat_roughness_offset));
 | 
						|
 | 
						|
  compiler.add_node(compiler.encode_uchar4(ior_offset,
 | 
						|
                                           transmission_offset,
 | 
						|
                                           anisotropic_rotation_offset,
 | 
						|
                                           transmission_roughness_offset),
 | 
						|
                    distribution,
 | 
						|
                    subsurface_method,
 | 
						|
                    SVM_STACK_INVALID);
 | 
						|
 | 
						|
  float3 bc_default = get_float3(base_color_in->socket_type);
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      ((base_color_in->link) ? compiler.stack_assign(base_color_in) : SVM_STACK_INVALID),
 | 
						|
      __float_as_int(bc_default.x),
 | 
						|
      __float_as_int(bc_default.y),
 | 
						|
      __float_as_int(bc_default.z));
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      clearcoat_normal_offset, subsurface_radius_offset, SVM_STACK_INVALID, SVM_STACK_INVALID);
 | 
						|
 | 
						|
  float3 ss_default = get_float3(subsurface_color_in->socket_type);
 | 
						|
 | 
						|
  compiler.add_node(((subsurface_color_in->link) ? compiler.stack_assign(subsurface_color_in) :
 | 
						|
                                                   SVM_STACK_INVALID),
 | 
						|
                    __float_as_int(ss_default.x),
 | 
						|
                    __float_as_int(ss_default.y),
 | 
						|
                    __float_as_int(ss_default.z));
 | 
						|
}
 | 
						|
 | 
						|
bool PrincipledBsdfNode::has_integrator_dependency()
 | 
						|
{
 | 
						|
  ShaderInput *roughness_input = input("Roughness");
 | 
						|
  return !roughness_input->link && roughness <= 1e-4f;
 | 
						|
}
 | 
						|
 | 
						|
void PrincipledBsdfNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  compile(compiler,
 | 
						|
          input("Metallic"),
 | 
						|
          input("Subsurface"),
 | 
						|
          input("Subsurface Radius"),
 | 
						|
          input("Specular"),
 | 
						|
          input("Roughness"),
 | 
						|
          input("Specular Tint"),
 | 
						|
          input("Anisotropic"),
 | 
						|
          input("Sheen"),
 | 
						|
          input("Sheen Tint"),
 | 
						|
          input("Clearcoat"),
 | 
						|
          input("Clearcoat Roughness"),
 | 
						|
          input("IOR"),
 | 
						|
          input("Transmission"),
 | 
						|
          input("Anisotropic Rotation"),
 | 
						|
          input("Transmission Roughness"));
 | 
						|
}
 | 
						|
 | 
						|
void PrincipledBsdfNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.parameter(this, "distribution");
 | 
						|
  compiler.parameter(this, "subsurface_method");
 | 
						|
  compiler.add(this, "node_principled_bsdf");
 | 
						|
}
 | 
						|
 | 
						|
bool PrincipledBsdfNode::has_bssrdf_bump()
 | 
						|
{
 | 
						|
  return has_surface_bssrdf() && has_bump();
 | 
						|
}
 | 
						|
 | 
						|
/* Translucent BSDF Closure */
 | 
						|
 | 
						|
NODE_DEFINE(TranslucentBsdfNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("translucent_bsdf", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
 | 
						|
  SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
 | 
						|
  SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
 | 
						|
 | 
						|
  SOCKET_OUT_CLOSURE(BSDF, "BSDF");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
TranslucentBsdfNode::TranslucentBsdfNode() : BsdfNode(node_type)
 | 
						|
{
 | 
						|
  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 */
 | 
						|
 | 
						|
NODE_DEFINE(TransparentBsdfNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("transparent_bsdf", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_COLOR(color, "Color", make_float3(1.0f, 1.0f, 1.0f));
 | 
						|
  SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
 | 
						|
 | 
						|
  SOCKET_OUT_CLOSURE(BSDF, "BSDF");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
TransparentBsdfNode::TransparentBsdfNode() : BsdfNode(node_type)
 | 
						|
{
 | 
						|
  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");
 | 
						|
}
 | 
						|
 | 
						|
/* Subsurface Scattering Closure */
 | 
						|
 | 
						|
NODE_DEFINE(SubsurfaceScatteringNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("subsurface_scattering", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
 | 
						|
  SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
 | 
						|
  SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
 | 
						|
 | 
						|
  static NodeEnum falloff_enum;
 | 
						|
  falloff_enum.insert("cubic", CLOSURE_BSSRDF_CUBIC_ID);
 | 
						|
  falloff_enum.insert("gaussian", CLOSURE_BSSRDF_GAUSSIAN_ID);
 | 
						|
  falloff_enum.insert("burley", CLOSURE_BSSRDF_BURLEY_ID);
 | 
						|
  falloff_enum.insert("random_walk", CLOSURE_BSSRDF_RANDOM_WALK_ID);
 | 
						|
  SOCKET_ENUM(falloff, "Falloff", falloff_enum, CLOSURE_BSSRDF_BURLEY_ID);
 | 
						|
  SOCKET_IN_FLOAT(scale, "Scale", 0.01f);
 | 
						|
  SOCKET_IN_VECTOR(radius, "Radius", make_float3(0.1f, 0.1f, 0.1f));
 | 
						|
  SOCKET_IN_FLOAT(sharpness, "Sharpness", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(texture_blur, "Texture Blur", 1.0f);
 | 
						|
 | 
						|
  SOCKET_OUT_CLOSURE(BSSRDF, "BSSRDF");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
SubsurfaceScatteringNode::SubsurfaceScatteringNode() : BsdfNode(node_type)
 | 
						|
{
 | 
						|
  closure = falloff;
 | 
						|
}
 | 
						|
 | 
						|
void SubsurfaceScatteringNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  closure = falloff;
 | 
						|
  BsdfNode::compile(
 | 
						|
      compiler, input("Scale"), input("Texture Blur"), input("Radius"), input("Sharpness"));
 | 
						|
}
 | 
						|
 | 
						|
void SubsurfaceScatteringNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  closure = falloff;
 | 
						|
  compiler.parameter(this, "falloff");
 | 
						|
  compiler.add(this, "node_subsurface_scattering");
 | 
						|
}
 | 
						|
 | 
						|
bool SubsurfaceScatteringNode::has_bssrdf_bump()
 | 
						|
{
 | 
						|
  /* detect if anything is plugged into the normal input besides the default */
 | 
						|
  ShaderInput *normal_in = input("Normal");
 | 
						|
  return (normal_in->link &&
 | 
						|
          normal_in->link->parent->special_type != SHADER_SPECIAL_TYPE_GEOMETRY);
 | 
						|
}
 | 
						|
 | 
						|
/* Emissive Closure */
 | 
						|
 | 
						|
NODE_DEFINE(EmissionNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("emission", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
 | 
						|
  SOCKET_IN_FLOAT(strength, "Strength", 10.0f);
 | 
						|
  SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
 | 
						|
 | 
						|
  SOCKET_OUT_CLOSURE(emission, "Emission");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
EmissionNode::EmissionNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void EmissionNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *color_in = input("Color");
 | 
						|
  ShaderInput *strength_in = input("Strength");
 | 
						|
 | 
						|
  if (color_in->link || strength_in->link) {
 | 
						|
    compiler.add_node(
 | 
						|
        NODE_EMISSION_WEIGHT, compiler.stack_assign(color_in), compiler.stack_assign(strength_in));
 | 
						|
  }
 | 
						|
  else
 | 
						|
    compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color * strength);
 | 
						|
 | 
						|
  compiler.add_node(NODE_CLOSURE_EMISSION, compiler.closure_mix_weight_offset());
 | 
						|
}
 | 
						|
 | 
						|
void EmissionNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_emission");
 | 
						|
}
 | 
						|
 | 
						|
void EmissionNode::constant_fold(const ConstantFolder &folder)
 | 
						|
{
 | 
						|
  ShaderInput *color_in = input("Color");
 | 
						|
  ShaderInput *strength_in = input("Strength");
 | 
						|
 | 
						|
  if ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) ||
 | 
						|
      (!strength_in->link && strength == 0.0f)) {
 | 
						|
    folder.discard();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* Background Closure */
 | 
						|
 | 
						|
NODE_DEFINE(BackgroundNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("background_shader", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
 | 
						|
  SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
 | 
						|
  SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
 | 
						|
 | 
						|
  SOCKET_OUT_CLOSURE(background, "Background");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
BackgroundNode::BackgroundNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void BackgroundNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *color_in = input("Color");
 | 
						|
  ShaderInput *strength_in = input("Strength");
 | 
						|
 | 
						|
  if (color_in->link || strength_in->link) {
 | 
						|
    compiler.add_node(
 | 
						|
        NODE_EMISSION_WEIGHT, compiler.stack_assign(color_in), compiler.stack_assign(strength_in));
 | 
						|
  }
 | 
						|
  else
 | 
						|
    compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color * strength);
 | 
						|
 | 
						|
  compiler.add_node(NODE_CLOSURE_BACKGROUND, compiler.closure_mix_weight_offset());
 | 
						|
}
 | 
						|
 | 
						|
void BackgroundNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_background");
 | 
						|
}
 | 
						|
 | 
						|
void BackgroundNode::constant_fold(const ConstantFolder &folder)
 | 
						|
{
 | 
						|
  ShaderInput *color_in = input("Color");
 | 
						|
  ShaderInput *strength_in = input("Strength");
 | 
						|
 | 
						|
  if ((!color_in->link && color == make_float3(0.0f, 0.0f, 0.0f)) ||
 | 
						|
      (!strength_in->link && strength == 0.0f)) {
 | 
						|
    folder.discard();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* Holdout Closure */
 | 
						|
 | 
						|
NODE_DEFINE(HoldoutNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("holdout", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
 | 
						|
  SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL);
 | 
						|
 | 
						|
  SOCKET_OUT_CLOSURE(holdout, "Holdout");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
HoldoutNode::HoldoutNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void HoldoutNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  float3 value = make_float3(1.0f, 1.0f, 1.0f);
 | 
						|
 | 
						|
  compiler.add_node(NODE_CLOSURE_SET_WEIGHT, value);
 | 
						|
  compiler.add_node(NODE_CLOSURE_HOLDOUT, compiler.closure_mix_weight_offset());
 | 
						|
}
 | 
						|
 | 
						|
void HoldoutNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_holdout");
 | 
						|
}
 | 
						|
 | 
						|
/* Ambient Occlusion */
 | 
						|
 | 
						|
NODE_DEFINE(AmbientOcclusionNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("ambient_occlusion", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_INT(samples, "Samples", 16);
 | 
						|
 | 
						|
  SOCKET_IN_COLOR(color, "Color", make_float3(1.0f, 1.0f, 1.0f));
 | 
						|
  SOCKET_IN_FLOAT(distance, "Distance", 1.0f);
 | 
						|
  SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
 | 
						|
 | 
						|
  SOCKET_BOOLEAN(inside, "Inside", false);
 | 
						|
  SOCKET_BOOLEAN(only_local, "Only Local", false);
 | 
						|
 | 
						|
  SOCKET_OUT_COLOR(color, "Color");
 | 
						|
  SOCKET_OUT_FLOAT(ao, "AO");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
AmbientOcclusionNode::AmbientOcclusionNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void AmbientOcclusionNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *color_in = input("Color");
 | 
						|
  ShaderInput *distance_in = input("Distance");
 | 
						|
  ShaderInput *normal_in = input("Normal");
 | 
						|
  ShaderOutput *color_out = output("Color");
 | 
						|
  ShaderOutput *ao_out = output("AO");
 | 
						|
 | 
						|
  int flags = (inside ? NODE_AO_INSIDE : 0) | (only_local ? NODE_AO_ONLY_LOCAL : 0);
 | 
						|
 | 
						|
  if (!distance_in->link && distance == 0.0f) {
 | 
						|
    flags |= NODE_AO_GLOBAL_RADIUS;
 | 
						|
  }
 | 
						|
 | 
						|
  compiler.add_node(NODE_AMBIENT_OCCLUSION,
 | 
						|
                    compiler.encode_uchar4(flags,
 | 
						|
                                           compiler.stack_assign_if_linked(distance_in),
 | 
						|
                                           compiler.stack_assign_if_linked(normal_in),
 | 
						|
                                           compiler.stack_assign(ao_out)),
 | 
						|
                    compiler.encode_uchar4(compiler.stack_assign(color_in),
 | 
						|
                                           compiler.stack_assign(color_out),
 | 
						|
                                           samples),
 | 
						|
                    __float_as_uint(distance));
 | 
						|
}
 | 
						|
 | 
						|
void AmbientOcclusionNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.parameter(this, "samples");
 | 
						|
  compiler.parameter(this, "inside");
 | 
						|
  compiler.parameter(this, "only_local");
 | 
						|
  compiler.add(this, "node_ambient_occlusion");
 | 
						|
}
 | 
						|
 | 
						|
/* Volume Closure */
 | 
						|
 | 
						|
VolumeNode::VolumeNode(const NodeType *node_type) : ShaderNode(node_type)
 | 
						|
{
 | 
						|
  closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
 | 
						|
}
 | 
						|
 | 
						|
void VolumeNode::compile(SVMCompiler &compiler, ShaderInput *param1, ShaderInput *param2)
 | 
						|
{
 | 
						|
  ShaderInput *color_in = input("Color");
 | 
						|
 | 
						|
  if (color_in->link)
 | 
						|
    compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
 | 
						|
  else
 | 
						|
    compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color);
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      NODE_CLOSURE_VOLUME,
 | 
						|
      compiler.encode_uchar4(closure,
 | 
						|
                             (param1) ? compiler.stack_assign(param1) : SVM_STACK_INVALID,
 | 
						|
                             (param2) ? compiler.stack_assign(param2) : SVM_STACK_INVALID,
 | 
						|
                             compiler.closure_mix_weight_offset()),
 | 
						|
      __float_as_int((param1) ? get_float(param1->socket_type) : 0.0f),
 | 
						|
      __float_as_int((param2) ? get_float(param2->socket_type) : 0.0f));
 | 
						|
}
 | 
						|
 | 
						|
void VolumeNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  compile(compiler, NULL, NULL);
 | 
						|
}
 | 
						|
 | 
						|
void VolumeNode::compile(OSLCompiler & /*compiler*/)
 | 
						|
{
 | 
						|
  assert(0);
 | 
						|
}
 | 
						|
 | 
						|
/* Absorption Volume Closure */
 | 
						|
 | 
						|
NODE_DEFINE(AbsorptionVolumeNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("absorption_volume", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
 | 
						|
  SOCKET_IN_FLOAT(density, "Density", 1.0f);
 | 
						|
  SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL);
 | 
						|
 | 
						|
  SOCKET_OUT_CLOSURE(volume, "Volume");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
AbsorptionVolumeNode::AbsorptionVolumeNode() : VolumeNode(node_type)
 | 
						|
{
 | 
						|
  closure = CLOSURE_VOLUME_ABSORPTION_ID;
 | 
						|
}
 | 
						|
 | 
						|
void AbsorptionVolumeNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  VolumeNode::compile(compiler, input("Density"), NULL);
 | 
						|
}
 | 
						|
 | 
						|
void AbsorptionVolumeNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_absorption_volume");
 | 
						|
}
 | 
						|
 | 
						|
/* Scatter Volume Closure */
 | 
						|
 | 
						|
NODE_DEFINE(ScatterVolumeNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("scatter_volume", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
 | 
						|
  SOCKET_IN_FLOAT(density, "Density", 1.0f);
 | 
						|
  SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL);
 | 
						|
 | 
						|
  SOCKET_OUT_CLOSURE(volume, "Volume");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
ScatterVolumeNode::ScatterVolumeNode() : VolumeNode(node_type)
 | 
						|
{
 | 
						|
  closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
 | 
						|
}
 | 
						|
 | 
						|
void ScatterVolumeNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  VolumeNode::compile(compiler, input("Density"), input("Anisotropy"));
 | 
						|
}
 | 
						|
 | 
						|
void ScatterVolumeNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_scatter_volume");
 | 
						|
}
 | 
						|
 | 
						|
/* Principled Volume Closure */
 | 
						|
 | 
						|
NODE_DEFINE(PrincipledVolumeNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("principled_volume", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_STRING(density_attribute, "Density Attribute", ustring());
 | 
						|
  SOCKET_IN_STRING(color_attribute, "Color Attribute", ustring());
 | 
						|
  SOCKET_IN_STRING(temperature_attribute, "Temperature Attribute", ustring());
 | 
						|
 | 
						|
  SOCKET_IN_COLOR(color, "Color", make_float3(0.5f, 0.5f, 0.5f));
 | 
						|
  SOCKET_IN_FLOAT(density, "Density", 1.0f);
 | 
						|
  SOCKET_IN_FLOAT(anisotropy, "Anisotropy", 0.0f);
 | 
						|
  SOCKET_IN_COLOR(absorption_color, "Absorption Color", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
  SOCKET_IN_FLOAT(emission_strength, "Emission Strength", 0.0f);
 | 
						|
  SOCKET_IN_COLOR(emission_color, "Emission Color", make_float3(1.0f, 1.0f, 1.0f));
 | 
						|
  SOCKET_IN_FLOAT(blackbody_intensity, "Blackbody Intensity", 0.0f);
 | 
						|
  SOCKET_IN_COLOR(blackbody_tint, "Blackbody Tint", make_float3(1.0f, 1.0f, 1.0f));
 | 
						|
  SOCKET_IN_FLOAT(temperature, "Temperature", 1000.0f);
 | 
						|
  SOCKET_IN_FLOAT(volume_mix_weight, "VolumeMixWeight", 0.0f, SocketType::SVM_INTERNAL);
 | 
						|
 | 
						|
  SOCKET_OUT_CLOSURE(volume, "Volume");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
PrincipledVolumeNode::PrincipledVolumeNode() : VolumeNode(node_type)
 | 
						|
{
 | 
						|
  closure = CLOSURE_VOLUME_HENYEY_GREENSTEIN_ID;
 | 
						|
  density_attribute = ustring("density");
 | 
						|
  temperature_attribute = ustring("temperature");
 | 
						|
}
 | 
						|
 | 
						|
void PrincipledVolumeNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 | 
						|
{
 | 
						|
  if (shader->has_volume) {
 | 
						|
    ShaderInput *density_in = input("Density");
 | 
						|
    ShaderInput *blackbody_in = input("Blackbody Intensity");
 | 
						|
 | 
						|
    if (density_in->link || density > 0.0f) {
 | 
						|
      attributes->add_standard(density_attribute);
 | 
						|
      attributes->add_standard(color_attribute);
 | 
						|
    }
 | 
						|
 | 
						|
    if (blackbody_in->link || blackbody_intensity > 0.0f) {
 | 
						|
      attributes->add_standard(temperature_attribute);
 | 
						|
    }
 | 
						|
 | 
						|
    attributes->add(ATTR_STD_GENERATED_TRANSFORM);
 | 
						|
  }
 | 
						|
 | 
						|
  ShaderNode::attributes(shader, attributes);
 | 
						|
}
 | 
						|
 | 
						|
void PrincipledVolumeNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *color_in = input("Color");
 | 
						|
  ShaderInput *density_in = input("Density");
 | 
						|
  ShaderInput *anisotropy_in = input("Anisotropy");
 | 
						|
  ShaderInput *absorption_color_in = input("Absorption Color");
 | 
						|
  ShaderInput *emission_in = input("Emission Strength");
 | 
						|
  ShaderInput *emission_color_in = input("Emission Color");
 | 
						|
  ShaderInput *blackbody_in = input("Blackbody Intensity");
 | 
						|
  ShaderInput *blackbody_tint_in = input("Blackbody Tint");
 | 
						|
  ShaderInput *temperature_in = input("Temperature");
 | 
						|
 | 
						|
  if (color_in->link)
 | 
						|
    compiler.add_node(NODE_CLOSURE_WEIGHT, compiler.stack_assign(color_in));
 | 
						|
  else
 | 
						|
    compiler.add_node(NODE_CLOSURE_SET_WEIGHT, color);
 | 
						|
 | 
						|
  compiler.add_node(NODE_PRINCIPLED_VOLUME,
 | 
						|
                    compiler.encode_uchar4(compiler.stack_assign_if_linked(density_in),
 | 
						|
                                           compiler.stack_assign_if_linked(anisotropy_in),
 | 
						|
                                           compiler.stack_assign(absorption_color_in),
 | 
						|
                                           compiler.closure_mix_weight_offset()),
 | 
						|
                    compiler.encode_uchar4(compiler.stack_assign_if_linked(emission_in),
 | 
						|
                                           compiler.stack_assign(emission_color_in),
 | 
						|
                                           compiler.stack_assign_if_linked(blackbody_in),
 | 
						|
                                           compiler.stack_assign(temperature_in)),
 | 
						|
                    compiler.stack_assign(blackbody_tint_in));
 | 
						|
 | 
						|
  int attr_density = compiler.attribute_standard(density_attribute);
 | 
						|
  int attr_color = compiler.attribute_standard(color_attribute);
 | 
						|
  int attr_temperature = compiler.attribute_standard(temperature_attribute);
 | 
						|
 | 
						|
  compiler.add_node(__float_as_int(density),
 | 
						|
                    __float_as_int(anisotropy),
 | 
						|
                    __float_as_int(emission_strength),
 | 
						|
                    __float_as_int(blackbody_intensity));
 | 
						|
 | 
						|
  compiler.add_node(attr_density, attr_color, attr_temperature);
 | 
						|
}
 | 
						|
 | 
						|
void PrincipledVolumeNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  if (Attribute::name_standard(density_attribute.c_str())) {
 | 
						|
    density_attribute = ustring("geom:" + density_attribute.string());
 | 
						|
  }
 | 
						|
  if (Attribute::name_standard(color_attribute.c_str())) {
 | 
						|
    color_attribute = ustring("geom:" + color_attribute.string());
 | 
						|
  }
 | 
						|
  if (Attribute::name_standard(temperature_attribute.c_str())) {
 | 
						|
    temperature_attribute = ustring("geom:" + temperature_attribute.string());
 | 
						|
  }
 | 
						|
 | 
						|
  compiler.add(this, "node_principled_volume");
 | 
						|
}
 | 
						|
 | 
						|
/* Principled Hair BSDF Closure */
 | 
						|
 | 
						|
NODE_DEFINE(PrincipledHairBsdfNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("principled_hair_bsdf", create, NodeType::SHADER);
 | 
						|
 | 
						|
  /* Color parametrization specified as enum. */
 | 
						|
  static NodeEnum parametrization_enum;
 | 
						|
  parametrization_enum.insert("Direct coloring", NODE_PRINCIPLED_HAIR_REFLECTANCE);
 | 
						|
  parametrization_enum.insert("Melanin concentration", NODE_PRINCIPLED_HAIR_PIGMENT_CONCENTRATION);
 | 
						|
  parametrization_enum.insert("Absorption coefficient", NODE_PRINCIPLED_HAIR_DIRECT_ABSORPTION);
 | 
						|
  SOCKET_ENUM(
 | 
						|
      parametrization, "Parametrization", parametrization_enum, NODE_PRINCIPLED_HAIR_REFLECTANCE);
 | 
						|
 | 
						|
  /* Initialize sockets to their default values. */
 | 
						|
  SOCKET_IN_COLOR(color, "Color", make_float3(0.017513f, 0.005763f, 0.002059f));
 | 
						|
  SOCKET_IN_FLOAT(melanin, "Melanin", 0.8f);
 | 
						|
  SOCKET_IN_FLOAT(melanin_redness, "Melanin Redness", 1.0f);
 | 
						|
  SOCKET_IN_COLOR(tint, "Tint", make_float3(1.f, 1.f, 1.f));
 | 
						|
  SOCKET_IN_VECTOR(absorption_coefficient,
 | 
						|
                   "Absorption Coefficient",
 | 
						|
                   make_float3(0.245531f, 0.52f, 1.365f),
 | 
						|
                   SocketType::VECTOR);
 | 
						|
 | 
						|
  SOCKET_IN_FLOAT(offset, "Offset", 2.f * M_PI_F / 180.f);
 | 
						|
  SOCKET_IN_FLOAT(roughness, "Roughness", 0.3f);
 | 
						|
  SOCKET_IN_FLOAT(radial_roughness, "Radial Roughness", 0.3f);
 | 
						|
  SOCKET_IN_FLOAT(coat, "Coat", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(ior, "IOR", 1.55f);
 | 
						|
 | 
						|
  SOCKET_IN_FLOAT(random_roughness, "Random Roughness", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(random_color, "Random Color", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(random, "Random", 0.0f);
 | 
						|
 | 
						|
  SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
 | 
						|
  SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
 | 
						|
 | 
						|
  SOCKET_OUT_CLOSURE(BSDF, "BSDF");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
PrincipledHairBsdfNode::PrincipledHairBsdfNode() : BsdfBaseNode(node_type)
 | 
						|
{
 | 
						|
  closure = CLOSURE_BSDF_HAIR_PRINCIPLED_ID;
 | 
						|
}
 | 
						|
 | 
						|
/* Enable retrieving Hair Info -> Random if Random isn't linked. */
 | 
						|
void PrincipledHairBsdfNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 | 
						|
{
 | 
						|
  if (!input("Random")->link) {
 | 
						|
    attributes->add(ATTR_STD_CURVE_RANDOM);
 | 
						|
  }
 | 
						|
  ShaderNode::attributes(shader, attributes);
 | 
						|
}
 | 
						|
 | 
						|
/* Prepares the input data for the SVM shader. */
 | 
						|
void PrincipledHairBsdfNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add_node(NODE_CLOSURE_SET_WEIGHT, make_float3(1.0f, 1.0f, 1.0f));
 | 
						|
 | 
						|
  ShaderInput *roughness_in = input("Roughness");
 | 
						|
  ShaderInput *radial_roughness_in = input("Radial Roughness");
 | 
						|
  ShaderInput *random_roughness_in = input("Random Roughness");
 | 
						|
  ShaderInput *offset_in = input("Offset");
 | 
						|
  ShaderInput *coat_in = input("Coat");
 | 
						|
  ShaderInput *ior_in = input("IOR");
 | 
						|
  ShaderInput *melanin_in = input("Melanin");
 | 
						|
  ShaderInput *melanin_redness_in = input("Melanin Redness");
 | 
						|
  ShaderInput *random_color_in = input("Random Color");
 | 
						|
 | 
						|
  int color_ofs = compiler.stack_assign(input("Color"));
 | 
						|
  int tint_ofs = compiler.stack_assign(input("Tint"));
 | 
						|
  int absorption_coefficient_ofs = compiler.stack_assign(input("Absorption Coefficient"));
 | 
						|
 | 
						|
  ShaderInput *random_in = input("Random");
 | 
						|
  int attr_random = random_in->link ? SVM_STACK_INVALID :
 | 
						|
                                      compiler.attribute(ATTR_STD_CURVE_RANDOM);
 | 
						|
 | 
						|
  /* Encode all parameters into data nodes. */
 | 
						|
  compiler.add_node(NODE_CLOSURE_BSDF,
 | 
						|
                    /* Socket IDs can be packed 4 at a time into a single data packet */
 | 
						|
                    compiler.encode_uchar4(closure,
 | 
						|
                                           compiler.stack_assign_if_linked(roughness_in),
 | 
						|
                                           compiler.stack_assign_if_linked(radial_roughness_in),
 | 
						|
                                           compiler.closure_mix_weight_offset()),
 | 
						|
                    /* The rest are stored as unsigned integers */
 | 
						|
                    __float_as_uint(roughness),
 | 
						|
                    __float_as_uint(radial_roughness));
 | 
						|
 | 
						|
  compiler.add_node(compiler.stack_assign_if_linked(input("Normal")),
 | 
						|
                    compiler.encode_uchar4(compiler.stack_assign_if_linked(offset_in),
 | 
						|
                                           compiler.stack_assign_if_linked(ior_in),
 | 
						|
                                           color_ofs,
 | 
						|
                                           parametrization),
 | 
						|
                    __float_as_uint(offset),
 | 
						|
                    __float_as_uint(ior));
 | 
						|
 | 
						|
  compiler.add_node(compiler.encode_uchar4(compiler.stack_assign_if_linked(coat_in),
 | 
						|
                                           compiler.stack_assign_if_linked(melanin_in),
 | 
						|
                                           compiler.stack_assign_if_linked(melanin_redness_in),
 | 
						|
                                           absorption_coefficient_ofs),
 | 
						|
                    __float_as_uint(coat),
 | 
						|
                    __float_as_uint(melanin),
 | 
						|
                    __float_as_uint(melanin_redness));
 | 
						|
 | 
						|
  compiler.add_node(compiler.encode_uchar4(tint_ofs,
 | 
						|
                                           compiler.stack_assign_if_linked(random_in),
 | 
						|
                                           compiler.stack_assign_if_linked(random_color_in),
 | 
						|
                                           compiler.stack_assign_if_linked(random_roughness_in)),
 | 
						|
                    __float_as_uint(random),
 | 
						|
                    __float_as_uint(random_color),
 | 
						|
                    __float_as_uint(random_roughness));
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      compiler.encode_uchar4(
 | 
						|
          SVM_STACK_INVALID, SVM_STACK_INVALID, SVM_STACK_INVALID, SVM_STACK_INVALID),
 | 
						|
      attr_random,
 | 
						|
      SVM_STACK_INVALID,
 | 
						|
      SVM_STACK_INVALID);
 | 
						|
}
 | 
						|
 | 
						|
/* Prepares the input data for the OSL shader. */
 | 
						|
void PrincipledHairBsdfNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.parameter(this, "parametrization");
 | 
						|
  compiler.add(this, "node_principled_hair_bsdf");
 | 
						|
}
 | 
						|
 | 
						|
/* Hair BSDF Closure */
 | 
						|
 | 
						|
NODE_DEFINE(HairBsdfNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("hair_bsdf", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_COLOR(color, "Color", make_float3(0.8f, 0.8f, 0.8f));
 | 
						|
  SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
 | 
						|
  SOCKET_IN_FLOAT(surface_mix_weight, "SurfaceMixWeight", 0.0f, SocketType::SVM_INTERNAL);
 | 
						|
 | 
						|
  static NodeEnum component_enum;
 | 
						|
  component_enum.insert("reflection", CLOSURE_BSDF_HAIR_REFLECTION_ID);
 | 
						|
  component_enum.insert("transmission", CLOSURE_BSDF_HAIR_TRANSMISSION_ID);
 | 
						|
  SOCKET_ENUM(component, "Component", component_enum, CLOSURE_BSDF_HAIR_REFLECTION_ID);
 | 
						|
  SOCKET_IN_FLOAT(offset, "Offset", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(roughness_u, "RoughnessU", 0.2f);
 | 
						|
  SOCKET_IN_FLOAT(roughness_v, "RoughnessV", 0.2f);
 | 
						|
  SOCKET_IN_VECTOR(tangent, "Tangent", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
 | 
						|
  SOCKET_OUT_CLOSURE(BSDF, "BSDF");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
HairBsdfNode::HairBsdfNode() : BsdfNode(node_type)
 | 
						|
{
 | 
						|
  closure = CLOSURE_BSDF_HAIR_REFLECTION_ID;
 | 
						|
}
 | 
						|
 | 
						|
void HairBsdfNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  closure = component;
 | 
						|
 | 
						|
  BsdfNode::compile(compiler, input("RoughnessU"), input("RoughnessV"), input("Offset"));
 | 
						|
}
 | 
						|
 | 
						|
void HairBsdfNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.parameter(this, "component");
 | 
						|
  compiler.add(this, "node_hair_bsdf");
 | 
						|
}
 | 
						|
 | 
						|
/* Geometry */
 | 
						|
 | 
						|
NODE_DEFINE(GeometryNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("geometry", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_NORMAL(normal_osl,
 | 
						|
                   "NormalIn",
 | 
						|
                   make_float3(0.0f, 0.0f, 0.0f),
 | 
						|
                   SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
 | 
						|
 | 
						|
  SOCKET_OUT_POINT(position, "Position");
 | 
						|
  SOCKET_OUT_NORMAL(normal, "Normal");
 | 
						|
  SOCKET_OUT_NORMAL(tangent, "Tangent");
 | 
						|
  SOCKET_OUT_NORMAL(true_normal, "True Normal");
 | 
						|
  SOCKET_OUT_VECTOR(incoming, "Incoming");
 | 
						|
  SOCKET_OUT_POINT(parametric, "Parametric");
 | 
						|
  SOCKET_OUT_FLOAT(backfacing, "Backfacing");
 | 
						|
  SOCKET_OUT_FLOAT(pointiness, "Pointiness");
 | 
						|
  SOCKET_OUT_FLOAT(random_per_island, "Random Per Island");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
GeometryNode::GeometryNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
  special_type = SHADER_SPECIAL_TYPE_GEOMETRY;
 | 
						|
}
 | 
						|
 | 
						|
void GeometryNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 | 
						|
{
 | 
						|
  if (shader->has_surface) {
 | 
						|
    if (!output("Tangent")->links.empty()) {
 | 
						|
      attributes->add(ATTR_STD_GENERATED);
 | 
						|
    }
 | 
						|
    if (!output("Pointiness")->links.empty()) {
 | 
						|
      attributes->add(ATTR_STD_POINTINESS);
 | 
						|
    }
 | 
						|
    if (!output("Random Per Island")->links.empty()) {
 | 
						|
      attributes->add(ATTR_STD_RANDOM_PER_ISLAND);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  ShaderNode::attributes(shader, attributes);
 | 
						|
}
 | 
						|
 | 
						|
void GeometryNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderOutput *out;
 | 
						|
  ShaderNodeType geom_node = NODE_GEOMETRY;
 | 
						|
  ShaderNodeType attr_node = NODE_ATTR;
 | 
						|
 | 
						|
  if (bump == SHADER_BUMP_DX) {
 | 
						|
    geom_node = NODE_GEOMETRY_BUMP_DX;
 | 
						|
    attr_node = NODE_ATTR_BUMP_DX;
 | 
						|
  }
 | 
						|
  else if (bump == SHADER_BUMP_DY) {
 | 
						|
    geom_node = NODE_GEOMETRY_BUMP_DY;
 | 
						|
    attr_node = NODE_ATTR_BUMP_DY;
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Position");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(geom_node, NODE_GEOM_P, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Normal");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(geom_node, NODE_GEOM_N, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Tangent");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(geom_node, NODE_GEOM_T, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("True Normal");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(geom_node, NODE_GEOM_Ng, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Incoming");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(geom_node, NODE_GEOM_I, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Parametric");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(geom_node, NODE_GEOM_uv, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Backfacing");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_LIGHT_PATH, NODE_LP_backfacing, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Pointiness");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    if (compiler.output_type() != SHADER_TYPE_VOLUME) {
 | 
						|
      compiler.add_node(
 | 
						|
          attr_node, ATTR_STD_POINTINESS, compiler.stack_assign(out), NODE_ATTR_FLOAT);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      compiler.add_node(NODE_VALUE_F, __float_as_int(0.0f), compiler.stack_assign(out));
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Random Per Island");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    if (compiler.output_type() != SHADER_TYPE_VOLUME) {
 | 
						|
      compiler.add_node(
 | 
						|
          attr_node, ATTR_STD_RANDOM_PER_ISLAND, compiler.stack_assign(out), NODE_ATTR_FLOAT);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      compiler.add_node(NODE_VALUE_F, __float_as_int(0.0f), compiler.stack_assign(out));
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
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");
 | 
						|
}
 | 
						|
 | 
						|
int GeometryNode::get_group()
 | 
						|
{
 | 
						|
  ShaderOutput *out;
 | 
						|
  int result = ShaderNode::get_group();
 | 
						|
 | 
						|
  /* Backfacing uses NODE_LIGHT_PATH */
 | 
						|
  out = output("Backfacing");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    result = max(result, NODE_GROUP_LEVEL_1);
 | 
						|
  }
 | 
						|
 | 
						|
  return result;
 | 
						|
}
 | 
						|
 | 
						|
/* TextureCoordinate */
 | 
						|
 | 
						|
NODE_DEFINE(TextureCoordinateNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("texture_coordinate", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_BOOLEAN(from_dupli, "From Dupli", false);
 | 
						|
  SOCKET_BOOLEAN(use_transform, "Use Transform", false);
 | 
						|
  SOCKET_TRANSFORM(ob_tfm, "Object Transform", transform_identity());
 | 
						|
 | 
						|
  SOCKET_IN_NORMAL(normal_osl,
 | 
						|
                   "NormalIn",
 | 
						|
                   make_float3(0.0f, 0.0f, 0.0f),
 | 
						|
                   SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
 | 
						|
 | 
						|
  SOCKET_OUT_POINT(generated, "Generated");
 | 
						|
  SOCKET_OUT_NORMAL(normal, "Normal");
 | 
						|
  SOCKET_OUT_POINT(UV, "UV");
 | 
						|
  SOCKET_OUT_POINT(object, "Object");
 | 
						|
  SOCKET_OUT_POINT(camera, "Camera");
 | 
						|
  SOCKET_OUT_POINT(window, "Window");
 | 
						|
  SOCKET_OUT_NORMAL(reflection, "Reflection");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
TextureCoordinateNode::TextureCoordinateNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void TextureCoordinateNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 | 
						|
{
 | 
						|
  if (shader->has_surface) {
 | 
						|
    if (!from_dupli) {
 | 
						|
      if (!output("Generated")->links.empty())
 | 
						|
        attributes->add(ATTR_STD_GENERATED);
 | 
						|
      if (!output("UV")->links.empty())
 | 
						|
        attributes->add(ATTR_STD_UV);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (shader->has_volume) {
 | 
						|
    if (!from_dupli) {
 | 
						|
      if (!output("Generated")->links.empty()) {
 | 
						|
        attributes->add(ATTR_STD_GENERATED_TRANSFORM);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  ShaderNode::attributes(shader, attributes);
 | 
						|
}
 | 
						|
 | 
						|
void TextureCoordinateNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderOutput *out;
 | 
						|
  ShaderNodeType texco_node = NODE_TEX_COORD;
 | 
						|
  ShaderNodeType attr_node = NODE_ATTR;
 | 
						|
  ShaderNodeType 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.add_node(geom_node, NODE_GEOM_P, compiler.stack_assign(out));
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      if (from_dupli) {
 | 
						|
        compiler.add_node(texco_node, NODE_TEXCO_DUPLI_GENERATED, compiler.stack_assign(out));
 | 
						|
      }
 | 
						|
      else if (compiler.output_type() == SHADER_TYPE_VOLUME) {
 | 
						|
        compiler.add_node(texco_node, NODE_TEXCO_VOLUME_GENERATED, compiler.stack_assign(out));
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        int attr = compiler.attribute(ATTR_STD_GENERATED);
 | 
						|
        compiler.add_node(attr_node, attr, compiler.stack_assign(out), NODE_ATTR_FLOAT3);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Normal");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(texco_node, NODE_TEXCO_NORMAL, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("UV");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    if (from_dupli) {
 | 
						|
      compiler.add_node(texco_node, NODE_TEXCO_DUPLI_UV, compiler.stack_assign(out));
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      int attr = compiler.attribute(ATTR_STD_UV);
 | 
						|
      compiler.add_node(attr_node, attr, compiler.stack_assign(out), NODE_ATTR_FLOAT3);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Object");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(texco_node, NODE_TEXCO_OBJECT, compiler.stack_assign(out), use_transform);
 | 
						|
    if (use_transform) {
 | 
						|
      Transform ob_itfm = transform_inverse(ob_tfm);
 | 
						|
      compiler.add_node(ob_itfm.x);
 | 
						|
      compiler.add_node(ob_itfm.y);
 | 
						|
      compiler.add_node(ob_itfm.z);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Camera");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(texco_node, NODE_TEXCO_CAMERA, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Window");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(texco_node, NODE_TEXCO_WINDOW, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Reflection");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    if (compiler.background) {
 | 
						|
      compiler.add_node(geom_node, NODE_GEOM_I, compiler.stack_assign(out));
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      compiler.add_node(texco_node, NODE_TEXCO_REFLECTION, compiler.stack_assign(out));
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
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);
 | 
						|
  if (compiler.output_type() == SHADER_TYPE_VOLUME)
 | 
						|
    compiler.parameter("is_volume", true);
 | 
						|
  compiler.parameter(this, "use_transform");
 | 
						|
  Transform ob_itfm = transform_inverse(ob_tfm);
 | 
						|
  compiler.parameter("object_itfm", ob_itfm);
 | 
						|
 | 
						|
  compiler.parameter(this, "from_dupli");
 | 
						|
 | 
						|
  compiler.add(this, "node_texture_coordinate");
 | 
						|
}
 | 
						|
 | 
						|
/* UV Map */
 | 
						|
 | 
						|
NODE_DEFINE(UVMapNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("uvmap", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_STRING(attribute, "attribute", ustring());
 | 
						|
  SOCKET_IN_BOOLEAN(from_dupli, "from dupli", false);
 | 
						|
 | 
						|
  SOCKET_OUT_POINT(UV, "UV");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
UVMapNode::UVMapNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void UVMapNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 | 
						|
{
 | 
						|
  if (shader->has_surface) {
 | 
						|
    if (!from_dupli) {
 | 
						|
      if (!output("UV")->links.empty()) {
 | 
						|
        if (attribute != "")
 | 
						|
          attributes->add(attribute);
 | 
						|
        else
 | 
						|
          attributes->add(ATTR_STD_UV);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  ShaderNode::attributes(shader, attributes);
 | 
						|
}
 | 
						|
 | 
						|
void UVMapNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderOutput *out = output("UV");
 | 
						|
  ShaderNodeType texco_node = NODE_TEX_COORD;
 | 
						|
  ShaderNodeType attr_node = NODE_ATTR;
 | 
						|
  int attr;
 | 
						|
 | 
						|
  if (bump == SHADER_BUMP_DX) {
 | 
						|
    texco_node = NODE_TEX_COORD_BUMP_DX;
 | 
						|
    attr_node = NODE_ATTR_BUMP_DX;
 | 
						|
  }
 | 
						|
  else if (bump == SHADER_BUMP_DY) {
 | 
						|
    texco_node = NODE_TEX_COORD_BUMP_DY;
 | 
						|
    attr_node = NODE_ATTR_BUMP_DY;
 | 
						|
  }
 | 
						|
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    if (from_dupli) {
 | 
						|
      compiler.add_node(texco_node, NODE_TEXCO_DUPLI_UV, compiler.stack_assign(out));
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      if (attribute != "")
 | 
						|
        attr = compiler.attribute(attribute);
 | 
						|
      else
 | 
						|
        attr = compiler.attribute(ATTR_STD_UV);
 | 
						|
 | 
						|
      compiler.add_node(attr_node, attr, compiler.stack_assign(out), NODE_ATTR_FLOAT3);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void UVMapNode::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(this, "from_dupli");
 | 
						|
  compiler.parameter(this, "attribute");
 | 
						|
  compiler.add(this, "node_uv_map");
 | 
						|
}
 | 
						|
 | 
						|
/* Light Path */
 | 
						|
 | 
						|
NODE_DEFINE(LightPathNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("light_path", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_OUT_FLOAT(is_camera_ray, "Is Camera Ray");
 | 
						|
  SOCKET_OUT_FLOAT(is_shadow_ray, "Is Shadow Ray");
 | 
						|
  SOCKET_OUT_FLOAT(is_diffuse_ray, "Is Diffuse Ray");
 | 
						|
  SOCKET_OUT_FLOAT(is_glossy_ray, "Is Glossy Ray");
 | 
						|
  SOCKET_OUT_FLOAT(is_singular_ray, "Is Singular Ray");
 | 
						|
  SOCKET_OUT_FLOAT(is_reflection_ray, "Is Reflection Ray");
 | 
						|
  SOCKET_OUT_FLOAT(is_transmission_ray, "Is Transmission Ray");
 | 
						|
  SOCKET_OUT_FLOAT(is_volume_scatter_ray, "Is Volume Scatter Ray");
 | 
						|
  SOCKET_OUT_FLOAT(ray_length, "Ray Length");
 | 
						|
  SOCKET_OUT_FLOAT(ray_depth, "Ray Depth");
 | 
						|
  SOCKET_OUT_FLOAT(diffuse_depth, "Diffuse Depth");
 | 
						|
  SOCKET_OUT_FLOAT(glossy_depth, "Glossy Depth");
 | 
						|
  SOCKET_OUT_FLOAT(transparent_depth, "Transparent Depth");
 | 
						|
  SOCKET_OUT_FLOAT(transmission_depth, "Transmission Depth");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
LightPathNode::LightPathNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void LightPathNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderOutput *out;
 | 
						|
 | 
						|
  out = output("Is Camera Ray");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_LIGHT_PATH, NODE_LP_camera, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Is Shadow Ray");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_LIGHT_PATH, NODE_LP_shadow, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Is Diffuse Ray");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_LIGHT_PATH, NODE_LP_diffuse, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Is Glossy Ray");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_LIGHT_PATH, NODE_LP_glossy, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Is Singular Ray");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_LIGHT_PATH, NODE_LP_singular, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Is Reflection Ray");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_LIGHT_PATH, NODE_LP_reflection, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Is Transmission Ray");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_LIGHT_PATH, NODE_LP_transmission, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Is Volume Scatter Ray");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_LIGHT_PATH, NODE_LP_volume_scatter, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Ray Length");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_length, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Ray Depth");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_depth, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Diffuse Depth");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_diffuse, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Glossy Depth");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_glossy, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Transparent Depth");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_transparent, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Transmission Depth");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_LIGHT_PATH, NODE_LP_ray_transmission, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void LightPathNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_light_path");
 | 
						|
}
 | 
						|
 | 
						|
/* Light Falloff */
 | 
						|
 | 
						|
NODE_DEFINE(LightFalloffNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("light_falloff", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_FLOAT(strength, "Strength", 100.0f);
 | 
						|
  SOCKET_IN_FLOAT(smooth, "Smooth", 0.0f);
 | 
						|
 | 
						|
  SOCKET_OUT_FLOAT(quadratic, "Quadratic");
 | 
						|
  SOCKET_OUT_FLOAT(linear, "Linear");
 | 
						|
  SOCKET_OUT_FLOAT(constant, "Constant");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
LightFalloffNode::LightFalloffNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void LightFalloffNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *strength_in = input("Strength");
 | 
						|
  ShaderInput *smooth_in = input("Smooth");
 | 
						|
 | 
						|
  ShaderOutput *out = output("Quadratic");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_LIGHT_FALLOFF,
 | 
						|
                      NODE_LIGHT_FALLOFF_QUADRATIC,
 | 
						|
                      compiler.encode_uchar4(compiler.stack_assign(strength_in),
 | 
						|
                                             compiler.stack_assign(smooth_in),
 | 
						|
                                             compiler.stack_assign(out)));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Linear");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_LIGHT_FALLOFF,
 | 
						|
                      NODE_LIGHT_FALLOFF_LINEAR,
 | 
						|
                      compiler.encode_uchar4(compiler.stack_assign(strength_in),
 | 
						|
                                             compiler.stack_assign(smooth_in),
 | 
						|
                                             compiler.stack_assign(out)));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Constant");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_LIGHT_FALLOFF,
 | 
						|
                      NODE_LIGHT_FALLOFF_CONSTANT,
 | 
						|
                      compiler.encode_uchar4(compiler.stack_assign(strength_in),
 | 
						|
                                             compiler.stack_assign(smooth_in),
 | 
						|
                                             compiler.stack_assign(out)));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void LightFalloffNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_light_falloff");
 | 
						|
}
 | 
						|
 | 
						|
/* Object Info */
 | 
						|
 | 
						|
NODE_DEFINE(ObjectInfoNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("object_info", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_OUT_VECTOR(location, "Location");
 | 
						|
  SOCKET_OUT_COLOR(color, "Color");
 | 
						|
  SOCKET_OUT_FLOAT(object_index, "Object Index");
 | 
						|
  SOCKET_OUT_FLOAT(material_index, "Material Index");
 | 
						|
  SOCKET_OUT_FLOAT(random, "Random");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
ObjectInfoNode::ObjectInfoNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void ObjectInfoNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderOutput *out = output("Location");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_LOCATION, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Color");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_COLOR, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Object Index");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_INDEX, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Material Index");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_MAT_INDEX, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Random");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_OBJECT_INFO, NODE_INFO_OB_RANDOM, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ObjectInfoNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_object_info");
 | 
						|
}
 | 
						|
 | 
						|
/* Particle Info */
 | 
						|
 | 
						|
NODE_DEFINE(ParticleInfoNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("particle_info", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_OUT_FLOAT(index, "Index");
 | 
						|
  SOCKET_OUT_FLOAT(random, "Random");
 | 
						|
  SOCKET_OUT_FLOAT(age, "Age");
 | 
						|
  SOCKET_OUT_FLOAT(lifetime, "Lifetime");
 | 
						|
  SOCKET_OUT_POINT(location, "Location");
 | 
						|
#if 0 /* not yet supported */
 | 
						|
  SOCKET_OUT_QUATERNION(rotation, "Rotation");
 | 
						|
#endif
 | 
						|
  SOCKET_OUT_FLOAT(size, "Size");
 | 
						|
  SOCKET_OUT_VECTOR(velocity, "Velocity");
 | 
						|
  SOCKET_OUT_VECTOR(angular_velocity, "Angular Velocity");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
ParticleInfoNode::ParticleInfoNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void ParticleInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 | 
						|
{
 | 
						|
  if (!output("Index")->links.empty())
 | 
						|
    attributes->add(ATTR_STD_PARTICLE);
 | 
						|
  if (!output("Random")->links.empty())
 | 
						|
    attributes->add(ATTR_STD_PARTICLE);
 | 
						|
  if (!output("Age")->links.empty())
 | 
						|
    attributes->add(ATTR_STD_PARTICLE);
 | 
						|
  if (!output("Lifetime")->links.empty())
 | 
						|
    attributes->add(ATTR_STD_PARTICLE);
 | 
						|
  if (!output("Location")->links.empty())
 | 
						|
    attributes->add(ATTR_STD_PARTICLE);
 | 
						|
#if 0 /* not yet supported */
 | 
						|
  if (!output("Rotation")->links.empty())
 | 
						|
    attributes->add(ATTR_STD_PARTICLE);
 | 
						|
#endif
 | 
						|
  if (!output("Size")->links.empty())
 | 
						|
    attributes->add(ATTR_STD_PARTICLE);
 | 
						|
  if (!output("Velocity")->links.empty())
 | 
						|
    attributes->add(ATTR_STD_PARTICLE);
 | 
						|
  if (!output("Angular Velocity")->links.empty())
 | 
						|
    attributes->add(ATTR_STD_PARTICLE);
 | 
						|
 | 
						|
  ShaderNode::attributes(shader, attributes);
 | 
						|
}
 | 
						|
 | 
						|
void ParticleInfoNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderOutput *out;
 | 
						|
 | 
						|
  out = output("Index");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_INDEX, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Random");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_RANDOM, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Age");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_AGE, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Lifetime");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_LIFETIME, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Location");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_LOCATION, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  /* quaternion data is not yet supported by Cycles */
 | 
						|
#if 0
 | 
						|
  out = output("Rotation");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_ROTATION, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
#endif
 | 
						|
 | 
						|
  out = output("Size");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_SIZE, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Velocity");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_PARTICLE_INFO, NODE_INFO_PAR_VELOCITY, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Angular Velocity");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(
 | 
						|
        NODE_PARTICLE_INFO, NODE_INFO_PAR_ANGULAR_VELOCITY, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ParticleInfoNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_particle_info");
 | 
						|
}
 | 
						|
 | 
						|
/* Hair Info */
 | 
						|
 | 
						|
NODE_DEFINE(HairInfoNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("hair_info", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_OUT_FLOAT(is_strand, "Is Strand");
 | 
						|
  SOCKET_OUT_FLOAT(intercept, "Intercept");
 | 
						|
  SOCKET_OUT_FLOAT(thickness, "Thickness");
 | 
						|
  SOCKET_OUT_NORMAL(tangent_normal, "Tangent Normal");
 | 
						|
#if 0 /*output for minimum hair width transparency - deactivated */
 | 
						|
  SOCKET_OUT_FLOAT(fade, "Fade");
 | 
						|
#endif
 | 
						|
  SOCKET_OUT_FLOAT(index, "Random");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
HairInfoNode::HairInfoNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void HairInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 | 
						|
{
 | 
						|
  if (shader->has_surface) {
 | 
						|
    ShaderOutput *intercept_out = output("Intercept");
 | 
						|
 | 
						|
    if (!intercept_out->links.empty())
 | 
						|
      attributes->add(ATTR_STD_CURVE_INTERCEPT);
 | 
						|
 | 
						|
    if (!output("Random")->links.empty())
 | 
						|
      attributes->add(ATTR_STD_CURVE_RANDOM);
 | 
						|
  }
 | 
						|
 | 
						|
  ShaderNode::attributes(shader, attributes);
 | 
						|
}
 | 
						|
 | 
						|
void HairInfoNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderOutput *out;
 | 
						|
 | 
						|
  out = output("Is Strand");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_IS_STRAND, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Intercept");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    int attr = compiler.attribute(ATTR_STD_CURVE_INTERCEPT);
 | 
						|
    compiler.add_node(NODE_ATTR, attr, compiler.stack_assign(out), NODE_ATTR_FLOAT);
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Thickness");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_THICKNESS, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  out = output("Tangent Normal");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_TANGENT_NORMAL, compiler.stack_assign(out));
 | 
						|
  }
 | 
						|
 | 
						|
  /*out = output("Fade");
 | 
						|
  if(!out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_HAIR_INFO, NODE_INFO_CURVE_FADE, compiler.stack_assign(out));
 | 
						|
  }*/
 | 
						|
 | 
						|
  out = output("Random");
 | 
						|
  if (!out->links.empty()) {
 | 
						|
    int attr = compiler.attribute(ATTR_STD_CURVE_RANDOM);
 | 
						|
    compiler.add_node(NODE_ATTR, attr, compiler.stack_assign(out), NODE_ATTR_FLOAT);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void HairInfoNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_hair_info");
 | 
						|
}
 | 
						|
 | 
						|
/* Volume Info */
 | 
						|
 | 
						|
NODE_DEFINE(VolumeInfoNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("volume_info", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_OUT_COLOR(color, "Color");
 | 
						|
  SOCKET_OUT_FLOAT(density, "Density");
 | 
						|
  SOCKET_OUT_FLOAT(flame, "Flame");
 | 
						|
  SOCKET_OUT_FLOAT(temperature, "Temperature");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
VolumeInfoNode::VolumeInfoNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
/* The requested attributes are not updated after node expansion.
 | 
						|
 * So we explicitly request the required attributes.
 | 
						|
 */
 | 
						|
void VolumeInfoNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 | 
						|
{
 | 
						|
  if (shader->has_volume) {
 | 
						|
    if (!output("Color")->links.empty()) {
 | 
						|
      attributes->add(ATTR_STD_VOLUME_COLOR);
 | 
						|
    }
 | 
						|
    if (!output("Density")->links.empty()) {
 | 
						|
      attributes->add(ATTR_STD_VOLUME_DENSITY);
 | 
						|
    }
 | 
						|
    if (!output("Flame")->links.empty()) {
 | 
						|
      attributes->add(ATTR_STD_VOLUME_FLAME);
 | 
						|
    }
 | 
						|
    if (!output("Temperature")->links.empty()) {
 | 
						|
      attributes->add(ATTR_STD_VOLUME_TEMPERATURE);
 | 
						|
    }
 | 
						|
    attributes->add(ATTR_STD_GENERATED_TRANSFORM);
 | 
						|
  }
 | 
						|
  ShaderNode::attributes(shader, attributes);
 | 
						|
}
 | 
						|
 | 
						|
void VolumeInfoNode::expand(ShaderGraph *graph)
 | 
						|
{
 | 
						|
  ShaderOutput *color_out = output("Color");
 | 
						|
  if (!color_out->links.empty()) {
 | 
						|
    AttributeNode *attr = new AttributeNode();
 | 
						|
    attr->attribute = "color";
 | 
						|
    graph->add(attr);
 | 
						|
    graph->relink(color_out, attr->output("Color"));
 | 
						|
  }
 | 
						|
 | 
						|
  ShaderOutput *density_out = output("Density");
 | 
						|
  if (!density_out->links.empty()) {
 | 
						|
    AttributeNode *attr = new AttributeNode();
 | 
						|
    attr->attribute = "density";
 | 
						|
    graph->add(attr);
 | 
						|
    graph->relink(density_out, attr->output("Fac"));
 | 
						|
  }
 | 
						|
 | 
						|
  ShaderOutput *flame_out = output("Flame");
 | 
						|
  if (!flame_out->links.empty()) {
 | 
						|
    AttributeNode *attr = new AttributeNode();
 | 
						|
    attr->attribute = "flame";
 | 
						|
    graph->add(attr);
 | 
						|
    graph->relink(flame_out, attr->output("Fac"));
 | 
						|
  }
 | 
						|
 | 
						|
  ShaderOutput *temperature_out = output("Temperature");
 | 
						|
  if (!temperature_out->links.empty()) {
 | 
						|
    AttributeNode *attr = new AttributeNode();
 | 
						|
    attr->attribute = "temperature";
 | 
						|
    graph->add(attr);
 | 
						|
    graph->relink(temperature_out, attr->output("Fac"));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void VolumeInfoNode::compile(SVMCompiler &)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void VolumeInfoNode::compile(OSLCompiler &)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
NODE_DEFINE(VertexColorNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("vertex_color", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_STRING(layer_name, "Layer Name", ustring());
 | 
						|
  SOCKET_OUT_COLOR(color, "Color");
 | 
						|
  SOCKET_OUT_FLOAT(alpha, "Alpha");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
VertexColorNode::VertexColorNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void VertexColorNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 | 
						|
{
 | 
						|
  if (!(output("Color")->links.empty() && output("Alpha")->links.empty())) {
 | 
						|
    if (layer_name != "")
 | 
						|
      attributes->add_standard(layer_name);
 | 
						|
    else
 | 
						|
      attributes->add(ATTR_STD_VERTEX_COLOR);
 | 
						|
  }
 | 
						|
  ShaderNode::attributes(shader, attributes);
 | 
						|
}
 | 
						|
 | 
						|
void VertexColorNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderOutput *color_out = output("Color");
 | 
						|
  ShaderOutput *alpha_out = output("Alpha");
 | 
						|
  int layer_id = 0;
 | 
						|
 | 
						|
  if (layer_name != "") {
 | 
						|
    layer_id = compiler.attribute(layer_name);
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    layer_id = compiler.attribute(ATTR_STD_VERTEX_COLOR);
 | 
						|
  }
 | 
						|
 | 
						|
  ShaderNodeType node;
 | 
						|
 | 
						|
  if (bump == SHADER_BUMP_DX)
 | 
						|
    node = NODE_VERTEX_COLOR_BUMP_DX;
 | 
						|
  else if (bump == SHADER_BUMP_DY)
 | 
						|
    node = NODE_VERTEX_COLOR_BUMP_DY;
 | 
						|
  else {
 | 
						|
    node = NODE_VERTEX_COLOR;
 | 
						|
  }
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      node, layer_id, compiler.stack_assign(color_out), compiler.stack_assign(alpha_out));
 | 
						|
}
 | 
						|
 | 
						|
void VertexColorNode::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 (layer_name.empty()) {
 | 
						|
    compiler.parameter("layer_name", ustring("geom:vertex_color"));
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    if (Attribute::name_standard(layer_name.c_str()) != ATTR_STD_NONE) {
 | 
						|
      compiler.parameter("name", (string("geom:") + layer_name.c_str()).c_str());
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      compiler.parameter("layer_name", layer_name.c_str());
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  compiler.add(this, "node_vertex_color");
 | 
						|
}
 | 
						|
 | 
						|
/* Value */
 | 
						|
 | 
						|
NODE_DEFINE(ValueNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("value", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_FLOAT(value, "Value", 0.0f);
 | 
						|
  SOCKET_OUT_FLOAT(value, "Value");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
ValueNode::ValueNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void ValueNode::constant_fold(const ConstantFolder &folder)
 | 
						|
{
 | 
						|
  folder.make_constant(value);
 | 
						|
}
 | 
						|
 | 
						|
void ValueNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderOutput *val_out = output("Value");
 | 
						|
 | 
						|
  compiler.add_node(NODE_VALUE_F, __float_as_int(value), compiler.stack_assign(val_out));
 | 
						|
}
 | 
						|
 | 
						|
void ValueNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.parameter("value_value", value);
 | 
						|
  compiler.add(this, "node_value");
 | 
						|
}
 | 
						|
 | 
						|
/* Color */
 | 
						|
 | 
						|
NODE_DEFINE(ColorNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("color", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_COLOR(value, "Value", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
  SOCKET_OUT_COLOR(color, "Color");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
ColorNode::ColorNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void ColorNode::constant_fold(const ConstantFolder &folder)
 | 
						|
{
 | 
						|
  folder.make_constant(value);
 | 
						|
}
 | 
						|
 | 
						|
void ColorNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderOutput *color_out = output("Color");
 | 
						|
 | 
						|
  if (!color_out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_VALUE_V, compiler.stack_assign(color_out));
 | 
						|
    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 */
 | 
						|
 | 
						|
NODE_DEFINE(AddClosureNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("add_closure", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_CLOSURE(closure1, "Closure1");
 | 
						|
  SOCKET_IN_CLOSURE(closure2, "Closure2");
 | 
						|
  SOCKET_OUT_CLOSURE(closure, "Closure");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
AddClosureNode::AddClosureNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
  special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE;
 | 
						|
}
 | 
						|
 | 
						|
void AddClosureNode::compile(SVMCompiler & /*compiler*/)
 | 
						|
{
 | 
						|
  /* handled in the SVM compiler */
 | 
						|
}
 | 
						|
 | 
						|
void AddClosureNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_add_closure");
 | 
						|
}
 | 
						|
 | 
						|
void AddClosureNode::constant_fold(const ConstantFolder &folder)
 | 
						|
{
 | 
						|
  ShaderInput *closure1_in = input("Closure1");
 | 
						|
  ShaderInput *closure2_in = input("Closure2");
 | 
						|
 | 
						|
  /* remove useless add closures nodes */
 | 
						|
  if (!closure1_in->link) {
 | 
						|
    folder.bypass_or_discard(closure2_in);
 | 
						|
  }
 | 
						|
  else if (!closure2_in->link) {
 | 
						|
    folder.bypass_or_discard(closure1_in);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* Mix Closure */
 | 
						|
 | 
						|
NODE_DEFINE(MixClosureNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("mix_closure", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_FLOAT(fac, "Fac", 0.5f);
 | 
						|
  SOCKET_IN_CLOSURE(closure1, "Closure1");
 | 
						|
  SOCKET_IN_CLOSURE(closure2, "Closure2");
 | 
						|
 | 
						|
  SOCKET_OUT_CLOSURE(closure, "Closure");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
MixClosureNode::MixClosureNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
  special_type = SHADER_SPECIAL_TYPE_COMBINE_CLOSURE;
 | 
						|
}
 | 
						|
 | 
						|
void MixClosureNode::compile(SVMCompiler & /*compiler*/)
 | 
						|
{
 | 
						|
  /* handled in the SVM compiler */
 | 
						|
}
 | 
						|
 | 
						|
void MixClosureNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_mix_closure");
 | 
						|
}
 | 
						|
 | 
						|
void MixClosureNode::constant_fold(const ConstantFolder &folder)
 | 
						|
{
 | 
						|
  ShaderInput *fac_in = input("Fac");
 | 
						|
  ShaderInput *closure1_in = input("Closure1");
 | 
						|
  ShaderInput *closure2_in = input("Closure2");
 | 
						|
 | 
						|
  /* remove useless mix closures nodes */
 | 
						|
  if (closure1_in->link == closure2_in->link) {
 | 
						|
    folder.bypass_or_discard(closure1_in);
 | 
						|
  }
 | 
						|
  /* remove unused mix closure input when factor is 0.0 or 1.0
 | 
						|
   * check for closure links and make sure factor link is disconnected */
 | 
						|
  else if (!fac_in->link) {
 | 
						|
    /* factor 0.0 */
 | 
						|
    if (fac <= 0.0f) {
 | 
						|
      folder.bypass_or_discard(closure1_in);
 | 
						|
    }
 | 
						|
    /* factor 1.0 */
 | 
						|
    else if (fac >= 1.0f) {
 | 
						|
      folder.bypass_or_discard(closure2_in);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* Mix Closure */
 | 
						|
 | 
						|
NODE_DEFINE(MixClosureWeightNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("mix_closure_weight", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_FLOAT(weight, "Weight", 1.0f);
 | 
						|
  SOCKET_IN_FLOAT(fac, "Fac", 1.0f);
 | 
						|
 | 
						|
  SOCKET_OUT_FLOAT(weight1, "Weight1");
 | 
						|
  SOCKET_OUT_FLOAT(weight2, "Weight2");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
MixClosureWeightNode::MixClosureWeightNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void MixClosureWeightNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *weight_in = input("Weight");
 | 
						|
  ShaderInput *fac_in = input("Fac");
 | 
						|
  ShaderOutput *weight1_out = output("Weight1");
 | 
						|
  ShaderOutput *weight2_out = output("Weight2");
 | 
						|
 | 
						|
  compiler.add_node(NODE_MIX_CLOSURE,
 | 
						|
                    compiler.encode_uchar4(compiler.stack_assign(fac_in),
 | 
						|
                                           compiler.stack_assign(weight_in),
 | 
						|
                                           compiler.stack_assign(weight1_out),
 | 
						|
                                           compiler.stack_assign(weight2_out)));
 | 
						|
}
 | 
						|
 | 
						|
void MixClosureWeightNode::compile(OSLCompiler & /*compiler*/)
 | 
						|
{
 | 
						|
  assert(0);
 | 
						|
}
 | 
						|
 | 
						|
/* Invert */
 | 
						|
 | 
						|
NODE_DEFINE(InvertNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("invert", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_FLOAT(fac, "Fac", 1.0f);
 | 
						|
  SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
 | 
						|
  SOCKET_OUT_COLOR(color, "Color");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
InvertNode::InvertNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void InvertNode::constant_fold(const ConstantFolder &folder)
 | 
						|
{
 | 
						|
  ShaderInput *fac_in = input("Fac");
 | 
						|
  ShaderInput *color_in = input("Color");
 | 
						|
 | 
						|
  if (!fac_in->link) {
 | 
						|
    /* evaluate fully constant node */
 | 
						|
    if (!color_in->link) {
 | 
						|
      folder.make_constant(interp(color, make_float3(1.0f, 1.0f, 1.0f) - color, fac));
 | 
						|
    }
 | 
						|
    /* remove no-op node */
 | 
						|
    else if (fac == 0.0f) {
 | 
						|
      folder.bypass(color_in->link);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void InvertNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *fac_in = input("Fac");
 | 
						|
  ShaderInput *color_in = input("Color");
 | 
						|
  ShaderOutput *color_out = output("Color");
 | 
						|
 | 
						|
  compiler.add_node(NODE_INVERT,
 | 
						|
                    compiler.stack_assign(fac_in),
 | 
						|
                    compiler.stack_assign(color_in),
 | 
						|
                    compiler.stack_assign(color_out));
 | 
						|
}
 | 
						|
 | 
						|
void InvertNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_invert");
 | 
						|
}
 | 
						|
 | 
						|
/* Mix */
 | 
						|
 | 
						|
NODE_DEFINE(MixNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("mix", create, NodeType::SHADER);
 | 
						|
 | 
						|
  static NodeEnum type_enum;
 | 
						|
  type_enum.insert("mix", NODE_MIX_BLEND);
 | 
						|
  type_enum.insert("add", NODE_MIX_ADD);
 | 
						|
  type_enum.insert("multiply", NODE_MIX_MUL);
 | 
						|
  type_enum.insert("screen", NODE_MIX_SCREEN);
 | 
						|
  type_enum.insert("overlay", NODE_MIX_OVERLAY);
 | 
						|
  type_enum.insert("subtract", NODE_MIX_SUB);
 | 
						|
  type_enum.insert("divide", NODE_MIX_DIV);
 | 
						|
  type_enum.insert("difference", NODE_MIX_DIFF);
 | 
						|
  type_enum.insert("darken", NODE_MIX_DARK);
 | 
						|
  type_enum.insert("lighten", NODE_MIX_LIGHT);
 | 
						|
  type_enum.insert("dodge", NODE_MIX_DODGE);
 | 
						|
  type_enum.insert("burn", NODE_MIX_BURN);
 | 
						|
  type_enum.insert("hue", NODE_MIX_HUE);
 | 
						|
  type_enum.insert("saturation", NODE_MIX_SAT);
 | 
						|
  type_enum.insert("value", NODE_MIX_VAL);
 | 
						|
  type_enum.insert("color", NODE_MIX_COLOR);
 | 
						|
  type_enum.insert("soft_light", NODE_MIX_SOFT);
 | 
						|
  type_enum.insert("linear_light", NODE_MIX_LINEAR);
 | 
						|
  SOCKET_ENUM(type, "Type", type_enum, NODE_MIX_BLEND);
 | 
						|
 | 
						|
  SOCKET_BOOLEAN(use_clamp, "Use Clamp", false);
 | 
						|
 | 
						|
  SOCKET_IN_FLOAT(fac, "Fac", 0.5f);
 | 
						|
  SOCKET_IN_COLOR(color1, "Color1", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
  SOCKET_IN_COLOR(color2, "Color2", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
 | 
						|
  SOCKET_OUT_COLOR(color, "Color");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
MixNode::MixNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
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.add_node(NODE_MIX,
 | 
						|
                    compiler.stack_assign(fac_in),
 | 
						|
                    compiler.stack_assign(color1_in),
 | 
						|
                    compiler.stack_assign(color2_in));
 | 
						|
  compiler.add_node(NODE_MIX, type, compiler.stack_assign(color_out));
 | 
						|
 | 
						|
  if (use_clamp) {
 | 
						|
    compiler.add_node(NODE_MIX, 0, compiler.stack_assign(color_out));
 | 
						|
    compiler.add_node(NODE_MIX, NODE_MIX_CLAMP, compiler.stack_assign(color_out));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void MixNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.parameter(this, "type");
 | 
						|
  compiler.parameter(this, "use_clamp");
 | 
						|
  compiler.add(this, "node_mix");
 | 
						|
}
 | 
						|
 | 
						|
void MixNode::constant_fold(const ConstantFolder &folder)
 | 
						|
{
 | 
						|
  if (folder.all_inputs_constant()) {
 | 
						|
    folder.make_constant_clamp(svm_mix(type, fac, color1, color2), use_clamp);
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    folder.fold_mix(type, use_clamp);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/* Combine RGB */
 | 
						|
 | 
						|
NODE_DEFINE(CombineRGBNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("combine_rgb", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_FLOAT(r, "R", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(g, "G", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(b, "B", 0.0f);
 | 
						|
 | 
						|
  SOCKET_OUT_COLOR(image, "Image");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
CombineRGBNode::CombineRGBNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void CombineRGBNode::constant_fold(const ConstantFolder &folder)
 | 
						|
{
 | 
						|
  if (folder.all_inputs_constant()) {
 | 
						|
    folder.make_constant(make_float3(r, g, b));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void CombineRGBNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *red_in = input("R");
 | 
						|
  ShaderInput *green_in = input("G");
 | 
						|
  ShaderInput *blue_in = input("B");
 | 
						|
  ShaderOutput *color_out = output("Image");
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      NODE_COMBINE_VECTOR, compiler.stack_assign(red_in), 0, compiler.stack_assign(color_out));
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      NODE_COMBINE_VECTOR, compiler.stack_assign(green_in), 1, compiler.stack_assign(color_out));
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      NODE_COMBINE_VECTOR, compiler.stack_assign(blue_in), 2, compiler.stack_assign(color_out));
 | 
						|
}
 | 
						|
 | 
						|
void CombineRGBNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_combine_rgb");
 | 
						|
}
 | 
						|
 | 
						|
/* Combine XYZ */
 | 
						|
 | 
						|
NODE_DEFINE(CombineXYZNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("combine_xyz", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_FLOAT(x, "X", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(y, "Y", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(z, "Z", 0.0f);
 | 
						|
 | 
						|
  SOCKET_OUT_VECTOR(vector, "Vector");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
CombineXYZNode::CombineXYZNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void CombineXYZNode::constant_fold(const ConstantFolder &folder)
 | 
						|
{
 | 
						|
  if (folder.all_inputs_constant()) {
 | 
						|
    folder.make_constant(make_float3(x, y, z));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void CombineXYZNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *x_in = input("X");
 | 
						|
  ShaderInput *y_in = input("Y");
 | 
						|
  ShaderInput *z_in = input("Z");
 | 
						|
  ShaderOutput *vector_out = output("Vector");
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      NODE_COMBINE_VECTOR, compiler.stack_assign(x_in), 0, compiler.stack_assign(vector_out));
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      NODE_COMBINE_VECTOR, compiler.stack_assign(y_in), 1, compiler.stack_assign(vector_out));
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      NODE_COMBINE_VECTOR, compiler.stack_assign(z_in), 2, compiler.stack_assign(vector_out));
 | 
						|
}
 | 
						|
 | 
						|
void CombineXYZNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_combine_xyz");
 | 
						|
}
 | 
						|
 | 
						|
/* Combine HSV */
 | 
						|
 | 
						|
NODE_DEFINE(CombineHSVNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("combine_hsv", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_FLOAT(h, "H", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(s, "S", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(v, "V", 0.0f);
 | 
						|
 | 
						|
  SOCKET_OUT_COLOR(color, "Color");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
CombineHSVNode::CombineHSVNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void CombineHSVNode::constant_fold(const ConstantFolder &folder)
 | 
						|
{
 | 
						|
  if (folder.all_inputs_constant()) {
 | 
						|
    folder.make_constant(hsv_to_rgb(make_float3(h, s, v)));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void CombineHSVNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *hue_in = input("H");
 | 
						|
  ShaderInput *saturation_in = input("S");
 | 
						|
  ShaderInput *value_in = input("V");
 | 
						|
  ShaderOutput *color_out = output("Color");
 | 
						|
 | 
						|
  compiler.add_node(NODE_COMBINE_HSV,
 | 
						|
                    compiler.stack_assign(hue_in),
 | 
						|
                    compiler.stack_assign(saturation_in),
 | 
						|
                    compiler.stack_assign(value_in));
 | 
						|
  compiler.add_node(NODE_COMBINE_HSV, compiler.stack_assign(color_out));
 | 
						|
}
 | 
						|
 | 
						|
void CombineHSVNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_combine_hsv");
 | 
						|
}
 | 
						|
 | 
						|
/* Gamma */
 | 
						|
 | 
						|
NODE_DEFINE(GammaNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("gamma", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
  SOCKET_IN_FLOAT(gamma, "Gamma", 1.0f);
 | 
						|
  SOCKET_OUT_COLOR(color, "Color");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
GammaNode::GammaNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void GammaNode::constant_fold(const ConstantFolder &folder)
 | 
						|
{
 | 
						|
  if (folder.all_inputs_constant()) {
 | 
						|
    folder.make_constant(svm_math_gamma_color(color, gamma));
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    ShaderInput *color_in = input("Color");
 | 
						|
    ShaderInput *gamma_in = input("Gamma");
 | 
						|
 | 
						|
    /* 1 ^ X == X ^ 0 == 1 */
 | 
						|
    if (folder.is_one(color_in) || folder.is_zero(gamma_in)) {
 | 
						|
      folder.make_one();
 | 
						|
    }
 | 
						|
    /* X ^ 1 == X */
 | 
						|
    else if (folder.is_one(gamma_in)) {
 | 
						|
      folder.try_bypass_or_make_constant(color_in, false);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void GammaNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *color_in = input("Color");
 | 
						|
  ShaderInput *gamma_in = input("Gamma");
 | 
						|
  ShaderOutput *color_out = output("Color");
 | 
						|
 | 
						|
  compiler.add_node(NODE_GAMMA,
 | 
						|
                    compiler.stack_assign(gamma_in),
 | 
						|
                    compiler.stack_assign(color_in),
 | 
						|
                    compiler.stack_assign(color_out));
 | 
						|
}
 | 
						|
 | 
						|
void GammaNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_gamma");
 | 
						|
}
 | 
						|
 | 
						|
/* Bright Contrast */
 | 
						|
 | 
						|
NODE_DEFINE(BrightContrastNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("brightness_contrast", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
  SOCKET_IN_FLOAT(bright, "Bright", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(contrast, "Contrast", 0.0f);
 | 
						|
 | 
						|
  SOCKET_OUT_COLOR(color, "Color");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
BrightContrastNode::BrightContrastNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void BrightContrastNode::constant_fold(const ConstantFolder &folder)
 | 
						|
{
 | 
						|
  if (folder.all_inputs_constant()) {
 | 
						|
    folder.make_constant(svm_brightness_contrast(color, bright, contrast));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void BrightContrastNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *color_in = input("Color");
 | 
						|
  ShaderInput *bright_in = input("Bright");
 | 
						|
  ShaderInput *contrast_in = input("Contrast");
 | 
						|
  ShaderOutput *color_out = output("Color");
 | 
						|
 | 
						|
  compiler.add_node(NODE_BRIGHTCONTRAST,
 | 
						|
                    compiler.stack_assign(color_in),
 | 
						|
                    compiler.stack_assign(color_out),
 | 
						|
                    compiler.encode_uchar4(compiler.stack_assign(bright_in),
 | 
						|
                                           compiler.stack_assign(contrast_in)));
 | 
						|
}
 | 
						|
 | 
						|
void BrightContrastNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_brightness");
 | 
						|
}
 | 
						|
 | 
						|
/* Separate RGB */
 | 
						|
 | 
						|
NODE_DEFINE(SeparateRGBNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("separate_rgb", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_COLOR(color, "Image", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
 | 
						|
  SOCKET_OUT_FLOAT(r, "R");
 | 
						|
  SOCKET_OUT_FLOAT(g, "G");
 | 
						|
  SOCKET_OUT_FLOAT(b, "B");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
SeparateRGBNode::SeparateRGBNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void SeparateRGBNode::constant_fold(const ConstantFolder &folder)
 | 
						|
{
 | 
						|
  if (folder.all_inputs_constant()) {
 | 
						|
    for (int channel = 0; channel < 3; channel++) {
 | 
						|
      if (outputs[channel] == folder.output) {
 | 
						|
        folder.make_constant(color[channel]);
 | 
						|
        return;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void SeparateRGBNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *color_in = input("Image");
 | 
						|
  ShaderOutput *red_out = output("R");
 | 
						|
  ShaderOutput *green_out = output("G");
 | 
						|
  ShaderOutput *blue_out = output("B");
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      NODE_SEPARATE_VECTOR, compiler.stack_assign(color_in), 0, compiler.stack_assign(red_out));
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      NODE_SEPARATE_VECTOR, compiler.stack_assign(color_in), 1, compiler.stack_assign(green_out));
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      NODE_SEPARATE_VECTOR, compiler.stack_assign(color_in), 2, compiler.stack_assign(blue_out));
 | 
						|
}
 | 
						|
 | 
						|
void SeparateRGBNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_separate_rgb");
 | 
						|
}
 | 
						|
 | 
						|
/* Separate XYZ */
 | 
						|
 | 
						|
NODE_DEFINE(SeparateXYZNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("separate_xyz", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_COLOR(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
 | 
						|
  SOCKET_OUT_FLOAT(x, "X");
 | 
						|
  SOCKET_OUT_FLOAT(y, "Y");
 | 
						|
  SOCKET_OUT_FLOAT(z, "Z");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
SeparateXYZNode::SeparateXYZNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void SeparateXYZNode::constant_fold(const ConstantFolder &folder)
 | 
						|
{
 | 
						|
  if (folder.all_inputs_constant()) {
 | 
						|
    for (int channel = 0; channel < 3; channel++) {
 | 
						|
      if (outputs[channel] == folder.output) {
 | 
						|
        folder.make_constant(vector[channel]);
 | 
						|
        return;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void SeparateXYZNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *vector_in = input("Vector");
 | 
						|
  ShaderOutput *x_out = output("X");
 | 
						|
  ShaderOutput *y_out = output("Y");
 | 
						|
  ShaderOutput *z_out = output("Z");
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      NODE_SEPARATE_VECTOR, compiler.stack_assign(vector_in), 0, compiler.stack_assign(x_out));
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      NODE_SEPARATE_VECTOR, compiler.stack_assign(vector_in), 1, compiler.stack_assign(y_out));
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      NODE_SEPARATE_VECTOR, compiler.stack_assign(vector_in), 2, compiler.stack_assign(z_out));
 | 
						|
}
 | 
						|
 | 
						|
void SeparateXYZNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_separate_xyz");
 | 
						|
}
 | 
						|
 | 
						|
/* Separate HSV */
 | 
						|
 | 
						|
NODE_DEFINE(SeparateHSVNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("separate_hsv", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
 | 
						|
  SOCKET_OUT_FLOAT(h, "H");
 | 
						|
  SOCKET_OUT_FLOAT(s, "S");
 | 
						|
  SOCKET_OUT_FLOAT(v, "V");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
SeparateHSVNode::SeparateHSVNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void SeparateHSVNode::constant_fold(const ConstantFolder &folder)
 | 
						|
{
 | 
						|
  if (folder.all_inputs_constant()) {
 | 
						|
    float3 hsv = rgb_to_hsv(color);
 | 
						|
 | 
						|
    for (int channel = 0; channel < 3; channel++) {
 | 
						|
      if (outputs[channel] == folder.output) {
 | 
						|
        folder.make_constant(hsv[channel]);
 | 
						|
        return;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void SeparateHSVNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *color_in = input("Color");
 | 
						|
  ShaderOutput *hue_out = output("H");
 | 
						|
  ShaderOutput *saturation_out = output("S");
 | 
						|
  ShaderOutput *value_out = output("V");
 | 
						|
 | 
						|
  compiler.add_node(NODE_SEPARATE_HSV,
 | 
						|
                    compiler.stack_assign(color_in),
 | 
						|
                    compiler.stack_assign(hue_out),
 | 
						|
                    compiler.stack_assign(saturation_out));
 | 
						|
  compiler.add_node(NODE_SEPARATE_HSV, compiler.stack_assign(value_out));
 | 
						|
}
 | 
						|
 | 
						|
void SeparateHSVNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_separate_hsv");
 | 
						|
}
 | 
						|
 | 
						|
/* Hue Saturation Value */
 | 
						|
 | 
						|
NODE_DEFINE(HSVNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("hsv", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_FLOAT(hue, "Hue", 0.5f);
 | 
						|
  SOCKET_IN_FLOAT(saturation, "Saturation", 1.0f);
 | 
						|
  SOCKET_IN_FLOAT(value, "Value", 1.0f);
 | 
						|
  SOCKET_IN_FLOAT(fac, "Fac", 1.0f);
 | 
						|
  SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
 | 
						|
  SOCKET_OUT_COLOR(color, "Color");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
HSVNode::HSVNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void HSVNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *hue_in = input("Hue");
 | 
						|
  ShaderInput *saturation_in = input("Saturation");
 | 
						|
  ShaderInput *value_in = input("Value");
 | 
						|
  ShaderInput *fac_in = input("Fac");
 | 
						|
  ShaderInput *color_in = input("Color");
 | 
						|
  ShaderOutput *color_out = output("Color");
 | 
						|
 | 
						|
  compiler.add_node(NODE_HSV,
 | 
						|
                    compiler.encode_uchar4(compiler.stack_assign(color_in),
 | 
						|
                                           compiler.stack_assign(fac_in),
 | 
						|
                                           compiler.stack_assign(color_out)),
 | 
						|
                    compiler.encode_uchar4(compiler.stack_assign(hue_in),
 | 
						|
                                           compiler.stack_assign(saturation_in),
 | 
						|
                                           compiler.stack_assign(value_in)));
 | 
						|
}
 | 
						|
 | 
						|
void HSVNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_hsv");
 | 
						|
}
 | 
						|
 | 
						|
/* Attribute */
 | 
						|
 | 
						|
NODE_DEFINE(AttributeNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("attribute", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_STRING(attribute, "Attribute", ustring());
 | 
						|
 | 
						|
  SOCKET_OUT_COLOR(color, "Color");
 | 
						|
  SOCKET_OUT_VECTOR(vector, "Vector");
 | 
						|
  SOCKET_OUT_FLOAT(fac, "Fac");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
AttributeNode::AttributeNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void AttributeNode::attributes(Shader *shader, 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_standard(attribute);
 | 
						|
  }
 | 
						|
 | 
						|
  if (shader->has_volume) {
 | 
						|
    attributes->add(ATTR_STD_GENERATED_TRANSFORM);
 | 
						|
  }
 | 
						|
 | 
						|
  ShaderNode::attributes(shader, attributes);
 | 
						|
}
 | 
						|
 | 
						|
void AttributeNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderOutput *color_out = output("Color");
 | 
						|
  ShaderOutput *vector_out = output("Vector");
 | 
						|
  ShaderOutput *fac_out = output("Fac");
 | 
						|
  ShaderNodeType attr_node = NODE_ATTR;
 | 
						|
  int attr = compiler.attribute_standard(attribute);
 | 
						|
 | 
						|
  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()) {
 | 
						|
    if (!color_out->links.empty()) {
 | 
						|
      compiler.add_node(attr_node, attr, compiler.stack_assign(color_out), NODE_ATTR_FLOAT3);
 | 
						|
    }
 | 
						|
    if (!vector_out->links.empty()) {
 | 
						|
      compiler.add_node(attr_node, attr, compiler.stack_assign(vector_out), NODE_ATTR_FLOAT3);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (!fac_out->links.empty()) {
 | 
						|
    compiler.add_node(attr_node, attr, compiler.stack_assign(fac_out), 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");
 | 
						|
 | 
						|
  if (Attribute::name_standard(attribute.c_str()) != ATTR_STD_NONE)
 | 
						|
    compiler.parameter("name", (string("geom:") + attribute.c_str()).c_str());
 | 
						|
  else
 | 
						|
    compiler.parameter("name", attribute.c_str());
 | 
						|
 | 
						|
  compiler.add(this, "node_attribute");
 | 
						|
}
 | 
						|
 | 
						|
/* Camera */
 | 
						|
 | 
						|
NODE_DEFINE(CameraNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("camera_info", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_OUT_VECTOR(view_vector, "View Vector");
 | 
						|
  SOCKET_OUT_FLOAT(view_z_depth, "View Z Depth");
 | 
						|
  SOCKET_OUT_FLOAT(view_distance, "View Distance");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
CameraNode::CameraNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void CameraNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderOutput *vector_out = output("View Vector");
 | 
						|
  ShaderOutput *z_depth_out = output("View Z Depth");
 | 
						|
  ShaderOutput *distance_out = output("View Distance");
 | 
						|
 | 
						|
  compiler.add_node(NODE_CAMERA,
 | 
						|
                    compiler.stack_assign(vector_out),
 | 
						|
                    compiler.stack_assign(z_depth_out),
 | 
						|
                    compiler.stack_assign(distance_out));
 | 
						|
}
 | 
						|
 | 
						|
void CameraNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_camera");
 | 
						|
}
 | 
						|
 | 
						|
/* Fresnel */
 | 
						|
 | 
						|
NODE_DEFINE(FresnelNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("fresnel", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_NORMAL(normal,
 | 
						|
                   "Normal",
 | 
						|
                   make_float3(0.0f, 0.0f, 0.0f),
 | 
						|
                   SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
 | 
						|
  SOCKET_IN_FLOAT(IOR, "IOR", 1.45f);
 | 
						|
 | 
						|
  SOCKET_OUT_FLOAT(fac, "Fac");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
FresnelNode::FresnelNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void FresnelNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *normal_in = input("Normal");
 | 
						|
  ShaderInput *IOR_in = input("IOR");
 | 
						|
  ShaderOutput *fac_out = output("Fac");
 | 
						|
 | 
						|
  compiler.add_node(NODE_FRESNEL,
 | 
						|
                    compiler.stack_assign(IOR_in),
 | 
						|
                    __float_as_int(IOR),
 | 
						|
                    compiler.encode_uchar4(compiler.stack_assign_if_linked(normal_in),
 | 
						|
                                           compiler.stack_assign(fac_out)));
 | 
						|
}
 | 
						|
 | 
						|
void FresnelNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_fresnel");
 | 
						|
}
 | 
						|
 | 
						|
/* Layer Weight */
 | 
						|
 | 
						|
NODE_DEFINE(LayerWeightNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("layer_weight", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_NORMAL(normal,
 | 
						|
                   "Normal",
 | 
						|
                   make_float3(0.0f, 0.0f, 0.0f),
 | 
						|
                   SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
 | 
						|
  SOCKET_IN_FLOAT(blend, "Blend", 0.5f);
 | 
						|
 | 
						|
  SOCKET_OUT_FLOAT(fresnel, "Fresnel");
 | 
						|
  SOCKET_OUT_FLOAT(facing, "Facing");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
LayerWeightNode::LayerWeightNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void LayerWeightNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *normal_in = input("Normal");
 | 
						|
  ShaderInput *blend_in = input("Blend");
 | 
						|
  ShaderOutput *fresnel_out = output("Fresnel");
 | 
						|
  ShaderOutput *facing_out = output("Facing");
 | 
						|
 | 
						|
  if (!fresnel_out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_LAYER_WEIGHT,
 | 
						|
                      compiler.stack_assign_if_linked(blend_in),
 | 
						|
                      __float_as_int(blend),
 | 
						|
                      compiler.encode_uchar4(NODE_LAYER_WEIGHT_FRESNEL,
 | 
						|
                                             compiler.stack_assign_if_linked(normal_in),
 | 
						|
                                             compiler.stack_assign(fresnel_out)));
 | 
						|
  }
 | 
						|
 | 
						|
  if (!facing_out->links.empty()) {
 | 
						|
    compiler.add_node(NODE_LAYER_WEIGHT,
 | 
						|
                      compiler.stack_assign_if_linked(blend_in),
 | 
						|
                      __float_as_int(blend),
 | 
						|
                      compiler.encode_uchar4(NODE_LAYER_WEIGHT_FACING,
 | 
						|
                                             compiler.stack_assign_if_linked(normal_in),
 | 
						|
                                             compiler.stack_assign(facing_out)));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void LayerWeightNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_layer_weight");
 | 
						|
}
 | 
						|
 | 
						|
/* Wireframe */
 | 
						|
 | 
						|
NODE_DEFINE(WireframeNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("wireframe", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_BOOLEAN(use_pixel_size, "Use Pixel Size", false);
 | 
						|
  SOCKET_IN_FLOAT(size, "Size", 0.01f);
 | 
						|
  SOCKET_OUT_FLOAT(fac, "Fac");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
WireframeNode::WireframeNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void WireframeNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *size_in = input("Size");
 | 
						|
  ShaderOutput *fac_out = output("Fac");
 | 
						|
  NodeBumpOffset bump_offset = NODE_BUMP_OFFSET_CENTER;
 | 
						|
  if (bump == SHADER_BUMP_DX) {
 | 
						|
    bump_offset = NODE_BUMP_OFFSET_DX;
 | 
						|
  }
 | 
						|
  else if (bump == SHADER_BUMP_DY) {
 | 
						|
    bump_offset = NODE_BUMP_OFFSET_DY;
 | 
						|
  }
 | 
						|
  compiler.add_node(NODE_WIREFRAME,
 | 
						|
                    compiler.stack_assign(size_in),
 | 
						|
                    compiler.stack_assign(fac_out),
 | 
						|
                    compiler.encode_uchar4(use_pixel_size, bump_offset, 0, 0));
 | 
						|
}
 | 
						|
 | 
						|
void WireframeNode::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(this, "use_pixel_size");
 | 
						|
  compiler.add(this, "node_wireframe");
 | 
						|
}
 | 
						|
 | 
						|
/* Wavelength */
 | 
						|
 | 
						|
NODE_DEFINE(WavelengthNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("wavelength", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_FLOAT(wavelength, "Wavelength", 500.0f);
 | 
						|
  SOCKET_OUT_COLOR(color, "Color");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
WavelengthNode::WavelengthNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void WavelengthNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *wavelength_in = input("Wavelength");
 | 
						|
  ShaderOutput *color_out = output("Color");
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      NODE_WAVELENGTH, compiler.stack_assign(wavelength_in), compiler.stack_assign(color_out));
 | 
						|
}
 | 
						|
 | 
						|
void WavelengthNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_wavelength");
 | 
						|
}
 | 
						|
 | 
						|
/* Blackbody */
 | 
						|
 | 
						|
NODE_DEFINE(BlackbodyNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("blackbody", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_FLOAT(temperature, "Temperature", 1200.0f);
 | 
						|
  SOCKET_OUT_COLOR(color, "Color");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
BlackbodyNode::BlackbodyNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void BlackbodyNode::constant_fold(const ConstantFolder &folder)
 | 
						|
{
 | 
						|
  if (folder.all_inputs_constant()) {
 | 
						|
    folder.make_constant(svm_math_blackbody_color(temperature));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void BlackbodyNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *temperature_in = input("Temperature");
 | 
						|
  ShaderOutput *color_out = output("Color");
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      NODE_BLACKBODY, compiler.stack_assign(temperature_in), compiler.stack_assign(color_out));
 | 
						|
}
 | 
						|
 | 
						|
void BlackbodyNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_blackbody");
 | 
						|
}
 | 
						|
 | 
						|
/* Output */
 | 
						|
 | 
						|
NODE_DEFINE(OutputNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("output", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_CLOSURE(surface, "Surface");
 | 
						|
  SOCKET_IN_CLOSURE(volume, "Volume");
 | 
						|
  SOCKET_IN_VECTOR(displacement, "Displacement", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
  SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
OutputNode::OutputNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
  special_type = SHADER_SPECIAL_TYPE_OUTPUT;
 | 
						|
}
 | 
						|
 | 
						|
void OutputNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  if (compiler.output_type() == SHADER_TYPE_DISPLACEMENT) {
 | 
						|
    ShaderInput *displacement_in = input("Displacement");
 | 
						|
 | 
						|
    if (displacement_in->link) {
 | 
						|
      compiler.add_node(NODE_SET_DISPLACEMENT, compiler.stack_assign(displacement_in));
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
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");
 | 
						|
}
 | 
						|
 | 
						|
/* Map Range Node */
 | 
						|
 | 
						|
NODE_DEFINE(MapRangeNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("map_range", create, NodeType::SHADER);
 | 
						|
 | 
						|
  static NodeEnum type_enum;
 | 
						|
  type_enum.insert("linear", NODE_MAP_RANGE_LINEAR);
 | 
						|
  type_enum.insert("stepped", NODE_MAP_RANGE_STEPPED);
 | 
						|
  type_enum.insert("smoothstep", NODE_MAP_RANGE_SMOOTHSTEP);
 | 
						|
  type_enum.insert("smootherstep", NODE_MAP_RANGE_SMOOTHERSTEP);
 | 
						|
  SOCKET_ENUM(type, "Type", type_enum, NODE_MAP_RANGE_LINEAR);
 | 
						|
 | 
						|
  SOCKET_IN_FLOAT(value, "Value", 1.0f);
 | 
						|
  SOCKET_IN_FLOAT(from_min, "From Min", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(from_max, "From Max", 1.0f);
 | 
						|
  SOCKET_IN_FLOAT(to_min, "To Min", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(to_max, "To Max", 1.0f);
 | 
						|
  SOCKET_IN_FLOAT(steps, "Steps", 4.0f);
 | 
						|
 | 
						|
  SOCKET_OUT_FLOAT(result, "Result");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
MapRangeNode::MapRangeNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void MapRangeNode::expand(ShaderGraph *graph)
 | 
						|
{
 | 
						|
  if (clamp) {
 | 
						|
    ShaderOutput *result_out = output("Result");
 | 
						|
    if (!result_out->links.empty()) {
 | 
						|
      ClampNode *clamp_node = new ClampNode();
 | 
						|
      clamp_node->type = NODE_CLAMP_RANGE;
 | 
						|
      graph->add(clamp_node);
 | 
						|
      graph->relink(result_out, clamp_node->output("Result"));
 | 
						|
      graph->connect(result_out, clamp_node->input("Value"));
 | 
						|
      if (input("To Min")->link) {
 | 
						|
        graph->connect(input("To Min")->link, clamp_node->input("Min"));
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        clamp_node->min = to_min;
 | 
						|
      }
 | 
						|
      if (input("To Max")->link) {
 | 
						|
        graph->connect(input("To Max")->link, clamp_node->input("Max"));
 | 
						|
      }
 | 
						|
      else {
 | 
						|
        clamp_node->max = to_max;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void MapRangeNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *value_in = input("Value");
 | 
						|
  ShaderInput *from_min_in = input("From Min");
 | 
						|
  ShaderInput *from_max_in = input("From Max");
 | 
						|
  ShaderInput *to_min_in = input("To Min");
 | 
						|
  ShaderInput *to_max_in = input("To Max");
 | 
						|
  ShaderInput *steps_in = input("Steps");
 | 
						|
  ShaderOutput *result_out = output("Result");
 | 
						|
 | 
						|
  int value_stack_offset = compiler.stack_assign(value_in);
 | 
						|
  int from_min_stack_offset = compiler.stack_assign_if_linked(from_min_in);
 | 
						|
  int from_max_stack_offset = compiler.stack_assign_if_linked(from_max_in);
 | 
						|
  int to_min_stack_offset = compiler.stack_assign_if_linked(to_min_in);
 | 
						|
  int to_max_stack_offset = compiler.stack_assign_if_linked(to_max_in);
 | 
						|
  int steps_stack_offset = compiler.stack_assign(steps_in);
 | 
						|
  int result_stack_offset = compiler.stack_assign(result_out);
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      NODE_MAP_RANGE,
 | 
						|
      value_stack_offset,
 | 
						|
      compiler.encode_uchar4(
 | 
						|
          from_min_stack_offset, from_max_stack_offset, to_min_stack_offset, to_max_stack_offset),
 | 
						|
      compiler.encode_uchar4(type, steps_stack_offset, result_stack_offset));
 | 
						|
 | 
						|
  compiler.add_node(__float_as_int(from_min),
 | 
						|
                    __float_as_int(from_max),
 | 
						|
                    __float_as_int(to_min),
 | 
						|
                    __float_as_int(to_max));
 | 
						|
  compiler.add_node(__float_as_int(steps));
 | 
						|
}
 | 
						|
 | 
						|
void MapRangeNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.parameter(this, "type");
 | 
						|
  compiler.add(this, "node_map_range");
 | 
						|
}
 | 
						|
 | 
						|
/* Clamp Node */
 | 
						|
 | 
						|
NODE_DEFINE(ClampNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("clamp", create, NodeType::SHADER);
 | 
						|
 | 
						|
  static NodeEnum type_enum;
 | 
						|
  type_enum.insert("minmax", NODE_CLAMP_MINMAX);
 | 
						|
  type_enum.insert("range", NODE_CLAMP_RANGE);
 | 
						|
  SOCKET_ENUM(type, "Type", type_enum, NODE_CLAMP_MINMAX);
 | 
						|
 | 
						|
  SOCKET_IN_FLOAT(value, "Value", 1.0f);
 | 
						|
  SOCKET_IN_FLOAT(min, "Min", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(max, "Max", 1.0f);
 | 
						|
 | 
						|
  SOCKET_OUT_FLOAT(result, "Result");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
ClampNode::ClampNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void ClampNode::constant_fold(const ConstantFolder &folder)
 | 
						|
{
 | 
						|
  if (folder.all_inputs_constant()) {
 | 
						|
    if (type == NODE_CLAMP_RANGE && (min > max)) {
 | 
						|
      folder.make_constant(clamp(value, max, min));
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      folder.make_constant(clamp(value, min, max));
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void ClampNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *value_in = input("Value");
 | 
						|
  ShaderInput *min_in = input("Min");
 | 
						|
  ShaderInput *max_in = input("Max");
 | 
						|
  ShaderOutput *result_out = output("Result");
 | 
						|
 | 
						|
  int value_stack_offset = compiler.stack_assign(value_in);
 | 
						|
  int min_stack_offset = compiler.stack_assign(min_in);
 | 
						|
  int max_stack_offset = compiler.stack_assign(max_in);
 | 
						|
  int result_stack_offset = compiler.stack_assign(result_out);
 | 
						|
 | 
						|
  compiler.add_node(NODE_CLAMP,
 | 
						|
                    value_stack_offset,
 | 
						|
                    compiler.encode_uchar4(min_stack_offset, max_stack_offset, type),
 | 
						|
                    result_stack_offset);
 | 
						|
  compiler.add_node(__float_as_int(min), __float_as_int(max));
 | 
						|
}
 | 
						|
 | 
						|
void ClampNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.parameter(this, "type");
 | 
						|
  compiler.add(this, "node_clamp");
 | 
						|
}
 | 
						|
 | 
						|
/* AOV Output */
 | 
						|
 | 
						|
NODE_DEFINE(OutputAOVNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("aov_output", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_COLOR(color, "Color", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
  SOCKET_IN_FLOAT(value, "Value", 0.0f);
 | 
						|
 | 
						|
  SOCKET_STRING(name, "AOV Name", ustring(""));
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
OutputAOVNode::OutputAOVNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
  special_type = SHADER_SPECIAL_TYPE_OUTPUT_AOV;
 | 
						|
  slot = -1;
 | 
						|
}
 | 
						|
 | 
						|
void OutputAOVNode::simplify_settings(Scene *scene)
 | 
						|
{
 | 
						|
  slot = scene->film->get_aov_offset(name.string(), is_color);
 | 
						|
  if (slot == -1) {
 | 
						|
    slot = scene->film->get_aov_offset(name.string(), is_color);
 | 
						|
  }
 | 
						|
 | 
						|
  if (slot == -1 || is_color) {
 | 
						|
    input("Value")->disconnect();
 | 
						|
  }
 | 
						|
  if (slot == -1 || !is_color) {
 | 
						|
    input("Color")->disconnect();
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void OutputAOVNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  assert(slot >= 0);
 | 
						|
 | 
						|
  if (is_color) {
 | 
						|
    compiler.add_node(NODE_AOV_COLOR, compiler.stack_assign(input("Color")), slot);
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    compiler.add_node(NODE_AOV_VALUE, compiler.stack_assign(input("Value")), slot);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void OutputAOVNode::compile(OSLCompiler & /*compiler*/)
 | 
						|
{
 | 
						|
  /* TODO */
 | 
						|
}
 | 
						|
 | 
						|
/* Math */
 | 
						|
 | 
						|
NODE_DEFINE(MathNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("math", create, NodeType::SHADER);
 | 
						|
 | 
						|
  static NodeEnum type_enum;
 | 
						|
  type_enum.insert("add", NODE_MATH_ADD);
 | 
						|
  type_enum.insert("subtract", NODE_MATH_SUBTRACT);
 | 
						|
  type_enum.insert("multiply", NODE_MATH_MULTIPLY);
 | 
						|
  type_enum.insert("divide", NODE_MATH_DIVIDE);
 | 
						|
  type_enum.insert("multiply_add", NODE_MATH_MULTIPLY_ADD);
 | 
						|
  type_enum.insert("sine", NODE_MATH_SINE);
 | 
						|
  type_enum.insert("cosine", NODE_MATH_COSINE);
 | 
						|
  type_enum.insert("tangent", NODE_MATH_TANGENT);
 | 
						|
  type_enum.insert("sinh", NODE_MATH_SINH);
 | 
						|
  type_enum.insert("cosh", NODE_MATH_COSH);
 | 
						|
  type_enum.insert("tanh", NODE_MATH_TANH);
 | 
						|
  type_enum.insert("arcsine", NODE_MATH_ARCSINE);
 | 
						|
  type_enum.insert("arccosine", NODE_MATH_ARCCOSINE);
 | 
						|
  type_enum.insert("arctangent", NODE_MATH_ARCTANGENT);
 | 
						|
  type_enum.insert("power", NODE_MATH_POWER);
 | 
						|
  type_enum.insert("logarithm", NODE_MATH_LOGARITHM);
 | 
						|
  type_enum.insert("minimum", NODE_MATH_MINIMUM);
 | 
						|
  type_enum.insert("maximum", NODE_MATH_MAXIMUM);
 | 
						|
  type_enum.insert("round", NODE_MATH_ROUND);
 | 
						|
  type_enum.insert("less_than", NODE_MATH_LESS_THAN);
 | 
						|
  type_enum.insert("greater_than", NODE_MATH_GREATER_THAN);
 | 
						|
  type_enum.insert("modulo", NODE_MATH_MODULO);
 | 
						|
  type_enum.insert("absolute", NODE_MATH_ABSOLUTE);
 | 
						|
  type_enum.insert("arctan2", NODE_MATH_ARCTAN2);
 | 
						|
  type_enum.insert("floor", NODE_MATH_FLOOR);
 | 
						|
  type_enum.insert("ceil", NODE_MATH_CEIL);
 | 
						|
  type_enum.insert("fraction", NODE_MATH_FRACTION);
 | 
						|
  type_enum.insert("trunc", NODE_MATH_TRUNC);
 | 
						|
  type_enum.insert("snap", NODE_MATH_SNAP);
 | 
						|
  type_enum.insert("wrap", NODE_MATH_WRAP);
 | 
						|
  type_enum.insert("pingpong", NODE_MATH_PINGPONG);
 | 
						|
  type_enum.insert("sqrt", NODE_MATH_SQRT);
 | 
						|
  type_enum.insert("inversesqrt", NODE_MATH_INV_SQRT);
 | 
						|
  type_enum.insert("sign", NODE_MATH_SIGN);
 | 
						|
  type_enum.insert("exponent", NODE_MATH_EXPONENT);
 | 
						|
  type_enum.insert("radians", NODE_MATH_RADIANS);
 | 
						|
  type_enum.insert("degrees", NODE_MATH_DEGREES);
 | 
						|
  type_enum.insert("smoothmin", NODE_MATH_SMOOTH_MIN);
 | 
						|
  type_enum.insert("smoothmax", NODE_MATH_SMOOTH_MAX);
 | 
						|
  type_enum.insert("compare", NODE_MATH_COMPARE);
 | 
						|
  SOCKET_ENUM(type, "Type", type_enum, NODE_MATH_ADD);
 | 
						|
 | 
						|
  SOCKET_BOOLEAN(use_clamp, "Use Clamp", false);
 | 
						|
 | 
						|
  SOCKET_IN_FLOAT(value1, "Value1", 0.5f);
 | 
						|
  SOCKET_IN_FLOAT(value2, "Value2", 0.5f);
 | 
						|
  SOCKET_IN_FLOAT(value3, "Value3", 0.0f);
 | 
						|
 | 
						|
  SOCKET_OUT_FLOAT(value, "Value");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
MathNode::MathNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void MathNode::expand(ShaderGraph *graph)
 | 
						|
{
 | 
						|
  if (use_clamp) {
 | 
						|
    ShaderOutput *result_out = output("Value");
 | 
						|
    if (!result_out->links.empty()) {
 | 
						|
      ClampNode *clamp_node = new ClampNode();
 | 
						|
      clamp_node->type = NODE_CLAMP_MINMAX;
 | 
						|
      clamp_node->min = 0.0f;
 | 
						|
      clamp_node->max = 1.0f;
 | 
						|
      graph->add(clamp_node);
 | 
						|
      graph->relink(result_out, clamp_node->output("Result"));
 | 
						|
      graph->connect(result_out, clamp_node->input("Value"));
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void MathNode::constant_fold(const ConstantFolder &folder)
 | 
						|
{
 | 
						|
  if (folder.all_inputs_constant()) {
 | 
						|
    folder.make_constant(svm_math(type, value1, value2, value3));
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    folder.fold_math(type);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void MathNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *value1_in = input("Value1");
 | 
						|
  ShaderInput *value2_in = input("Value2");
 | 
						|
  ShaderInput *value3_in = input("Value3");
 | 
						|
  ShaderOutput *value_out = output("Value");
 | 
						|
 | 
						|
  int value1_stack_offset = compiler.stack_assign(value1_in);
 | 
						|
  int value2_stack_offset = compiler.stack_assign(value2_in);
 | 
						|
  int value3_stack_offset = compiler.stack_assign(value3_in);
 | 
						|
  int value_stack_offset = compiler.stack_assign(value_out);
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      NODE_MATH,
 | 
						|
      type,
 | 
						|
      compiler.encode_uchar4(value1_stack_offset, value2_stack_offset, value3_stack_offset),
 | 
						|
      value_stack_offset);
 | 
						|
}
 | 
						|
 | 
						|
void MathNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.parameter(this, "type");
 | 
						|
  compiler.add(this, "node_math");
 | 
						|
}
 | 
						|
 | 
						|
/* VectorMath */
 | 
						|
 | 
						|
NODE_DEFINE(VectorMathNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("vector_math", create, NodeType::SHADER);
 | 
						|
 | 
						|
  static NodeEnum type_enum;
 | 
						|
  type_enum.insert("add", NODE_VECTOR_MATH_ADD);
 | 
						|
  type_enum.insert("subtract", NODE_VECTOR_MATH_SUBTRACT);
 | 
						|
  type_enum.insert("multiply", NODE_VECTOR_MATH_MULTIPLY);
 | 
						|
  type_enum.insert("divide", NODE_VECTOR_MATH_DIVIDE);
 | 
						|
 | 
						|
  type_enum.insert("cross_product", NODE_VECTOR_MATH_CROSS_PRODUCT);
 | 
						|
  type_enum.insert("project", NODE_VECTOR_MATH_PROJECT);
 | 
						|
  type_enum.insert("reflect", NODE_VECTOR_MATH_REFLECT);
 | 
						|
  type_enum.insert("dot_product", NODE_VECTOR_MATH_DOT_PRODUCT);
 | 
						|
 | 
						|
  type_enum.insert("distance", NODE_VECTOR_MATH_DISTANCE);
 | 
						|
  type_enum.insert("length", NODE_VECTOR_MATH_LENGTH);
 | 
						|
  type_enum.insert("scale", NODE_VECTOR_MATH_SCALE);
 | 
						|
  type_enum.insert("normalize", NODE_VECTOR_MATH_NORMALIZE);
 | 
						|
 | 
						|
  type_enum.insert("snap", NODE_VECTOR_MATH_SNAP);
 | 
						|
  type_enum.insert("floor", NODE_VECTOR_MATH_FLOOR);
 | 
						|
  type_enum.insert("ceil", NODE_VECTOR_MATH_CEIL);
 | 
						|
  type_enum.insert("modulo", NODE_VECTOR_MATH_MODULO);
 | 
						|
  type_enum.insert("wrap", NODE_VECTOR_MATH_WRAP);
 | 
						|
  type_enum.insert("fraction", NODE_VECTOR_MATH_FRACTION);
 | 
						|
  type_enum.insert("absolute", NODE_VECTOR_MATH_ABSOLUTE);
 | 
						|
  type_enum.insert("minimum", NODE_VECTOR_MATH_MINIMUM);
 | 
						|
  type_enum.insert("maximum", NODE_VECTOR_MATH_MAXIMUM);
 | 
						|
 | 
						|
  type_enum.insert("sine", NODE_VECTOR_MATH_SINE);
 | 
						|
  type_enum.insert("cosine", NODE_VECTOR_MATH_COSINE);
 | 
						|
  type_enum.insert("tangent", NODE_VECTOR_MATH_TANGENT);
 | 
						|
  SOCKET_ENUM(type, "Type", type_enum, NODE_VECTOR_MATH_ADD);
 | 
						|
 | 
						|
  SOCKET_IN_VECTOR(vector1, "Vector1", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
  SOCKET_IN_VECTOR(vector2, "Vector2", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
  SOCKET_IN_VECTOR(vector3, "Vector3", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
  SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
 | 
						|
 | 
						|
  SOCKET_OUT_FLOAT(value, "Value");
 | 
						|
  SOCKET_OUT_VECTOR(vector, "Vector");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
VectorMathNode::VectorMathNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void VectorMathNode::constant_fold(const ConstantFolder &folder)
 | 
						|
{
 | 
						|
  float value = 0.0f;
 | 
						|
  float3 vector = make_float3(0.0f, 0.0f, 0.0f);
 | 
						|
 | 
						|
  if (folder.all_inputs_constant()) {
 | 
						|
    svm_vector_math(&value, &vector, type, vector1, vector2, vector3, scale);
 | 
						|
    if (folder.output == output("Value")) {
 | 
						|
      folder.make_constant(value);
 | 
						|
    }
 | 
						|
    else if (folder.output == output("Vector")) {
 | 
						|
      folder.make_constant(vector);
 | 
						|
    }
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    folder.fold_vector_math(type);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void VectorMathNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *vector1_in = input("Vector1");
 | 
						|
  ShaderInput *vector2_in = input("Vector2");
 | 
						|
  ShaderInput *scale_in = input("Scale");
 | 
						|
  ShaderOutput *value_out = output("Value");
 | 
						|
  ShaderOutput *vector_out = output("Vector");
 | 
						|
 | 
						|
  int vector1_stack_offset = compiler.stack_assign(vector1_in);
 | 
						|
  int vector2_stack_offset = compiler.stack_assign(vector2_in);
 | 
						|
  int scale_stack_offset = compiler.stack_assign(scale_in);
 | 
						|
  int value_stack_offset = compiler.stack_assign_if_linked(value_out);
 | 
						|
  int vector_stack_offset = compiler.stack_assign_if_linked(vector_out);
 | 
						|
 | 
						|
  /* 3 Vector Operators */
 | 
						|
  if (type == NODE_VECTOR_MATH_WRAP) {
 | 
						|
    ShaderInput *vector3_in = input("Vector3");
 | 
						|
    int vector3_stack_offset = compiler.stack_assign(vector3_in);
 | 
						|
    compiler.add_node(
 | 
						|
        NODE_VECTOR_MATH,
 | 
						|
        type,
 | 
						|
        compiler.encode_uchar4(vector1_stack_offset, vector2_stack_offset, scale_stack_offset),
 | 
						|
        compiler.encode_uchar4(value_stack_offset, vector_stack_offset));
 | 
						|
    compiler.add_node(vector3_stack_offset);
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    compiler.add_node(
 | 
						|
        NODE_VECTOR_MATH,
 | 
						|
        type,
 | 
						|
        compiler.encode_uchar4(vector1_stack_offset, vector2_stack_offset, scale_stack_offset),
 | 
						|
        compiler.encode_uchar4(value_stack_offset, vector_stack_offset));
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void VectorMathNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.parameter(this, "type");
 | 
						|
  compiler.add(this, "node_vector_math");
 | 
						|
}
 | 
						|
 | 
						|
/* Vector Rotate */
 | 
						|
 | 
						|
NODE_DEFINE(VectorRotateNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("vector_rotate", create, NodeType::SHADER);
 | 
						|
 | 
						|
  static NodeEnum type_enum;
 | 
						|
  type_enum.insert("axis", NODE_VECTOR_ROTATE_TYPE_AXIS);
 | 
						|
  type_enum.insert("x_axis", NODE_VECTOR_ROTATE_TYPE_AXIS_X);
 | 
						|
  type_enum.insert("y_axis", NODE_VECTOR_ROTATE_TYPE_AXIS_Y);
 | 
						|
  type_enum.insert("z_axis", NODE_VECTOR_ROTATE_TYPE_AXIS_Z);
 | 
						|
  type_enum.insert("euler_xyz", NODE_VECTOR_ROTATE_TYPE_EULER_XYZ);
 | 
						|
  SOCKET_ENUM(type, "Type", type_enum, NODE_VECTOR_ROTATE_TYPE_AXIS);
 | 
						|
 | 
						|
  SOCKET_BOOLEAN(invert, "Invert", false);
 | 
						|
 | 
						|
  SOCKET_IN_VECTOR(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
  SOCKET_IN_POINT(rotation, "Rotation", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
  SOCKET_IN_POINT(center, "Center", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
  SOCKET_IN_VECTOR(axis, "Axis", make_float3(0.0f, 0.0f, 1.0f));
 | 
						|
  SOCKET_IN_FLOAT(angle, "Angle", 0.0f);
 | 
						|
  SOCKET_OUT_VECTOR(vector, "Vector");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
VectorRotateNode::VectorRotateNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void VectorRotateNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *vector_in = input("Vector");
 | 
						|
  ShaderInput *rotation_in = input("Rotation");
 | 
						|
  ShaderInput *center_in = input("Center");
 | 
						|
  ShaderInput *axis_in = input("Axis");
 | 
						|
  ShaderInput *angle_in = input("Angle");
 | 
						|
  ShaderOutput *vector_out = output("Vector");
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      NODE_VECTOR_ROTATE,
 | 
						|
      compiler.encode_uchar4(
 | 
						|
          type, compiler.stack_assign(vector_in), compiler.stack_assign(rotation_in), invert),
 | 
						|
      compiler.encode_uchar4(compiler.stack_assign(center_in),
 | 
						|
                             compiler.stack_assign(axis_in),
 | 
						|
                             compiler.stack_assign(angle_in)),
 | 
						|
      compiler.stack_assign(vector_out));
 | 
						|
}
 | 
						|
 | 
						|
void VectorRotateNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.parameter(this, "type");
 | 
						|
  compiler.parameter(this, "invert");
 | 
						|
  compiler.add(this, "node_vector_rotate");
 | 
						|
}
 | 
						|
 | 
						|
/* VectorTransform */
 | 
						|
 | 
						|
NODE_DEFINE(VectorTransformNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("vector_transform", create, NodeType::SHADER);
 | 
						|
 | 
						|
  static NodeEnum type_enum;
 | 
						|
  type_enum.insert("vector", NODE_VECTOR_TRANSFORM_TYPE_VECTOR);
 | 
						|
  type_enum.insert("point", NODE_VECTOR_TRANSFORM_TYPE_POINT);
 | 
						|
  type_enum.insert("normal", NODE_VECTOR_TRANSFORM_TYPE_NORMAL);
 | 
						|
  SOCKET_ENUM(type, "Type", type_enum, NODE_VECTOR_TRANSFORM_TYPE_VECTOR);
 | 
						|
 | 
						|
  static NodeEnum space_enum;
 | 
						|
  space_enum.insert("world", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD);
 | 
						|
  space_enum.insert("object", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT);
 | 
						|
  space_enum.insert("camera", NODE_VECTOR_TRANSFORM_CONVERT_SPACE_CAMERA);
 | 
						|
  SOCKET_ENUM(convert_from, "Convert From", space_enum, NODE_VECTOR_TRANSFORM_CONVERT_SPACE_WORLD);
 | 
						|
  SOCKET_ENUM(convert_to, "Convert To", space_enum, NODE_VECTOR_TRANSFORM_CONVERT_SPACE_OBJECT);
 | 
						|
 | 
						|
  SOCKET_IN_VECTOR(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
  SOCKET_OUT_VECTOR(vector, "Vector");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
VectorTransformNode::VectorTransformNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void VectorTransformNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *vector_in = input("Vector");
 | 
						|
  ShaderOutput *vector_out = output("Vector");
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      NODE_VECTOR_TRANSFORM,
 | 
						|
      compiler.encode_uchar4(type, convert_from, convert_to),
 | 
						|
      compiler.encode_uchar4(compiler.stack_assign(vector_in), compiler.stack_assign(vector_out)));
 | 
						|
}
 | 
						|
 | 
						|
void VectorTransformNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.parameter(this, "type");
 | 
						|
  compiler.parameter(this, "convert_from");
 | 
						|
  compiler.parameter(this, "convert_to");
 | 
						|
  compiler.add(this, "node_vector_transform");
 | 
						|
}
 | 
						|
 | 
						|
/* BumpNode */
 | 
						|
 | 
						|
NODE_DEFINE(BumpNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("bump", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_BOOLEAN(invert, "Invert", false);
 | 
						|
  SOCKET_BOOLEAN(use_object_space, "UseObjectSpace", false);
 | 
						|
 | 
						|
  /* this input is used by the user, but after graph transform it is no longer
 | 
						|
   * used and moved to sampler center/x/y instead */
 | 
						|
  SOCKET_IN_FLOAT(height, "Height", 1.0f);
 | 
						|
 | 
						|
  SOCKET_IN_FLOAT(sample_center, "SampleCenter", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(sample_x, "SampleX", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(sample_y, "SampleY", 0.0f);
 | 
						|
  SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
 | 
						|
  SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
 | 
						|
  SOCKET_IN_FLOAT(distance, "Distance", 0.1f);
 | 
						|
 | 
						|
  SOCKET_OUT_NORMAL(normal, "Normal");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
BumpNode::BumpNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
  special_type = SHADER_SPECIAL_TYPE_BUMP;
 | 
						|
}
 | 
						|
 | 
						|
void BumpNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *center_in = input("SampleCenter");
 | 
						|
  ShaderInput *dx_in = input("SampleX");
 | 
						|
  ShaderInput *dy_in = input("SampleY");
 | 
						|
  ShaderInput *normal_in = input("Normal");
 | 
						|
  ShaderInput *strength_in = input("Strength");
 | 
						|
  ShaderInput *distance_in = input("Distance");
 | 
						|
  ShaderOutput *normal_out = output("Normal");
 | 
						|
 | 
						|
  /* pack all parameters in the node */
 | 
						|
  compiler.add_node(NODE_SET_BUMP,
 | 
						|
                    compiler.encode_uchar4(compiler.stack_assign_if_linked(normal_in),
 | 
						|
                                           compiler.stack_assign(distance_in),
 | 
						|
                                           invert,
 | 
						|
                                           use_object_space),
 | 
						|
                    compiler.encode_uchar4(compiler.stack_assign(center_in),
 | 
						|
                                           compiler.stack_assign(dx_in),
 | 
						|
                                           compiler.stack_assign(dy_in),
 | 
						|
                                           compiler.stack_assign(strength_in)),
 | 
						|
                    compiler.stack_assign(normal_out));
 | 
						|
}
 | 
						|
 | 
						|
void BumpNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.parameter(this, "invert");
 | 
						|
  compiler.parameter(this, "use_object_space");
 | 
						|
  compiler.add(this, "node_bump");
 | 
						|
}
 | 
						|
 | 
						|
void BumpNode::constant_fold(const ConstantFolder &folder)
 | 
						|
{
 | 
						|
  ShaderInput *height_in = input("Height");
 | 
						|
  ShaderInput *normal_in = input("Normal");
 | 
						|
 | 
						|
  if (height_in->link == NULL) {
 | 
						|
    if (normal_in->link == NULL) {
 | 
						|
      GeometryNode *geom = new GeometryNode();
 | 
						|
      folder.graph->add(geom);
 | 
						|
      folder.bypass(geom->output("Normal"));
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      folder.bypass(normal_in->link);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  /* TODO(sergey): Ignore bump with zero strength. */
 | 
						|
}
 | 
						|
 | 
						|
/* Curve node */
 | 
						|
 | 
						|
CurvesNode::CurvesNode(const NodeType *node_type) : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void CurvesNode::constant_fold(const ConstantFolder &folder, ShaderInput *value_in)
 | 
						|
{
 | 
						|
  ShaderInput *fac_in = input("Fac");
 | 
						|
 | 
						|
  /* evaluate fully constant node */
 | 
						|
  if (folder.all_inputs_constant()) {
 | 
						|
    if (curves.size() == 0) {
 | 
						|
      return;
 | 
						|
    }
 | 
						|
 | 
						|
    float3 pos = (value - make_float3(min_x, min_x, min_x)) / (max_x - min_x);
 | 
						|
    float3 result;
 | 
						|
 | 
						|
    result[0] = rgb_ramp_lookup(curves.data(), pos[0], true, true, curves.size()).x;
 | 
						|
    result[1] = rgb_ramp_lookup(curves.data(), pos[1], true, true, curves.size()).y;
 | 
						|
    result[2] = rgb_ramp_lookup(curves.data(), pos[2], true, true, curves.size()).z;
 | 
						|
 | 
						|
    folder.make_constant(interp(value, result, fac));
 | 
						|
  }
 | 
						|
  /* remove no-op node */
 | 
						|
  else if (!fac_in->link && fac == 0.0f) {
 | 
						|
    /* link is not null because otherwise all inputs are constant */
 | 
						|
    folder.bypass(value_in->link);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void CurvesNode::compile(SVMCompiler &compiler,
 | 
						|
                         int type,
 | 
						|
                         ShaderInput *value_in,
 | 
						|
                         ShaderOutput *value_out)
 | 
						|
{
 | 
						|
  if (curves.size() == 0)
 | 
						|
    return;
 | 
						|
 | 
						|
  ShaderInput *fac_in = input("Fac");
 | 
						|
 | 
						|
  compiler.add_node(type,
 | 
						|
                    compiler.encode_uchar4(compiler.stack_assign(fac_in),
 | 
						|
                                           compiler.stack_assign(value_in),
 | 
						|
                                           compiler.stack_assign(value_out)),
 | 
						|
                    __float_as_int(min_x),
 | 
						|
                    __float_as_int(max_x));
 | 
						|
 | 
						|
  compiler.add_node(curves.size());
 | 
						|
  for (int i = 0; i < curves.size(); i++)
 | 
						|
    compiler.add_node(float3_to_float4(curves[i]));
 | 
						|
}
 | 
						|
 | 
						|
void CurvesNode::compile(OSLCompiler &compiler, const char *name)
 | 
						|
{
 | 
						|
  if (curves.size() == 0)
 | 
						|
    return;
 | 
						|
 | 
						|
  compiler.parameter_color_array("ramp", curves);
 | 
						|
  compiler.parameter(this, "min_x");
 | 
						|
  compiler.parameter(this, "max_x");
 | 
						|
  compiler.add(this, name);
 | 
						|
}
 | 
						|
 | 
						|
void CurvesNode::compile(SVMCompiler & /*compiler*/)
 | 
						|
{
 | 
						|
  assert(0);
 | 
						|
}
 | 
						|
 | 
						|
void CurvesNode::compile(OSLCompiler & /*compiler*/)
 | 
						|
{
 | 
						|
  assert(0);
 | 
						|
}
 | 
						|
 | 
						|
/* RGBCurvesNode */
 | 
						|
 | 
						|
NODE_DEFINE(RGBCurvesNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("rgb_curves", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_COLOR_ARRAY(curves, "Curves", array<float3>());
 | 
						|
  SOCKET_FLOAT(min_x, "Min X", 0.0f);
 | 
						|
  SOCKET_FLOAT(max_x, "Max X", 1.0f);
 | 
						|
 | 
						|
  SOCKET_IN_FLOAT(fac, "Fac", 0.0f);
 | 
						|
  SOCKET_IN_COLOR(value, "Color", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
 | 
						|
  SOCKET_OUT_COLOR(value, "Color");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
RGBCurvesNode::RGBCurvesNode() : CurvesNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void RGBCurvesNode::constant_fold(const ConstantFolder &folder)
 | 
						|
{
 | 
						|
  CurvesNode::constant_fold(folder, input("Color"));
 | 
						|
}
 | 
						|
 | 
						|
void RGBCurvesNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  CurvesNode::compile(compiler, NODE_RGB_CURVES, input("Color"), output("Color"));
 | 
						|
}
 | 
						|
 | 
						|
void RGBCurvesNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  CurvesNode::compile(compiler, "node_rgb_curves");
 | 
						|
}
 | 
						|
 | 
						|
/* VectorCurvesNode */
 | 
						|
 | 
						|
NODE_DEFINE(VectorCurvesNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("vector_curves", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_VECTOR_ARRAY(curves, "Curves", array<float3>());
 | 
						|
  SOCKET_FLOAT(min_x, "Min X", 0.0f);
 | 
						|
  SOCKET_FLOAT(max_x, "Max X", 1.0f);
 | 
						|
 | 
						|
  SOCKET_IN_FLOAT(fac, "Fac", 0.0f);
 | 
						|
  SOCKET_IN_VECTOR(value, "Vector", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
 | 
						|
  SOCKET_OUT_VECTOR(value, "Vector");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
VectorCurvesNode::VectorCurvesNode() : CurvesNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void VectorCurvesNode::constant_fold(const ConstantFolder &folder)
 | 
						|
{
 | 
						|
  CurvesNode::constant_fold(folder, input("Vector"));
 | 
						|
}
 | 
						|
 | 
						|
void VectorCurvesNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  CurvesNode::compile(compiler, NODE_VECTOR_CURVES, input("Vector"), output("Vector"));
 | 
						|
}
 | 
						|
 | 
						|
void VectorCurvesNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  CurvesNode::compile(compiler, "node_vector_curves");
 | 
						|
}
 | 
						|
 | 
						|
/* RGBRampNode */
 | 
						|
 | 
						|
NODE_DEFINE(RGBRampNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("rgb_ramp", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_COLOR_ARRAY(ramp, "Ramp", array<float3>());
 | 
						|
  SOCKET_FLOAT_ARRAY(ramp_alpha, "Ramp Alpha", array<float>());
 | 
						|
  SOCKET_BOOLEAN(interpolate, "Interpolate", true);
 | 
						|
 | 
						|
  SOCKET_IN_FLOAT(fac, "Fac", 0.0f);
 | 
						|
 | 
						|
  SOCKET_OUT_COLOR(color, "Color");
 | 
						|
  SOCKET_OUT_FLOAT(alpha, "Alpha");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
RGBRampNode::RGBRampNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void RGBRampNode::constant_fold(const ConstantFolder &folder)
 | 
						|
{
 | 
						|
  if (ramp.size() == 0 || ramp.size() != ramp_alpha.size())
 | 
						|
    return;
 | 
						|
 | 
						|
  if (folder.all_inputs_constant()) {
 | 
						|
    float f = clamp(fac, 0.0f, 1.0f) * (ramp.size() - 1);
 | 
						|
 | 
						|
    /* clamp int as well in case of NaN */
 | 
						|
    int i = clamp((int)f, 0, ramp.size() - 1);
 | 
						|
    float t = f - (float)i;
 | 
						|
 | 
						|
    bool use_lerp = interpolate && t > 0.0f;
 | 
						|
 | 
						|
    if (folder.output == output("Color")) {
 | 
						|
      float3 color = rgb_ramp_lookup(ramp.data(), fac, use_lerp, false, ramp.size());
 | 
						|
      folder.make_constant(color);
 | 
						|
    }
 | 
						|
    else if (folder.output == output("Alpha")) {
 | 
						|
      float alpha = float_ramp_lookup(ramp_alpha.data(), fac, use_lerp, false, ramp_alpha.size());
 | 
						|
      folder.make_constant(alpha);
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void RGBRampNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  if (ramp.size() == 0 || ramp.size() != ramp_alpha.size())
 | 
						|
    return;
 | 
						|
 | 
						|
  ShaderInput *fac_in = input("Fac");
 | 
						|
  ShaderOutput *color_out = output("Color");
 | 
						|
  ShaderOutput *alpha_out = output("Alpha");
 | 
						|
 | 
						|
  compiler.add_node(NODE_RGB_RAMP,
 | 
						|
                    compiler.encode_uchar4(compiler.stack_assign(fac_in),
 | 
						|
                                           compiler.stack_assign_if_linked(color_out),
 | 
						|
                                           compiler.stack_assign_if_linked(alpha_out)),
 | 
						|
                    interpolate);
 | 
						|
 | 
						|
  compiler.add_node(ramp.size());
 | 
						|
  for (int i = 0; i < ramp.size(); i++)
 | 
						|
    compiler.add_node(make_float4(ramp[i].x, ramp[i].y, ramp[i].z, ramp_alpha[i]));
 | 
						|
}
 | 
						|
 | 
						|
void RGBRampNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  if (ramp.size() == 0 || ramp.size() != ramp_alpha.size())
 | 
						|
    return;
 | 
						|
 | 
						|
  compiler.parameter_color_array("ramp_color", ramp);
 | 
						|
  compiler.parameter_array("ramp_alpha", ramp_alpha.data(), ramp_alpha.size());
 | 
						|
  compiler.parameter(this, "interpolate");
 | 
						|
 | 
						|
  compiler.add(this, "node_rgb_ramp");
 | 
						|
}
 | 
						|
 | 
						|
/* Set Normal Node */
 | 
						|
 | 
						|
NODE_DEFINE(SetNormalNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("set_normal", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_IN_VECTOR(direction, "Direction", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
  SOCKET_OUT_NORMAL(normal, "Normal");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
SetNormalNode::SetNormalNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void SetNormalNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *direction_in = input("Direction");
 | 
						|
  ShaderOutput *normal_out = output("Normal");
 | 
						|
 | 
						|
  compiler.add_node(NODE_CLOSURE_SET_NORMAL,
 | 
						|
                    compiler.stack_assign(direction_in),
 | 
						|
                    compiler.stack_assign(normal_out));
 | 
						|
}
 | 
						|
 | 
						|
void SetNormalNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.add(this, "node_set_normal");
 | 
						|
}
 | 
						|
 | 
						|
/* OSLNode */
 | 
						|
 | 
						|
OSLNode::OSLNode() : ShaderNode(new NodeType(NodeType::SHADER))
 | 
						|
{
 | 
						|
  special_type = SHADER_SPECIAL_TYPE_OSL;
 | 
						|
}
 | 
						|
 | 
						|
OSLNode::~OSLNode()
 | 
						|
{
 | 
						|
  delete type;
 | 
						|
}
 | 
						|
 | 
						|
ShaderNode *OSLNode::clone() const
 | 
						|
{
 | 
						|
  return OSLNode::create(this->inputs.size(), this);
 | 
						|
}
 | 
						|
 | 
						|
OSLNode *OSLNode::create(size_t num_inputs, const OSLNode *from)
 | 
						|
{
 | 
						|
  /* allocate space for the node itself and parameters, aligned to 16 bytes
 | 
						|
   * assuming that's the most parameter types need */
 | 
						|
  size_t node_size = align_up(sizeof(OSLNode), 16);
 | 
						|
  size_t inputs_size = align_up(SocketType::max_size(), 16) * num_inputs;
 | 
						|
 | 
						|
  char *node_memory = (char *)operator new(node_size + inputs_size);
 | 
						|
  memset(node_memory, 0, node_size + inputs_size);
 | 
						|
 | 
						|
  if (!from) {
 | 
						|
    return new (node_memory) OSLNode();
 | 
						|
  }
 | 
						|
  else {
 | 
						|
    /* copy input default values and node type for cloning */
 | 
						|
    memcpy(node_memory + node_size, (char *)from + node_size, inputs_size);
 | 
						|
 | 
						|
    OSLNode *node = new (node_memory) OSLNode(*from);
 | 
						|
    node->type = new NodeType(*(from->type));
 | 
						|
    return node;
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
char *OSLNode::input_default_value()
 | 
						|
{
 | 
						|
  /* pointer to default value storage, which is the same as our actual value */
 | 
						|
  size_t num_inputs = type->inputs.size();
 | 
						|
  size_t inputs_size = align_up(SocketType::max_size(), 16) * num_inputs;
 | 
						|
  return (char *)this + align_up(sizeof(OSLNode), 16) + inputs_size;
 | 
						|
}
 | 
						|
 | 
						|
void OSLNode::add_input(ustring name, SocketType::Type socket_type)
 | 
						|
{
 | 
						|
  char *memory = input_default_value();
 | 
						|
  size_t offset = memory - (char *)this;
 | 
						|
  const_cast<NodeType *>(type)->register_input(
 | 
						|
      name, name, socket_type, offset, memory, NULL, NULL, SocketType::LINKABLE);
 | 
						|
}
 | 
						|
 | 
						|
void OSLNode::add_output(ustring name, SocketType::Type socket_type)
 | 
						|
{
 | 
						|
  const_cast<NodeType *>(type)->register_output(name, name, socket_type);
 | 
						|
}
 | 
						|
 | 
						|
void OSLNode::compile(SVMCompiler &)
 | 
						|
{
 | 
						|
  /* doesn't work for SVM, obviously ... */
 | 
						|
}
 | 
						|
 | 
						|
void OSLNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  if (!filepath.empty())
 | 
						|
    compiler.add(this, filepath.c_str(), true);
 | 
						|
  else
 | 
						|
    compiler.add(this, bytecode_hash.c_str(), false);
 | 
						|
}
 | 
						|
 | 
						|
/* Normal Map */
 | 
						|
 | 
						|
NODE_DEFINE(NormalMapNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("normal_map", create, NodeType::SHADER);
 | 
						|
 | 
						|
  static NodeEnum space_enum;
 | 
						|
  space_enum.insert("tangent", NODE_NORMAL_MAP_TANGENT);
 | 
						|
  space_enum.insert("object", NODE_NORMAL_MAP_OBJECT);
 | 
						|
  space_enum.insert("world", NODE_NORMAL_MAP_WORLD);
 | 
						|
  space_enum.insert("blender_object", NODE_NORMAL_MAP_BLENDER_OBJECT);
 | 
						|
  space_enum.insert("blender_world", NODE_NORMAL_MAP_BLENDER_WORLD);
 | 
						|
  SOCKET_ENUM(space, "Space", space_enum, NODE_NORMAL_MAP_TANGENT);
 | 
						|
 | 
						|
  SOCKET_STRING(attribute, "Attribute", ustring());
 | 
						|
 | 
						|
  SOCKET_IN_NORMAL(normal_osl,
 | 
						|
                   "NormalIn",
 | 
						|
                   make_float3(0.0f, 0.0f, 0.0f),
 | 
						|
                   SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
 | 
						|
  SOCKET_IN_FLOAT(strength, "Strength", 1.0f);
 | 
						|
  SOCKET_IN_COLOR(color, "Color", make_float3(0.5f, 0.5f, 1.0f));
 | 
						|
 | 
						|
  SOCKET_OUT_NORMAL(normal, "Normal");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
NormalMapNode::NormalMapNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void NormalMapNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 | 
						|
{
 | 
						|
  if (shader->has_surface && space == NODE_NORMAL_MAP_TANGENT) {
 | 
						|
    if (attribute.empty()) {
 | 
						|
      attributes->add(ATTR_STD_UV_TANGENT);
 | 
						|
      attributes->add(ATTR_STD_UV_TANGENT_SIGN);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      attributes->add(ustring((string(attribute.c_str()) + ".tangent").c_str()));
 | 
						|
      attributes->add(ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
 | 
						|
    }
 | 
						|
 | 
						|
    attributes->add(ATTR_STD_VERTEX_NORMAL);
 | 
						|
  }
 | 
						|
 | 
						|
  ShaderNode::attributes(shader, attributes);
 | 
						|
}
 | 
						|
 | 
						|
void NormalMapNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *color_in = input("Color");
 | 
						|
  ShaderInput *strength_in = input("Strength");
 | 
						|
  ShaderOutput *normal_out = output("Normal");
 | 
						|
  int attr = 0, attr_sign = 0;
 | 
						|
 | 
						|
  if (space == NODE_NORMAL_MAP_TANGENT) {
 | 
						|
    if (attribute.empty()) {
 | 
						|
      attr = compiler.attribute(ATTR_STD_UV_TANGENT);
 | 
						|
      attr_sign = compiler.attribute(ATTR_STD_UV_TANGENT_SIGN);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      attr = compiler.attribute(ustring((string(attribute.c_str()) + ".tangent").c_str()));
 | 
						|
      attr_sign = compiler.attribute(
 | 
						|
          ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  compiler.add_node(NODE_NORMAL_MAP,
 | 
						|
                    compiler.encode_uchar4(compiler.stack_assign(color_in),
 | 
						|
                                           compiler.stack_assign(strength_in),
 | 
						|
                                           compiler.stack_assign(normal_out),
 | 
						|
                                           space),
 | 
						|
                    attr,
 | 
						|
                    attr_sign);
 | 
						|
}
 | 
						|
 | 
						|
void NormalMapNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  if (space == NODE_NORMAL_MAP_TANGENT) {
 | 
						|
    if (attribute.empty()) {
 | 
						|
      compiler.parameter("attr_name", ustring("geom:tangent"));
 | 
						|
      compiler.parameter("attr_sign_name", ustring("geom:tangent_sign"));
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str()));
 | 
						|
      compiler.parameter("attr_sign_name",
 | 
						|
                         ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  compiler.parameter(this, "space");
 | 
						|
  compiler.add(this, "node_normal_map");
 | 
						|
}
 | 
						|
 | 
						|
/* Tangent */
 | 
						|
 | 
						|
NODE_DEFINE(TangentNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("tangent", create, NodeType::SHADER);
 | 
						|
 | 
						|
  static NodeEnum direction_type_enum;
 | 
						|
  direction_type_enum.insert("radial", NODE_TANGENT_RADIAL);
 | 
						|
  direction_type_enum.insert("uv_map", NODE_TANGENT_UVMAP);
 | 
						|
  SOCKET_ENUM(direction_type, "Direction Type", direction_type_enum, NODE_TANGENT_RADIAL);
 | 
						|
 | 
						|
  static NodeEnum axis_enum;
 | 
						|
  axis_enum.insert("x", NODE_TANGENT_AXIS_X);
 | 
						|
  axis_enum.insert("y", NODE_TANGENT_AXIS_Y);
 | 
						|
  axis_enum.insert("z", NODE_TANGENT_AXIS_Z);
 | 
						|
  SOCKET_ENUM(axis, "Axis", axis_enum, NODE_TANGENT_AXIS_X);
 | 
						|
 | 
						|
  SOCKET_STRING(attribute, "Attribute", ustring());
 | 
						|
 | 
						|
  SOCKET_IN_NORMAL(normal_osl,
 | 
						|
                   "NormalIn",
 | 
						|
                   make_float3(0.0f, 0.0f, 0.0f),
 | 
						|
                   SocketType::LINK_NORMAL | SocketType::OSL_INTERNAL);
 | 
						|
  SOCKET_OUT_NORMAL(tangent, "Tangent");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
TangentNode::TangentNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void TangentNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 | 
						|
{
 | 
						|
  if (shader->has_surface) {
 | 
						|
    if (direction_type == NODE_TANGENT_UVMAP) {
 | 
						|
      if (attribute.empty())
 | 
						|
        attributes->add(ATTR_STD_UV_TANGENT);
 | 
						|
      else
 | 
						|
        attributes->add(ustring((string(attribute.c_str()) + ".tangent").c_str()));
 | 
						|
    }
 | 
						|
    else
 | 
						|
      attributes->add(ATTR_STD_GENERATED);
 | 
						|
  }
 | 
						|
 | 
						|
  ShaderNode::attributes(shader, attributes);
 | 
						|
}
 | 
						|
 | 
						|
void TangentNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderOutput *tangent_out = output("Tangent");
 | 
						|
  int attr;
 | 
						|
 | 
						|
  if (direction_type == NODE_TANGENT_UVMAP) {
 | 
						|
    if (attribute.empty())
 | 
						|
      attr = compiler.attribute(ATTR_STD_UV_TANGENT);
 | 
						|
    else
 | 
						|
      attr = compiler.attribute(ustring((string(attribute.c_str()) + ".tangent").c_str()));
 | 
						|
  }
 | 
						|
  else
 | 
						|
    attr = compiler.attribute(ATTR_STD_GENERATED);
 | 
						|
 | 
						|
  compiler.add_node(
 | 
						|
      NODE_TANGENT,
 | 
						|
      compiler.encode_uchar4(compiler.stack_assign(tangent_out), direction_type, axis),
 | 
						|
      attr);
 | 
						|
}
 | 
						|
 | 
						|
void TangentNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  if (direction_type == NODE_TANGENT_UVMAP) {
 | 
						|
    if (attribute.empty())
 | 
						|
      compiler.parameter("attr_name", ustring("geom:tangent"));
 | 
						|
    else
 | 
						|
      compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str()));
 | 
						|
  }
 | 
						|
 | 
						|
  compiler.parameter(this, "direction_type");
 | 
						|
  compiler.parameter(this, "axis");
 | 
						|
  compiler.add(this, "node_tangent");
 | 
						|
}
 | 
						|
 | 
						|
/* Bevel */
 | 
						|
 | 
						|
NODE_DEFINE(BevelNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("bevel", create, NodeType::SHADER);
 | 
						|
 | 
						|
  SOCKET_INT(samples, "Samples", 4);
 | 
						|
 | 
						|
  SOCKET_IN_FLOAT(radius, "Radius", 0.05f);
 | 
						|
  SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
 | 
						|
 | 
						|
  SOCKET_OUT_NORMAL(bevel, "Normal");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
BevelNode::BevelNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void BevelNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *radius_in = input("Radius");
 | 
						|
  ShaderInput *normal_in = input("Normal");
 | 
						|
  ShaderOutput *normal_out = output("Normal");
 | 
						|
 | 
						|
  compiler.add_node(NODE_BEVEL,
 | 
						|
                    compiler.encode_uchar4(samples,
 | 
						|
                                           compiler.stack_assign(radius_in),
 | 
						|
                                           compiler.stack_assign_if_linked(normal_in),
 | 
						|
                                           compiler.stack_assign(normal_out)));
 | 
						|
}
 | 
						|
 | 
						|
void BevelNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.parameter(this, "samples");
 | 
						|
  compiler.add(this, "node_bevel");
 | 
						|
}
 | 
						|
 | 
						|
/* Displacement */
 | 
						|
 | 
						|
NODE_DEFINE(DisplacementNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("displacement", create, NodeType::SHADER);
 | 
						|
 | 
						|
  static NodeEnum space_enum;
 | 
						|
  space_enum.insert("object", NODE_NORMAL_MAP_OBJECT);
 | 
						|
  space_enum.insert("world", NODE_NORMAL_MAP_WORLD);
 | 
						|
 | 
						|
  SOCKET_ENUM(space, "Space", space_enum, NODE_NORMAL_MAP_OBJECT);
 | 
						|
 | 
						|
  SOCKET_IN_FLOAT(height, "Height", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(midlevel, "Midlevel", 0.5f);
 | 
						|
  SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
 | 
						|
  SOCKET_IN_NORMAL(normal, "Normal", make_float3(0.0f, 0.0f, 0.0f), SocketType::LINK_NORMAL);
 | 
						|
 | 
						|
  SOCKET_OUT_VECTOR(displacement, "Displacement");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
DisplacementNode::DisplacementNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void DisplacementNode::constant_fold(const ConstantFolder &folder)
 | 
						|
{
 | 
						|
  if (folder.all_inputs_constant()) {
 | 
						|
    if ((height - midlevel == 0.0f) || (scale == 0.0f)) {
 | 
						|
      folder.make_zero();
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void DisplacementNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *height_in = input("Height");
 | 
						|
  ShaderInput *midlevel_in = input("Midlevel");
 | 
						|
  ShaderInput *scale_in = input("Scale");
 | 
						|
  ShaderInput *normal_in = input("Normal");
 | 
						|
  ShaderOutput *displacement_out = output("Displacement");
 | 
						|
 | 
						|
  compiler.add_node(NODE_DISPLACEMENT,
 | 
						|
                    compiler.encode_uchar4(compiler.stack_assign(height_in),
 | 
						|
                                           compiler.stack_assign(midlevel_in),
 | 
						|
                                           compiler.stack_assign(scale_in),
 | 
						|
                                           compiler.stack_assign_if_linked(normal_in)),
 | 
						|
                    compiler.stack_assign(displacement_out),
 | 
						|
                    space);
 | 
						|
}
 | 
						|
 | 
						|
void DisplacementNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  compiler.parameter(this, "space");
 | 
						|
  compiler.add(this, "node_displacement");
 | 
						|
}
 | 
						|
 | 
						|
/* Vector Displacement */
 | 
						|
 | 
						|
NODE_DEFINE(VectorDisplacementNode)
 | 
						|
{
 | 
						|
  NodeType *type = NodeType::add("vector_displacement", create, NodeType::SHADER);
 | 
						|
 | 
						|
  static NodeEnum space_enum;
 | 
						|
  space_enum.insert("tangent", NODE_NORMAL_MAP_TANGENT);
 | 
						|
  space_enum.insert("object", NODE_NORMAL_MAP_OBJECT);
 | 
						|
  space_enum.insert("world", NODE_NORMAL_MAP_WORLD);
 | 
						|
 | 
						|
  SOCKET_ENUM(space, "Space", space_enum, NODE_NORMAL_MAP_TANGENT);
 | 
						|
  SOCKET_STRING(attribute, "Attribute", ustring());
 | 
						|
 | 
						|
  SOCKET_IN_COLOR(vector, "Vector", make_float3(0.0f, 0.0f, 0.0f));
 | 
						|
  SOCKET_IN_FLOAT(midlevel, "Midlevel", 0.0f);
 | 
						|
  SOCKET_IN_FLOAT(scale, "Scale", 1.0f);
 | 
						|
 | 
						|
  SOCKET_OUT_VECTOR(displacement, "Displacement");
 | 
						|
 | 
						|
  return type;
 | 
						|
}
 | 
						|
 | 
						|
VectorDisplacementNode::VectorDisplacementNode() : ShaderNode(node_type)
 | 
						|
{
 | 
						|
}
 | 
						|
 | 
						|
void VectorDisplacementNode::constant_fold(const ConstantFolder &folder)
 | 
						|
{
 | 
						|
  if (folder.all_inputs_constant()) {
 | 
						|
    if ((vector == make_float3(0.0f, 0.0f, 0.0f) && midlevel == 0.0f) || (scale == 0.0f)) {
 | 
						|
      folder.make_zero();
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void VectorDisplacementNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 | 
						|
{
 | 
						|
  if (shader->has_surface && space == NODE_NORMAL_MAP_TANGENT) {
 | 
						|
    if (attribute.empty()) {
 | 
						|
      attributes->add(ATTR_STD_UV_TANGENT);
 | 
						|
      attributes->add(ATTR_STD_UV_TANGENT_SIGN);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      attributes->add(ustring((string(attribute.c_str()) + ".tangent").c_str()));
 | 
						|
      attributes->add(ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
 | 
						|
    }
 | 
						|
 | 
						|
    attributes->add(ATTR_STD_VERTEX_NORMAL);
 | 
						|
  }
 | 
						|
 | 
						|
  ShaderNode::attributes(shader, attributes);
 | 
						|
}
 | 
						|
 | 
						|
void VectorDisplacementNode::compile(SVMCompiler &compiler)
 | 
						|
{
 | 
						|
  ShaderInput *vector_in = input("Vector");
 | 
						|
  ShaderInput *midlevel_in = input("Midlevel");
 | 
						|
  ShaderInput *scale_in = input("Scale");
 | 
						|
  ShaderOutput *displacement_out = output("Displacement");
 | 
						|
  int attr = 0, attr_sign = 0;
 | 
						|
 | 
						|
  if (space == NODE_NORMAL_MAP_TANGENT) {
 | 
						|
    if (attribute.empty()) {
 | 
						|
      attr = compiler.attribute(ATTR_STD_UV_TANGENT);
 | 
						|
      attr_sign = compiler.attribute(ATTR_STD_UV_TANGENT_SIGN);
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      attr = compiler.attribute(ustring((string(attribute.c_str()) + ".tangent").c_str()));
 | 
						|
      attr_sign = compiler.attribute(
 | 
						|
          ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  compiler.add_node(NODE_VECTOR_DISPLACEMENT,
 | 
						|
                    compiler.encode_uchar4(compiler.stack_assign(vector_in),
 | 
						|
                                           compiler.stack_assign(midlevel_in),
 | 
						|
                                           compiler.stack_assign(scale_in),
 | 
						|
                                           compiler.stack_assign(displacement_out)),
 | 
						|
                    attr,
 | 
						|
                    attr_sign);
 | 
						|
 | 
						|
  compiler.add_node(space);
 | 
						|
}
 | 
						|
 | 
						|
void VectorDisplacementNode::compile(OSLCompiler &compiler)
 | 
						|
{
 | 
						|
  if (space == NODE_NORMAL_MAP_TANGENT) {
 | 
						|
    if (attribute.empty()) {
 | 
						|
      compiler.parameter("attr_name", ustring("geom:tangent"));
 | 
						|
      compiler.parameter("attr_sign_name", ustring("geom:tangent_sign"));
 | 
						|
    }
 | 
						|
    else {
 | 
						|
      compiler.parameter("attr_name", ustring((string(attribute.c_str()) + ".tangent").c_str()));
 | 
						|
      compiler.parameter("attr_sign_name",
 | 
						|
                         ustring((string(attribute.c_str()) + ".tangent_sign").c_str()));
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  compiler.parameter(this, "space");
 | 
						|
  compiler.add(this, "node_vector_displacement");
 | 
						|
}
 | 
						|
 | 
						|
CCL_NAMESPACE_END
 |