Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrecht Van Lommel <brechtvanlommel@gmail.com>2016-05-07 20:47:37 +0300
committerBrecht Van Lommel <brechtvanlommel@gmail.com>2016-05-22 18:29:24 +0300
commitec51175f1fd6c91d53b0d24daccfd5cc9bddf59d (patch)
tree1ad5b06b2318998cc4f03d78a8e7b1ce38e7cbf3 /intern/cycles/graph
parent841d008b98de5d0fa106ff3fa4731be63fc29f9a (diff)
Code refactor: add generic Cycles node infrastructure.
Differential Revision: https://developer.blender.org/D2016
Diffstat (limited to 'intern/cycles/graph')
-rw-r--r--intern/cycles/graph/CMakeLists.txt22
-rw-r--r--intern/cycles/graph/node.cpp354
-rw-r--r--intern/cycles/graph/node.h90
-rw-r--r--intern/cycles/graph/node_enum.h48
-rw-r--r--intern/cycles/graph/node_type.cpp190
-rw-r--r--intern/cycles/graph/node_type.h252
6 files changed, 956 insertions, 0 deletions
diff --git a/intern/cycles/graph/CMakeLists.txt b/intern/cycles/graph/CMakeLists.txt
new file mode 100644
index 00000000000..401bdb47392
--- /dev/null
+++ b/intern/cycles/graph/CMakeLists.txt
@@ -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
index 00000000000..d9a6bde4fcd
--- /dev/null
+++ b/intern/cycles/graph/node.cpp
@@ -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
index 00000000000..33971fa714a
--- /dev/null
+++ b/intern/cycles/graph/node.h
@@ -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
index 00000000000..2bae531c036
--- /dev/null
+++ b/intern/cycles/graph/node_enum.h
@@ -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
index 00000000000..dc879655d7f
--- /dev/null
+++ b/intern/cycles/graph/node_type.cpp
@@ -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
index 00000000000..82ddd29da33
--- /dev/null
+++ b/intern/cycles/graph/node_type.h
@@ -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
+