Shading: Add more operators to Vector Math node.
authorOmarSquircleArt <omar.squircleart@gmail.com>
Wed, 21 Aug 2019 17:36:33 +0000 (19:36 +0200)
committerOmarSquircleArt <omar.squircleart@gmail.com>
Wed, 21 Aug 2019 17:36:33 +0000 (19:36 +0200)
Add Multiply, Divide, Project, Reflect, Distance, Length, Scale, Snap,
Floor, Ceil, Modulo, Fraction, Absolute, Minimum, and Maximum operators
to the Vector Math node. The Value output has been removed from operators
whose output is a vector, and the other way around. All of those removals
has been handled properly in versioning code.

The patch doesn't include tests for the new operators. Tests will be added
in a later patch.

Reviewers: brecht, JacquesLucke

Differential Revision: https://developer.blender.org/D5523

32 files changed:
.clang-format
intern/cycles/blender/blender_session.cpp
intern/cycles/blender/blender_shader.cpp
intern/cycles/kernel/shaders/node_vector_math.osl
intern/cycles/kernel/svm/svm_math.h
intern/cycles/kernel/svm/svm_math_util.h
intern/cycles/kernel/svm/svm_types.h
intern/cycles/render/bake.cpp
intern/cycles/render/constant_fold.cpp
intern/cycles/render/constant_fold.h
intern/cycles/render/nodes.cpp
intern/cycles/render/nodes.h
intern/cycles/subd/subd_dice.cpp
intern/cycles/subd/subd_split.cpp
intern/cycles/test/render_graph_finalize_test.cpp
intern/cycles/util/util_math_float3.h
source/blender/blenkernel/BKE_node.h
source/blender/blenkernel/intern/node.c
source/blender/blenlib/BLI_listbase.h
source/blender/blenloader/intern/versioning_cycles.c
source/blender/editors/space_node/drawnode.c
source/blender/gpu/shaders/gpu_shader_material.glsl
source/blender/makesdna/DNA_node_types.h
source/blender/makesrna/intern/rna_nodetree.c
source/blender/nodes/CMakeLists.txt
source/blender/nodes/NOD_static_types.h
source/blender/nodes/intern/node_util.c
source/blender/nodes/intern/node_util.h
source/blender/nodes/shader/node_shader_tree.c
source/blender/nodes/shader/nodes/node_shader_normal_map.c
source/blender/nodes/shader/nodes/node_shader_vectMath.c [deleted file]
source/blender/nodes/shader/nodes/node_shader_vector_math.c [new file with mode: 0644]

index bbbe3f1bac4c19daab085fd2d8de3b0bc4852540..b81403c46ceb263f4461b19d5d012ee28a1b3a37 100644 (file)
@@ -224,7 +224,9 @@ ForEachMacros:
   - LISTBASE_CIRCULAR_BACKWARD_BEGIN
   - LISTBASE_CIRCULAR_FORWARD_BEGIN
   - LISTBASE_FOREACH
+  - LISTBASE_FOREACH_BACKWARD
   - LISTBASE_FOREACH_MUTABLE
+  - LISTBASE_FOREACH_BACKWARD_MUTABLE
   - MAN2D_ITER_AXES_BEGIN
   - MAN_ITER_AXES_BEGIN
   - NODE_INSTANCE_HASH_ITER
index d38a97dc4ea53eb4c4d12e3d19e15ddeb7175ba3..047cc82dbfcead4553a7f3cad8851db64990850a 100644 (file)
@@ -1481,8 +1481,8 @@ void BlenderSession::update_resumable_tile_manager(int num_samples)
 
   /* Round after doing the multiplications with num_chunks and num_samples_per_chunk
    * to allow for many small chunks. */
