Code refactor: add generic Cycles node infrastructure.
authorBrecht Van Lommel <brechtvanlommel@gmail.com>
Sat, 7 May 2016 17:47:37 +0000 (19:47 +0200)
committerBrecht Van Lommel <brechtvanlommel@gmail.com>
Sun, 22 May 2016 15:29:24 +0000 (17:29 +0200)
Differential Revision: https://developer.blender.org/D2016

20 files changed:
build_files/cmake/macros.cmake
intern/cycles/CMakeLists.txt
intern/cycles/app/CMakeLists.txt
intern/cycles/blender/CMakeLists.txt
intern/cycles/bvh/CMakeLists.txt
intern/cycles/device/CMakeLists.txt
intern/cycles/graph/CMakeLists.txt [new file with mode: 0644]
intern/cycles/graph/node.cpp [new file with mode: 0644]
intern/cycles/graph/node.h [new file with mode: 0644]
intern/cycles/graph/node_enum.h [new file with mode: 0644]
intern/cycles/graph/node_type.cpp [new file with mode: 0644]
intern/cycles/graph/node_type.h [new file with mode: 0644]
intern/cycles/kernel/osl/CMakeLists.txt
intern/cycles/kernel/svm/svm_types.h
intern/cycles/render/CMakeLists.txt
intern/cycles/render/nodes.cpp
intern/cycles/render/svm.cpp
intern/cycles/render/svm.h
intern/cycles/subd/CMakeLists.txt
intern/cycles/util/util_vector.h