-  int rounded_range_start_sample = (int)floor(range_start_sample + 0.5f);
-  int rounded_range_num_samples = max((int)floor(range_num_samples + 0.5f), 1);
+  int rounded_range_start_sample = (int)floorf(range_start_sample + 0.5f);
+  int rounded_range_num_samples = max((int)floorf(range_num_samples + 0.5f), 1);
 
   /* Make sure we don't overshoot. */
   if (rounded_range_start_sample + rounded_range_num_samples > num_samples) {
index 626a1dad7db3415b119f01ad3f05a365b94a945e..322a17717864923b198d9280e0edf5daf868638e 100644 (file)
@@ -333,9 +333,9 @@ static ShaderNode *add_node(Scene *scene,
   }
   else if (b_node.is_a(&RNA_ShaderNodeVectorMath)) {
     BL::ShaderNodeVectorMath b_vector_math_node(b_node);
-    VectorMathNode *vmath = new VectorMathNode();
-    vmath->type = (NodeVectorMath)b_vector_math_node.operation();
-    node = vmath;
+    VectorMathNode *vector_math_node = new VectorMathNode();
+    vector_math_node->type = (NodeVectorMathType)b_vector_math_node.operation();
+    node = vector_math_node;
   }
   else if (b_node.is_a(&RNA_ShaderNodeVectorTransform)) {
     BL::ShaderNodeVectorTransform b_vector_transform_node(b_node);
index 10bb0c7283cbb2c5d65e283ebdb35b2ce23ddaeb..fd5e27aa144e93d80cb63caa61aefe6d8483bc03 100644 (file)
 
 #include "stdosl.h"
 
+float safe_divide(float a, float b)
+{
+  return (b != 0.0) ? a / b : 0.0;
+}
+
+vector safe_divide(vector a, vector b)
+{
+  return vector((b[0] != 0.0) ? a[0] / b[0] : 0.0,
+                (b[1] != 0.0) ? a[1] / b[1] : 0.0,
+                (b[2] != 0.0) ? a[2] / b[2] : 0.0);
+}
+
+vector project(vector v, vector v_proj)
+{
+  float lenSquared = dot(v_proj, v_proj);
+  return (lenSquared != 0.0) ? (dot(v, v_proj) / lenSquared) * v_proj : vector(0.0);
+}
+
+vector snap(vector a, vector b)
+{
+  return floor(safe_divide(a, b)) * b;
+}
+
 shader node_vector_math(string type = "add",
                         vector Vector1 = vector(0.0, 0.0, 0.0),
                         vector Vector2 = vector(0.0, 0.0, 0.0),
+                        float Scale = 1.0,
                         output float Value = 0.0,
                         output vector Vector = vector(0.0, 0.0, 0.0))
 {
   if (type == "add") {
     Vector = Vector1 + Vector2;
-    Value = (abs(Vector[0]) + abs(Vector[1]) + abs(Vector[2])) / 3.0;
   }
   else if (type == "subtract") {
     Vector = Vector1 - Vector2;
-    Value = (abs(Vector[0]) + abs(Vector[1]) + abs(Vector[2])) / 3.0;
   }
-  else if (type == "average") {
-    Value = length(Vector1 + Vector2);
-    Vector = normalize(Vector1 + Vector2);
+  else if (type == "multiply") {
+    Vector = Vector1 * Vector2;
+  }
+  else if (type == "divide") {
+    Vector = safe_divide(Vector1, Vector2);
+  }
+  else if (type == "cross_product") {
+    Vector = cross(Vector1, Vector2);
+  }
+  else if (type == "project") {
+    Vector = project(Vector1, Vector2);
+  }
+  else if (type == "reflect") {
+    Vector = reflect(Vector1, normalize(Vector2));
   }
   else if (type == "dot_product") {
     Value = dot(Vector1, Vector2);
   }
-  else if (type == "cross_product") {
-    vector c = cross(Vector1, Vector2);
-    Value = length(c);
-    Vector = normalize(c);
+  else if (type == "distance") {
+    Value = distance(Vector1, Vector2);
   }
-  else if (type == "normalize") {
+  else if (type == "length") {
     Value = length(Vector1);
+  }
+  else if (type == "scale") {
+    Vector = Vector1 * Scale;
+  }
+  else if (type == "normalize") {
     Vector = normalize(Vector1);
   }
+  else if (type == "snap") {
+    Vector = snap(Vector1, Vector2);
+  }
+  else if (type == "floor") {
+    Vector = floor(Vector1);
+  }
+  else if (type == "ceil") {
+    Vector = ceil(Vector1);
+  }
+  else if (type == "modulo") {
+    Vector = mod(Vector1, Vector2);
+  }
+  else if (type == "fraction") {
+    Vector = Vector1 - floor(Vector1);
+  }
+  else if (type == "absolute") {
+    Vector = abs(Vector1);
+  }
+  else if (type == "minimum") {
+    Vector = min(Vector1, Vector2);
+  }
+  else if (type == "maximum") {
+    Vector = max(Vector1, Vector2);
+  }
+  else {
+    warning("%s", "Unknown vector math operator!");
+  }
 }
index 402290d72188fa803f777bf2997ef9a535557726..c577a7f13c75fe11227418d4c031315280370427 100644 (file)
@@ -37,25 +37,29 @@ ccl_device void svm_node_math(KernelGlobals *kg,
 ccl_device void svm_node_vector_math(KernelGlobals *kg,
                                      ShaderData *sd,
                                      float *stack,
-                                     uint itype,
-                                     uint v1_offset,
-                                     uint v2_offset,
+                                     uint type,
+                                     uint inputs_stack_offsets,
+                                     uint outputs_stack_offsets,
                                      int *offset)
 {
-  NodeVectorMath type = (NodeVectorMath)itype;
-  float3 v1 = stack_load_float3(stack, v1_offset);
-  float3 v2 = stack_load_float3(stack, v2_offset);
-  float f;
-  float3 v;
+  uint value_stack_offset, vector_stack_offset;
+  uint a_stack_offset, b_stack_offset, scale_stack_offset;
+  decode_node_uchar4(
+      inputs_stack_offsets, &a_stack_offset, &b_stack_offset, &scale_stack_offset, NULL);
+  decode_node_uchar4(outputs_stack_offsets, &value_stack_offset, &vector_stack_offset, NULL, NULL);
 
-  svm_vector_math(&f, &v, type, v1, v2);
+  float3 a = stack_load_float3(stack, a_stack_offset);
+  float3 b = stack_load_float3(stack, b_stack_offset);
+  float scale = stack_load_float(stack, scale_stack_offset);
 
-  uint4 node1 = read_node(kg, offset);
+  float value;
+  float3 vector;
+  svm_vector_math(&value, &vector, (NodeVectorMathType)type, a, b, scale);
 
-  if (stack_valid(node1.y))
-    stack_store_float(stack, node1.y, f);
-  if (stack_valid(node1.z))
-    stack_store_float3(stack, node1.z, v);
+  if (stack_valid(value_stack_offset))
+    stack_store_float(stack, value_stack_offset, value);
+  if (stack_valid(vector_stack_offset))
+    stack_store_float3(stack, vector_stack_offset, vector);
 }
 
 CCL_NAMESPACE_END
index d880422648705486a1bcc70de692086e89f838ed..c87ca0defa7beeaefda1ce216b42d2383f825f90 100644 (file)
 
 CCL_NAMESPACE_BEGIN
 
-ccl_device float average_fac(float3 v)
-{
-  return (fabsf(v.x) + fabsf(v.y) + fabsf(v.z)) / 3.0f;
-}
-
 ccl_device void svm_vector_math(
-    float *Fac, float3 *Vector, NodeVectorMath type, float3 Vector1, float3 Vector2)
+    float *value, float3 *vector, NodeVectorMathType type, float3 a, float3 b, float scale)
 {
-  if (type == NODE_VECTOR_MATH_ADD) {
-    *Vector = Vector1 + Vector2;
-    *Fac = average_fac(*Vector);
-  }
-  else if (type == NODE_VECTOR_MATH_SUBTRACT) {
-    *Vector = Vector1 - Vector2;
-    *Fac = average_fac(*Vector);
-  }
-  else if (type == NODE_VECTOR_MATH_AVERAGE) {
-    *Vector = safe_normalize_len(Vector1 + Vector2, Fac);
-  }
-  else if (type == NODE_VECTOR_MATH_DOT_PRODUCT) {
-    *Fac = dot(Vector1, Vector2);
-    *Vector = make_float3(0.0f, 0.0f, 0.0f);
-  }
-  else if (type == NODE_VECTOR_MATH_CROSS_PRODUCT) {
-    *Vector = safe_normalize_len(cross(Vector1, Vector2), Fac);
-  }
-  else if (type == NODE_VECTOR_MATH_NORMALIZE) {
-    *Vector = safe_normalize_len(Vector1, Fac);
-  }
-  else {
-    *Fac = 0.0f;
-    *Vector = make_float3(0.0f, 0.0f, 0.0f);
+  switch (type) {
+    case NODE_VECTOR_MATH_ADD:
+      *vector = a + b;
+      break;
+    case NODE_VECTOR_MATH_SUBTRACT:
+      *vector = a - b;
+      break;
+    case NODE_VECTOR_MATH_MULTIPLY:
+      *vector = a * b;
+      break;
+    case NODE_VECTOR_MATH_DIVIDE:
+      *vector = safe_divide_float3_float3(a, b);
+      break;
+    case NODE_VECTOR_MATH_CROSS_PRODUCT:
+      *vector = cross(a, b);
+      break;
+    case NODE_VECTOR_MATH_PROJECT:
+      *vector = project(a, b);
+      break;
+    case NODE_VECTOR_MATH_REFLECT:
+      *vector = reflect(a, b);
+      break;
+    case NODE_VECTOR_MATH_DOT_PRODUCT:
+      *value = dot(a, b);
+      break;
+    case NODE_VECTOR_MATH_DISTANCE:
+      *value = distance(a, b);
+      break;
+    case NODE_VECTOR_MATH_LENGTH:
+      *value = len(a);
+      break;
+    case NODE_VECTOR_MATH_SCALE:
+      *vector = a * scale;
+      break;
+    case NODE_VECTOR_MATH_NORMALIZE:
+      *vector = safe_normalize(a);
+      break;
+    case NODE_VECTOR_MATH_SNAP:
+      *vector = floor(safe_divide_float3_float3(a, b)) * b;
+      break;
+    case NODE_VECTOR_MATH_FLOOR:
+      *vector = floor(a);
+      break;
+    case NODE_VECTOR_MATH_CEIL:
+      *vector = ceil(a);
+      break;
+    case NODE_VECTOR_MATH_MODULO:
+      *vector = make_float3(safe_modulo(a.x, b.x), safe_modulo(a.y, b.y), safe_modulo(a.z, b.z));
+      break;
+    case NODE_VECTOR_MATH_FRACTION:
+      *vector = fract(a);
+      break;
+    case NODE_VECTOR_MATH_ABSOLUTE:
+      *vector = fabs(a);
+      break;
+    case NODE_VECTOR_MATH_MINIMUM:
+      *vector = min(a, b);
+      break;
+    case NODE_VECTOR_MATH_MAXIMUM:
+      *vector = max(a, b);
+      break;
+    default:
+      *vector = make_float3(0.0f, 0.0f, 0.0f);
+      *value = 0.0f;
   }
 }
 
index 6b0d10adc74ee98e931542ee3b94f2f464d71d0f..884ad76a9b7ecc3bba9bb96881e28e3996a069c7 100644 (file)
@@ -271,14 +271,31 @@ typedef enum NodeMathType {
   NODE_MATH_SQRT,
 } NodeMathType;
 
-typedef enum NodeVectorMath {
+typedef enum NodeVectorMathType {
   NODE_VECTOR_MATH_ADD,
   NODE_VECTOR_MATH_SUBTRACT,
-  NODE_VECTOR_MATH_AVERAGE,
-  NODE_VECTOR_MATH_DOT_PRODUCT,
+  NODE_VECTOR_MATH_MULTIPLY,
+  NODE_VECTOR_MATH_DIVIDE,
+
   NODE_VECTOR_MATH_CROSS_PRODUCT,
-  NODE_VECTOR_MATH_NORMALIZE
-} NodeVectorMath;
+  NODE_VECTOR_MATH_PROJECT,
+  NODE_VECTOR_MATH_REFLECT,
+  NODE_VECTOR_MATH_DOT_PRODUCT,
+
+  NODE_VECTOR_MATH_DISTANCE,
+  NODE_VECTOR_MATH_LENGTH,
+  NODE_VECTOR_MATH_SCALE,
+  NODE_VECTOR_MATH_NORMALIZE,
+
+  NODE_VECTOR_MATH_SNAP,
+  NODE_VECTOR_MATH_FLOOR,
+  NODE_VECTOR_MATH_CEIL,
+  NODE_VECTOR_MATH_MODULO,
+  NODE_VECTOR_MATH_FRACTION,
+  NODE_VECTOR_MATH_ABSOLUTE,
+  NODE_VECTOR_MATH_MINIMUM,
+  NODE_VECTOR_MATH_MAXIMUM,
+} NodeVectorMathType;
 
 typedef enum NodeVectorTransformType {
   NODE_VECTOR_TRANSFORM_TYPE_VECTOR,
index 7389392150024d87011aa4c0e743e00adebb0fd2..b906357b7b539f3afae30e0f941cf02d6ffc2f92 100644 (file)
@@ -124,7 +124,7 @@ BakeData *BakeManager::init(const int object, const size_t tri_offset, const siz
 void BakeManager::set_shader_limit(const size_t x, const size_t y)
 {
   m_shader_limit = x * y;
-  m_shader_limit = (size_t)pow(2, ceil(log(m_shader_limit) / log(2)));
+  m_shader_limit = (size_t)pow(2, std::ceil(log(m_shader_limit) / log(2)));
 }
 
 bool BakeManager::bake(Device *device,
index d6fdc49434ee8338697bbc5faee1e1a678b36a7b..851d4b71df80d95295d5c7a4921dfbf62d422601 100644 (file)
@@ -359,10 +359,11 @@ void ConstantFolder::fold_math(NodeMathType type) const
   }
 }
 
-void ConstantFolder::fold_vector_math(NodeVectorMath type) const
+void ConstantFolder::fold_vector_math(NodeVectorMathType type) const
 {
   ShaderInput *vector1_in = node->input("Vector1");
   ShaderInput *vector2_in = node->input("Vector2");
+  ShaderInput *scale_in = node->input("Scale");
 
   switch (type) {
     case NODE_VECTOR_MATH_ADD:
@@ -380,6 +381,27 @@ void ConstantFolder::fold_vector_math(NodeVectorMath type) const
         try_bypass_or_make_constant(vector1_in);
       }
       break;
+    case NODE_VECTOR_MATH_MULTIPLY:
+      /* X * 0 == 0 * X == 0 */
+      if (is_zero(vector1_in) || is_zero(vector2_in)) {
+        make_zero();
+      } /* X * 1 == 1 * X == X */
+      else if (is_one(vector1_in)) {
+        try_bypass_or_make_constant(vector2_in);
+      }
+      else if (is_one(vector2_in)) {
+        try_bypass_or_make_constant(vector1_in);
+      }
+      break;
+    case NODE_VECTOR_MATH_DIVIDE:
+      /* X / 0 == 0 / X == 0 */
+      if (is_zero(vector1_in) || is_zero(vector2_in)) {
+        make_zero();
+      } /* X / 1 == X */
+      else if (is_one(vector2_in)) {
+        try_bypass_or_make_constant(vector1_in);
+      }
+      break;
     case NODE_VECTOR_MATH_DOT_PRODUCT:
     case NODE_VECTOR_MATH_CROSS_PRODUCT:
       /* X * 0 == 0 * X == 0 */
@@ -387,6 +409,21 @@ void ConstantFolder::fold_vector_math(NodeVectorMath type) const
         make_zero();
       }
       break;
+    case NODE_VECTOR_MATH_LENGTH:
+    case NODE_VECTOR_MATH_ABSOLUTE:
+      if (is_zero(vector1_in)) {
+        make_zero();
+      }
+      break;
+    case NODE_VECTOR_MATH_SCALE:
+      /* X * 0 == 0 * X == 0 */
+      if (is_zero(vector1_in) || is_zero(scale_in)) {
+        make_zero();
+      } /* X * 1 == X */
+      else if (is_one(scale_in)) {
+        try_bypass_or_make_constant(vector1_in);
+      }
+      break;
     default:
       break;
   }
index d223fd861973c09b5635239baea9bd027df4fc16..881636a9fe1465729c33f4923d855168f46a9b32 100644 (file)
@@ -65,7 +65,7 @@ class ConstantFolder {
   /* Specific nodes. */
   void fold_mix(NodeMix type, bool clamp) const;
   void fold_math(NodeMathType type) const;
-  void fold_vector_math(NodeVectorMath type) const;
+  void fold_vector_math(NodeVectorMathType type) const;
 };
 
 CCL_NAMESPACE_END
index 642f7beaf3c6205d45c450a59407b0b036f3e323..8c8bb559c30a9233700d27330a637fdfcb16abb2 100644 (file)
@@ -163,8 +163,10 @@ void TextureMapping::compile(SVMCompiler &compiler, int offset_in, int offset_ou
   }
 
   if (type == NORMAL) {
-    compiler.add_node(NODE_VECTOR_MATH, NODE_VECTOR_MATH_NORMALIZE, offset_out, offset_out);
-    compiler.add_node(NODE_VECTOR_MATH, SVM_STACK_INVALID, offset_out);
+    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));
   }
 }
 
@@ -5496,14 +5498,32 @@ NODE_DEFINE(VectorMathNode)
   static NodeEnum type_enum;
   type_enum.insert("add", NODE_VECTOR_MATH_ADD);
   type_enum.insert("subtract", NODE_VECTOR_MATH_SUBTRACT);
-  type_enum.insert("average", NODE_VECTOR_MATH_AVERAGE);
-  type_enum.insert("dot_product", NODE_VECTOR_MATH_DOT_PRODUCT);
+  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("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);
   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_FLOAT(scale, "Scale", 1.0f);
 
   SOCKET_OUT_FLOAT(value, "Value");
   SOCKET_OUT_VECTOR(vector, "Vector");
@@ -5521,8 +5541,7 @@ void VectorMathNode::constant_fold(const ConstantFolder &folder)
   float3 vector;
 
   if (folder.all_inputs_constant()) {
-    svm_vector_math(&value, &vector, type, vector1, vector2);
-
+    svm_vector_math(&value, &vector, type, vector1, vector2, scale);
     if (folder.output == output("Value")) {
       folder.make_constant(value);
     }
@@ -5539,15 +5558,21 @@ 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");
 
-  compiler.add_node(NODE_VECTOR_MATH,
-                    type,
-                    compiler.stack_assign(vector1_in),
-                    compiler.stack_assign(vector2_in));
+  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);
+
   compiler.add_node(
-      NODE_VECTOR_MATH, compiler.stack_assign(value_out), compiler.stack_assign(vector_out));
+      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)
index 514ab3db8eb268a97581fde96d1e6513d9b591dc..417623c756295848d3b0fc0cc845c3972baa865c 100644 (file)
@@ -1292,7 +1292,8 @@ class VectorMathNode : public ShaderNode {
 
   float3 vector1;
   float3 vector2;
-  NodeVectorMath type;
+  float scale;
+  NodeVectorMathType type;
 };
 
 class VectorTransformNode : public ShaderNode {
index fb96be5065b31cef37053d1dc9621eb9d7a9bce6..914b408911e909492ac6a587c9e483a0314e82be 100644 (file)
@@ -323,8 +323,8 @@ void QuadDice::dice(SubPatch &sub, EdgeFactors &ef)
   float S = 1.0f;
 #endif
 
-  Mu = max((int)ceil(S * Mu), 2);  // XXX handle 0 & 1?
-  Mv = max((int)ceil(S * Mv), 2);  // XXX handle 0 & 1?
+  Mu = max((int)ceilf(S * Mu), 2);  // XXX handle 0 & 1?
+  Mv = max((int)ceilf(S * Mv), 2);  // XXX handle 0 & 1?
 
   /* reserve space for new verts */
   int offset = params.mesh->verts.size();
index e6603632ba72db88258244f4a6d590dba72bdce6..e5b85fcfd609da108f168e5209652df0f3da2473 100644 (file)
@@ -80,9 +80,9 @@ int DiagSplit::T(Patch *patch, float2 Pstart, float2 Pend)
     Plast = P;
   }
 
-  int tmin = (int)ceil(Lsum / params.dicing_rate);
-  int tmax = (int)ceil((params.test_steps - 1) * Lmax /
-                       params.dicing_rate);  // XXX paper says N instead of N-1, seems wrong?
+  int tmin = (int)ceilf(Lsum / params.dicing_rate);
+  int tmax = (int)ceilf((params.test_steps - 1) * Lmax /
+                        params.dicing_rate);  // XXX paper says N instead of N-1, seems wrong?
 
   if (tmax - tmin > params.split_threshold)
     return DSPLIT_NON_UNIFORM;
@@ -99,7 +99,7 @@ void DiagSplit::partition_edge(
     *t1 = T(patch, *P, Pend);
   }
   else {
-    int I = (int)floor((float)t * 0.5f);
+    int I = (int)floorf((float)t * 0.5f);
     *P = interp(Pstart, Pend, (t == 0) ? 0 : I / (float)t); /* XXX is t faces or verts */
     *t0 = I;
     *t1 = t - I;
index 7d4b600350bb999dd993995379a19d68381e6fc1..ca93f8b02d0fbfd0deeacc38b63a3686cf1a7a56 100644 (file)
@@ -1163,21 +1163,14 @@ TEST_F(RenderGraph, constant_fold_part_math_pow_1)
 TEST_F(RenderGraph, constant_fold_vector_math)
 {
   EXPECT_ANY_MESSAGE(log);
-  CORRECT_INFO_MESSAGE(log, "Folding VectorMath::Value to constant (1).");
   CORRECT_INFO_MESSAGE(log, "Folding VectorMath::Vector to constant (3, 0, 0).");
-  CORRECT_INFO_MESSAGE(log, "Folding convert_vector_to_float::value_float to constant (1).");
-  CORRECT_INFO_MESSAGE(log, "Folding Math::Value to constant (2).");
-  CORRECT_INFO_MESSAGE(log, "Folding convert_float_to_color::value_color to constant (2, 2, 2).");
 
   builder
       .add_node(ShaderNodeBuilder<VectorMathNode>("VectorMath")
                     .set(&VectorMathNode::type, NODE_VECTOR_MATH_SUBTRACT)
                     .set("Vector1", make_float3(1.3f, 0.5f, 0.7f))
                     .set("Vector2", make_float3(-1.7f, 0.5f, 0.7f)))
-      .add_node(ShaderNodeBuilder<MathNode>("Math").set(&MathNode::type, NODE_MATH_ADD))
-      .add_connection("VectorMath::Vector", "Math::Value1")
-      .add_connection("VectorMath::Value", "Math::Value2")
-      .output_color("Math::Value");
+      .output_color("VectorMath::Vector");
 
   graph.finalize(scene);
 }
@@ -1187,7 +1180,7 @@ TEST_F(RenderGraph, constant_fold_vector_math)
  * Includes 2 tests: constant on each side.
  */
 static void build_vecmath_partial_test_graph(ShaderGraphBuilder &builder,
-                                             NodeVectorMath type,
+                                             NodeVectorMathType type,
                                              float3 constval)
 {
   builder
@@ -1240,22 +1233,6 @@ TEST_F(RenderGraph, constant_fold_part_vecmath_sub_0)
   graph.finalize(scene);
 }
 
-/*
- * Tests: partial folding for Vector Math Dot Product with known 0.
- */
-TEST_F(RenderGraph, constant_fold_part_vecmath_dot_0)
-{
-  EXPECT_ANY_MESSAGE(log);
-  /* X * 0 == 0 * X == X */
-  CORRECT_INFO_MESSAGE(log, "Folding Math_Cx::Vector to constant (0, 0, 0).");
-  CORRECT_INFO_MESSAGE(log, "Folding Math_xC::Vector to constant (0, 0, 0).");
-  CORRECT_INFO_MESSAGE(log, "Folding Out::Vector to constant (0, 0, 0).");
-  CORRECT_INFO_MESSAGE(log, "Discarding closure EmissionNode.");
-
-  build_vecmath_partial_test_graph(builder, NODE_VECTOR_MATH_DOT_PRODUCT, make_float3(0, 0, 0));
-  graph.finalize(scene);
-}
-
 /*
  * Tests: partial folding for Vector Math Cross Product with known 0.
  */
index 554b740814845e6f8be3ca8c7ec8888b4f7f8dbb..0d7588da690b544ed4327da81498e9124e5da3a1 100644 (file)
@@ -47,6 +47,7 @@ ccl_device_inline float3 operator/=(float3 &a, float f);
 ccl_device_inline bool operator==(const float3 &a, const float3 &b);
 ccl_device_inline bool operator!=(const float3 &a, const float3 &b);
 
+ccl_device_inline float distance(const float3 &a, const float3 &b);
 ccl_device_inline float dot(const float3 &a, const float3 &b);
 ccl_device_inline float dot_xy(const float3 &a, const float3 &b);
 ccl_device_inline float3 cross(const float3 &a, const float3 &b);
@@ -58,6 +59,9 @@ ccl_device_inline float3 fabs(const float3 &a);
 ccl_device_inline float3 mix(const float3 &a, const float3 &b, float t);
 ccl_device_inline float3 rcp(const float3 &a);
 ccl_device_inline float3 sqrt(const float3 &a);
+ccl_device_inline float3 floor(const float3 &a);
+ccl_device_inline float3 ceil(const float3 &a);
+ccl_device_inline float3 fract(const float3 &a);
 #endif /* !__KERNEL_OPENCL__ */
 
 ccl_device_inline float min3(float3 a);
@@ -65,10 +69,15 @@ ccl_device_inline float max3(float3 a);
 ccl_device_inline float len(const float3 a);
 ccl_device_inline float len_squared(const float3 a);
 
+ccl_device_inline float3 reflect(const float3 incident, const float3 normal);
+ccl_device_inline float3 project(const float3 v, const float3 v_proj);
+
 ccl_device_inline float3 saturate3(float3 a);
 ccl_device_inline float3 safe_normalize(const float3 a);
 ccl_device_inline float3 normalize_len(const float3 a, float *t);
 ccl_device_inline float3 safe_normalize_len(const float3 a, float *t);
+ccl_device_inline float3 safe_divide_float3_float3(const float3 a, const float3 b);
+ccl_device_inline float3 safe_divide_float3_float(const float3 a, const float b);
 ccl_device_inline float3 interp(float3 a, float3 b, float t);
 ccl_device_inline float3 sqr3(float3 a);
 
@@ -205,6 +214,11 @@ ccl_device_inline bool operator!=(const float3 &a, const float3 &b)
   return !(a == b);
 }
 
+ccl_device_inline float distance(const float3 &a, const float3 &b)
+{
+  return len(a - b);
+}
+
 ccl_device_inline float dot(const float3 &a, const float3 &b)
 {
 #  if defined(__KERNEL_SSE41__) && defined(__KERNEL_SSE__)
@@ -281,6 +295,29 @@ ccl_device_inline float3 sqrt(const float3 &a)
 #  endif
 }
 
+ccl_device_inline float3 floor(const float3 &a)
+{
+#  ifdef __KERNEL_SSE__
+  return float3(_mm_floor_ps(a));
+#  else
+  return make_float3(floorf(a.x), floorf(a.y), floorf(a.z));
+#  endif
+}
+
+ccl_device_inline float3 ceil(const float3 &a)
+{
+#  ifdef __KERNEL_SSE__
+  return float3(_mm_ceil_ps(a));
+#  else
+  return make_float3(ceilf(a.x), ceilf(a.y), ceilf(a.z));
+#  endif
+}
+
+ccl_device_inline float3 fract(const float3 &a)
+{
+  return a - floor(a);
+}
+
 ccl_device_inline float3 mix(const float3 &a, const float3 &b, float t)
 {
   return a + t * (b - a);
@@ -321,6 +358,19 @@ ccl_device_inline float len_squared(const float3 a)
   return dot(a, a);
 }
 
+ccl_device_inline float3 reflect(const float3 incident, const float3 normal)
+{
+  float3 unit_normal = normalize(normal);
+  return incident - 2.0f * unit_normal * dot(incident, unit_normal);
+}
+
+ccl_device_inline float3 project(const float3 v, const float3 v_proj)
+{
+  float len_squared = dot(v_proj, v_proj);
+  return (len_squared != 0.0f) ? (dot(v, v_proj) / len_squared) * v_proj :
+                                 make_float3(0.0f, 0.0f, 0.0f);
+}
+
 ccl_device_inline float3 saturate3(float3 a)
 {
   return make_float3(saturate(a.x), saturate(a.y), saturate(a.z));
@@ -345,6 +395,18 @@ ccl_device_inline float3 safe_normalize_len(const float3 a, float *t)
   return (*t != 0.0f) ? a / (*t) : a;
 }
 
+ccl_device_inline float3 safe_divide_float3_float3(const float3 a, const float3 b)
+{
+  return make_float3((b.x != 0.0f) ? a.x / b.x : 0.0f,
+                     (b.y != 0.0f) ? a.y / b.y : 0.0f,
+                     (b.z != 0.0f) ? a.z / b.z : 0.0f);
+}
+
+ccl_device_inline float3 safe_divide_float3_float(const float3 a, const float b)
+{
+  return (b != 0.0f) ? a / b : make_float3(0.0f, 0.0f, 0.0f);
+}
+
 ccl_device_inline float3 interp(float3 a, float3 b, float t)
 {
   return a + t * (b - a);
index 7d427cb7799749258766ee740a2ae6aaf26c7271..1b7debe4496b00db594f2b2095b37effebcc6415 100644 (file)
@@ -895,7 +895,7 @@ void BKE_nodetree_remove_layer_n(struct bNodeTree *ntree,
 #define SH_NODE_CURVE_RGB 111
 #define SH_NODE_CAMERA 114
 #define SH_NODE_MATH 115
-#define SH_NODE_VECT_MATH 116
+#define SH_NODE_VECTOR_MATH 116
 #define SH_NODE_SQUEEZE 117
 //#define SH_NODE_MATERIAL_EXT  118
 #define SH_NODE_INVERT 119
index d64a5a33ef13d4ce782c076882a1bb74e438f967..7e455ba742a9b16dce78dd514c1882419d694ed8 100644 (file)
@@ -3232,11 +3232,6 @@ void ntreeTagUsedSockets(bNodeTree *ntree)
   }
 
   for (link = ntree->links.first; link; link = link->next) {
-    /* link is unused if either side is disabled */
-    if ((link->fromsock->flag & SOCK_UNAVAIL) || (link->tosock->flag & SOCK_UNAVAIL)) {
-      continue;
-    }
-
     link->fromsock->flag |= SOCK_IN_USE;
     link->tosock->flag |= SOCK_IN_USE;
   }
index c235a72e7e406cfa0fac798b9cb69b654c0cda99..b8b62dd3451d8bd8910fb611be687056d72b256a 100644 (file)
@@ -171,12 +171,21 @@ struct LinkData *BLI_genericNodeN(void *data);
 #define LISTBASE_FOREACH(type, var, list) \
   for (type var = (type)((list)->first); var != NULL; var = (type)(((Link *)(var))->next))
 
+#define LISTBASE_FOREACH_BACKWARD(type, var, list) \
+  for (type var = (type)((list)->last); var != NULL; var = (type)(((Link *)(var))->prev))
+
 /** A version of #LISTBASE_FOREACH that supports removing the item we're looping over. */
 #define LISTBASE_FOREACH_MUTABLE(type, var, list) \
   for (type var = (type)((list)->first), *var##_iter_next; \
        ((var != NULL) ? ((void)(var##_iter_next = (type)(((Link *)(var))->next)), 1) : 0); \
        var = var##_iter_next)
 
+/** A version of #LISTBASE_FOREACH_BACKWARD that supports removing the item we're looping over. */
+#define LISTBASE_FOREACH_BACKWARD_MUTABLE(type, var, list) \
+  for (type var = (type)((list)->last), *var##_iter_prev; \
+       ((var != NULL) ? ((void)(var##_iter_prev = (type)(((Link *)(var))->prev)), 1) : 0); \
+       var = var##_iter_prev)
+
 #ifdef __cplusplus
 }
 #endif
index 10f24cff61b0ce3b2b50b5da65e598d9c4495dd1..a3e9b8dc206348788c1d7ad357c37e3fbe52e5a0 100644 (file)
 #include "BLO_readfile.h"
 #include "readfile.h"
 
+static bool socket_is_used(bNodeSocket *sock)
+{
+  return sock->flag & SOCK_IN_USE;
+}
+
 static float *cycles_node_socket_float_value(bNodeSocket *socket)
 {
   bNodeSocketValueFloat *socket_data = socket->default_value;
@@ -57,6 +62,12 @@ static float *cycles_node_socket_rgba_value(bNodeSocket *socket)
   return socket_data->value;
 }
 
+static float *cycles_node_socket_vector_value(bNodeSocket *socket)
+{
+  bNodeSocketValueVector *socket_data = socket->default_value;
+  return socket_data->value;
+}
+
 static IDProperty *cycles_properties_from_ID(ID *id)
 {
   IDProperty *idprop = IDP_GetProperties(id, false);
@@ -426,6 +437,325 @@ static void update_math_node_single_operand_operators(bNodeTree *ntree)
   }
 }
 
+/* The Value output of the Vector Math node is no longer available in the Add
+ * and Subtract operators. Previously, this Value output was computed from the
+ * Vector output V as follows:
+ *
+ *   Value = (abs(V.x) + abs(V.y) + abs(V.z)) / 3
+ *
+ * Or more compactly using vector operators:
+ *
+ *   Value = dot(abs(V), (1 / 3, 1 / 3, 1 / 3))
+ *
+ * To correct this, if the Value output was used, we are going to compute
+ * it using the second equation by adding an absolute and a dot node, and
+ * then connect them appropriately.
+ */
+static void update_vector_math_node_add_and_subtract_operators(bNodeTree *ntree)
+{
+  bool need_update = false;
+
+  for (bNode *node = ntree->nodes.first; node; node = node->next) {
+    if (node->type == SH_NODE_VECTOR_MATH) {
+      bNodeSocket *sockOutValue = nodeFindSocket(node, SOCK_OUT, "Value");
+      if (socket_is_used(sockOutValue) &&
+          ELEM(node->custom1, NODE_VECTOR_MATH_ADD, NODE_VECTOR_MATH_SUBTRACT)) {
+
+        bNode *absNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
+        absNode->custom1 = NODE_VECTOR_MATH_ABSOLUTE;
+        absNode->locx = node->locx + node->width + 20.0f;
+        absNode->locy = node->locy;
+
+        bNode *dotNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
+        dotNode->custom1 = NODE_VECTOR_MATH_DOT_PRODUCT;
+        dotNode->locx = absNode->locx + absNode->width + 20.0f;
+        dotNode->locy = absNode->locy;
+        bNodeSocket *sockDotB = BLI_findlink(&dotNode->inputs, 1);
+        bNodeSocket *sockDotOutValue = nodeFindSocket(dotNode, SOCK_OUT, "Value");
+        copy_v3_fl(cycles_node_socket_vector_value(sockDotB), 1 / 3.0f);
+
+        LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
+          if (link->fromsock == sockOutValue) {
+            nodeAddLink(ntree, dotNode, sockDotOutValue, link->tonode, link->tosock);
+            nodeRemLink(ntree, link);
+          }
+        }
+
+        bNodeSocket *sockAbsA = BLI_findlink(&absNode->inputs, 0);
+        bNodeSocket *sockDotA = BLI_findlink(&dotNode->inputs, 0);
+        bNodeSocket *sockOutVector = nodeFindSocket(node, SOCK_OUT, "Vector");
+        bNodeSocket *sockAbsOutVector = nodeFindSocket(absNode, SOCK_OUT, "Vector");
+
+        nodeAddLink(ntree, node, sockOutVector, absNode, sockAbsA);
+        nodeAddLink(ntree, absNode, sockAbsOutVector, dotNode, sockDotA);
+
+        need_update = true;
+      }
+    }
+  }
+
+  if (need_update) {
+    ntreeUpdateTree(NULL, ntree);
+  }
+}
+
+/* The Vector output of the Vector Math node is no longer available in the Dot
+ * Product operator. Previously, this Vector was always zero initialized. To
+ * correct this, we zero out any socket the Vector Output was connected to.
+ */
+static void update_vector_math_node_dot_product_operator(bNodeTree *ntree)
+{
+  bool need_update = false;
+
+  for (bNode *node = ntree->nodes.first; node; node = node->next) {
+    if (node->type == SH_NODE_VECTOR_MATH) {
+      bNodeSocket *sockOutVector = nodeFindSocket(node, SOCK_OUT, "Vector");
+      if (socket_is_used(sockOutVector) && node->custom1 == NODE_VECTOR_MATH_DOT_PRODUCT) {
+        LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &ntree->links) {
+          if (link->fromsock == sockOutVector) {
+            switch (link->tosock->type) {
+              case SOCK_FLOAT:
+                *cycles_node_socket_float_value(link->tosock) = 0.0f;
+                break;
+              case SOCK_VECTOR:
+                copy_v3_fl(cycles_node_socket_vector_value(link->tosock), 0.0f);
+                break;
+              case SOCK_RGBA:
+                copy_v4_fl(cycles_node_socket_rgba_value(link->tosock), 0.0f);
+                break;
+            }
+            nodeRemLink(ntree, link);
+          }
+        }
+        need_update = true;
+      }
+    }
+  }
+
+  if (need_update) {
+    ntreeUpdateTree(NULL, ntree);
+  }
+}
+
+/* Previously, the Vector output of the cross product operator was normalized.
+ * To correct this, a Normalize node is added to normalize the output if used.
+ * Moreover, the Value output was removed. This Value was equal to the length
+ * of the cross product. To correct this, a Length node is added if needed.
+ */
+static void update_vector_math_node_cross_product_operator(bNodeTree *ntree)
+{
+  bool need_update = false;
+
+  for (bNode *node = ntree->nodes.first; node; node = node->next) {
+    if (node->type == SH_NODE_VECTOR_MATH) {
+      if (node->custom1 == NODE_VECTOR_MATH_CROSS_PRODUCT) {
+        bNodeSocket *sockOutVector = nodeFindSocket(node, SOCK_OUT, "Vector");
+        if (socket_is_used(sockOutVector)) {
+          bNode *normalizeNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
+          normalizeNode->custom1 = NODE_VECTOR_MATH_NORMALIZE;
+          normalizeNode->locx = node->locx + node->width + 20.0f;
+          normalizeNode->locy = node->locy;
+          bNodeSocket *sockNormalizeOut = nodeFindSocket(normalizeNode, SOCK_OUT, "Vector");
+
+          LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
+            if (link->fromsock == sockOutVector) {
+              nodeAddLink(ntree, normalizeNode, sockNormalizeOut, link->tonode, link->tosock);
+              nodeRemLink(ntree, link);
+            }
+          }
+          bNodeSocket *sockNormalizeA = BLI_findlink(&normalizeNode->inputs, 0);
+          nodeAddLink(ntree, node, sockOutVector, normalizeNode, sockNormalizeA);
+
+          need_update = true;
+        }
+
+        bNodeSocket *sockOutValue = nodeFindSocket(node, SOCK_OUT, "Value");
+        if (socket_is_used(sockOutValue)) {
+          bNode *lengthNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
+          lengthNode->custom1 = NODE_VECTOR_MATH_LENGTH;
+          lengthNode->locx = node->locx + node->width + 20.0f;
+          if (socket_is_used(sockOutVector)) {
+            lengthNode->locy = node->locy - lengthNode->height - 20.0f;
+          }
+          else {
+            lengthNode->locy = node->locy;
+          }
+          bNodeSocket *sockLengthOut = nodeFindSocket(lengthNode, SOCK_OUT, "Value");
+
+          LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
+            if (link->fromsock == sockOutValue) {
+              nodeAddLink(ntree, lengthNode, sockLengthOut, link->tonode, link->tosock);
+              nodeRemLink(ntree, link);
+            }
+          }
+          bNodeSocket *sockLengthA = BLI_findlink(&lengthNode->inputs, 0);
+          nodeAddLink(ntree, node, sockOutVector, lengthNode, sockLengthA);
+
+          need_update = true;
+        }
+      }
+    }
+  }
+
+  if (need_update) {
+    ntreeUpdateTree(NULL, ntree);
+  }
+}
+
+/* The Value output of the Vector Math node is no longer available in the
+ * Normalize operator. This Value output was equal to the length of the
+ * the input vector A. To correct this, we either add a Length node or
+ * convert the Normalize node into a Length node, depending on if the
+ * Vector output is needed.
+ */
+static void update_vector_math_node_normalize_operator(bNodeTree *ntree)
+{
+  bool need_update = false;
+
+  for (bNode *node = ntree->nodes.first; node; node = node->next) {
+    if (node->type == SH_NODE_VECTOR_MATH) {
+      bNodeSocket *sockOutValue = nodeFindSocket(node, SOCK_OUT, "Value");
+      if (node->custom1 == NODE_VECTOR_MATH_NORMALIZE && socket_is_used(sockOutValue)) {
+        bNodeSocket *sockOutVector = nodeFindSocket(node, SOCK_OUT, "Vector");
+        if (socket_is_used(sockOutVector)) {
+          bNode *lengthNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
+          lengthNode->custom1 = NODE_VECTOR_MATH_LENGTH;
+          lengthNode->locx = node->locx + node->width + 20.0f;
+          lengthNode->locy = node->locy;
+          bNodeSocket *sockLengthValue = nodeFindSocket(lengthNode, SOCK_OUT, "Value");
+
+          LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
+            if (link->fromsock == sockOutValue) {
+              nodeAddLink(ntree, lengthNode, sockLengthValue, link->tonode, link->tosock);
+              nodeRemLink(ntree, link);
+            }
+          }
+          bNodeSocket *sockA = BLI_findlink(&node->inputs, 0);
+          bNodeSocket *sockLengthA = BLI_findlink(&lengthNode->inputs, 0);
+          if (sockA->link) {
+            bNodeLink *link = sockA->link;
+            nodeAddLink(ntree, link->fromnode, link->fromsock, lengthNode, sockLengthA);
+          }
+          else {
+            copy_v3_v3(cycles_node_socket_vector_value(sockLengthA),
+                       cycles_node_socket_vector_value(sockA));
+          }
+
+          need_update = true;
+        }
+        else {
+          node->custom1 = NODE_VECTOR_MATH_LENGTH;
+        }
+      }
+    }
+  }
+  if (need_update) {
+    ntreeUpdateTree(NULL, ntree);
+  }
+}
+
+/* The Vector Math operator types didn't have an enum, but rather, their
+ * values were hard coded into the code. After the enum was created and
+ * after more vector operators were added, the hard coded values needs
+ * to be remapped to their correct enum values. To fix this, we remap
+ * the values according to the following rules:
+ *
+ * Dot Product Operator : 3 -> 7
+ * Normalize Operator   : 5 -> 11
+ *
+ * Additionally, since the Average operator was removed, it is assigned
+ * a value of -1 just to be identified later in the versioning code:
+ *
+ * Average Operator : 2 -> -1
+ *
+ */
+static void update_vector_math_node_operators_enum_mapping(bNodeTree *ntree)
+{
+  for (bNode *node = ntree->nodes.first; node; node = node->next) {
+    if (node->type == SH_NODE_VECTOR_MATH) {
+      switch (node->custom1) {
+        case 2:
+          node->custom1 = -1;
+          break;
+        case 3:
+          node->custom1 = 7;
+          break;
+        case 5:
+          node->custom1 = 11;
+          break;
+      }
+    }
+  }
+}
+
+/* The Average operator is no longer available in the Vector Math node.
+ * The Vector output was equal to the normalized sum of input vectors while
+ * the Value output was equal to the length of the sum of input vectors.
+ * To correct this, we convert the node into an Add node and add a length
+ * node or a normalize node if needed.
+ */
+static void update_vector_math_node_average_operator(bNodeTree *ntree)
+{
+  bool need_update = false;
+
+  for (bNode *node = ntree->nodes.first; node; node = node->next) {
+    if (node->type == SH_NODE_VECTOR_MATH) {
+      /* See update_vector_math_node_operators_enum_mapping. */
+      if (node->custom1 == -1) {
+        node->custom1 = NODE_VECTOR_MATH_ADD;
+        bNodeSocket *sockOutVector = nodeFindSocket(node, SOCK_OUT, "Vector");
+        if (socket_is_used(sockOutVector)) {
+          bNode *normalizeNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
+          normalizeNode->custom1 = NODE_VECTOR_MATH_NORMALIZE;
+          normalizeNode->locx = node->locx + node->width + 20.0f;
+          normalizeNode->locy = node->locy;
+          bNodeSocket *sockNormalizeOut = nodeFindSocket(normalizeNode, SOCK_OUT, "Vector");
+
+          LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
+            if (link->fromsock == sockOutVector) {
+              nodeAddLink(ntree, normalizeNode, sockNormalizeOut, link->tonode, link->tosock);
+              nodeRemLink(ntree, link);
+            }
+          }
+          bNodeSocket *sockNormalizeA = BLI_findlink(&normalizeNode->inputs, 0);
+          nodeAddLink(ntree, node, sockOutVector, normalizeNode, sockNormalizeA);
+
+          need_update = true;
+        }
+
+        bNodeSocket *sockOutValue = nodeFindSocket(node, SOCK_OUT, "Value");
+        if (socket_is_used(sockOutValue)) {
+          bNode *lengthNode = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
+          lengthNode->custom1 = NODE_VECTOR_MATH_LENGTH;
+          lengthNode->locx = node->locx + node->width + 20.0f;
+          if (socket_is_used(sockOutVector)) {
+            lengthNode->locy = node->locy - lengthNode->height - 20.0f;
+          }
+          else {
+            lengthNode->locy = node->locy;
+          }
+          bNodeSocket *sockLengthOut = nodeFindSocket(lengthNode, SOCK_OUT, "Value");
+
+          LISTBASE_FOREACH_BACKWARD_MUTABLE (bNodeLink *, link, &ntree->links) {
+            if (link->fromsock == sockOutValue) {
+              nodeAddLink(ntree, lengthNode, sockLengthOut, link->tonode, link->tosock);
+              nodeRemLink(ntree, link);
+            }
+          }
+          bNodeSocket *sockLengthA = BLI_findlink(&lengthNode->inputs, 0);
+          nodeAddLink(ntree, node, sockOutVector, lengthNode, sockLengthA);
+
+          need_update = true;
+        }
+      }
+    }
+  }
+
+  if (need_update) {
+    ntreeUpdateTree(NULL, ntree);
+  }
+}
+
 void blo_do_versions_cycles(FileData *UNUSED(fd), Library *UNUSED(lib), Main *bmain)
 {
   /* Particle shape shared with Eevee. */
@@ -458,6 +788,15 @@ void blo_do_versions_cycles(FileData *UNUSED(fd), Library *UNUSED(lib), Main *bm
       }
     }
   }
+
+  if (!MAIN_VERSION_ATLEAST(bmain, 281, 3)) {
+    FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+      if (ntree->type == NTREE_SHADER) {
+        update_vector_math_node_operators_enum_mapping(ntree);
+      }
+    }
+    FOREACH_NODETREE_END;
+  }
 }
 
 void do_versions_after_linking_cycles(Main *bmain)
@@ -576,4 +915,17 @@ void do_versions_after_linking_cycles(Main *bmain)
     }
     FOREACH_NODETREE_END;
   }