index 08d26e55ed430ee0973a331c9dbea422fb81693a..f14c954b0255dbe65c049c55e10a9e2872765104 100644 (file)
@@ -487,6 +487,7 @@ function(SETUP_BLENDER_SORTED_LIBS)
        if(WITH_CYCLES)
                list(APPEND BLENDER_LINK_LIBS
                        cycles_render
+                       cycles_graph
                        cycles_bvh
                        cycles_device
                        cycles_kernel
@@ -600,6 +601,7 @@ function(SETUP_BLENDER_SORTED_LIBS)
                bf_intern_dualcon
                bf_intern_cycles
                cycles_render
+               cycles_graph
                cycles_bvh
                cycles_device
                cycles_kernel
index efc36f0e6b8f6dfc4a046e0d10e32b1b2f4d8140..3b410b2a1e1751e07304b84394f9212489c34ff4 100644 (file)
@@ -237,6 +237,7 @@ endif()
 add_subdirectory(bvh)
 add_subdirectory(device)
 add_subdirectory(doc)
+add_subdirectory(graph)
 add_subdirectory(kernel)
 add_subdirectory(render)
 add_subdirectory(subd)
index d40a1a14f7232c87357b23019d603ad4a065dc52..73dbf16a3d3d9161cd91d7f66b5a24b435820be3 100644 (file)
@@ -1,13 +1,14 @@
 
 set(INC
        .
+       ../bvh
        ../device
+       ../graph
        ../kernel
        ../kernel/svm
-       ../bvh
-       ../util
        ../render
        ../subd
+       ../util
 )
 set(INC_SYS
 )
@@ -20,6 +21,7 @@ set(LIBRARIES
        cycles_render
        cycles_bvh
        cycles_subd
+       cycles_graph
        cycles_util
        ${BLENDER_GL_LIBRARIES}
        ${CYCLES_APP_GLEW_LIBRARY}
index a8cc4907cbf56ac14a7c4f47bb82dee57ed387f7..a79deca53e186e6ea87d30a9c1313a14de4b561e 100644 (file)
@@ -1,5 +1,6 @@
 
 set(INC
+       ../graph
        ../render
        ../device
        ../kernel
index cbbd23fcff82a2b932630f04f2f1ed6d779bc16c..5729fa6113d15808ab8cd4531aafe3ec02b8f6ff 100644 (file)
@@ -1,6 +1,7 @@
 
 set(INC
        .
+       ../graph
        ../kernel
        ../kernel/svm
        ../render
index 2a9ec0c38182eec2d6c74dc72514f1a9a10a5a3c..c34677e1b78a0876b43e484457043c0bb958c429 100644 (file)
@@ -1,6 +1,7 @@
 
 set(INC
        .
+       ../graph
        ../kernel
        ../kernel/svm
        ../kernel/osl
diff --git a/intern/cycles/graph/CMakeLists.txt b/intern/cycles/graph/CMakeLists.txt
new file mode 100644 (file)
index 0000000..401bdb4
--- /dev/null
@@ -0,0 +1,22 @@
+
+set(INC
+       .
+       ../util
+)
+
+set(SRC
+       node.cpp
+       node_type.cpp
+)
+
+set(SRC_HEADERS
+       node.h
+       node_enum.h
+       node_type.h
+)
+
+include_directories(${INC})
+include_directories(SYSTEM ${INC_SYS})
+
+add_library(cycles_graph ${SRC} ${SRC_HEADERS})
+
diff --git a/intern/cycles/graph/node.cpp b/intern/cycles/graph/node.cpp
new file mode 100644 (file)
index 0000000..d9a6bde
--- /dev/null
@@ -0,0 +1,354 @@
+/*
+ * Copyright 2011-2016 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 "node.h"
+#include "node_type.h"
+
+#include "util_foreach.h"
+#include "util_param.h"
+#include "util_transform.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Node Type */
+
+Node::Node(const NodeType *type_, ustring name_)
+: name(name_), type(type_)
+{
+       assert(type);
+
+       /* assign non-empty name, convenient for debugging */
+       if(name.empty()) {
+               name = type->name;
+       }
+
+       /* initialize default values */
+       typedef unordered_map<ustring, SocketType, ustringHash> map_type;
+       foreach(const map_type::value_type& it, type->inputs) {
+               const SocketType& socket = it.second;
+               const void *src = socket.default_value;
+               void *dst = ((char*)this) + socket.struct_offset;
+               memcpy(dst, src, socket.size());
+       }
+}
+
+Node::~Node()
+{
+}
+
+template<typename T>
+static T& get_socket_value(const Node *node, const SocketType& socket)
+{
+       return (T&)*(((char*)node) + socket.struct_offset);
+}
+
+static bool is_socket_float3(const SocketType& socket)
+{
+       return socket.type == SocketType::COLOR ||
+              socket.type == SocketType::POINT ||
+                  socket.type == SocketType::VECTOR ||
+                  socket.type == SocketType::NORMAL;
+}
+
+static bool is_socket_array_float3(const SocketType& socket)
+{
+       return socket.type == SocketType::COLOR_ARRAY ||
+              socket.type == SocketType::POINT_ARRAY ||
+                  socket.type == SocketType::VECTOR_ARRAY ||
+                  socket.type == SocketType::NORMAL_ARRAY;
+}
+
+/* set values */
+void Node::set(const SocketType& input, bool value)
+{
+       assert(input.type == SocketType::BOOLEAN);
+       get_socket_value<bool>(this, input) = value;
+}
+
+void Node::set(const SocketType& input, int value)
+{
+       assert((input.type == SocketType::INT || input.type == SocketType::ENUM));
+       get_socket_value<int>(this, input) = value;
+}
+
+void Node::set(const SocketType& input, float value)
+{
+       assert(input.type == SocketType::FLOAT);
+       get_socket_value<float>(this, input) = value;
+}
+
+void Node::set(const SocketType& input, float2 value)
+{
+       assert(input.type == SocketType::FLOAT);
+       get_socket_value<float2>(this, input) = value;
+}
+
+void Node::set(const SocketType& input, float3 value)
+{
+       assert(is_socket_float3(input));
+       get_socket_value<float3>(this, input) = value;
+}
+
+void Node::set(const SocketType& input, ustring value)
+{
+       if(input.type == SocketType::STRING) {
+               get_socket_value<ustring>(this, input) = value;
+       }
+       else if(input.type == SocketType::ENUM) {
+               const NodeEnum& enm = *input.enum_values;
+               if(enm.exists(value)) {
+                       get_socket_value<int>(this, input) = enm[value];
+               }
+               else {
+                       assert(0);
+               }
+       }
+       else {
+               assert(0);
+       }
+}
+
+void Node::set(const SocketType& input, const Transform& value)
+{
+       assert(input.type == SocketType::TRANSFORM);
+       get_socket_value<Transform>(this, input) = value;
+}
+
+void Node::set(const SocketType& input, Node *value)
+{
+       assert(input.type == SocketType::TRANSFORM);
+       get_socket_value<Node*>(this, input) = value;
+}
+
+/* set array values */
+void Node::set(const SocketType& input, array<bool>& value)
+{
+       assert(input.type == SocketType::BOOLEAN_ARRAY);
+       get_socket_value<array<bool> >(this, input).steal_data(value);
+}
+
+void Node::set(const SocketType& input, array<int>& value)
+{
+       assert(input.type == SocketType::INT_ARRAY);
+       get_socket_value<array<int> >(this, input).steal_data(value);
+}
+
+void Node::set(const SocketType& input, array<float>& value)
+{
+       assert(input.type == SocketType::FLOAT_ARRAY);
+       get_socket_value<array<float> >(this, input).steal_data(value);
+}
+
+void Node::set(const SocketType& input, array<float2>& value)
+{
+       assert(input.type == SocketType::FLOAT_ARRAY);
+       get_socket_value<array<float2> >(this, input).steal_data(value);
+}
+
+void Node::set(const SocketType& input, array<float3>& value)
+{
+       assert(is_socket_array_float3(input));
+       get_socket_value<array<float3> >(this, input).steal_data(value);
+}
+
+void Node::set(const SocketType& input, array<ustring>& value)
+{
+       assert(input.type == SocketType::STRING_ARRAY);
+       get_socket_value<array<ustring> >(this, input).steal_data(value);
+}
+
+void Node::set(const SocketType& input, array<Transform>& value)
+{
+       assert(input.type == SocketType::TRANSFORM_ARRAY);
+       get_socket_value<array<Transform> >(this, input).steal_data(value);
+}
+
+void Node::set(const SocketType& input, array<Node*>& value)
+{
+       assert(input.type == SocketType::TRANSFORM_ARRAY);
+       get_socket_value<array<Node*> >(this, input).steal_data(value);
+}
+
+/* get values */
+bool Node::get_bool(const SocketType& input) const
+{
+       assert(input.type == SocketType::BOOLEAN);
+       return get_socket_value<bool>(this, input);
+}
+
+int Node::get_int(const SocketType& input) const
+{
+       assert(input.type == SocketType::INT || input.type == SocketType::ENUM);
+       return get_socket_value<int>(this, input);
+}
+
+float Node::get_float(const SocketType& input) const
+{
+       assert(input.type == SocketType::FLOAT);
+       return get_socket_value<float>(this, input);
+}
+
+float2 Node::get_float2(const SocketType& input) const
+{
+       assert(input.type == SocketType::FLOAT);
+       return get_socket_value<float2>(this, input);
+}
+
+float3 Node::get_float3(const SocketType& input) const
+{
+       assert(is_socket_float3(input));
+       return get_socket_value<float3>(this, input);
+}
+
+ustring Node::get_string(const SocketType& input) const
+{
+       if(input.type == SocketType::STRING) {
+               return get_socket_value<ustring>(this, input);
+       }
+       else if(input.type == SocketType::ENUM) {
+               const NodeEnum& enm = *input.enum_values;
+               int intvalue = get_socket_value<int>(this, input);
+               return (enm.exists(intvalue)) ? enm[intvalue] : ustring();
+       }
+       else {
+               assert(0);
+               return ustring();
+       }
+}
+
+Transform Node::get_transform(const SocketType& input) const
+{
+       assert(input.type == SocketType::TRANSFORM);
+       return get_socket_value<Transform>(this, input);
+}
+
+Node *Node::get_node(const SocketType& input) const
+{
+       assert(input.type == SocketType::NODE);
+       return get_socket_value<Node*>(this, input);
+}
+
+/* get array values */
+const array<bool>& Node::get_bool_array(const SocketType& input) const
+{
+       assert(input.type == SocketType::BOOLEAN_ARRAY);
+       return get_socket_value<array<bool> >(this, input);
+}
+
+const array<int>& Node::get_int_array(const SocketType& input) const
+{
+       assert(input.type == SocketType::INT_ARRAY);
+       return get_socket_value<array<int> >(this, input);
+}
+
+const array<float>& Node::get_float_array(const SocketType& input) const
+{
+       assert(input.type == SocketType::FLOAT_ARRAY);
+       return get_socket_value<array<float> >(this, input);
+}
+
+const array<float2>& Node::get_float2_array(const SocketType& input) const
+{
+       assert(input.type == SocketType::FLOAT_ARRAY);
+       return get_socket_value<array<float2> >(this, input);
+}
+
+const array<float3>& Node::get_float3_array(const SocketType& input) const
+{
+       assert(is_socket_array_float3(input));
+       return get_socket_value<array<float3> >(this, input);
+}
+
+const array<ustring>& Node::get_string_array(const SocketType& input) const
+{
+       assert(input.type == SocketType::STRING_ARRAY);
+       return get_socket_value<array<ustring> >(this, input);
+}
+
+const array<Transform>& Node::get_transform_array(const SocketType& input) const
+{
+       assert(input.type == SocketType::TRANSFORM_ARRAY);
+       return get_socket_value<array<Transform> >(this, input);
+}
+
+const array<Node*>& Node::get_node_array(const SocketType& input) const
+{
+       assert(input.type == SocketType::NODE_ARRAY);
+       return get_socket_value<array<Node*> >(this, input);
+}
+
+/* default values */
+bool Node::has_default_value(const SocketType& input) const
+{
+       const void *src = input.default_value;
+       void *dst = &get_socket_value<char>(this, input);
+       return memcmp(dst, src, input.size()) == 0;
+}
+
+template<typename T>
+static bool is_array_equal(const Node *node, const Node *other, const SocketType& socket)
+{
+       const array<T>* a = (const array<T>*)(((char*)node) + socket.struct_offset);
+       const array<T>* b = (const array<T>*)(((char*)other) + socket.struct_offset);
+       return *a == *b;
+}
+
+/* modified */
+bool Node::modified(const Node& other)
+{
+       assert(type == other.type);
+
+       typedef unordered_map<ustring, SocketType, ustringHash> map_type;
+       foreach(const map_type::value_type& it, type->inputs) {
+               const SocketType& socket = it.second;
+
+               if(socket.is_array()) {
+                       bool equal = true;
+
+                       switch(socket.type)
+                       {
+                               case SocketType::BOOLEAN_ARRAY: equal = is_array_equal<bool>(this, &other, socket); break;
+                               case SocketType::FLOAT_ARRAY: equal = is_array_equal<float>(this, &other, socket); break;
+                               case SocketType::INT_ARRAY: equal = is_array_equal<int>(this, &other, socket); break;
+                               case SocketType::COLOR_ARRAY: equal = is_array_equal<float3>(this, &other, socket); break;
+                               case SocketType::VECTOR_ARRAY: equal = is_array_equal<float3>(this, &other, socket); break;
+                               case SocketType::POINT_ARRAY: equal = is_array_equal<float3>(this, &other, socket); break;
+                               case SocketType::NORMAL_ARRAY: equal = is_array_equal<float3>(this, &other, socket); break;
+                               case SocketType::POINT2_ARRAY: equal = is_array_equal<float2>(this, &other, socket); break;
+                               case SocketType::STRING_ARRAY: equal = is_array_equal<ustring>(this, &other, socket); break;
+                               case SocketType::TRANSFORM_ARRAY: equal = is_array_equal<Transform>(this, &other, socket); break;
+                               case SocketType::NODE_ARRAY: equal = is_array_equal<void*>(this, &other, socket); break;
+                               default: assert(0); break;
+                       }
+
+                       if(!equal) {
+                               return true;
+                       }
+               }
+               else {
+                       const void *a = ((char*)this) + socket.struct_offset;
+                       const void *b = ((char*)&other) + socket.struct_offset;
+                       if(memcmp(a, b, socket.size()) != 0) {
+                               return true;
+                       }
+               }
+       }
+
+       return false;
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/graph/node.h b/intern/cycles/graph/node.h
new file mode 100644 (file)
index 0000000..33971fa
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2011-2016 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.
+ */
+
+#pragma once
+
+#include "node_type.h"
+
+#include "util_map.h"
+#include "util_param.h"
+#include "util_vector.h"
+
+CCL_NAMESPACE_BEGIN
+
+struct Node;
+struct NodeType;
+struct Transform;
+
+/* Node */
+
+struct Node
+{
+       explicit Node(const NodeType *type, ustring name = ustring());
+       virtual ~Node();
+
+       /* set values */
+       void set(const SocketType& input, bool value);
+       void set(const SocketType& input, int value);
+       void set(const SocketType& input, float value);
+       void set(const SocketType& input, float2 value);
+       void set(const SocketType& input, float3 value);
+       void set(const SocketType& input, ustring value);
+       void set(const SocketType& input, const Transform& value);
+       void set(const SocketType& input, Node *value);
+
+       /* set array values. the memory from the input array will taken over
+        * by the node and the input array will be empty after return */
+       void set(const SocketType& input, array<bool>& value);
+       void set(const SocketType& input, array<int>& value);
+       void set(const SocketType& input, array<float>& value);
+       void set(const SocketType& input, array<float2>& value);
+       void set(const SocketType& input, array<float3>& value);
+       void set(const SocketType& input, array<ustring>& value);
+       void set(const SocketType& input, array<Transform>& value);
+       void set(const SocketType& input, array<Node*>& value);
+
+       /* get values */
+       bool get_bool(const SocketType& input) const;
+       int get_int(const SocketType& input) const;
+       float get_float(const SocketType& input) const;
+       float2 get_float2(const SocketType& input) const;
+       float3 get_float3(const SocketType& input) const;
+       ustring get_string(const SocketType& input) const;
+       Transform get_transform(const SocketType& input) const;
+       Node *get_node(const SocketType& input) const;
+
+       /* get array values */
+       const array<bool>& get_bool_array(const SocketType& input) const;
+       const array<int>& get_int_array(const SocketType& input) const;
+       const array<float>& get_float_array(const SocketType& input) const;
+       const array<float2>& get_float2_array(const SocketType& input) const;
+       const array<float3>& get_float3_array(const SocketType& input) const;
+       const array<ustring>& get_string_array(const SocketType& input) const;
+       const array<Transform>& get_transform_array(const SocketType& input) const;
+       const array<Node*>& get_node_array(const SocketType& input) const;
+
+       /* default values */
+       bool has_default_value(const SocketType& input) const;
+
+       /* modified */
+       bool modified(const Node& other);
+
+       ustring name;
+       const NodeType *type;
+};
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/graph/node_enum.h b/intern/cycles/graph/node_enum.h
new file mode 100644 (file)
index 0000000..2bae531
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright 2011-2016 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.
+ */
+
+#pragma once
+
+#include "util_map.h"
+#include "util_param.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Enum
+ *
+ * Utility class for enum values. */
+
+struct NodeEnum {
+       bool empty() const { return left.empty(); }
+       void insert(const char *x, int y) {
+               left[ustring(x)] = y;
+               right[y] = ustring(x);
+       }
+
+       bool exists(ustring x) const { return left.find(x) != left.end(); }
+       bool exists(int y) const { return right.find(y) != right.end(); }
+
+       int operator[](const char *x) const { return left.find(ustring(x))->second; }
+       int operator[](ustring x) const { return left.find(x)->second; }
+       ustring operator[](int y) const { return right.find(y)->second; }
+
+private:
+       unordered_map<ustring, int, ustringHash> left;
+       unordered_map<int, ustring> right;
+};
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/graph/node_type.cpp b/intern/cycles/graph/node_type.cpp
new file mode 100644 (file)
index 0000000..dc87965
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * Copyright 2011-2016 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 "node_type.h"
+#include "util_foreach.h"
+#include "util_transform.h"
+
+CCL_NAMESPACE_BEGIN
+
+/* Node Socket Type */
+
+size_t SocketType::size() const
+{
+       return size(type);
+}
+
+bool SocketType::is_array() const
+{
+       return (type >= BOOLEAN_ARRAY);
+}
+
+size_t SocketType::size(Type type)
+{
+       switch(type)
+       {
+               case UNDEFINED: return 0;
+
+               case BOOLEAN: return sizeof(bool);
+               case FLOAT: return sizeof(float);
+               case INT: return sizeof(int);
+               case COLOR: return sizeof(float3);
+               case VECTOR: return sizeof(float3);
+               case POINT: return sizeof(float3);
+               case NORMAL: return sizeof(float3);
+               case POINT2: return sizeof(float2);
+               case CLOSURE: return 0;
+               case STRING: return sizeof(ustring);
+               case ENUM: return sizeof(int);
+               case TRANSFORM: return sizeof(Transform);
+               case NODE: return sizeof(void*);
+
+               case BOOLEAN_ARRAY: return sizeof(array<bool>);
+               case FLOAT_ARRAY: return sizeof(array<float>);
+               case INT_ARRAY: return sizeof(array<int>);
+               case COLOR_ARRAY: return sizeof(array<float3>);
+               case VECTOR_ARRAY: return sizeof(array<float3>);
+               case POINT_ARRAY: return sizeof(array<float3>);
+               case NORMAL_ARRAY: return sizeof(array<float3>);
+               case POINT2_ARRAY: return sizeof(array<float2>);
+               case STRING_ARRAY: return sizeof(array<ustring>);
+               case TRANSFORM_ARRAY: return sizeof(array<Transform>);
+               case NODE_ARRAY: return sizeof(array<void*>);
+       }
+
+       assert(0);
+       return 0;
+}
+
+size_t SocketType::max_size()
+{
+       return sizeof(Transform);
+}
+
+void *SocketType::zero_default_value()
+{
+       static Transform zero_transform = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}};
+       return &zero_transform;
+}
+
+ustring SocketType::type_name(Type type)
+{
+       static ustring names[] = {
+               ustring("undefined"),
+
+               ustring("boolean"),
+               ustring("float"),
+               ustring("int"),
+               ustring("color"),
+               ustring("vector"),
+               ustring("point"),
+               ustring("normal"),
+               ustring("point2"),
+               ustring("closure"),
+               ustring("string"),
+               ustring("enum"),
+               ustring("transform"),
+               ustring("node"),
+
+               ustring("array_boolean"),
+               ustring("array_float"),
+               ustring("array_int"),
+               ustring("array_color"),
+               ustring("array_vector"),
+               ustring("array_point"),
+               ustring("array_normal"),
+               ustring("array_point2"),
+               ustring("array_string"),
+               ustring("array_transform"),
+               ustring("array_node")};
+
+       return names[(int)type];
+}
+
+/* Node Type */
+
+NodeType::NodeType()
+{
+}
+
+NodeType::~NodeType()
+{
+}
+
+void NodeType::register_input(ustring name, ustring ui_name, SocketType::Type type, int struct_offset,
+                              const void *default_value, const NodeEnum *enum_values,
+                                                         const NodeType **node_type, int flags, int extra_flags)
+{
+       SocketType socket;
+       socket.name = name;
+       socket.ui_name = ui_name;
+       socket.type = type;
+       socket.struct_offset = struct_offset;
+       socket.default_value = default_value;
+       socket.enum_values = enum_values;
+       socket.node_type = node_type;
+       socket.flags = flags | extra_flags;
+       inputs[name] = socket;
+}
+
+void NodeType::register_output(ustring name, ustring ui_name, SocketType::Type type)
+{
+       SocketType socket;
+       socket.name = name;
+       socket.ui_name = ui_name;
+       socket.type = type;
+       socket.struct_offset = 0;
+       socket.default_value = NULL;
+       socket.enum_values = NULL;
+       socket.node_type = NULL;
+       socket.flags = SocketType::LINKABLE;
+       outputs[name] = socket;
+}
+
+/* Node Type Registry */
+
+unordered_map<ustring, NodeType, ustringHash>& NodeType::types()
+{
+       static unordered_map<ustring, NodeType, ustringHash> _types;
+       return _types;
+}
+
+NodeType *NodeType::add(const char *name_, CreateFunc create_)
+{
+       ustring name(name_);
+
+       if(types().find(name) != types().end()) {
+               fprintf(stderr, "Node type %s registered twice!\n", name_);
+               assert(0);
+               return NULL;
+       }
+
+       types()[name] = NodeType();
+
+       NodeType *type = &types()[name];
+       type->name = name;
+       type->create = create_;
+       return type;
+}
+
+const NodeType *NodeType::find(ustring name)
+{
+       unordered_map<ustring, NodeType, ustringHash>::iterator it = types().find(name);
+       return (it == types().end()) ? NULL : &it->second;
+}
+
+CCL_NAMESPACE_END
+
diff --git a/intern/cycles/graph/node_type.h b/intern/cycles/graph/node_type.h
new file mode 100644 (file)
index 0000000..82ddd29
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * Copyright 2011-2016 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.
+ */
+
+#pragma once
+
+#include "node_enum.h"
+
+#include "util_map.h"
+#include "util_param.h"
+#include "util_string.h"
+
+CCL_NAMESPACE_BEGIN
+
+struct Node;
+struct NodeType;
+
+/* Socket Type */
+
+struct SocketType
+{
+       enum Type
+       {
+               UNDEFINED,
+
+               BOOLEAN,
+               FLOAT,
+               INT,
+               COLOR,
+               VECTOR,
+               POINT,
+               NORMAL,
+               POINT2,
+               CLOSURE,
+               STRING,
+               ENUM,
+               TRANSFORM,
+               NODE,
+
+               BOOLEAN_ARRAY,
+               FLOAT_ARRAY,
+               INT_ARRAY,
+               COLOR_ARRAY,
+               VECTOR_ARRAY,
+               POINT_ARRAY,
+               NORMAL_ARRAY,
+               POINT2_ARRAY,
+               STRING_ARRAY,
+               TRANSFORM_ARRAY,
+               NODE_ARRAY,
+       };
+
+       enum Flags {
+               LINKABLE               = (1 << 0),
+               ANIMATABLE             = (1 << 1),
+
+               SVM_INTERNAL           = (1 << 2),
+               OSL_INTERNAL           = (1 << 3),
+               INTERNAL               = (1 << 2) | (1 << 3),
+
+               LINK_TEXTURE_GENERATED = (1 << 4),
+               LINK_TEXTURE_UV        = (1 << 5),
+               LINK_INCOMING          = (1 << 6),
+               LINK_NORMAL            = (1 << 7),
+               LINK_POSITION          = (1 << 8),
+               LINK_TANGENT           = (1 << 9),
+               DEFAULT_LINK_MASK      = (1 << 4) | (1 << 5) | (1 << 6) | (1 << 7) | (1 << 8) | (1 << 9)
+       };
+
+       ustring name;
+       Type type;
+       int struct_offset;
+       const void *default_value;
+       const NodeEnum *enum_values;
+       const NodeType **node_type;
+       int flags;
+       ustring ui_name;
+
+       size_t size() const;
+       bool is_array() const;
+       static size_t size(Type type);
+       static size_t max_size();
+       static ustring type_name(Type type);
+       static void *zero_default_value();
+};
+
+/* Node Type */
+
+struct NodeType
+{
+       explicit NodeType();
+       ~NodeType();
+
+       void register_input(ustring name, ustring ui_name, SocketType::Type type,
+                           int struct_offset, const void *default_value,
+                                               const NodeEnum *enum_values = NULL,
+                                               const NodeType **node_type = NULL,
+                                               int flags = 0, int extra_flags = 0);
+       void register_output(ustring name, ustring ui_name, SocketType::Type type);
+
+       typedef Node *(*CreateFunc)(const NodeType *type);
+       typedef unordered_map<ustring, SocketType, ustringHash> SocketMap;
+
+       ustring name;
+       SocketMap inputs;
+       SocketMap outputs;
+       CreateFunc create;
+
+       static NodeType *add(const char *name, CreateFunc create);
+       static const NodeType *find(ustring name);
+       static unordered_map<ustring, NodeType, ustringHash>& types();
+};
+
+/* Node Definition Macros */
+
+#define NODE_DECLARE                       \
+template<typename T>                       \
+static const NodeType *register_type();    \
+static Node *create(const NodeType *type); \
+static const NodeType *node_type;
+
+#define NODE_DEFINE(structname)                                                  \
+const NodeType *structname::node_type = structname::register_type<structname>(); \
+Node *structname::create(const NodeType*) { return new structname(); }           \
+template<typename T>                                                             \
+const NodeType *structname::register_type()
+
+/* Sock Definition Macros */
+
+#define SOCKET_OFFSETOF(T, name) (((char *)&(((T *)1)->name)) - (char *)1)
+#define SOCKET_SIZEOF(T, name) (sizeof(((T *)1)->name))
+#define SOCKET_DEFINE(name, ui_name, default_value, datatype, TYPE, flags, ...) \
+       { \
+               static datatype defval = default_value; \
+               assert(SOCKET_SIZEOF(T, name) == sizeof(datatype)); \
+               type->register_input(ustring(#name), ustring(ui_name), TYPE, SOCKET_OFFSETOF(T, name), &defval, NULL, NULL, flags, ##__VA_ARGS__); \
+       }
+
+#define SOCKET_BOOLEAN(name, ui_name, default_value, ...) \
+       SOCKET_DEFINE(name, ui_name, default_value, bool, SocketType::BOOLEAN, 0, ##__VA_ARGS__)
+#define SOCKET_INT(name, ui_name, default_value, ...) \
+       SOCKET_DEFINE(name, ui_name, default_value, int, SocketType::INT, 0, ##__VA_ARGS__)
+#define SOCKET_FLOAT(name, ui_name, default_value, ...) \
+       SOCKET_DEFINE(name, ui_name, default_value, float, SocketType::FLOAT, 0, ##__VA_ARGS__)
+#define SOCKET_COLOR(name, ui_name, default_value, ...) \
+       SOCKET_DEFINE(name, ui_name, default_value, float3, SocketType::COLOR, 0, ##__VA_ARGS__)
+#define SOCKET_VECTOR(name, ui_name, default_value, ...) \
+       SOCKET_DEFINE(name, ui_name, default_value, float3, SocketType::VECTOR, 0, ##__VA_ARGS__)
+#define SOCKET_POINT(name, ui_name, default_value, ...) \
+       SOCKET_DEFINE(name, ui_name, default_value, float3, SocketType::POINT, 0, ##__VA_ARGS__)
+#define SOCKET_NORMAL(name, ui_name, default_value, ...) \
+       SOCKET_DEFINE(name, ui_name, default_value, float3, SocketType::NORMAL, 0, ##__VA_ARGS__)
+#define SOCKET_POINT2(name, ui_name, default_value, ...) \
+       SOCKET_DEFINE(name, ui_name, default_value, float2, SocketType::POINT2, 0, ##__VA_ARGS__)
+#define SOCKET_STRING(name, ui_name, default_value, ...) \
+       SOCKET_DEFINE(name, ui_name, default_value, ustring, SocketType::STRING, 0, ##__VA_ARGS__)
+#define SOCKET_TRANSFORM(name, ui_name, default_value, ...) \
+       SOCKET_DEFINE(name, ui_name, default_value, Transform, SocketType::TRANSFORM, 0, ##__VA_ARGS__)
+#define SOCKET_ENUM(name, ui_name, values, default_value, ...) \
+       { \
+               static int defval = default_value; \
+               assert(SOCKET_SIZEOF(T, name) == sizeof(int)); \
+               type->register_input(ustring(#name), ustring(ui_name), SocketType::ENUM, SOCKET_OFFSETOF(T, name), &defval, &values, NULL, ##__VA_ARGS__); \
+       }
+#define SOCKET_NODE(name, ui_name, node_type, ...) \
+       { \
+           static Node *defval = NULL; \
+               assert(SOCKET_SIZEOF(T, name) == sizeof(Node*)); \
+               type->register_input(ustring(#name), ustring(ui_name), SocketType::NODE, SOCKET_OFFSETOF(T, name), &defval, NULL, node_type, ##__VA_ARGS__); \
+       }
+
+#define SOCKET_BOOLEAN_ARRAY(name, ui_name, default_value, ...) \
+       SOCKET_DEFINE(name, ui_name, default_value, array<bool>, SocketType::BOOLEAN_ARRAY, 0, ##__VA_ARGS__)
+#define SOCKET_INT_ARRAY(name, ui_name, default_value, ...) \
+       SOCKET_DEFINE(name, ui_name, default_value, array<int>, SocketType::INT_ARRAY, 0, ##__VA_ARGS__)
+#define SOCKET_FLOAT_ARRAY(name, ui_name, default_value, ...) \
+       SOCKET_DEFINE(name, ui_name, default_value, array<float>, SocketType::FLOAT_ARRAY, 0, ##__VA_ARGS__)
+#define SOCKET_COLOR_ARRAY(name, ui_name, default_value, ...) \
+       SOCKET_DEFINE(name, ui_name, default_value, array<float3>, SocketType::COLOR_ARRAY, 0, ##__VA_ARGS__)
+#define SOCKET_VECTOR_ARRAY(name, ui_name, default_value, ...) \
+       SOCKET_DEFINE(name, ui_name, default_value, array<float3>, SocketType::VECTOR_ARRAY, 0, ##__VA_ARGS__)
+#define SOCKET_POINT_ARRAY(name, ui_name, default_value, ...) \
+       SOCKET_DEFINE(name, ui_name, default_value, array<float3>, SocketType::POINT_ARRAY, 0, ##__VA_ARGS__)
+#define SOCKET_NORMAL_ARRAY(name, ui_name, default_value, ...) \
+       SOCKET_DEFINE(name, ui_name, default_value, array<float3>, SocketType::NORMAL_ARRAY, 0, ##__VA_ARGS__)
+#define SOCKET_POINT2_ARRAY(name, ui_name, default_value, ...) \
+       SOCKET_DEFINE(name, ui_name, default_value, array<float2>, SocketType::POINT2_ARRAY, 0, ##__VA_ARGS__)
+#define SOCKET_STRING_ARRAY(name, ui_name, default_value, ...) \
+       SOCKET_DEFINE(name, ui_name, default_value, array<ustring>, SocketType::STRING_ARRAY, 0, ##__VA_ARGS__)
+#define SOCKET_TRANSFORM_ARRAY(name, ui_name, default_value, ...) \
+       SOCKET_DEFINE(name, ui_name, default_value, array<Transform>, SocketType::TRANSFORM_ARRAY, 0, ##__VA_ARGS__)
+#define SOCKET_NODE_ARRAY(name, ui_name, node_type, ...) \
+       { \
+           static Node *defval = NULL; \
+               assert(SOCKET_SIZEOF(T, name) == sizeof(Node*)); \
+               type->register_input(ustring(#name), ustring(ui_name), SocketType::NODE_ARRAY, SOCKET_OFFSETOF(T, name), &defval, NULL, node_type, ##__VA_ARGS__); \
+       }
+
+#define SOCKET_IN_BOOLEAN(name, ui_name, default_value, ...) \
+       SOCKET_DEFINE(name, ui_name, default_value, bool, SocketType::BOOLEAN, SocketType::LINKABLE, ##__VA_ARGS__)
+#define SOCKET_IN_INT(name, ui_name, default_value, ...) \
+       SOCKET_DEFINE(name, ui_name, default_value, int, SocketType::INT, SocketType::LINKABLE, ##__VA_ARGS__)
+#define SOCKET_IN_FLOAT(name, ui_name, default_value, ...) \
+       SOCKET_DEFINE(name, ui_name, default_value, float, SocketType::FLOAT, SocketType::LINKABLE, ##__VA_ARGS__)
+#define SOCKET_IN_COLOR(name, ui_name, default_value, ...) \
+       SOCKET_DEFINE(name, ui_name, default_value, float3, SocketType::COLOR, SocketType::LINKABLE, ##__VA_ARGS__)
+#define SOCKET_IN_VECTOR(name, ui_name, default_value, ...) \
+       SOCKET_DEFINE(name, ui_name, default_value, float3, SocketType::VECTOR, SocketType::LINKABLE, ##__VA_ARGS__)
+#define SOCKET_IN_POINT(name, ui_name, default_value, ...) \
+       SOCKET_DEFINE(name, ui_name, default_value, float3, SocketType::POINT, SocketType::LINKABLE, ##__VA_ARGS__)
+#define SOCKET_IN_NORMAL(name, ui_name, default_value, ...) \
+       SOCKET_DEFINE(name, ui_name, default_value, float3, SocketType::NORMAL, SocketType::LINKABLE, ##__VA_ARGS__)
+#define SOCKET_IN_STRING(name, ui_name, default_value, ...) \
+       SOCKET_DEFINE(name, ui_name, default_value, ustring, SocketType::STRING, SocketType::LINKABLE, ##__VA_ARGS__)
+#define SOCKET_IN_CLOSURE(name, ui_name, ...) \
+       type->register_input(ustring(#name), ustring(ui_name), SocketType::CLOSURE, 0, NULL, NULL, NULL, SocketType::LINKABLE, ##__VA_ARGS__)
+
+#define SOCKET_OUT_BOOLEAN(name, ui_name) \
+       { type->register_output(ustring(#name), ustring(ui_name), SocketType::BOOLEAN); }
+#define SOCKET_OUT_INT(name, ui_name) \
+       { type->register_output(ustring(#name), ustring(ui_name), SocketType::INT); }
+#define SOCKET_OUT_FLOAT(name, ui_name) \
+       { type->register_output(ustring(#name), ustring(ui_name), SocketType::FLOAT); }
+#define SOCKET_OUT_COLOR(name, ui_name) \
+       { type->register_output(ustring(#name), ustring(ui_name), SocketType::COLOR); }
+#define SOCKET_OUT_VECTOR(name, ui_name) \
+       { type->register_output(ustring(#name), ustring(ui_name), SocketType::VECTOR); }
+#define SOCKET_OUT_POINT(name, ui_name) \
+       { type->register_output(ustring(#name), ustring(ui_name), SocketType::POINT); }
+#define SOCKET_OUT_NORMAL(name, ui_name) \
+       { type->register_output(ustring(#name), ustring(ui_name), SocketType::NORMAL); }
+#define SOCKET_OUT_CLOSURE(name, ui_name) \
+       { type->register_output(ustring(#name), ustring(ui_name), SocketType::CLOSURE); }
+#define SOCKET_OUT_STRING(name, ui_name) \
+       { type->register_output(ustring(#name), ustring(ui_name), SocketType::STRING); }
+#define SOCKET_OUT_ENUM(name, ui_name) \
+       { type->register_output(ustring(#name), ustring(ui_name), SocketType::ENUM); }
+
+CCL_NAMESPACE_END
+
index b10ec5887573c19c74f63c6af8439528a672ca5b..9cf4f2d759a7876a9791e66d2906a7009580bca1 100644 (file)
@@ -3,6 +3,7 @@ set(INC
        .
        ..
        ../svm
+       ../../graph
        ../../render
        ../../util
        ../../device
index 21b0cb15a4f3f30078fd52fcc2ea70df94122359..8c69c589ebb72976804d5109f70c27c82f1bb746 100644 (file)
@@ -51,7 +51,7 @@ CCL_NAMESPACE_BEGIN
  */
 #define NODE_FEATURE_ALL        (NODE_FEATURE_VOLUME|NODE_FEATURE_HAIR|NODE_FEATURE_BUMP)
 
-typedef enum NodeType {
+typedef enum ShaderNodeType {
        NODE_END = 0,
        NODE_CLOSURE_BSDF,
        NODE_CLOSURE_EMISSION,
@@ -127,7 +127,7 @@ typedef enum NodeType {
        NODE_HAIR_INFO,
        NODE_UVMAP,
        NODE_TEX_VOXEL,
-} NodeType;
+} ShaderNodeType;
 
 typedef enum NodeAttributeType {
        NODE_ATTR_FLOAT = 0,
index 38450a9f7627567d052e01b026ad39a608098be9..b14da3e63d0e7550a17a48abd8e2602d5e389914 100644 (file)
@@ -2,6 +2,7 @@
 set(INC
        .
        ../device
+       ../graph
        ../kernel
        ../kernel/svm
        ../kernel/osl
index b14363d076766b486d12713c601b86fc6e0d196d..110bbca85769547d9ee5819bc18de3e832b7cb4d 100644 (file)
@@ -2476,8 +2476,8 @@ void GeometryNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 void GeometryNode::compile(SVMCompiler& compiler)
 {
        ShaderOutput *out;
-       NodeType geom_node = NODE_GEOMETRY;
-       NodeType attr_node = NODE_ATTR;
+       ShaderNodeType geom_node = NODE_GEOMETRY;
+       ShaderNodeType attr_node = NODE_ATTR;
 
        if(bump == SHADER_BUMP_DX) {
                geom_node = NODE_GEOMETRY_BUMP_DX;
@@ -2593,9 +2593,9 @@ void TextureCoordinateNode::attributes(Shader *shader, AttributeRequestSet *attr
 void TextureCoordinateNode::compile(SVMCompiler& compiler)
 {
        ShaderOutput *out;
-       NodeType texco_node = NODE_TEX_COORD;
-       NodeType attr_node = NODE_ATTR;
-       NodeType geom_node = NODE_GEOMETRY;
+       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;
@@ -2726,8 +2726,8 @@ void UVMapNode::attributes(Shader *shader, AttributeRequestSet *attributes)
 void UVMapNode::compile(SVMCompiler& compiler)
 {
        ShaderOutput *out = output("UV");
-       NodeType texco_node = NODE_TEX_COORD;
-       NodeType attr_node = NODE_ATTR;
+       ShaderNodeType texco_node = NODE_TEX_COORD;
+       ShaderNodeType attr_node = NODE_ATTR;
        int attr;
 
        if(bump == SHADER_BUMP_DX) {
@@ -3757,7 +3757,7 @@ void AttributeNode::compile(SVMCompiler& compiler)
        ShaderOutput *color_out = output("Color");
        ShaderOutput *vector_out = output("Vector");
        ShaderOutput *fac_out = output("Fac");
-       NodeType attr_node = NODE_ATTR;
+       ShaderNodeType attr_node = NODE_ATTR;
        AttributeStandard std = Attribute::name_standard(attribute.c_str());
        int attr;
 
index ab4fe4193dbefcab7b1ca543e5fdd197f8aececb..4c97a5ad792c845d8ae65ca0402f90a30b476937 100644 (file)
@@ -314,12 +314,12 @@ void SVMCompiler::add_node(int a, int b, int c, int d)
        svm_nodes.push_back(make_int4(a, b, c, d));
 }
 
-void SVMCompiler::add_node(NodeType type, int a, int b, int c)
+void SVMCompiler::add_node(ShaderNodeType type, int a, int b, int c)
 {
        svm_nodes.push_back(make_int4(type, a, b, c));
 }
 
-void SVMCompiler::add_node(NodeType type, const float3& f)
+void SVMCompiler::add_node(ShaderNodeType type, const float3& f)
 {
        svm_nodes.push_back(make_int4(type,
                __float_as_int(f.x),
index c85c866ddbd37505bc45b778a5418ccaf35aa666..dbf1b1de94761798259ba65c1ead1ac68aa43793 100644 (file)
@@ -103,9 +103,9 @@ public:
        void stack_clear_offset(ShaderSocketType type, int offset);
        void stack_link(ShaderInput *input, ShaderOutput *output);
 
-       void add_node(NodeType type, int a = 0, int b = 0, int c = 0);
+       void add_node(ShaderNodeType type, int a = 0, int b = 0, int c = 0);
        void add_node(int a = 0, int b = 0, int c = 0, int d = 0);
-       void add_node(NodeType type, const float3& f);
+       void add_node(ShaderNodeType type, const float3& f);
        void add_node(const float4& f);
        uint attribute(ustring name);
        uint attribute(AttributeStandard std);
index 1ccf80d945716810319691c2b56043fbc12cb457..d1708868fd061abc5e9e322ca4186f8e6052c065 100644 (file)
@@ -1,10 +1,11 @@
 
 set(INC
        .
-       ../util
+       ../graph
        ../kernel
        ../kernel/svm
        ../render
+       ../util
 )
 
 set(INC_SYS
index 8f833af18446d19d4483e1f65f684ff9fd8c8d54..6f8c3f6f3de3bfaf9c6bfabf4a8499bc33114839 100644 (file)
@@ -153,7 +153,7 @@ public:
                mem_free(data_, capacity_);
        }
 
-       bool operator==(const vector<T>& other)
+       bool operator==(const array<T>& other) const
        {
                if(datasize_ != other.datasize_) {
                        return false;
@@ -162,6 +162,21 @@ public:
                return memcmp(data_, other.data_, datasize_*sizeof(T)) == 0;
        }
 
+       void steal_data(array& from)
+       {
+               if(this != &from) {
+                       clear();
+
+                       data_ = from.data_;
+                       datasize_ = from.datasize_;
+                       capacity_ = from.capacity_;
+
+                       from.data_ = NULL;
+                       from.datasize_ = 0;
+                       from.capacity_ = 0;
+               }
+       }
+
        T* resize(size_t newsize)
        {
                if(newsize == 0) {