+
+  if (!MAIN_VERSION_ATLEAST(bmain, 281, 3)) {
+    FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+      if (ntree->type == NTREE_SHADER) {
+        update_vector_math_node_add_and_subtract_operators(ntree);
+        update_vector_math_node_dot_product_operator(ntree);
+        update_vector_math_node_cross_product_operator(ntree);
+        update_vector_math_node_normalize_operator(ntree);
+        update_vector_math_node_average_operator(ntree);
+      }
+    }
+    FOREACH_NODETREE_END;
+  }
 }
index c3ecc34aaf4877ed5b98ad4f28c6a99326896367..4201fe7c289c7cf0df76d978feb4e020ef7b44cb 100644 (file)
@@ -1220,7 +1220,7 @@ static void node_shader_set_butfunc(bNodeType *ntype)
     case SH_NODE_MATH:
       ntype->draw_buttons = node_buts_math;
       break;
-    case SH_NODE_VECT_MATH:
+    case SH_NODE_VECTOR_MATH:
       ntype->draw_buttons = node_shader_buts_vect_math;
       break;
     case SH_NODE_VECT_TRANSFORM:
index 1529279ca0346c64e6857d222e9c6c882ac6dece..1817efd35d252404f54c6f0fbb635ae826d3032b 100644 (file)
@@ -400,46 +400,118 @@ void map_range(
   }
 }
 
-void vec_math_add(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
+vec3 safe_divide(vec3 a, vec3 b) {
+  return vec3((b.x != 0.0) ? a.x / b.x : 0.0,
+              (b.y != 0.0) ? a.y / b.y : 0.0,
+              (b.z != 0.0) ? a.z / b.z : 0.0);
+}
+
+void vector_math_add(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+  outVector = a + b;
+}
+
+void vector_math_subtract(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+  outVector = a - b;
+}
+
+void vector_math_multiply(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+  outVector = a * b;
+}
+
+void vector_math_divide(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+  outVector = safe_divide(a, b);
+}
+
+void vector_math_cross(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+  outVector = cross(a, b);
+}
+
+void vector_math_project(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+  float lenSquared = dot(b, b);
+  outVector = (lenSquared != 0.0) ? (dot(a, b) / lenSquared) * b : vec3(0.0);
+}
+
+void vector_math_reflect(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+  outVector = reflect(a, normalize(b));
+}
+
+void vector_math_dot(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
 {
-  outvec = v1 + v2;
-  outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) * 0.333333;
+  outValue = dot(a, b);
 }
 
-void vec_math_sub(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
+void vector_math_distance(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
 {
-  outvec = v1 - v2;
-  outval = (abs(outvec[0]) + abs(outvec[1]) + abs(outvec[2])) * 0.333333;
+  outValue = distance(a, b);
 }
 
-void vec_math_average(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
+void vector_math_length(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
 {
-  outvec = v1 + v2;
-  outval = length(outvec);
-  outvec = normalize(outvec);
+  outValue = length(a);
 }
-void vec_math_mix(float strength, vec3 v1, vec3 v2, out vec3 outvec)
+
+void vector_math_scale(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+  outVector = a * scale;
+}
+
+void vector_math_normalize(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+  outVector = normalize(a);
+}
+
+void vector_math_snap(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+  outVector = floor(safe_divide(a, b)) * b;
+}
+
+void vector_math_floor(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+  outVector = floor(a);
+}
+
+void vector_math_ceil(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+  outVector = ceil(a);
+}
+
+void vector_math_modulo(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+  math_modulo(a.x, b.x, outVector.x);
+  math_modulo(a.y, b.y, outVector.y);
+  math_modulo(a.z, b.z, outVector.z);
+}
+
+void vector_math_fraction(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
+{
+  outVector = fract(a);
+}
+
+void vector_math_absolute(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
 {
-  outvec = strength * v1 + (1 - strength) * v2;
+  outVector = abs(a);
 }
 
-void vec_math_dot(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
+void vector_math_minimum(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
 {
-  outvec = vec3(0);
-  outval = dot(v1, v2);
+  outVector = min(a, b);
 }
 
-void vec_math_cross(vec3 v1, vec3 v2, out vec3 outvec, out float outval)
+void vector_math_maximum(vec3 a, vec3 b, float scale, out vec3 outVector, out float outValue)
 {
-  outvec = cross(v1, v2);
-  outval = length(outvec);
-  outvec /= outval;
+  outVector = max(a, b);
 }
 
-void vec_math_normalize(vec3 v, out vec3 outvec, out float outval)
+void vector_math_mix(float strength, vec3 a, vec3 b, out vec3 outVector)
 {
-  outval = length(v);
-  outvec = normalize(v);
+  outVector = strength * a + (1 - strength) * b;
 }
 
 void vec_math_negate(vec3 v, out vec3 outv)
index 81b93ce654126739eb6b365b810f607a8dc6bfa8..385a5bd4428f6fbcc42601c322dcec13c5a95848 100644 (file)
@@ -1195,6 +1195,33 @@ enum {
   NODE_MATH_SQRT = 23,
 };
 
+/* Vector Math node operations. */
+enum {
+  NODE_VECTOR_MATH_ADD = 0,
+  NODE_VECTOR_MATH_SUBTRACT = 1,
+  NODE_VECTOR_MATH_MULTIPLY = 2,
+  NODE_VECTOR_MATH_DIVIDE = 3,
+
+  NODE_VECTOR_MATH_CROSS_PRODUCT = 4,
+  NODE_VECTOR_MATH_PROJECT = 5,
+  NODE_VECTOR_MATH_REFLECT = 6,
+  NODE_VECTOR_MATH_DOT_PRODUCT = 7,
+
+  NODE_VECTOR_MATH_DISTANCE = 8,
+  NODE_VECTOR_MATH_LENGTH = 9,
+  NODE_VECTOR_MATH_SCALE = 10,
+  NODE_VECTOR_MATH_NORMALIZE = 11,
+
+  NODE_VECTOR_MATH_SNAP = 12,
+  NODE_VECTOR_MATH_FLOOR = 13,
+  NODE_VECTOR_MATH_CEIL = 14,
+  NODE_VECTOR_MATH_MODULO = 15,
+  NODE_VECTOR_MATH_FRACTION = 16,
+  NODE_VECTOR_MATH_ABSOLUTE = 17,
+  NODE_VECTOR_MATH_MINIMUM = 18,
+  NODE_VECTOR_MATH_MAXIMUM = 19,
+};
+
 /* mix rgb node flags */
 #define SHD_MIXRGB_USE_ALPHA 1
 #define SHD_MIXRGB_CLAMP 2
index 020f4296ddd1e5ad59f84309bb79752fc5a2fb28..f377ae9a84f93c5ce866e3ca9245acc48283af12 100644 (file)
@@ -136,12 +136,37 @@ const EnumPropertyItem rna_enum_node_math_items[] = {
 };
 
 const EnumPropertyItem rna_enum_node_vec_math_items[] = {
-    {0, "ADD", 0, "Add", ""},
-    {1, "SUBTRACT", 0, "Subtract", ""},
-    {2, "AVERAGE", 0, "Average", ""},
-    {3, "DOT_PRODUCT", 0, "Dot Product", ""},
-    {4, "CROSS_PRODUCT", 0, "Cross Product", ""},
-    {5, "NORMALIZE", 0, "Normalize", ""},
+    {NODE_VECTOR_MATH_ADD, "ADD", 0, "Add", "A + B"},
+    {NODE_VECTOR_MATH_SUBTRACT, "SUBTRACT", 0, "Subtract", "A - B"},
+    {NODE_VECTOR_MATH_MULTIPLY, "MULTIPLY", 0, "Multiply", "Entrywise multiply"},
+    {NODE_VECTOR_MATH_DIVIDE, "DIVIDE", 0, "Divide", "Entrywise divide"},
+    {0, "", ICON_NONE, NULL, NULL},
+    {NODE_VECTOR_MATH_CROSS_PRODUCT, "CROSS_PRODUCT", 0, "Cross Product", "A cross B"},
+    {NODE_VECTOR_MATH_PROJECT, "PROJECT", 0, "Project", "Project A onto B"},
+    {NODE_VECTOR_MATH_REFLECT,
+     "REFLECT",
+     0,
+     "Reflect",
+     "Reflect A around the normal B. B needn't be normalized"},
+    {NODE_VECTOR_MATH_DOT_PRODUCT, "DOT_PRODUCT", 0, "Dot Product", "A dot B"},
+    {0, "", ICON_NONE, NULL, NULL},
+    {NODE_VECTOR_MATH_DISTANCE, "DISTANCE", 0, "Distance", "Distance between A and B"},
+    {NODE_VECTOR_MATH_LENGTH, "LENGTH", 0, "Length", "Length of A"},
+    {NODE_VECTOR_MATH_SCALE, "SCALE", 0, "Scale", "A multiplied by Scale"},
+    {NODE_VECTOR_MATH_NORMALIZE, "NORMALIZE", 0, "Normalize", "Normalize A"},
+    {0, "", ICON_NONE, NULL, NULL},
+    {NODE_VECTOR_MATH_SNAP,
+     "SNAP",
+     0,
+     "Snap",
+     "Round A to the largest integer multiple of B less than or equal A"},
+    {NODE_VECTOR_MATH_FLOOR, "FLOOR", 0, "Floor", "Entrywise floor"},
+    {NODE_VECTOR_MATH_CEIL, "CEIL", 0, "Ceil", "Entrywise ceil"},
+    {NODE_VECTOR_MATH_MODULO, "MODULO", 0, "Modulo", "Entrywise modulo"},
+    {NODE_VECTOR_MATH_FRACTION, "FRACTION", 0, "Fraction", "The fraction part of A entrywise"},
+    {NODE_VECTOR_MATH_ABSOLUTE, "ABSOLUTE", 0, "Absolute", "Entrywise absolute"},
+    {NODE_VECTOR_MATH_MINIMUM, "MINIMUM", 0, "Minimum", "Entrywise minimum"},
+    {NODE_VECTOR_MATH_MAXIMUM, "MAXIMUM", 0, "Maximum", "Entrywise maximum"},
     {0, NULL, 0, NULL, NULL},
 };
 
@@ -3873,7 +3898,7 @@ static void def_vector_math(StructRNA *srna)
   RNA_def_property_enum_sdna(prop, NULL, "custom1");
   RNA_def_property_enum_items(prop, rna_enum_node_vec_math_items);
   RNA_def_property_ui_text(prop, "Operation", "");
-  RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+  RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_ShaderNode_socket_update");
 }
 
 static void def_rgb_curve(StructRNA *srna)
index 284eaa8b70bda120c3f3841632a8a469be51d147..3c97bdae9292ce3911b5834941d53e238042b668 100644 (file)
@@ -204,7 +204,7 @@ set(SRC
   shader/nodes/node_shader_uvmap.c
   shader/nodes/node_shader_valToRgb.c
   shader/nodes/node_shader_value.c
-  shader/nodes/node_shader_vectMath.c
+  shader/nodes/node_shader_vector_math.c
   shader/nodes/node_shader_vectTransform.c
   shader/nodes/node_shader_vector_displacement.c
   shader/nodes/node_shader_volume_absorption.c
index c72e97642a231d60246cd014e1a696eeccebe65a..c08911c1db803693f714696173fab66311586bb5 100644 (file)
@@ -53,7 +53,7 @@ DefNode(ShaderNode,     SH_NODE_CAMERA,          0,                      "CAMERA
 DefNode(ShaderNode,     SH_NODE_MAP_RANGE,       def_map_range,          "MAP_RANGE",      MapRange,         "Map Range",         ""              )
 DefNode(ShaderNode,     SH_NODE_CLAMP,           0,                      "CLAMP",          Clamp,            "Clamp",             ""              )
 DefNode(ShaderNode,     SH_NODE_MATH,            def_math,               "MATH",           Math,             "Math",              ""              )
-DefNode(ShaderNode,     SH_NODE_VECT_MATH,       def_vector_math,        "VECT_MATH",      VectorMath,       "Vector Math",       ""              )
+DefNode(ShaderNode,     SH_NODE_VECTOR_MATH,     def_vector_math,        "VECT_MATH",      VectorMath,       "Vector Math",       ""              )
 DefNode(ShaderNode,     SH_NODE_SQUEEZE,         0,                      "SQUEEZE",        Squeeze,          "Squeeze Value",     ""              )
 DefNode(ShaderNode,     SH_NODE_INVERT,          0,                      "INVERT",         Invert,           "Invert",            ""              )
 DefNode(ShaderNode,     SH_NODE_SEPRGB,          0,                      "SEPRGB",         SeparateRGB,      "Separate RGB",      ""              )
index e9a825b5b3ffcc7d1fd8f1388defff242df2fcd5..0d7f19fb67a1e5033bff4280b1f1fbd10cd8d9f6 100644 (file)
@@ -100,7 +100,7 @@ void node_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int max
   BLI_strncpy(label, IFACE_(name), maxlen);
 }
 
-void node_vect_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+void node_vector_math_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
 {
   const char *name;
   RNA_enum_name(rna_enum_node_vec_math_items, node->custom1, &name);
index 7eef70db49899980fa1b3e68d6240fbb5f6c7538..49117b38abac9a3baed311b2a63c573055a84802 100644 (file)
@@ -71,7 +71,7 @@ extern void *node_initexec_curves(struct bNodeExecContext *context,
 void node_blend_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
 void node_image_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
 void node_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
-void node_vect_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
+void node_vector_math_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
 void node_filter_label(struct bNodeTree *ntree, struct bNode *node, char *label, int maxlen);
 
 /*** Link Handling */
index 4891fb323ad98ba591a13d91473641fe3e4ddf98..60a6cc91630d74a725a2526a3be31e57d458fbe5 100644 (file)
@@ -799,7 +799,7 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree, bNode *output_nod
   nodeRemLink(ntree, displacement_link);
 
   /* Convert displacement vector to bump height. */
-  bNode *dot_node = nodeAddStaticNode(NULL, ntree, SH_NODE_VECT_MATH);
+  bNode *dot_node = nodeAddStaticNode(NULL, ntree, SH_NODE_VECTOR_MATH);
   bNode *geo_node = nodeAddStaticNode(NULL, ntree, SH_NODE_NEW_GEOMETRY);
   bNodeSocket *normal_socket = ntree_shader_node_find_output(geo_node, "Normal");
   dot_node->custom1 = 3; /* dot product */
index 3d034372300dcbb1793d7b3d6dff09fcc2e3e1c0..712c64084ccbb07e892e3ea43c366a825f733012 100644 (file)
@@ -114,7 +114,7 @@ static int gpu_shader_normal_map(GPUMaterial *mat,
       break;
   }
 
-  GPU_link(mat, "vec_math_mix", strength, realnorm, negnorm, &out[0].link);
+  GPU_link(mat, "vector_math_mix", strength, realnorm, negnorm, &out[0].link);
   GPU_link(mat, "vect_normalize", out[0].link, &out[0].link);
 
   return true;
diff --git a/source/blender/nodes/shader/nodes/node_shader_vectMath.c b/source/blender/nodes/shader/nodes/node_shader_vectMath.c
deleted file mode 100644 (file)
index 41273a6..0000000
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2005 Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup shdnodes
- */
-
-#include "node_shader_util.h"
-
-/* **************** VECTOR MATH ******************** */
-static bNodeSocketTemplate sh_node_vect_math_in[] = {
-    {SOCK_VECTOR, 1, N_("Vector"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
-    {SOCK_VECTOR, 1, N_("Vector"), 0.5f, 0.5f, 0.5f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
-    {-1, 0, ""}};
-
-static bNodeSocketTemplate sh_node_vect_math_out[] = {
-    {SOCK_VECTOR, 0, N_("Vector")}, {SOCK_FLOAT, 0, N_("Value")}, {-1, 0, ""}};
-
-static void node_shader_exec_vect_math(void *UNUSED(data),
-                                       int UNUSED(thread),
-                                       bNode *node,
-                                       bNodeExecData *UNUSED(execdata),
-                                       bNodeStack **in,
-                                       bNodeStack **out)
-{
-  float vec1[3], vec2[3];
-
-  nodestack_get_vec(vec1, SOCK_VECTOR, in[0]);
-  nodestack_get_vec(vec2, SOCK_VECTOR, in[1]);
-
-  if (node->custom1 == 0) { /* Add */
-    out[0]->vec[0] = vec1[0] + vec2[0];
-    out[0]->vec[1] = vec1[1] + vec2[1];
-    out[0]->vec[2] = vec1[2] + vec2[2];
-
-    out[1]->vec[0] = (fabsf(out[0]->vec[0]) + fabsf(out[0]->vec[1]) + fabsf(out[0]->vec[2])) /
-                     3.0f;
-  }
-  else if (node->custom1 == 1) { /* Subtract */
-    out[0]->vec[0] = vec1[0] - vec2[0];
-    out[0]->vec[1] = vec1[1] - vec2[1];
-    out[0]->vec[2] = vec1[2] - vec2[2];
-
-    out[1]->vec[0] = (fabsf(out[0]->vec[0]) + fabsf(out[0]->vec[1]) + fabsf(out[0]->vec[2])) /
-                     3.0f;
-  }
-  else if (node->custom1 == 2) { /* Average */
-    out[0]->vec[0] = vec1[0] + vec2[0];
-    out[0]->vec[1] = vec1[1] + vec2[1];
-    out[0]->vec[2] = vec1[2] + vec2[2];
-
-    out[1]->vec[0] = normalize_v3(out[0]->vec);
-  }
-  else if (node->custom1 == 3) { /* Dot product */
-    out[1]->vec[0] = (vec1[0] * vec2[0]) + (vec1[1] * vec2[1]) + (vec1[2] * vec2[2]);
-  }
-  else if (node->custom1 == 4) { /* Cross product */
-    out[0]->vec[0] = (vec1[1] * vec2[2]) - (vec1[2] * vec2[1]);
-    out[0]->vec[1] = (vec1[2] * vec2[0]) - (vec1[0] * vec2[2]);
-    out[0]->vec[2] = (vec1[0] * vec2[1]) - (vec1[1] * vec2[0]);
-
-    out[1]->vec[0] = normalize_v3(out[0]->vec);
-  }
-  else if (node->custom1 == 5) { /* Normalize */
-    /* This one only takes one input, so we've got to choose. */
-    if (in[0]->hasinput || !in[1]->hasinput) {
-      out[0]->vec[0] = vec1[0];
-      out[0]->vec[1] = vec1[1];
-      out[0]->vec[2] = vec1[2];
-    }
-    else {
-      out[0]->vec[0] = vec2[0];
-      out[0]->vec[1] = vec2[1];
-      out[0]->vec[2] = vec2[2];
-    }
-
-    out[1]->vec[0] = normalize_v3(out[0]->vec);
-  }
-}
-
-static int gpu_shader_vect_math(GPUMaterial *mat,
-                                bNode *node,
-                                bNodeExecData *UNUSED(execdata),
-                                GPUNodeStack *in,
-                                GPUNodeStack *out)
-{
-  static const char *names[] = {
-      "vec_math_add",
-      "vec_math_sub",
-      "vec_math_average",
-      "vec_math_dot",
-      "vec_math_cross",
-      "vec_math_normalize",
-  };
-
-  switch (node->custom1) {
-    case 0:
-    case 1:
-    case 2:
-    case 3:
-    case 4:
-      GPU_stack_link(mat, node, names[node->custom1], in, out);
-      break;
-    case 5:
-      if (in[0].hasinput || !in[1].hasinput) {
-        /* use only first item and terminator */
-        GPUNodeStack tmp_in[2];
-        memcpy(&tmp_in[0], &in[0], sizeof(GPUNodeStack));
-        memcpy(&tmp_in[1], &in[2], sizeof(GPUNodeStack));
-        GPU_stack_link(mat, node, names[node->custom1], tmp_in, out);
-      }
-      else {
-        /* use only second item and terminator */
-        GPUNodeStack tmp_in[2];
-        memcpy(&tmp_in[0], &in[1], sizeof(GPUNodeStack));
-        memcpy(&tmp_in[1], &in[2], sizeof(GPUNodeStack));
-        GPU_stack_link(mat, node, names[node->custom1], tmp_in, out);
-      }
-      break;
-    default:
-      return false;
-  }
-
-  return true;
-}
-
-void register_node_type_sh_vect_math(void)
-{
-  static bNodeType ntype;
-
-  sh_node_type_base(&ntype, SH_NODE_VECT_MATH, "Vector Math", NODE_CLASS_CONVERTOR, 0);
-  node_type_socket_templates(&ntype, sh_node_vect_math_in, sh_node_vect_math_out);
-  node_type_label(&ntype, node_vect_math_label);
-  node_type_storage(&ntype, "", NULL, NULL);
-  node_type_exec(&ntype, NULL, NULL, node_shader_exec_vect_math);
-  node_type_gpu(&ntype, gpu_shader_vect_math);
-
-  nodeRegisterType(&ntype);
-}
diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_math.c b/source/blender/nodes/shader/nodes/node_shader_vector_math.c
new file mode 100644 (file)
index 0000000..03de836
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2005 Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup shdnodes
+ */
+
+#include "node_shader_util.h"
+
+/* **************** VECTOR MATH ******************** */
+static bNodeSocketTemplate sh_node_vector_math_in[] = {
+    {SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
+    {SOCK_VECTOR, 1, N_("Vector"), 0.0f, 0.0f, 0.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
+    {SOCK_FLOAT, 1, N_("Scale"), 1.0f, 1.0f, 1.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE},
+    {-1, 0, ""}};
+
+static bNodeSocketTemplate sh_node_vector_math_out[] = {
+    {SOCK_VECTOR, 0, N_("Vector")}, {SOCK_FLOAT, 0, N_("Value")}, {-1, 0, ""}};
+
+static int gpu_shader_vector_math(GPUMaterial *mat,
+                                  bNode *node,
+                                  bNodeExecData *UNUSED(execdata),
+                                  GPUNodeStack *in,
+                                  GPUNodeStack *out)
+{
+  static const char *names[] = {
+      [NODE_VECTOR_MATH_ADD] = "vector_math_add",
+      [NODE_VECTOR_MATH_SUBTRACT] = "vector_math_subtract",
+      [NODE_VECTOR_MATH_MULTIPLY] = "vector_math_multiply",
+      [NODE_VECTOR_MATH_DIVIDE] = "vector_math_divide",
+
+      [NODE_VECTOR_MATH_CROSS_PRODUCT] = "vector_math_cross",
+      [NODE_VECTOR_MATH_PROJECT] = "vector_math_project",
+      [NODE_VECTOR_MATH_REFLECT] = "vector_math_reflect",
+      [NODE_VECTOR_MATH_DOT_PRODUCT] = "vector_math_dot",
+
+      [NODE_VECTOR_MATH_DISTANCE] = "vector_math_distance",
+      [NODE_VECTOR_MATH_LENGTH] = "vector_math_length",
+      [NODE_VECTOR_MATH_SCALE] = "vector_math_scale",
+      [NODE_VECTOR_MATH_NORMALIZE] = "vector_math_normalize",
+
+      [NODE_VECTOR_MATH_SNAP] = "vector_math_snap",
+      [NODE_VECTOR_MATH_FLOOR] = "vector_math_floor",
+      [NODE_VECTOR_MATH_CEIL] = "vector_math_ceil",
+      [NODE_VECTOR_MATH_MODULO] = "vector_math_modulo",
+      [NODE_VECTOR_MATH_FRACTION] = "vector_math_fraction",
+      [NODE_VECTOR_MATH_ABSOLUTE] = "vector_math_absolute",
+      [NODE_VECTOR_MATH_MINIMUM] = "vector_math_minimum",
+      [NODE_VECTOR_MATH_MAXIMUM] = "vector_math_maximum",
+  };
+
+  GPU_stack_link(mat, node, names[node->custom1], in, out);
+  return true;
+}
+
+static void node_shader_update_vector_math(bNodeTree *UNUSED(ntree), bNode *node)
+{
+  bNodeSocket *sockB = BLI_findlink(&node->inputs, 1);
+  bNodeSocket *sockScale = nodeFindSocket(node, SOCK_IN, "Scale");
+
+  bNodeSocket *sockVector = nodeFindSocket(node, SOCK_OUT, "Vector");
+  bNodeSocket *sockValue = nodeFindSocket(node, SOCK_OUT, "Value");
+
+  nodeSetSocketAvailability(sockB,
+                            !ELEM(node->custom1,
+                                  NODE_VECTOR_MATH_CEIL,
+                                  NODE_VECTOR_MATH_SCALE,
+                                  NODE_VECTOR_MATH_FLOOR,
+                                  NODE_VECTOR_MATH_LENGTH,
+                                  NODE_VECTOR_MATH_ABSOLUTE,
+                                  NODE_VECTOR_MATH_FRACTION,
+                                  NODE_VECTOR_MATH_NORMALIZE));
+  nodeSetSocketAvailability(sockScale, node->custom1 == NODE_VECTOR_MATH_SCALE);
+  nodeSetSocketAvailability(sockVector,
+                            !ELEM(node->custom1,
+                                  NODE_VECTOR_MATH_LENGTH,
+                                  NODE_VECTOR_MATH_DISTANCE,
+                                  NODE_VECTOR_MATH_DOT_PRODUCT));
+  nodeSetSocketAvailability(sockValue,
+                            ELEM(node->custom1,
+                                 NODE_VECTOR_MATH_LENGTH,
+                                 NODE_VECTOR_MATH_DISTANCE,
+                                 NODE_VECTOR_MATH_DOT_PRODUCT));
+}
+
+void register_node_type_sh_vect_math(void)
+{
+  static bNodeType ntype;
+
+  sh_node_type_base(&ntype, SH_NODE_VECTOR_MATH, "Vector Math", NODE_CLASS_CONVERTOR, 0);
+  node_type_socket_templates(&ntype, sh_node_vector_math_in, sh_node_vector_math_out);
+  node_type_label(&ntype, node_vector_math_label);
+  node_type_gpu(&ntype, gpu_shader_vector_math);
+  node_type_update(&ntype, node_shader_update_vector_math);
+
+  nodeRegisterType(&ntype);
+}