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:
-rw-r--r--release/scripts/startup/bl_operators/__init__.py2
-rw-r--r--release/scripts/startup/bl_operators/geometry_nodes.py (renamed from release/scripts/startup/bl_operators/simulation.py)23
-rw-r--r--release/scripts/startup/bl_ui/space_node.py11
-rw-r--r--release/scripts/startup/nodeitems_builtins.py41
-rw-r--r--source/blender/blenkernel/BKE_geometry.hh204
-rw-r--r--source/blender/blenkernel/BKE_node.h32
-rw-r--r--source/blender/blenkernel/CMakeLists.txt2
-rw-r--r--source/blender/blenkernel/intern/geometry.cc152
-rw-r--r--source/blender/blenkernel/intern/node.c24
-rw-r--r--source/blender/blenkernel/intern/pointcache.c3
-rw-r--r--source/blender/blenkernel/intern/simulation.cc4
-rw-r--r--source/blender/blenloader/intern/readfile.c1
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_build.h3
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc12
-rw-r--r--source/blender/editors/include/ED_node.h2
-rw-r--r--source/blender/editors/space_node/drawnode.c11
-rw-r--r--source/blender/editors/space_node/node_draw.c3
-rw-r--r--source/blender/editors/space_node/node_edit.c14
-rw-r--r--source/blender/editors/space_node/node_group.c8
-rw-r--r--source/blender/editors/space_node/node_relationships.c4
-rw-r--r--source/blender/editors/space_node/space_node.c2
-rw-r--r--source/blender/functions/CMakeLists.txt1
-rw-r--r--source/blender/functions/FN_cpp_type.hh136
-rw-r--r--source/blender/functions/FN_generic_pointer.hh76
-rw-r--r--source/blender/makesdna/DNA_modifier_defaults.h2
-rw-r--r--source/blender/makesdna/DNA_modifier_types.h7
-rw-r--r--source/blender/makesdna/DNA_node_types.h15
-rw-r--r--source/blender/makesdna/intern/dna_defaults.c4
-rw-r--r--source/blender/makesrna/RNA_access.h6
-rw-r--r--source/blender/makesrna/intern/rna_modifier.c34
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c66
-rw-r--r--source/blender/makesrna/intern/rna_space.c48
-rw-r--r--source/blender/modifiers/CMakeLists.txt4
-rw-r--r--source/blender/modifiers/MOD_modifiertypes.h2
-rw-r--r--source/blender/modifiers/intern/MOD_edgesplit.c5
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc436
-rw-r--r--source/blender/modifiers/intern/MOD_simulation.cc194
-rw-r--r--source/blender/modifiers/intern/MOD_triangulate.c16
-rw-r--r--source/blender/modifiers/intern/MOD_util.c2
-rw-r--r--source/blender/nodes/CMakeLists.txt19
-rw-r--r--source/blender/nodes/NOD_derived_node_tree.hh24
-rw-r--r--source/blender/nodes/NOD_geometry.h (renamed from source/blender/nodes/NOD_simulation.h)9
-rw-r--r--source/blender/nodes/NOD_geometry_exec.hh92
-rw-r--r--source/blender/nodes/NOD_node_tree_multi_function.hh51
-rw-r--r--source/blender/nodes/NOD_node_tree_ref.hh6
-rw-r--r--source/blender/nodes/NOD_static_types.h3
-rw-r--r--source/blender/nodes/NOD_type_callbacks.hh36
-rw-r--r--source/blender/nodes/function/node_function_util.cc2
-rw-r--r--source/blender/nodes/function/nodes/node_fn_random_float.cc2
-rw-r--r--source/blender/nodes/geometry/node_geometry_exec.cc23
-rw-r--r--source/blender/nodes/geometry/node_geometry_tree.cc (renamed from source/blender/nodes/simulation/node_simulation_tree.cc)20
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.cc (renamed from source/blender/nodes/simulation/node_simulation_util.cc)10
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.hh (renamed from source/blender/nodes/simulation/node_simulation_util.h)7
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_common.cc (renamed from source/blender/nodes/simulation/nodes/node_sim_common.cc)12
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_edge_split.cc83
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_triangulate.cc64
-rw-r--r--source/blender/nodes/intern/node_socket.cc65
-rw-r--r--source/blender/nodes/intern/node_tree_multi_function.cc227
-rw-r--r--source/blender/nodes/intern/type_callbacks.cc76
-rw-r--r--source/blender/nodes/shader/node_shader_util.c2
60 files changed, 1958 insertions, 487 deletions
diff --git a/release/scripts/startup/bl_operators/__init__.py b/release/scripts/startup/bl_operators/__init__.py
index c927cc184a3..7682effaf41 100644
--- a/release/scripts/startup/bl_operators/__init__.py
+++ b/release/scripts/startup/bl_operators/__init__.py
@@ -31,6 +31,7 @@ _modules = [
"console",
"constraint",
"file",
+ "geometry_nodes",
"image",
"mesh",
"node",
@@ -42,7 +43,6 @@ _modules = [
"rigidbody",
"screen_play_rendered_anim",
"sequencer",
- "simulation",
"userpref",
"uvcalc_follow_active",
"uvcalc_lightmap",
diff --git a/release/scripts/startup/bl_operators/simulation.py b/release/scripts/startup/bl_operators/geometry_nodes.py
index 0981baa5941..7643c49f33e 100644
--- a/release/scripts/startup/bl_operators/simulation.py
+++ b/release/scripts/startup/bl_operators/geometry_nodes.py
@@ -19,23 +19,30 @@
import bpy
-class NewSimulation(bpy.types.Operator):
- """Create a new simulation data block and edit it in the opened simulation editor"""
+class NewGeometryNodeTree(bpy.types.Operator):
+ """Create a new geometry node tree"""
- bl_idname = "simulation.new"
- bl_label = "New Simulation"
+ bl_idname = "node.new_geometry_node_tree"
+ bl_label = "New Geometry Node Tree"
bl_options = {'REGISTER', 'UNDO'}
@classmethod
def poll(cls, context):
- return context.area.type == 'NODE_EDITOR' and context.space_data.tree_type == 'SimulationNodeTree'
+ return context.area.type == 'NODE_EDITOR' and context.space_data.tree_type == 'GeometryNodeTree'
def execute(self, context):
- simulation = bpy.data.simulations.new("Simulation")
- context.space_data.simulation = simulation
+ group = bpy.data.node_groups.new("Geometry Node Group", 'GeometryNodeTree')
+ group.inputs.new('NodeSocketGeometry', "Geometry")
+ group.outputs.new('NodeSocketGeometry', "Geometry")
+ input_node = group.nodes.new('NodeGroupInput')
+ output_node = group.nodes.new('NodeGroupOutput')
+
+ input_node.location.x = -200 - input_node.width
+ output_node.location.x = 200
+ context.space_data.node_tree = group
return {'FINISHED'}
classes = (
- NewSimulation,
+ NewGeometryNodeTree,
)
diff --git a/release/scripts/startup/bl_ui/space_node.py b/release/scripts/startup/bl_ui/space_node.py
index c0c38c02c63..4cd38831cdf 100644
--- a/release/scripts/startup/bl_ui/space_node.py
+++ b/release/scripts/startup/bl_ui/space_node.py
@@ -151,13 +151,10 @@ class NODE_HT_header(Header):
if snode_id:
layout.prop(snode_id, "use_nodes")
- elif snode.tree_type == 'SimulationNodeTree':
- row = layout.row(align=True)
- row.prop(snode, "simulation", text="")
- row.operator("simulation.new", text="", icon='ADD')
- simulation = snode.simulation
- if simulation:
- row.prop(snode.simulation, "use_fake_user", text="")
+ elif snode.tree_type == 'GeometryNodeTree':
+ NODE_MT_editor_menus.draw_collapsible(context, layout)
+ layout.separator_spacer()
+ layout.template_ID(snode, "node_tree", new="node.new_geometry_node_tree")
else:
# Custom node tree is edited as independent ID block
diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py
index 8d2b6198fd5..d95ec5d840d 100644
--- a/release/scripts/startup/nodeitems_builtins.py
+++ b/release/scripts/startup/nodeitems_builtins.py
@@ -58,11 +58,11 @@ class TextureNodeCategory(SortedNodeCategory):
context.space_data.tree_type == 'TextureNodeTree')
-class SimulationNodeCategory(SortedNodeCategory):
+class GeometryNodeCategory(SortedNodeCategory):
@classmethod
def poll(cls, context):
return (context.space_data.type == 'NODE_EDITOR' and
- context.space_data.tree_type == 'SimulationNodeTree')
+ context.space_data.tree_type == 'GeometryNodeTree')
# menu entry for node group tools
@@ -77,11 +77,11 @@ node_tree_group_type = {
'CompositorNodeTree': 'CompositorNodeGroup',
'ShaderNodeTree': 'ShaderNodeGroup',
'TextureNodeTree': 'TextureNodeGroup',
- 'SimulationNodeTree': 'SimulationNodeGroup',
+ 'GeometryNodeTree': 'GeometryNodeGroup',
}
-# generic node group items generator for shader, compositor, simulation and texture node groups
+# generic node group items generator for shader, compositor, geometry and texture node groups
def node_group_items(context):
if context is None:
return
@@ -483,10 +483,31 @@ def not_implemented_node(idname):
return NodeItem(idname, label=label)
-simulation_node_categories = [
- # Simulation Nodes
- SimulationNodeCategory("SIM_GROUP", "Group", items=node_group_items),
- SimulationNodeCategory("SIM_LAYOUT", "Layout", items=[
+geometry_node_categories = [
+ # Geometry Nodes
+ GeometryNodeCategory("GEO_MESH", "Mesh", items=[
+ NodeItem("GeometryNodeTriangulate"),
+ NodeItem("GeometryNodeEdgeSplit"),
+ ]),
+ GeometryNodeCategory("GEO_MATH", "Misc", items=[
+ NodeItem("ShaderNodeMapRange"),
+ NodeItem("ShaderNodeClamp"),
+ NodeItem("ShaderNodeMath"),
+ NodeItem("ShaderNodeValToRGB"),
+ NodeItem("ShaderNodeVectorMath"),
+ NodeItem("ShaderNodeSeparateRGB"),
+ NodeItem("ShaderNodeCombineRGB"),
+ NodeItem("ShaderNodeSeparateXYZ"),
+ NodeItem("ShaderNodeCombineXYZ"),
+ NodeItem("FunctionNodeBooleanMath"),
+ NodeItem("FunctionNodeFloatCompare"),
+ NodeItem("FunctionNodeCombineStrings"),
+ NodeItem("FunctionNodeRandomFloat"),
+ NodeItem("ShaderNodeValue"),
+ NodeItem("FunctionNodeGroupInstanceID"),
+ ]),
+ GeometryNodeCategory("GEO_GROUP", "Group", items=node_group_items),
+ GeometryNodeCategory("GEO_LAYOUT", "Layout", items=[
NodeItem("NodeFrame"),
NodeItem("NodeReroute"),
]),
@@ -497,14 +518,14 @@ def register():
nodeitems_utils.register_node_categories('SHADER', shader_node_categories)
nodeitems_utils.register_node_categories('COMPOSITING', compositor_node_categories)
nodeitems_utils.register_node_categories('TEXTURE', texture_node_categories)
- nodeitems_utils.register_node_categories('SIMULATION', simulation_node_categories)
+ nodeitems_utils.register_node_categories('GEOMETRY', geometry_node_categories)
def unregister():
nodeitems_utils.unregister_node_categories('SHADER')
nodeitems_utils.unregister_node_categories('COMPOSITING')
nodeitems_utils.unregister_node_categories('TEXTURE')
- nodeitems_utils.unregister_node_categories('SIMULATION')
+ nodeitems_utils.unregister_node_categories('GEOMETRY')
if __name__ == "__main__":
diff --git a/source/blender/blenkernel/BKE_geometry.hh b/source/blender/blenkernel/BKE_geometry.hh
new file mode 100644
index 00000000000..e2532d639c4
--- /dev/null
+++ b/source/blender/blenkernel/BKE_geometry.hh
@@ -0,0 +1,204 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/** \file
+ * \ingroup bke
+ */
+
+#include <atomic>
+#include <iostream>
+
+#include "BLI_hash.hh"
+
+struct Mesh;
+
+namespace blender::bke {
+
+/**
+ * Geometry can contain geometry of different types, such as meshes and curves (although currently
+ * only meshes are supported).
+ *
+ * Geometries are reference counted. This allows them to be shared without making unnecessary
+ * copies. A geometry that is shared is immutable. If some code wants to change it,
+ * #make_geometry_mutable should be called first.
+ */
+class Geometry {
+ private:
+ /* Number of users of this geometry. If this number goes to zero, the geometry is freed. If it is
+ * above 1, the geometry is immutable. */
+ std::atomic<int> users_ = 1;
+
+ /* Only contains a mesh for now. */
+ Mesh *mesh_ = nullptr;
+ /* Determines if the mesh is freed when the geometry does not want to reference it anymore. */
+ bool mesh_owned_ = false;
+
+ public:
+ Geometry() = default;
+ Geometry(const Geometry &other);
+ Geometry(Geometry &&other) = delete;
+ ~Geometry();
+
+ /* Disable copy and move assignment operators. */
+ Geometry &operator=(const Geometry &other) = delete;
+ Geometry &operator=(Geometry &&other) = delete;
+
+ void user_add();
+ void user_remove();
+ bool is_mutable() const;
+
+ void mesh_set_and_keep_ownership(Mesh *mesh);
+ void mesh_set_and_transfer_ownership(Mesh *mesh);
+ void mesh_reset();
+ Mesh *mesh_get_for_read();
+ Mesh *mesh_get_for_write();
+ Mesh *mesh_release();
+};
+
+/**
+ * A simple automatic reference counter. This should probably be moved to another file eventually.
+ * It is similar to std::shared_ptr, but expects that the reference count is inside the object.
+ */
+template<typename T> class UserCounter {
+ private:
+ T *data_ = nullptr;
+
+ public:
+ UserCounter() = default;
+
+ UserCounter(T *data) : data_(data)
+ {
+ }
+
+ UserCounter(const UserCounter &other) : data_(other.data_)
+ {
+ this->user_add(data_);
+ }
+
+ UserCounter(UserCounter &&other) : data_(other.data_)
+ {
+ other.data_ = nullptr;
+ }
+
+ ~UserCounter()
+ {
+ this->user_remove(data_);
+ }
+
+ UserCounter &operator=(const UserCounter &other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+
+ this->user_remove(data_);
+ data_ = other.data_;
+ this->user_add(data_);
+ return *this;
+ }
+
+ UserCounter &operator=(UserCounter &&other)
+ {
+ if (this == &other) {
+ return *this;
+ }
+
+ this->user_remove(data_);
+ data_ = other.data_;
+ other.data_ = nullptr;
+ return *this;
+ }
+
+ T *operator->()
+ {
+ BLI_assert(data_ != nullptr);
+ return data_;
+ }
+
+ T &operator*()
+ {
+ BLI_assert(data_ != nullptr);
+ return *data_;
+ }
+
+ operator bool() const
+ {
+ return data_ != nullptr;
+ }
+
+ T *get()
+ {
+ return data_;
+ }
+
+ T *release()
+ {
+ T *data = data_;
+ data_ = nullptr;
+ return data;
+ }
+
+ void reset()
+ {
+ this->user_remove(data_);
+ data_ = nullptr;
+ }
+
+ bool has_value() const
+ {
+ return data_ != nullptr;
+ }
+
+ uint64_t hash() const
+ {
+ return DefaultHash<T *>{}(data_);
+ }
+
+ friend bool operator==(const UserCounter &a, const UserCounter &b)
+ {
+ return a.data_ == b.data_;
+ }
+
+ friend std::ostream &operator<<(std::ostream &stream, const UserCounter &value)
+ {
+ stream << value.data_;
+ return stream;
+ }
+
+ private:
+ static void user_add(T *data)
+ {
+ if (data != nullptr) {
+ data->user_add();
+ }
+ }
+
+ static void user_remove(T *data)
+ {
+ if (data != nullptr) {
+ data->user_remove();
+ }
+ }
+};
+
+/* An automatically reference counted geometry. */
+using GeometryPtr = UserCounter<class Geometry>;
+
+void make_geometry_mutable(GeometryPtr &geometry);
+
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index 38045e22def..da4bcb8a00e 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -112,20 +112,28 @@ namespace blender {
namespace nodes {
class SocketMFNetworkBuilder;
class NodeMFNetworkBuilder;
+class GValueByName;
} // namespace nodes
namespace fn {
+class CPPType;
class MFDataType;
-}
+} // namespace fn
} // namespace blender
using NodeExpandInMFNetworkFunction = void (*)(blender::nodes::NodeMFNetworkBuilder &builder);
-using SocketGetMFDataTypeFunction = blender::fn::MFDataType (*)();
+using NodeGeometryExecFunction = void (*)(struct bNode *node,
+ blender::nodes::GValueByName &inputs,
+ blender::nodes::GValueByName &outputs);
+using SocketGetCPPTypeFunction = const blender::fn::CPPType *(*)();
+using SocketGetCPPValueFunction = void (*)(const struct bNodeSocket &socket, void *r_value);
using SocketExpandInMFNetworkFunction = void (*)(blender::nodes::SocketMFNetworkBuilder &builder);
#else
typedef void *NodeExpandInMFNetworkFunction;
-typedef void *SocketGetMFDataTypeFunction;
typedef void *SocketExpandInMFNetworkFunction;
+typedef void *NodeGeometryExecFunction;
+typedef void *SocketGetCPPTypeFunction;
+typedef void *SocketGetCPPValueFunction;
#endif
/**
@@ -181,10 +189,12 @@ typedef struct bNodeSocketType {
/* Callback to free the socket type. */
void (*free_self)(struct bNodeSocketType *stype);
- /* Returns the multi-function data type of this socket type. */
- SocketGetMFDataTypeFunction get_mf_data_type;
/* Expands the socket into a multi-function node that outputs the socket value. */
SocketExpandInMFNetworkFunction expand_in_mf_network;
+ /* Return the CPPType of this socket. */
+ SocketGetCPPTypeFunction get_cpp_type;
+ /* Get the value of this socket in a generic way. */
+ SocketGetCPPValueFunction get_cpp_value;
} bNodeSocketType;
typedef void *(*NodeInitExecFunction)(struct bNodeExecContext *context,
@@ -302,6 +312,9 @@ typedef struct bNodeType {
/* Expands the bNode into nodes in a multi-function network, which will be evaluated later on. */
NodeExpandInMFNetworkFunction expand_in_mf_network;
+ /* Execute a geometry node. */
+ NodeGeometryExecFunction geometry_node_execute;
+
/* RNA integration */
ExtensionRNA rna_ext;
} bNodeType;
@@ -1324,6 +1337,15 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
/** \} */
/* -------------------------------------------------------------------- */
+/** \name Geometry Nodes
+ * \{ */
+
+#define GEO_NODE_TRIANGULATE 1000
+#define GEO_NODE_EDGE_SPLIT 1001
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
/** \name Function Nodes
* \{ */
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index 0fbc8c4c229..070e54653fd 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -124,6 +124,7 @@ set(SRC
intern/fmodifier.c
intern/font.c
intern/freestyle.c
+ intern/geometry.cc
intern/gpencil.c
intern/gpencil_curve.c
intern/gpencil_geom.c
@@ -310,6 +311,7 @@ set(SRC
BKE_fluid.h
BKE_font.h
BKE_freestyle.h
+ BKE_geometry.hh
BKE_global.h
BKE_gpencil.h
BKE_gpencil_curve.h
diff --git a/source/blender/blenkernel/intern/geometry.cc b/source/blender/blenkernel/intern/geometry.cc
new file mode 100644
index 00000000000..014197ed423
--- /dev/null
+++ b/source/blender/blenkernel/intern/geometry.cc
@@ -0,0 +1,152 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BKE_geometry.hh"
+#include "BKE_lib_id.h"
+#include "BKE_mesh.h"
+
+#include "MEM_guardedalloc.h"
+
+namespace blender::bke {
+
+/* Make a copy of the geometry. */
+Geometry::Geometry(const Geometry &other)
+{
+ if (other.mesh_ != nullptr) {
+ mesh_ = BKE_mesh_copy_for_eval(other.mesh_, false);
+ /* Own the new mesh, regardless of whether the original mesh was owned. */
+ mesh_owned_ = true;
+ }
+}
+
+Geometry::~Geometry()
+{
+ this->mesh_reset();
+}
+
+void Geometry::user_add()
+{
+ users_.fetch_add(1);
+}
+
+void Geometry::user_remove()
+{
+ const int new_users = users_.fetch_sub(1) - 1;
+ if (new_users == 0) {
+ delete this;
+ }
+}
+
+bool Geometry::is_mutable() const
+{
+ /* If the geometry is shared, it is read-only. */
+ /* The user count can be 0, when this is called from the destructor. */
+ return users_ <= 1;
+}
+
+/**
+ * Replace the mesh in the geometry. The caller remains the owner of the given mesh and is
+ * responsible for freeing it eventually.
+ */
+void Geometry::mesh_set_and_keep_ownership(Mesh *mesh)
+{
+ BLI_assert(this->is_mutable());
+ this->mesh_reset();
+ mesh_ = mesh;
+ mesh_owned_ = false;
+}
+
+/**
+ * Replace the mesh in the geometry. The geometry becomes responsible for freeing the mesh.
+ */
+void Geometry::mesh_set_and_transfer_ownership(Mesh *mesh)
+{
+ BLI_assert(this->is_mutable());
+ this->mesh_reset();
+ mesh_ = mesh;
+ mesh_owned_ = true;
+}
+
+/**
+ * Clear any mesh data the geometry might have.
+ */
+void Geometry::mesh_reset()
+{
+ BLI_assert(this->is_mutable());
+ if (mesh_ != nullptr) {
+ if (mesh_owned_) {
+ BKE_id_free(nullptr, mesh_);
+ }
+ mesh_ = nullptr;
+ }
+}
+
+/**
+ * Get the mesh from the geometry. This mesh should only be read and not modified. This can be used
+ * on shared geometries.
+ * Might return null.
+ */
+Mesh *Geometry::mesh_get_for_read()
+{
+ return mesh_;
+}
+
+/**
+ * Get the mesh from the geometry. The caller is allowed to modify the mesh. This method can only
+ * be used on mutable geometries.
+ * Might return null.
+ */
+Mesh *Geometry::mesh_get_for_write()
+{
+ BLI_assert(this->is_mutable());
+ return mesh_;
+}
+
+/**
+ * Return the mesh in the geometry and remove it. This only works on mutable geometries.
+ * Might return null;
+ */
+Mesh *Geometry::mesh_release()
+{
+ BLI_assert(this->is_mutable());
+ Mesh *mesh = mesh_;
+ mesh_ = nullptr;
+ return mesh;
+}
+
+/**
+ * Changes the given pointer so that it points to a mutable geometry. This might do nothing, create
+ * a new empty geometry or copy the entire geometry.
+ */
+void make_geometry_mutable(GeometryPtr &geometry)
+{
+ if (!geometry) {
+ /* If the pointer is null, create a new instance. */
+ geometry = GeometryPtr{new Geometry()};
+ }
+ else if (geometry->is_mutable()) {
+ /* If the instance is mutable already, do nothing. */
+ }
+ else {
+ /* This geometry is shared, make a copy that is independent of the other users. */
+ Geometry *shared_geometry = geometry.release();
+ Geometry *new_geometry = new Geometry(*shared_geometry);
+ shared_geometry->user_remove();
+ geometry = GeometryPtr{new_geometry};
+ }
+}
+
+} // namespace blender::bke
diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c
index 80a553ff525..cf06e55814f 100644
--- a/source/blender/blenkernel/intern/node.c
+++ b/source/blender/blenkernel/intern/node.c
@@ -65,7 +65,6 @@
#include "BKE_lib_query.h"
#include "BKE_main.h"
#include "BKE_node.h"
-#include "BKE_simulation.h"
#include "BLI_ghash.h"
#include "BLI_threads.h"
@@ -75,8 +74,8 @@
#include "NOD_common.h"
#include "NOD_composite.h"
#include "NOD_function.h"
+#include "NOD_geometry.h"
#include "NOD_shader.h"
-#include "NOD_simulation.h"
#include "NOD_socket.h"
#include "NOD_texture.h"
@@ -281,6 +280,7 @@ static void library_foreach_node_socket(LibraryForeachIDData *data, bNodeSocket
case __SOCK_MESH:
case SOCK_CUSTOM:
case SOCK_SHADER:
+ case SOCK_GEOMETRY:
break;
}
}
@@ -373,6 +373,7 @@ static void write_node_socket_default_value(BlendWriter *writer, bNodeSocket *so
case __SOCK_MESH:
case SOCK_CUSTOM:
case SOCK_SHADER:
+ case SOCK_GEOMETRY:
BLI_assert(false);
break;
}
@@ -715,6 +716,7 @@ static void lib_link_node_socket(BlendLibReader *reader, Library *lib, bNodeSock
case __SOCK_MESH:
case SOCK_CUSTOM:
case SOCK_SHADER:
+ case SOCK_GEOMETRY:
break;
}
}
@@ -793,6 +795,7 @@ static void expand_node_socket(BlendExpander *expander, bNodeSocket *sock)
case __SOCK_MESH:
case SOCK_CUSTOM:
case SOCK_SHADER:
+ case SOCK_GEOMETRY:
break;
}
}
@@ -1345,6 +1348,7 @@ static void socket_id_user_increment(bNodeSocket *sock)
case __SOCK_MESH:
case SOCK_CUSTOM:
case SOCK_SHADER:
+ case SOCK_GEOMETRY:
break;
}
}
@@ -1371,6 +1375,7 @@ static void socket_id_user_decrement(bNodeSocket *sock)
case __SOCK_MESH:
case SOCK_CUSTOM:
case SOCK_SHADER:
+ case SOCK_GEOMETRY:
break;
}
}
@@ -1498,6 +1503,8 @@ const char *nodeStaticSocketType(int type, int subtype)
return "NodeSocketObject";
case SOCK_IMAGE:
return "NodeSocketImage";
+ case SOCK_GEOMETRY:
+ return "NodeSocketGeometry";
}
return NULL;
}
@@ -1563,6 +1570,8 @@ const char *nodeStaticSocketInterfaceType(int type, int subtype)
return "NodeSocketInterfaceObject";
case SOCK_IMAGE:
return "NodeSocketInterfaceImage";
+ case SOCK_GEOMETRY:
+ return "NodeSocketInterfaceGeometry";
}
return NULL;
}
@@ -4646,9 +4655,12 @@ static void registerTextureNodes(void)
register_node_type_tex_proc_distnoise();
}
-static void registerSimulationNodes(void)
+static void registerGeometryNodes(void)
{
- register_node_type_sim_group();
+ register_node_type_geo_group();
+
+ register_node_type_geo_triangulate();
+ register_node_type_geo_edge_split();
}
static void registerFunctionNodes(void)
@@ -4675,7 +4687,7 @@ void init_nodesystem(void)
register_node_tree_type_cmp();
register_node_tree_type_sh();
register_node_tree_type_tex();
- register_node_tree_type_sim();
+ register_node_tree_type_geo();
register_node_type_frame();
register_node_type_reroute();
@@ -4685,7 +4697,7 @@ void init_nodesystem(void)
registerCompositNodes();
registerShaderNodes();
registerTextureNodes();
- registerSimulationNodes();
+ registerGeometryNodes();
registerFunctionNodes();
}
diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c
index 7c8527a8702..5944d1a693b 100644
--- a/source/blender/blenkernel/intern/pointcache.c
+++ b/source/blender/blenkernel/intern/pointcache.c
@@ -1187,9 +1187,6 @@ static bool foreach_object_modifier_ptcache(Object *object,
}
}
}
- else if (md->type == eModifierType_Simulation) {
- /* TODO(jacques): */
- }
}
return true;
}
diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc
index 2e1f8bd581e..418746a680e 100644
--- a/source/blender/blenkernel/intern/simulation.cc
+++ b/source/blender/blenkernel/intern/simulation.cc
@@ -48,8 +48,8 @@
#include "BKE_pointcache.h"
#include "BKE_simulation.h"
+#include "NOD_geometry.h"
#include "NOD_node_tree_multi_function.hh"
-#include "NOD_simulation.h"
#include "BLI_map.hh"
#include "BLT_translation.h"
@@ -70,7 +70,7 @@ static void simulation_init_data(ID *id)
MEMCPY_STRUCT_AFTER(simulation, DNA_struct_default_get(Simulation), id);
- bNodeTree *ntree = ntreeAddTree(nullptr, "Simulation Nodetree", ntreeType_Simulation->idname);
+ bNodeTree *ntree = ntreeAddTree(nullptr, "Geometry Nodetree", ntreeType_Geometry->idname);
simulation->nodetree = ntree;
}
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index c49808c3718..5ff3d383a72 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -158,7 +158,6 @@
#include "BKE_screen.h"
#include "BKE_sequencer.h"
#include "BKE_shader_fx.h"
-#include "BKE_simulation.h"
#include "BKE_sound.h"
#include "BKE_volume.h"
#include "BKE_workspace.h"
diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h
index 2147a584765..f894bdabba4 100644
--- a/source/blender/depsgraph/DEG_depsgraph_build.h
+++ b/source/blender/depsgraph/DEG_depsgraph_build.h
@@ -141,6 +141,9 @@ void DEG_add_object_relation(struct DepsNodeHandle *node_handle,
void DEG_add_simulation_relation(struct DepsNodeHandle *node_handle,
struct Simulation *simulation,
const char *description);
+void DEG_add_node_tree_relation(struct DepsNodeHandle *node_handle,
+ struct bNodeTree *node_tree,
+ const char *description);
void DEG_add_bone_relation(struct DepsNodeHandle *handle,
struct Object *object,
const char *bone_name,
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
index 96c17ae4dc5..6717ba521f6 100644
--- a/source/blender/depsgraph/intern/depsgraph_build.cc
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -32,6 +32,7 @@
#include "PIL_time_utildefines.h"
#include "DNA_cachefile_types.h"
+#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_simulation_types.h"
@@ -116,6 +117,17 @@ void DEG_add_simulation_relation(DepsNodeHandle *node_handle,
deg_node_handle->builder->add_node_handle_relation(operation_key, deg_node_handle, description);
}
+void DEG_add_node_tree_relation(DepsNodeHandle *node_handle,
+ bNodeTree *node_tree,
+ const char *description)
+{
+ /* Using shading key, because that's the one that exists right now. Should use something else in
+ * the future. */
+ deg::ComponentKey shading_key(&node_tree->id, deg::NodeType::SHADING);
+ deg::DepsNodeHandle *deg_node_handle = get_node_handle(node_handle);
+ deg_node_handle->builder->add_node_handle_relation(shading_key, deg_node_handle, description);
+}
+
void DEG_add_object_cache_relation(DepsNodeHandle *node_handle,
CacheFile *cache_file,
eDepsObjectComponentType component,
diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h
index ecb98a46f99..417cae800ea 100644
--- a/source/blender/editors/include/ED_node.h
+++ b/source/blender/editors/include/ED_node.h
@@ -96,7 +96,7 @@ void ED_node_set_tree_type(struct SpaceNode *snode, struct bNodeTreeType *typein
bool ED_node_is_compositor(struct SpaceNode *snode);
bool ED_node_is_shader(struct SpaceNode *snode);
bool ED_node_is_texture(struct SpaceNode *snode);
-bool ED_node_is_simulation(struct SpaceNode *snode);
+bool ED_node_is_geometry(struct SpaceNode *snode);
void ED_node_shader_default(const struct bContext *C, struct ID *id);
void ED_node_composit_default(const struct bContext *C, struct Scene *scene);
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 66da2887427..b9495519427 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -68,8 +68,8 @@
#include "IMB_imbuf_types.h"
#include "NOD_composite.h"
+#include "NOD_geometry.h"
#include "NOD_shader.h"
-#include "NOD_simulation.h"
#include "NOD_texture.h"
#include "node_intern.h" /* own include */
@@ -3138,9 +3138,9 @@ static void node_texture_set_butfunc(bNodeType *ntype)
}
}
-/* ****************** BUTTON CALLBACKS FOR SIMULATION NODES ***************** */
+/* ****************** BUTTON CALLBACKS FOR GEOMETRY NODES ***************** */
-static void node_simulation_set_butfunc(bNodeType *UNUSED(ntype))
+static void node_geometry_set_butfunc(bNodeType *UNUSED(ntype))
{
}
@@ -3286,7 +3286,7 @@ void ED_node_init_butfuncs(void)
node_composit_set_butfunc(ntype);
node_shader_set_butfunc(ntype);
node_texture_set_butfunc(ntype);
- node_simulation_set_butfunc(ntype);
+ node_geometry_set_butfunc(ntype);
node_function_set_butfunc(ntype);
/* define update callbacks for socket properties */
@@ -3298,7 +3298,7 @@ void ED_node_init_butfuncs(void)
ntreeType_Composite->ui_icon = ICON_NODE_COMPOSITING;
ntreeType_Shader->ui_icon = ICON_NODE_MATERIAL;
ntreeType_Texture->ui_icon = ICON_NODE_TEXTURE;
- ntreeType_Simulation->ui_icon = ICON_PHYSICS; /* TODO: Use correct icon. */
+ ntreeType_Geometry->ui_icon = ICON_PHYSICS; /* TODO: Use correct icon. */
}
void ED_init_custom_node_type(bNodeType *ntype)
@@ -3329,6 +3329,7 @@ static const float std_node_socket_colors[][4] = {
{0.39, 0.39, 0.39, 1.0}, /* SOCK_STRING */
{0.40, 0.10, 0.10, 1.0}, /* SOCK_OBJECT */
{0.10, 0.40, 0.10, 1.0}, /* SOCK_IMAGE */
+ {0.00, 0.00, 0.00, 1.0}, /* SOCK_GEOMETRY, TODO: Choose color. */
};
/* common color callbacks for standard types */
diff --git a/source/blender/editors/space_node/node_draw.c b/source/blender/editors/space_node/node_draw.c
index bafd1b9a388..2335bde33a7 100644
--- a/source/blender/editors/space_node/node_draw.c
+++ b/source/blender/editors/space_node/node_draw.c
@@ -138,6 +138,9 @@ void ED_node_tag_update_id(ID *id)
DEG_id_tag_update(id, 0);
WM_main_add_notifier(NC_TEXTURE | ND_NODES, id);
}
+ else if (ntree->type == NTREE_GEOMETRY) {
+ WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, id);
+ }
else if (id == &ntree->id) {
/* node groups */
DEG_id_tag_update(id, 0);
diff --git a/source/blender/editors/space_node/node_edit.c b/source/blender/editors/space_node/node_edit.c
index b1659bcd023..76fde9a36e2 100644
--- a/source/blender/editors/space_node/node_edit.c
+++ b/source/blender/editors/space_node/node_edit.c
@@ -68,8 +68,8 @@
#include "IMB_imbuf_types.h"
#include "NOD_composite.h"
+#include "NOD_geometry.h"
#include "NOD_shader.h"
-#include "NOD_simulation.h"
#include "NOD_texture.h"
#include "node_intern.h" /* own include */
@@ -391,6 +391,7 @@ void snode_dag_update(bContext *C, SpaceNode *snode)
}
DEG_id_tag_update(snode->id, 0);
+ DEG_id_tag_update(&snode->nodetree->id, 0);
}
void snode_notify(bContext *C, SpaceNode *snode)
@@ -416,6 +417,9 @@ void snode_notify(bContext *C, SpaceNode *snode)
else if (ED_node_is_texture(snode)) {
WM_event_add_notifier(C, NC_TEXTURE | ND_NODES, id);
}
+ else if (ED_node_is_geometry(snode)) {
+ WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, id);
+ }
}
void ED_node_set_tree_type(SpaceNode *snode, bNodeTreeType *typeinfo)
@@ -443,9 +447,9 @@ bool ED_node_is_texture(struct SpaceNode *snode)
return STREQ(snode->tree_idname, ntreeType_Texture->idname);
}
-bool ED_node_is_simulation(struct SpaceNode *snode)
+bool ED_node_is_geometry(struct SpaceNode *snode)
{
- return STREQ(snode->tree_idname, ntreeType_Simulation->idname);
+ return STREQ(snode->tree_idname, ntreeType_Geometry->idname);
}
/* assumes nothing being done in ntree yet, sets the default in/out node */
@@ -1696,7 +1700,7 @@ static int node_mute_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- do_tag_update |= ED_node_is_simulation(snode);
+ do_tag_update |= ED_node_is_geometry(snode);
snode_notify(C, snode);
if (do_tag_update) {
@@ -1740,7 +1744,7 @@ static int node_delete_exec(bContext *C, wmOperator *UNUSED(op))
}
}
- do_tag_update |= ED_node_is_simulation(snode);
+ do_tag_update |= ED_node_is_geometry(snode);
ntreeUpdateTree(CTX_data_main(C), snode->edittree);
diff --git a/source/blender/editors/space_node/node_group.c b/source/blender/editors/space_node/node_group.c
index c6c14a9886e..1e679d7d7c9 100644
--- a/source/blender/editors/space_node/node_group.c
+++ b/source/blender/editors/space_node/node_group.c
@@ -71,7 +71,7 @@ static bool node_group_operator_active(bContext *C)
if (STREQ(snode->tree_idname, "ShaderNodeTree") ||
STREQ(snode->tree_idname, "CompositorNodeTree") ||
STREQ(snode->tree_idname, "TextureNodeTree") ||
- STREQ(snode->tree_idname, "SimulationNodeTree")) {
+ STREQ(snode->tree_idname, "GeometryNodeTree")) {
return true;
}
}
@@ -88,7 +88,7 @@ static bool node_group_operator_editable(bContext *C)
* with same keymap.
*/
if (ED_node_is_shader(snode) || ED_node_is_compositor(snode) || ED_node_is_texture(snode) ||
- ED_node_is_simulation(snode)) {
+ ED_node_is_geometry(snode)) {
return true;
}
}
@@ -114,8 +114,8 @@ static const char *group_node_idname(bContext *C)
if (ED_node_is_texture(snode)) {
return "TextureNodeGroup";
}
- if (ED_node_is_simulation(snode)) {
- return "SimulationNodeGroup";
+ if (ED_node_is_geometry(snode)) {
+ return "GeometryNodeGroup";
}
return "";
diff --git a/source/blender/editors/space_node/node_relationships.c b/source/blender/editors/space_node/node_relationships.c
index b6d9cdc729d..203aebfc041 100644
--- a/source/blender/editors/space_node/node_relationships.c
+++ b/source/blender/editors/space_node/node_relationships.c
@@ -655,7 +655,7 @@ static void node_link_exit(bContext *C, wmOperator *op, bool apply_links)
}
ntree->is_updating = false;
- do_tag_update |= ED_node_is_simulation(snode);
+ do_tag_update |= ED_node_is_geometry(snode);
ntreeUpdateTree(bmain, ntree);
snode_notify(C, snode);
@@ -1052,7 +1052,7 @@ static int cut_links_exec(bContext *C, wmOperator *op)
}
}
- do_tag_update |= ED_node_is_simulation(snode);
+ do_tag_update |= ED_node_is_geometry(snode);
if (found) {
ntreeUpdateTree(CTX_data_main(C), snode->edittree);
diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c
index d2502e6408c..ec294ed4298 100644
--- a/source/blender/editors/space_node/space_node.c
+++ b/source/blender/editors/space_node/space_node.c
@@ -936,7 +936,7 @@ static void node_space_subtype_item_extend(bContext *C, EnumPropertyItem **item,
const EnumPropertyItem *item_src = RNA_enum_node_tree_types_itemf_impl(C, &free);
for (const EnumPropertyItem *item_iter = item_src; item_iter->identifier; item_iter++) {
if (!U.experimental.use_new_geometry_nodes &&
- STREQ(item_iter->identifier, "SimulationNodeTree")) {
+ STREQ(item_iter->identifier, "GeometryNodeTree")) {
continue;
}
RNA_enum_item_add(item, totitem, item_iter);
diff --git a/source/blender/functions/CMakeLists.txt b/source/blender/functions/CMakeLists.txt
index 9a6b6f4a4db..e005753e228 100644
--- a/source/blender/functions/CMakeLists.txt
+++ b/source/blender/functions/CMakeLists.txt
@@ -38,6 +38,7 @@ set(SRC
FN_array_spans.hh
FN_attributes_ref.hh
FN_cpp_type.hh
+ FN_generic_pointer.hh
FN_generic_vector_array.hh
FN_multi_function.hh
FN_multi_function_builder.hh
diff --git a/source/blender/functions/FN_cpp_type.hh b/source/blender/functions/FN_cpp_type.hh
index 5f3981826c5..5a7dfadf537 100644
--- a/source/blender/functions/FN_cpp_type.hh
+++ b/source/blender/functions/FN_cpp_type.hh
@@ -91,6 +91,14 @@ class CPPType : NonCopyable, NonMovable {
using CopyToUninitializedNF = void (*)(const void *src, void *dst, int64_t n);
using CopyToUninitializedIndicesF = void (*)(const void *src, void *dst, IndexMask mask);
+ using MoveToInitializedF = void (*)(void *src, void *dst);
+ using MoveToInitializedNF = void (*)(void *src, void *dst, int64_t n);
+ using MoveToInitializedIndicesF = void (*)(void *src, void *dst, IndexMask mask);
+
+ using MoveToUninitializedF = void (*)(void *src, void *dst);
+ using MoveToUninitializedNF = void (*)(void *src, void *dst, int64_t n);
+ using MoveToUninitializedIndicesF = void (*)(void *src, void *dst, IndexMask mask);
+
using RelocateToInitializedF = void (*)(void *src, void *dst);
using RelocateToInitializedNF = void (*)(void *src, void *dst, int64_t n);
using RelocateToInitializedIndicesF = void (*)(void *src, void *dst, IndexMask mask);
@@ -131,6 +139,14 @@ class CPPType : NonCopyable, NonMovable {
CopyToUninitializedNF copy_to_uninitialized_n_;
CopyToUninitializedIndicesF copy_to_uninitialized_indices_;
+ MoveToInitializedF move_to_initialized_;
+ MoveToInitializedNF move_to_initialized_n_;
+ MoveToInitializedIndicesF move_to_initialized_indices_;
+
+ MoveToUninitializedF move_to_uninitialized_;
+ MoveToUninitializedNF move_to_uninitialized_n_;
+ MoveToUninitializedIndicesF move_to_uninitialized_indices_;
+
RelocateToInitializedF relocate_to_initialized_;
RelocateToInitializedNF relocate_to_initialized_n_;
RelocateToInitializedIndicesF relocate_to_initialized_indices_;
@@ -169,6 +185,12 @@ class CPPType : NonCopyable, NonMovable {
CopyToUninitializedF copy_to_uninitialized,
CopyToUninitializedNF copy_to_uninitialized_n,
CopyToUninitializedIndicesF copy_to_uninitialized_indices,
+ MoveToInitializedF move_to_initialized,
+ MoveToInitializedNF move_to_initialized_n,
+ MoveToInitializedIndicesF move_to_initialized_indices,
+ MoveToUninitializedF move_to_uninitialized,
+ MoveToUninitializedNF move_to_uninitialized_n,
+ MoveToUninitializedIndicesF move_to_uninitialized_indices,
RelocateToInitializedF relocate_to_initialized,
RelocateToInitializedNF relocate_to_initialized_n,
RelocateToInitializedIndicesF relocate_to_initialized_indices,
@@ -198,6 +220,12 @@ class CPPType : NonCopyable, NonMovable {
copy_to_uninitialized_(copy_to_uninitialized),
copy_to_uninitialized_n_(copy_to_uninitialized_n),
copy_to_uninitialized_indices_(copy_to_uninitialized_indices),
+ move_to_initialized_(move_to_initialized),
+ move_to_initialized_n_(move_to_initialized_n),
+ move_to_initialized_indices_(move_to_initialized_indices),
+ move_to_uninitialized_(move_to_uninitialized),
+ move_to_uninitialized_n_(move_to_uninitialized_n),
+ move_to_uninitialized_indices_(move_to_uninitialized_indices),
relocate_to_initialized_(relocate_to_initialized),
relocate_to_initialized_n_(relocate_to_initialized_n),
relocate_to_initialized_indices_(relocate_to_initialized_indices),
@@ -422,6 +450,76 @@ class CPPType : NonCopyable, NonMovable {
}
/**
+ * Move an instance of this type from src to dst.
+ *
+ * The memory pointed to by dst should be initialized.
+ *
+ * C++ equivalent:
+ * dst = std::move(src);
+ */
+ void move_to_initialized(void *src, void *dst) const
+ {
+ BLI_assert(src != dst);
+ BLI_assert(this->pointer_can_point_to_instance(src));
+ BLI_assert(this->pointer_can_point_to_instance(dst));
+
+ move_to_initialized_(src, dst);
+ }
+
+ void move_to_initialized_n(void *src, void *dst, int64_t n) const
+ {
+ BLI_assert(n == 0 || src != dst);
+ BLI_assert(n == 0 || this->pointer_can_point_to_instance(src));
+ BLI_assert(n == 0 || this->pointer_can_point_to_instance(dst));
+
+ move_to_initialized_n_(src, dst, n);
+ }
+
+ void move_to_initialized_indices(void *src, void *dst, IndexMask mask) const
+ {
+ BLI_assert(mask.size() == 0 || src != dst);
+ BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src));
+ BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst));
+
+ move_to_initialized_indices_(src, dst, mask);
+ }
+
+ /**
+ * Move an instance of this type from src to dst.
+ *
+ * The memory pointed to by dst should be uninitialized.
+ *
+ * C++ equivalent:
+ * new (dst) T(std::move(src));
+ */
+ void move_to_uninitialized(void *src, void *dst) const
+ {
+ BLI_assert(src != dst);
+ BLI_assert(this->pointer_can_point_to_instance(src));
+ BLI_assert(this->pointer_can_point_to_instance(dst));
+
+ move_to_uninitialized_(src, dst);
+ }
+
+ void move_to_uninitialized_n(void *src, void *dst, int64_t n) const
+ {
+ BLI_assert(n == 0 || src != dst);
+ BLI_assert(n == 0 || this->pointer_can_point_to_instance(src));
+ BLI_assert(n == 0 || this->pointer_can_point_to_instance(dst));
+
+ move_to_uninitialized_n_(src, dst, n);
+ }
+
+ void move_to_uninitialized_indices(void *src, void *dst, IndexMask mask) const
+ {
+ BLI_assert(mask.size() == 0 || src != dst);
+ BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(src));
+ BLI_assert(mask.size() == 0 || this->pointer_can_point_to_instance(dst));
+
+ move_to_uninitialized_indices_(src, dst, mask);
+ }
+
+ /**
* Relocates an instance of this type from src to dst. src will point to uninitialized memory
* afterwards.
*
@@ -644,6 +742,38 @@ void copy_to_uninitialized_indices_cb(const void *src, void *dst, IndexMask mask
mask.foreach_index([&](int64_t i) { new (dst_ + i) T(src_[i]); });
}
+template<typename T> void move_to_initialized_cb(void *src, void *dst)
+{
+ blender::initialized_move_n(static_cast<T *>(src), 1, static_cast<T *>(dst));
+}
+template<typename T> void move_to_initialized_n_cb(void *src, void *dst, int64_t n)
+{
+ blender::initialized_move_n(static_cast<T *>(src), n, static_cast<T *>(dst));
+}
+template<typename T> void move_to_initialized_indices_cb(void *src, void *dst, IndexMask mask)
+{
+ T *src_ = static_cast<T *>(src);
+ T *dst_ = static_cast<T *>(dst);
+
+ mask.foreach_index([&](int64_t i) { dst_[i] = std::move(src_[i]); });
+}
+
+template<typename T> void move_to_uninitialized_cb(void *src, void *dst)
+{
+ blender::uninitialized_move_n(static_cast<T *>(src), 1, static_cast<T *>(dst));
+}
+template<typename T> void move_to_uninitialized_n_cb(void *src, void *dst, int64_t n)
+{
+ blender::uninitialized_move_n(static_cast<T *>(src), n, static_cast<T *>(dst));
+}
+template<typename T> void move_to_uninitialized_indices_cb(void *src, void *dst, IndexMask mask)
+{
+ T *src_ = static_cast<T *>(src);
+ T *dst_ = static_cast<T *>(dst);
+
+ mask.foreach_index([&](int64_t i) { new (dst_ + i) T(std::move(src_[i])); });
+}
+
template<typename T> void relocate_to_initialized_cb(void *src, void *dst)
{
T *src_ = static_cast<T *>(src);
@@ -767,6 +897,12 @@ inline std::unique_ptr<const CPPType> create_cpp_type(StringRef name, const T &d
copy_to_uninitialized_cb<T>,
copy_to_uninitialized_n_cb<T>,
copy_to_uninitialized_indices_cb<T>,
+ move_to_initialized_cb<T>,
+ move_to_initialized_n_cb<T>,
+ move_to_initialized_indices_cb<T>,
+ move_to_uninitialized_cb<T>,
+ move_to_uninitialized_n_cb<T>,
+ move_to_uninitialized_indices_cb<T>,
relocate_to_initialized_cb<T>,
relocate_to_initialized_n_cb<T>,
relocate_to_initialized_indices_cb<T>,
diff --git a/source/blender/functions/FN_generic_pointer.hh b/source/blender/functions/FN_generic_pointer.hh
new file mode 100644
index 00000000000..5c2b611c614
--- /dev/null
+++ b/source/blender/functions/FN_generic_pointer.hh
@@ -0,0 +1,76 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "FN_cpp_type.hh"
+
+namespace blender::fn {
+
+/**
+ * A generic pointer whose type is only known at runtime.
+ */
+class GMutablePointer {
+ private:
+ const CPPType *type_ = nullptr;
+ void *data_ = nullptr;
+
+ public:
+ GMutablePointer() = default;
+
+ GMutablePointer(const CPPType *type, void *data = nullptr) : type_(type), data_(data)
+ {
+ /* If there is data, there has to be a type. */
+ BLI_assert(data_ == nullptr || type_ != nullptr);
+ }
+
+ GMutablePointer(const CPPType &type, void *data = nullptr) : GMutablePointer(&type, data)
+ {
+ }
+
+ template<typename T> GMutablePointer(T *data) : GMutablePointer(&CPPType::get<T>(), data)
+ {
+ }
+
+ void *get() const
+ {
+ return data_;
+ }
+
+ const CPPType *type() const
+ {
+ return type_;
+ }
+
+ template<typename T> T *get() const
+ {
+ BLI_assert(this->is_type<T>());
+ return reinterpret_cast<T *>(data_);
+ }
+
+ template<typename T> bool is_type() const
+ {
+ return type_ != nullptr && type_->is<T>();
+ }
+
+ void destruct()
+ {
+ BLI_assert(data_ != nullptr);
+ type_->destruct(data_);
+ }
+};
+
+} // namespace blender::fn
diff --git a/source/blender/makesdna/DNA_modifier_defaults.h b/source/blender/makesdna/DNA_modifier_defaults.h
index 34a951ca988..0131339127e 100644
--- a/source/blender/makesdna/DNA_modifier_defaults.h
+++ b/source/blender/makesdna/DNA_modifier_defaults.h
@@ -574,7 +574,7 @@
.flag = 0, \
}
-#define _DNA_DEFAULT_SimulationModifierData \
+#define _DNA_DEFAULT_NodesModifierData \
{ 0 }
#define _DNA_DEFAULT_SkinModifierData \
diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h
index 0d642e4f3d5..414c21fd428 100644
--- a/source/blender/makesdna/DNA_modifier_types.h
+++ b/source/blender/makesdna/DNA_modifier_types.h
@@ -94,7 +94,7 @@ typedef enum ModifierType {
eModifierType_WeightedNormal = 54,
eModifierType_Weld = 55,
eModifierType_Fluid = 56,
- eModifierType_Simulation = 57,
+ eModifierType_Nodes = 57,
eModifierType_MeshToVolume = 58,
eModifierType_VolumeDisplace = 59,
eModifierType_VolumeToMesh = 60,
@@ -2219,9 +2219,10 @@ enum {
#define MOD_MESHSEQ_READ_ALL \
(MOD_MESHSEQ_READ_VERT | MOD_MESHSEQ_READ_POLY | MOD_MESHSEQ_READ_UV | MOD_MESHSEQ_READ_COLOR)
-typedef struct SimulationModifierData {
+typedef struct NodesModifierData {
ModifierData modifier;
-} SimulationModifierData;
+ struct bNodeTree *node_group;
+} NodesModifierData;
typedef struct MeshToVolumeModifierData {
ModifierData modifier;
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index cba93bbadfc..c3dbd9f7d30 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -155,6 +155,7 @@ typedef enum eNodeSocketDatatype {
SOCK_STRING = 7,
SOCK_OBJECT = 8,
SOCK_IMAGE = 9,
+ SOCK_GEOMETRY = 10,
} eNodeSocketDatatype;
/* socket shape */
@@ -499,7 +500,7 @@ typedef struct bNodeTree {
#define NTREE_SHADER 0
#define NTREE_COMPOSIT 1
#define NTREE_TEXTURE 2
-#define NTREE_SIMULATION 3
+#define NTREE_GEOMETRY 3
/* ntree->init, flag */
#define NTREE_TYPE_INIT 1
@@ -1422,15 +1423,3 @@ typedef enum NodeShaderOutputTarget {
SHD_OUTPUT_EEVEE = 1,
SHD_OUTPUT_CYCLES = 2,
} NodeShaderOutputTarget;
-
-/* Particle Time Step Event node */
-typedef enum NodeSimParticleTimeStepEventType {
- NODE_PARTICLE_TIME_STEP_EVENT_BEGIN = 0,
- NODE_PARTICLE_TIME_STEP_EVENT_END = 1,
-} NodeSimParticleTimeStepEventType;
-
-/* Simulation Time node */
-typedef enum NodeSimInputTimeType {
- NODE_SIM_INPUT_SIMULATION_TIME = 0,
- NODE_SIM_INPUT_SCENE_TIME = 1,
-} NodeSimInputTimeType;
diff --git a/source/blender/makesdna/intern/dna_defaults.c b/source/blender/makesdna/intern/dna_defaults.c
index 8c95a6d2a31..1a8bd25215f 100644
--- a/source/blender/makesdna/intern/dna_defaults.c
+++ b/source/blender/makesdna/intern/dna_defaults.c
@@ -271,7 +271,7 @@ SDNA_DEFAULT_DECL_STRUCT(ScrewModifierData);
/* Shape key modifier has no items. */
SDNA_DEFAULT_DECL_STRUCT(ShrinkwrapModifierData);
SDNA_DEFAULT_DECL_STRUCT(SimpleDeformModifierData);
-SDNA_DEFAULT_DECL_STRUCT(SimulationModifierData);
+SDNA_DEFAULT_DECL_STRUCT(NodesModifierData);
SDNA_DEFAULT_DECL_STRUCT(SkinModifierData);
SDNA_DEFAULT_DECL_STRUCT(SmoothModifierData);
/* Softbody modifier skipped for now. */
@@ -491,7 +491,7 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = {
/* Shape key modifier has no items. */
SDNA_DEFAULT_DECL(ShrinkwrapModifierData),
SDNA_DEFAULT_DECL(SimpleDeformModifierData),
- SDNA_DEFAULT_DECL(SimulationModifierData),
+ SDNA_DEFAULT_DECL(NodesModifierData),
SDNA_DEFAULT_DECL(SkinModifierData),
SDNA_DEFAULT_DECL(SmoothModifierData),
/* Softbody modifier skipped for now. */
diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h
index 6dfd7b0fdf5..a6601951e3b 100644
--- a/source/blender/makesrna/RNA_access.h
+++ b/source/blender/makesrna/RNA_access.h
@@ -566,10 +566,10 @@ extern StructRNA RNA_SimpleDeformModifier;
extern StructRNA RNA_SimplifyGpencilModifier;
extern StructRNA RNA_Simulation;
#ifdef WITH_GEOMETRY_NODES
-extern StructRNA RNA_SimulationModifier;
+extern StructRNA RNA_NodesModifier;
#endif
-extern StructRNA RNA_SimulationNode;
-extern StructRNA RNA_SimulationNodeTree;
+extern StructRNA RNA_GeometryNode;
+extern StructRNA RNA_GeometryNodeTree;
extern StructRNA RNA_SkinModifier;
extern StructRNA RNA_SmoothGpencilModifier;
extern StructRNA RNA_SmoothModifier;
diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c
index 7885e182787..7715a35af76 100644
--- a/source/blender/makesrna/intern/rna_modifier.c
+++ b/source/blender/makesrna/intern/rna_modifier.c
@@ -29,7 +29,6 @@
#include "DNA_object_force_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
-#include "DNA_simulation_types.h"
#include "MEM_guardedalloc.h"
@@ -161,6 +160,7 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
ICON_MOD_MULTIRES,
"Multiresolution",
"Subdivide the mesh in a way that allows editing the higher subdivision levels"},
+ {eModifierType_Nodes, "NODES", ICON_MESH_DATA, "Nodes", ""}, /* TODO: Use correct icon. */
{eModifierType_Remesh,
"REMESH",
ICON_MOD_REMESH,
@@ -305,11 +305,6 @@ const EnumPropertyItem rna_enum_object_modifier_type_items[] = {
"Spawn particles from the shape"},
{eModifierType_Softbody, "SOFT_BODY", ICON_MOD_SOFT, "Soft Body", ""},
{eModifierType_Surface, "SURFACE", ICON_MODIFIER, "Surface", ""},
- {eModifierType_Simulation,
- "SIMULATION",
- ICON_PHYSICS,
- "Simulation",
- ""}, /* TODO: Use correct icon. */
{0, NULL, 0, NULL, NULL},
};
@@ -1602,6 +1597,14 @@ static int rna_MeshSequenceCacheModifier_read_velocity_get(PointerRNA *ptr)
# endif
}
+static bool rna_NodesModifier_node_group_poll(PointerRNA *ptr, PointerRNA value)
+{
+ NodesModifierData *nmd = ptr->data;
+ bNodeTree *ntree = value.data;
+ UNUSED_VARS(nmd, ntree);
+ return true;
+}
+
#else
/* NOTE: *MUST* return subdivision_type property. */
@@ -6920,17 +6923,24 @@ static void rna_def_modifier_weightednormal(BlenderRNA *brna)
}
# ifdef WITH_GEOMETRY_NODES
-static void rna_def_modifier_simulation(BlenderRNA *brna)
+static void rna_def_modifier_nodes(BlenderRNA *brna)
{
StructRNA *srna;
+ PropertyRNA *prop;
- srna = RNA_def_struct(brna, "SimulationModifier", "Modifier");
- RNA_def_struct_ui_text(srna, "Simulation Modifier", "");
- RNA_def_struct_sdna(srna, "SimulationModifierData");
- RNA_def_struct_ui_icon(srna, ICON_PHYSICS); /* TODO: Use correct icon. */
+ srna = RNA_def_struct(brna, "NodesModifier", "Modifier");
+ RNA_def_struct_ui_text(srna, "Nodes Modifier", "");
+ RNA_def_struct_sdna(srna, "NodesModifierData");
+ RNA_def_struct_ui_icon(srna, ICON_MESH_DATA); /* TODO: Use correct icon. */
RNA_define_lib_overridable(true);
+ prop = RNA_def_property(srna, "node_group", PROP_POINTER, PROP_NONE);
+ RNA_def_property_ui_text(prop, "Node Group", "Node group that controls what this modifier does");
+ RNA_def_property_pointer_funcs(prop, NULL, NULL, NULL, "rna_NodesModifier_node_group_poll");
+ RNA_def_property_flag(prop, PROP_EDITABLE);
+ RNA_def_property_update(prop, 0, "rna_Modifier_dependency_update");
+
RNA_define_lib_overridable(false);
}
# endif
@@ -7290,7 +7300,7 @@ void RNA_def_modifier(BlenderRNA *brna)
rna_def_modifier_surfacedeform(brna);
rna_def_modifier_weightednormal(brna);
# ifdef WITH_GEOMETRY_NODES
- rna_def_modifier_simulation(brna);
+ rna_def_modifier_nodes(brna);
# endif
rna_def_modifier_mesh_to_volume(brna);
rna_def_modifier_volume_displace(brna);
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 0dea0e47978..b0f039c5b21 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -38,7 +38,6 @@
#include "BKE_animsys.h"
#include "BKE_image.h"
#include "BKE_node.h"
-#include "BKE_simulation.h"
#include "BKE_texture.h"
#include "RNA_access.h"
@@ -84,6 +83,7 @@ static const EnumPropertyItem node_socket_type_items[] = {
{SOCK_SHADER, "SHADER", 0, "Shader", ""},
{SOCK_OBJECT, "OBJECT", 0, "Object", ""},
{SOCK_IMAGE, "IMAGE", 0, "Image", ""},
+ {SOCK_GEOMETRY, "GEOMETRY", 0, "Geometry", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -96,6 +96,7 @@ static const EnumPropertyItem node_socket_data_type_items[] = {
{SOCK_RGBA, "RGBA", 0, "Color", ""},
{SOCK_OBJECT, "OBJECT", 0, "Object", ""},
{SOCK_IMAGE, "IMAGE", 0, "Image", ""},
+ {SOCK_GEOMETRY, "GEOMETRY", 0, "Geometry", ""},
{0, NULL, 0, NULL, NULL},
};
@@ -725,9 +726,9 @@ static const EnumPropertyItem *rna_node_static_type_itemf(bContext *UNUSED(C),
# undef DefNode
}
- if (RNA_struct_is_a(ptr->type, &RNA_SimulationNode)) {
+ if (RNA_struct_is_a(ptr->type, &RNA_GeometryNode)) {
# define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \
- if (STREQ(#Category, "SimulationNode")) { \
+ if (STREQ(#Category, "GeometryNode")) { \
tmp.value = ID; \
tmp.identifier = EnumName; \
tmp.name = UIName; \
@@ -1868,16 +1869,16 @@ static StructRNA *rna_TextureNode_register(Main *bmain,
return nt->rna_ext.srna;
}
-static StructRNA *rna_SimulationNode_register(Main *bmain,
- ReportList *reports,
- void *data,
- const char *identifier,
- StructValidateFunc validate,
- StructCallbackFunc call,
- StructFreeFunc free)
+static StructRNA *rna_GeometryNode_register(Main *bmain,
+ ReportList *reports,
+ void *data,
+ const char *identifier,
+ StructValidateFunc validate,
+ StructCallbackFunc call,
+ StructFreeFunc free)
{
bNodeType *nt = rna_Node_register_base(
- bmain, reports, &RNA_SimulationNode, data, identifier, validate, call, free);
+ bmain, reports, &RNA_GeometryNode, data, identifier, validate, call, free);
if (!nt) {
return NULL;
}
@@ -8177,14 +8178,14 @@ static void rna_def_texture_node(BlenderRNA *brna)
RNA_def_struct_register_funcs(srna, "rna_TextureNode_register", "rna_Node_unregister", NULL);
}
-static void rna_def_simulation_node(BlenderRNA *brna)
+static void rna_def_geometry_node(BlenderRNA *brna)
{
StructRNA *srna;
- srna = RNA_def_struct(brna, "SimulationNode", "NodeInternal");
- RNA_def_struct_ui_text(srna, "Simulation Node", "");
+ srna = RNA_def_struct(brna, "GeometryNode", "NodeInternal");
+ RNA_def_struct_ui_text(srna, "Geometry Node", "");
RNA_def_struct_sdna(srna, "bNode");
- RNA_def_struct_register_funcs(srna, "rna_SimulationNode_register", "rna_Node_unregister", NULL);
+ RNA_def_struct_register_funcs(srna, "rna_GeometryNode_register", "rna_Node_unregister", NULL);
}
static void rna_def_function_node(BlenderRNA *brna)
@@ -8831,6 +8832,21 @@ static void rna_def_node_socket_image(BlenderRNA *brna,
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_NodeSocketInterface_update");
}
+static void rna_def_node_socket_geometry(BlenderRNA *brna,
+ const char *identifier,
+ const char *interface_idname)
+{
+ StructRNA *srna;
+
+ srna = RNA_def_struct(brna, identifier, "NodeSocketStandard");
+ RNA_def_struct_ui_text(srna, "Geometry Node Socket", "Geometry socket of a node");
+ RNA_def_struct_sdna(srna, "bNodeSocket");
+
+ srna = RNA_def_struct(brna, interface_idname, "NodeSocketInterfaceStandard");
+ RNA_def_struct_ui_text(srna, "Geometry Node Socket Interface", "Geometry socket of a node");
+ RNA_def_struct_sdna(srna, "bNodeSocket");
+}
+
static void rna_def_node_socket_standard_types(BlenderRNA *brna)
{
/* XXX Workaround: Registered functions are not exposed in python by bpy,
@@ -8969,6 +8985,8 @@ static void rna_def_node_socket_standard_types(BlenderRNA *brna)
rna_def_node_socket_object(brna, "NodeSocketObject", "NodeSocketInterfaceObject");
rna_def_node_socket_image(brna, "NodeSocketImage", "NodeSocketInterfaceImage");
+
+ rna_def_node_socket_geometry(brna, "NodeSocketGeometry", "NodeSocketInterfaceGeometry");
}
static void rna_def_internal_node(BlenderRNA *brna)
@@ -9606,7 +9624,7 @@ static void rna_def_nodetree(BlenderRNA *brna)
{NTREE_SHADER, "SHADER", ICON_MATERIAL, "Shader", "Shader nodes"},
{NTREE_TEXTURE, "TEXTURE", ICON_TEXTURE, "Texture", "Texture nodes"},
{NTREE_COMPOSIT, "COMPOSITING", ICON_RENDERLAYERS, "Compositing", "Compositing nodes"},
- {NTREE_SIMULATION, "SIMULATION", ICON_PHYSICS, "Simulation", "Simulation nodes"},
+ {NTREE_GEOMETRY, "GEOMETRY", ICON_MESH_DATA, "Geometry", "Geometry nodes"},
{0, NULL, 0, NULL, NULL},
};
@@ -9830,15 +9848,15 @@ static void rna_def_texture_nodetree(BlenderRNA *brna)
RNA_def_struct_ui_icon(srna, ICON_TEXTURE);
}
-static void rna_def_simulation_nodetree(BlenderRNA *brna)
+static void rna_def_geometry_nodetree(BlenderRNA *brna)
{
StructRNA *srna;
- srna = RNA_def_struct(brna, "SimulationNodeTree", "NodeTree");
+ srna = RNA_def_struct(brna, "GeometryNodeTree", "NodeTree");
RNA_def_struct_ui_text(
- srna, "Simulation Node Tree", "Node tree consisting of linked nodes used for simulations");
+ srna, "Geometry Node Tree", "Node tree consisting of linked nodes used for geometries");
RNA_def_struct_sdna(srna, "bNodeTree");
- RNA_def_struct_ui_icon(srna, ICON_PHYSICS); /* TODO: Use correct icon. */
+ RNA_def_struct_ui_icon(srna, ICON_MESH_DATA); /* TODO: Use correct icon. */
}
static StructRNA *define_specific_node(BlenderRNA *brna,
@@ -9927,7 +9945,7 @@ void RNA_def_nodetree(BlenderRNA *brna)
rna_def_shader_node(brna);
rna_def_compositor_node(brna);
rna_def_texture_node(brna);
- rna_def_simulation_node(brna);
+ rna_def_geometry_node(brna);
rna_def_function_node(brna);
rna_def_nodetree(brna);
@@ -9937,7 +9955,7 @@ void RNA_def_nodetree(BlenderRNA *brna)
rna_def_composite_nodetree(brna);
rna_def_shader_nodetree(brna);
rna_def_texture_nodetree(brna);
- rna_def_simulation_nodetree(brna);
+ rna_def_geometry_nodetree(brna);
# define DefNode(Category, ID, DefFunc, EnumName, StructName, UIName, UIDesc) \
{ \
@@ -9954,13 +9972,13 @@ void RNA_def_nodetree(BlenderRNA *brna)
*/
# include "../../nodes/NOD_static_types.h"
- /* Node group types need to be defined for shader, compositor, texture, simulation nodes
+ /* Node group types need to be defined for shader, compositor, texture, geometry nodes
* individually. Cannot use the static types header for this, since they share the same int id.
*/
define_specific_node(brna, "ShaderNodeGroup", "ShaderNode", "Group", "", def_group);
define_specific_node(brna, "CompositorNodeGroup", "CompositorNode", "Group", "", def_group);
define_specific_node(brna, "TextureNodeGroup", "TextureNode", "Group", "", def_group);
- define_specific_node(brna, "SimulationNodeGroup", "SimulationNode", "Group", "", def_group);
+ define_specific_node(brna, "GeometryNodeGroup", "GeometryNode", "Group", "", def_group);
def_custom_group(brna,
"ShaderNodeCustomGroup",
"ShaderNode",
diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c
index 3255f335e74..91e572caab0 100644
--- a/source/blender/makesrna/intern/rna_space.c
+++ b/source/blender/makesrna/intern/rna_space.c
@@ -45,7 +45,6 @@
#include "DNA_node_types.h"
#include "DNA_object_types.h"
#include "DNA_sequence_types.h"
-#include "DNA_simulation_types.h"
#include "DNA_space_types.h"
#include "DNA_view3d_types.h"
#include "DNA_workspace_types.h"
@@ -2178,40 +2177,6 @@ static void rna_SpaceNodeEditor_node_tree_update(const bContext *C, PointerRNA *
ED_node_tree_update(C);
}
-# ifdef WITH_GEOMETRY_NODES
-static PointerRNA rna_SpaceNodeEditor_simulation_get(PointerRNA *ptr)
-{
- SpaceNode *snode = (SpaceNode *)ptr->data;
- ID *id = snode->id;
- if (id && GS(id->name) == ID_SIM) {
- return rna_pointer_inherit_refine(ptr, &RNA_Simulation, snode->id);
- }
- else {
- return PointerRNA_NULL;
- }
-}
-
-static void rna_SpaceNodeEditor_simulation_set(PointerRNA *ptr,
- const PointerRNA value,
- struct ReportList *UNUSED(reports))
-{
- SpaceNode *snode = (SpaceNode *)ptr->data;
- if (!STREQ(snode->tree_idname, "SimulationNodeTree")) {
- return;
- }
-
- Simulation *sim = (Simulation *)value.data;
- if (sim != NULL) {
- bNodeTree *ntree = sim->nodetree;
- ED_node_tree_start(snode, ntree, NULL, NULL);
- }
- else {
- ED_node_tree_start(snode, NULL, NULL, NULL);
- }
- snode->id = &sim->id;
-}
-# endif
-
static int rna_SpaceNodeEditor_tree_type_get(PointerRNA *ptr)
{
SpaceNode *snode = (SpaceNode *)ptr->data;
@@ -6347,19 +6312,6 @@ static void rna_def_space_node(BlenderRNA *brna)
RNA_def_property_ui_text(
prop, "ID From", "Data-block from which the edited data-block is linked");
-# ifdef WITH_GEOMETRY_NODES
- prop = RNA_def_property(srna, "simulation", PROP_POINTER, PROP_NONE);
- RNA_def_property_flag(prop, PROP_EDITABLE);
- RNA_def_property_struct_type(prop, "Simulation");
- RNA_def_property_ui_text(prop, "Simulation", "Simulation that is being edited");
- RNA_def_property_pointer_funcs(prop,
- "rna_SpaceNodeEditor_simulation_get",
- "rna_SpaceNodeEditor_simulation_set",
- NULL,
- NULL);
- RNA_def_property_update(prop, NC_SPACE | ND_SPACE_NODE, NULL);
-# endif
-
prop = RNA_def_property(srna, "path", PROP_COLLECTION, PROP_NONE);
RNA_def_property_collection_sdna(prop, NULL, "treepath", NULL);
RNA_def_property_struct_type(prop, "NodeTreePath");
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index 65024e46a2b..bacde95ee20 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -29,8 +29,10 @@ set(INC
../bmesh
../depsgraph
../editors/include
+ ../functions
../makesdna
../makesrna
+ ../nodes
../render/extern/include
../windowmanager
../../../intern/eigen
@@ -86,7 +88,7 @@ set(SRC
intern/MOD_shapekey.c
intern/MOD_shrinkwrap.c
intern/MOD_simpledeform.c
- intern/MOD_simulation.cc
+ intern/MOD_nodes.cc
intern/MOD_skin.c
intern/MOD_smooth.c
intern/MOD_softbody.c
diff --git a/source/blender/modifiers/MOD_modifiertypes.h b/source/blender/modifiers/MOD_modifiertypes.h
index 9c488780366..f36cb7ded9c 100644
--- a/source/blender/modifiers/MOD_modifiertypes.h
+++ b/source/blender/modifiers/MOD_modifiertypes.h
@@ -85,7 +85,7 @@ extern ModifierTypeInfo modifierType_CorrectiveSmooth;
extern ModifierTypeInfo modifierType_MeshSequenceCache;
extern ModifierTypeInfo modifierType_SurfaceDeform;
extern ModifierTypeInfo modifierType_WeightedNormal;
-extern ModifierTypeInfo modifierType_Simulation;
+extern ModifierTypeInfo modifierType_Nodes;
extern ModifierTypeInfo modifierType_MeshToVolume;
extern ModifierTypeInfo modifierType_VolumeDisplace;
extern ModifierTypeInfo modifierType_VolumeToMesh;
diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c
index 882d080c08d..1743321d44d 100644
--- a/source/blender/modifiers/intern/MOD_edgesplit.c
+++ b/source/blender/modifiers/intern/MOD_edgesplit.c
@@ -53,7 +53,10 @@
#include "MOD_modifiertypes.h"
#include "MOD_ui_common.h"
-static Mesh *doEdgeSplit(Mesh *mesh, EdgeSplitModifierData *emd)
+/* For edge split modifier node. */
+Mesh *doEdgeSplit(Mesh *mesh, EdgeSplitModifierData *emd);
+
+Mesh *doEdgeSplit(Mesh *mesh, EdgeSplitModifierData *emd)
{
Mesh *result;
BMesh *bm;
diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc
new file mode 100644
index 00000000000..38712054f22
--- /dev/null
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -0,0 +1,436 @@
+/*
+ * 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 by the Blender Foundation.
+ * All rights reserved.
+ */
+
+/** \file
+ * \ingroup modifiers
+ */
+
+#include <cstring>
+#include <iostream>
+#include <string>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_float3.hh"
+#include "BLI_listbase.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_defaults.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+#include "DNA_modifier_types.h"
+#include "DNA_node_types.h"
+#include "DNA_object_types.h"
+#include "DNA_pointcloud_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_screen_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_lib_query.h"
+#include "BKE_mesh.h"
+#include "BKE_modifier.h"
+#include "BKE_pointcloud.h"
+#include "BKE_screen.h"
+#include "BKE_simulation.h"
+
+#include "BLO_read_write.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "RNA_access.h"
+
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MOD_modifiertypes.h"
+#include "MOD_ui_common.h"
+
+#include "NOD_derived_node_tree.hh"
+#include "NOD_geometry_exec.hh"
+#include "NOD_node_tree_multi_function.hh"
+#include "NOD_type_callbacks.hh"
+
+using blender::float3;
+
+static void initData(ModifierData *md)
+{
+ NodesModifierData *nmd = (NodesModifierData *)md;
+
+ BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(nmd, modifier));
+
+ MEMCPY_STRUCT_AFTER(nmd, DNA_struct_default_get(NodesModifierData), modifier);
+}
+
+static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *ctx)
+{
+ NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
+ if (nmd->node_group != nullptr) {
+ DEG_add_node_tree_relation(ctx->node, nmd->node_group, "Nodes Modifier");
+ }
+}
+
+static void foreachIDLink(ModifierData *md, Object *ob, IDWalkFunc walk, void *userData)
+{
+ NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
+ walk(userData, ob, (ID **)&nmd->node_group, IDWALK_CB_USER);
+}
+
+static bool isDisabled(const struct Scene *UNUSED(scene),
+ ModifierData *md,
+ bool UNUSED(useRenderParams))
+{
+ NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
+ UNUSED_VARS(nmd);
+ return false;
+}
+
+static PointCloud *modifyPointCloud(ModifierData *md,
+ const ModifierEvalContext *UNUSED(ctx),
+ PointCloud *pointcloud)
+{
+ NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
+ UNUSED_VARS(nmd);
+ std::cout << __func__ << "\n";
+ return pointcloud;
+}
+
+/* To be replaced soon. */
+using namespace blender;
+using namespace blender::nodes;
+using namespace blender::fn;
+using namespace blender::bke;
+
+class GeometryNodesEvaluator {
+ private:
+ LinearAllocator<> allocator_;
+ const DerivedNodeTree &tree_;
+ Map<const DOutputSocket *, GMutablePointer> group_input_data_;
+ Vector<const DInputSocket *> group_outputs_;
+ MultiFunctionByNode &mf_by_node_;
+ const DataTypeConversions &conversions_;
+
+ public:
+ GeometryNodesEvaluator(const DerivedNodeTree &tree,
+ Map<const DOutputSocket *, GMutablePointer> group_input_data,
+ Vector<const DInputSocket *> group_outputs,
+ MultiFunctionByNode &mf_by_node)
+ : tree_(tree),
+ group_input_data_(std::move(group_input_data)),
+ group_outputs_(std::move(group_outputs)),
+ mf_by_node_(mf_by_node),
+ conversions_(get_implicit_type_conversions())
+ {
+ }
+
+ Vector<GMutablePointer> execute()
+ {
+ Vector<GMutablePointer> results;
+ for (const DInputSocket *group_output : group_outputs_) {
+ const CPPType &type = *socket_cpp_type_get(*group_output->typeinfo());
+ void *result_buffer = allocator_.allocate(type.size(), type.alignment());
+ this->compute_input_socket(*group_output, result_buffer);
+ results.append(GMutablePointer{type, result_buffer});
+ }
+ for (GMutablePointer value : group_input_data_.values()) {
+ value.type()->destruct(value.get());
+ }
+ return results;
+ }
+
+ private:
+ void compute_input_socket(const DInputSocket &socket_to_compute, void *r_value)
+ {
+ Span<const DOutputSocket *> from_sockets = socket_to_compute.linked_sockets();
+ Span<const DGroupInput *> from_group_inputs = socket_to_compute.linked_group_inputs();
+ const int total_inputs = from_sockets.size() + from_group_inputs.size();
+ BLI_assert(total_inputs <= 1);
+
+ if (total_inputs == 0) {
+ bNodeSocket &bsocket = *socket_to_compute.bsocket();
+ socket_cpp_value_get(bsocket, r_value);
+ return;
+ }
+ if (from_group_inputs.size() == 1) {
+ bNodeSocket &bsocket = *from_group_inputs[0]->bsocket();
+ socket_cpp_value_get(bsocket, r_value);
+ return;
+ }
+
+ const DOutputSocket &from_socket = *from_sockets[0];
+ const CPPType &from_type = *socket_cpp_type_get(*from_socket.typeinfo());
+ const CPPType &to_type = *socket_cpp_type_get(*socket_to_compute.typeinfo());
+ if (from_type == to_type) {
+ this->compute_output_socket(from_socket, r_value);
+ }
+ else {
+ /* The type of both sockets don't match, so a conversion is necessary. */
+ if (conversions_.is_convertible(from_type, to_type)) {
+ void *from_value = allocator_.allocate(from_type.size(), from_type.alignment());
+ this->compute_output_socket(from_socket, from_value);
+ conversions_.convert(from_type, to_type, from_value, r_value);
+ from_type.destruct(from_value);
+ }
+ else {
+ /* Use a default value when the types cannot be converted. */
+ to_type.copy_to_uninitialized(to_type.default_value(), r_value);
+ }
+ }
+ }
+
+ void compute_output_socket(const DOutputSocket &socket_to_compute, void *r_value)
+ {
+ const GMutablePointer *group_input = group_input_data_.lookup_ptr(&socket_to_compute);
+ if (group_input != nullptr) {
+ const CPPType &type = *group_input->type();
+ type.copy_to_uninitialized(group_input->get(), r_value);
+ return;
+ }
+
+ const DNode &node = socket_to_compute.node();
+ GValueByName node_inputs{allocator_};
+
+ /* Compute all inputs for the node. */
+ for (const DInputSocket *input_socket : node.inputs()) {
+ const CPPType &type = *socket_cpp_type_get(*input_socket->typeinfo());
+ void *buffer = allocator_.allocate(type.size(), type.alignment());
+ compute_input_socket(*input_socket, buffer);
+ node_inputs.move_in(input_socket->identifier(), GMutablePointer{type, buffer});
+ type.destruct(buffer);
+ }
+
+ /* Execute the node itself. */
+ GValueByName node_outputs{allocator_};
+ this->execute_node(node, node_inputs, node_outputs);
+
+ /* Pass relevant value to the caller. */
+ bNodeSocket *bsocket_to_compute = socket_to_compute.bsocket();
+ const CPPType &type_to_compute = *socket_cpp_type_get(*bsocket_to_compute->typeinfo);
+ GMutablePointer computed_value = node_outputs.extract(bsocket_to_compute->identifier);
+ type_to_compute.relocate_to_uninitialized(computed_value.get(), r_value);
+ }
+
+ void execute_node(const DNode &node, GValueByName &node_inputs, GValueByName &node_outputs)
+ {
+ bNode *bnode = node.bnode();
+ if (bnode->typeinfo->geometry_node_execute != nullptr) {
+ bnode->typeinfo->geometry_node_execute(bnode, node_inputs, node_outputs);
+ return;
+ }
+
+ /* Use the multi-function implementation of the node. */
+ const MultiFunction &fn = *mf_by_node_.lookup(&node);
+ MFContextBuilder context;
+ MFParamsBuilder params{fn, 1};
+ Vector<GMutablePointer> input_data;
+ for (const DInputSocket *dsocket : node.inputs()) {
+ if (dsocket->is_available()) {
+ GMutablePointer data = node_inputs.extract(dsocket->identifier());
+ params.add_readonly_single_input(GSpan(*data.type(), data.get(), 1));
+ input_data.append(data);
+ }
+ }
+ Vector<GMutablePointer> output_data;
+ for (const DOutputSocket *dsocket : node.outputs()) {
+ if (dsocket->is_available()) {
+ const CPPType &type = *socket_cpp_type_get(*dsocket->typeinfo());
+ void *buffer = allocator_.allocate(type.size(), type.alignment());
+ params.add_uninitialized_single_output(GMutableSpan(type, buffer, 1));
+ output_data.append(GMutablePointer(type, buffer));
+ }
+ }
+ fn.call(IndexRange(1), params, context);
+ for (GMutablePointer value : input_data) {
+ value.destruct();
+ }
+ for (const int i : node.outputs().index_range()) {
+ GMutablePointer value = output_data[i];
+ node_outputs.move_in(node.output(i).identifier(), value);
+ value.destruct();
+ }
+ }
+};
+
+/**
+ * Evaluate a node group to compute the output geometry.
+ * Currently, this uses a fairly basic and inefficient algorithm that might compute things more
+ * often than necessary. It's going to be replaced soon.
+ */
+static GeometryPtr compute_geometry(const DerivedNodeTree &tree,
+ const DOutputSocket *group_input,
+ GeometryPtr group_input_geometry,
+ const DInputSocket &socket_to_compute)
+{
+ ResourceCollector resources;
+ MultiFunctionByNode mf_by_node = get_multi_function_per_node(tree, resources);
+
+ /* Use this buffer so that it is not destructed when the scope ends. The evaluator is responsible
+ * for destructing it. */
+ TypedBuffer<GeometryPtr> buffer;
+ new (buffer.ptr()) GeometryPtr(std::move(group_input_geometry));
+
+ Map<const DOutputSocket *, GMutablePointer> group_inputs;
+ group_inputs.add_new(group_input, GMutablePointer{buffer.ptr()});
+
+ Vector<const DInputSocket *> group_outputs;
+ group_outputs.append(&socket_to_compute);
+
+ GeometryNodesEvaluator evaluator{tree, group_inputs, group_outputs, mf_by_node};
+ Vector<GMutablePointer> results = evaluator.execute();
+ BLI_assert(results.size() == 1);
+ GMutablePointer result = results[0];
+
+ GeometryPtr output_geometry = std::move(*(GeometryPtr *)result.get());
+ return output_geometry;
+}
+
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *UNUSED(ctx), Mesh *mesh)
+{
+ NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
+ if (nmd->node_group == nullptr) {
+ return mesh;
+ }
+
+ NodeTreeRefMap tree_refs;
+ DerivedNodeTree tree{nmd->node_group, tree_refs};
+ ResourceCollector resources;
+
+ Span<const DNode *> input_nodes = tree.nodes_by_type("NodeGroupInput");
+ Span<const DNode *> output_nodes = tree.nodes_by_type("NodeGroupOutput");
+
+ if (input_nodes.size() > 1) {
+ return mesh;
+ }
+ if (output_nodes.size() != 1) {
+ return mesh;
+ }
+
+ Span<const DOutputSocket *> group_inputs = (input_nodes.size() == 1) ?
+ input_nodes[0]->outputs().drop_back(1) :
+ Span<const DOutputSocket *>{};
+ Span<const DInputSocket *> group_outputs = output_nodes[0]->inputs().drop_back(1);
+
+ if (group_outputs.size() != 1) {
+ return mesh;
+ }
+
+ const DInputSocket *group_output = group_outputs[0];
+ if (group_output->idname() != "NodeSocketGeometry") {
+ return mesh;
+ }
+
+ GeometryPtr input_geometry{new Geometry()};
+ input_geometry->mesh_set_and_keep_ownership(mesh);
+
+ GeometryPtr new_geometry = compute_geometry(
+ tree, group_inputs[0], std::move(input_geometry), *group_outputs[0]);
+ make_geometry_mutable(new_geometry);
+ Mesh *new_mesh = new_geometry->mesh_release();
+ if (new_mesh == nullptr) {
+ return BKE_mesh_new_nomain(0, 0, 0, 0, 0);
+ }
+ return new_mesh;
+}
+
+static void panel_draw(const bContext *UNUSED(C), Panel *panel)
+{
+ uiLayout *layout = panel->layout;
+
+ PointerRNA ob_ptr;
+ PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
+
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+
+ uiItemR(layout, ptr, "node_group", 0, NULL, ICON_MESH_DATA);
+
+ modifier_panel_end(layout, ptr);
+}
+
+static void panelRegister(ARegionType *region_type)
+{
+ modifier_panel_register(region_type, eModifierType_Nodes, panel_draw);
+}
+
+static void blendWrite(BlendWriter *writer, const ModifierData *md)
+{
+ const NodesModifierData *nmd = reinterpret_cast<const NodesModifierData *>(md);
+ UNUSED_VARS(nmd, writer);
+}
+
+static void blendRead(BlendDataReader *reader, ModifierData *md)
+{
+ NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
+ UNUSED_VARS(nmd, reader);
+}
+
+static void copyData(const ModifierData *md, ModifierData *target, const int flag)
+{
+ const NodesModifierData *nmd = reinterpret_cast<const NodesModifierData *>(md);
+ NodesModifierData *tnmd = reinterpret_cast<NodesModifierData *>(target);
+ UNUSED_VARS(nmd, tnmd);
+
+ BKE_modifier_copydata_generic(md, target, flag);
+}
+
+static void freeData(ModifierData *md)
+{
+ NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
+ UNUSED_VARS(nmd);
+}
+
+ModifierTypeInfo modifierType_Nodes = {
+ /* name */ "Nodes",
+ /* structName */ "NodesModifierData",
+ /* structSize */ sizeof(NodesModifierData),
+#ifdef WITH_GEOMETRY_NODES
+ /* srna */ &RNA_NodesModifier,
+#else
+ /* srna */ &RNA_Modifier,
+#endif
+ /* type */ eModifierTypeType_Constructive,
+ /* flags */ eModifierTypeFlag_AcceptsMesh,
+ /* icon */ ICON_MESH_DATA, /* TODO: Use correct icon. */
+
+ /* copyData */ copyData,
+
+ /* deformVerts */ NULL,
+ /* deformMatrices */ NULL,
+ /* deformVertsEM */ NULL,
+ /* deformMatricesEM */ NULL,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ NULL,
+ /* modifyPointCloud */ modifyPointCloud,
+ /* modifyVolume */ NULL,
+
+ /* initData */ initData,
+ /* requiredDataMask */ NULL,
+ /* freeData */ freeData,
+ /* isDisabled */ isDisabled,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ NULL,
+ /* dependsOnNormals */ NULL,
+ /* foreachIDLink */ foreachIDLink,
+ /* foreachTexLink */ NULL,
+ /* freeRuntimeData */ NULL,
+ /* panelRegister */ panelRegister,
+ /* blendWrite */ blendWrite,
+ /* blendRead */ blendRead,
+};
diff --git a/source/blender/modifiers/intern/MOD_simulation.cc b/source/blender/modifiers/intern/MOD_simulation.cc
deleted file mode 100644
index 10a4b3f7cf9..00000000000
--- a/source/blender/modifiers/intern/MOD_simulation.cc
+++ /dev/null
@@ -1,194 +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 by the Blender Foundation.
- * All rights reserved.
- */
-
-/** \file
- * \ingroup modifiers
- */
-
-#include <cstring>
-#include <iostream>
-#include <string>
-
-#include "MEM_guardedalloc.h"
-
-#include "BLI_float3.hh"
-#include "BLI_listbase.h"
-#include "BLI_string.h"
-#include "BLI_utildefines.h"
-
-#include "DNA_defaults.h"
-#include "DNA_mesh_types.h"
-#include "DNA_meshdata_types.h"
-#include "DNA_modifier_types.h"
-#include "DNA_object_types.h"
-#include "DNA_pointcloud_types.h"
-#include "DNA_scene_types.h"
-#include "DNA_screen_types.h"
-#include "DNA_simulation_types.h"
-
-#include "BKE_customdata.h"
-#include "BKE_lib_query.h"
-#include "BKE_mesh.h"
-#include "BKE_modifier.h"
-#include "BKE_pointcloud.h"
-#include "BKE_screen.h"
-#include "BKE_simulation.h"
-
-#include "BLO_read_write.h"
-
-#include "UI_interface.h"
-#include "UI_resources.h"
-
-#include "RNA_access.h"
-
-#include "DEG_depsgraph_build.h"
-#include "DEG_depsgraph_query.h"
-
-#include "MOD_modifiertypes.h"
-#include "MOD_ui_common.h"
-
-using blender::float3;
-
-static void initData(ModifierData *md)
-{
- SimulationModifierData *smd = (SimulationModifierData *)md;
-
- BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(smd, modifier));
-
- MEMCPY_STRUCT_AFTER(smd, DNA_struct_default_get(SimulationModifierData), modifier);
-}
-
-static void updateDepsgraph(ModifierData *md, const ModifierUpdateDepsgraphContext *UNUSED(ctx))
-{
- SimulationModifierData *smd = reinterpret_cast<SimulationModifierData *>(md);
- UNUSED_VARS(smd);
-}
-
-static void foreachIDLink(ModifierData *md,
- Object *UNUSED(ob),
- IDWalkFunc UNUSED(walk),
- void *UNUSED(userData))
-{
- SimulationModifierData *smd = reinterpret_cast<SimulationModifierData *>(md);
- UNUSED_VARS(smd);
-}
-
-static bool isDisabled(const struct Scene *UNUSED(scene),
- ModifierData *md,
- bool UNUSED(useRenderParams))
-{
- SimulationModifierData *smd = reinterpret_cast<SimulationModifierData *>(md);
- UNUSED_VARS(smd);
- return false;
-}
-
-static PointCloud *modifyPointCloud(ModifierData *md,
- const ModifierEvalContext *UNUSED(ctx),
- PointCloud *pointcloud)
-{
- SimulationModifierData *smd = reinterpret_cast<SimulationModifierData *>(md);
- UNUSED_VARS(smd);
- return pointcloud;
-}
-
-static void panel_draw(const bContext *UNUSED(C), Panel *panel)
-{
- uiLayout *layout = panel->layout;
-
- PointerRNA ob_ptr;
- PointerRNA *ptr = modifier_panel_get_property_pointers(panel, &ob_ptr);
-
- uiLayoutSetPropSep(layout, true);
- uiLayoutSetPropDecorate(layout, false);
-
- uiItemL(layout, "This modifier does nothing currently", ICON_INFO);
-
- modifier_panel_end(layout, ptr);
-}
-
-static void panelRegister(ARegionType *region_type)
-{
- modifier_panel_register(region_type, eModifierType_Simulation, panel_draw);
-}
-
-static void blendWrite(BlendWriter *writer, const ModifierData *md)
-{
- const SimulationModifierData *smd = reinterpret_cast<const SimulationModifierData *>(md);
- UNUSED_VARS(smd, writer);
-}
-
-static void blendRead(BlendDataReader *reader, ModifierData *md)
-{
- SimulationModifierData *smd = reinterpret_cast<SimulationModifierData *>(md);
- UNUSED_VARS(smd, reader);
-}
-
-static void copyData(const ModifierData *md, ModifierData *target, const int flag)
-{
- const SimulationModifierData *smd = reinterpret_cast<const SimulationModifierData *>(md);
- SimulationModifierData *tsmd = reinterpret_cast<SimulationModifierData *>(target);
- UNUSED_VARS(smd, tsmd);
-
- BKE_modifier_copydata_generic(md, target, flag);
-}
-
-static void freeData(ModifierData *md)
-{
- SimulationModifierData *smd = reinterpret_cast<SimulationModifierData *>(md);
- UNUSED_VARS(smd);
-}
-
-ModifierTypeInfo modifierType_Simulation = {
- /* name */ "Simulation",
- /* structName */ "SimulationModifierData",
- /* structSize */ sizeof(SimulationModifierData),
-#ifdef WITH_GEOMETRY_NODES
- /* srna */ &RNA_SimulationModifier,
-#else
- /* srna */ &RNA_Modifier,
-#endif
- /* type */ eModifierTypeType_None,
- /* flags */ (ModifierTypeFlag)0,
- /* icon */ ICON_PHYSICS, /* TODO: Use correct icon. */
-
- /* copyData */ copyData,
-
- /* deformVerts */ NULL,
- /* deformMatrices */ NULL,
- /* deformVertsEM */ NULL,
- /* deformMatricesEM */ NULL,
- /* modifyMesh */ NULL,
- /* modifyHair */ NULL,
- /* modifyPointCloud */ modifyPointCloud,
- /* modifyVolume */ NULL,
-
- /* initData */ initData,
- /* requiredDataMask */ NULL,
- /* freeData */ freeData,
- /* isDisabled */ isDisabled,
- /* updateDepsgraph */ updateDepsgraph,
- /* dependsOnTime */ NULL,
- /* dependsOnNormals */ NULL,
- /* foreachIDLink */ foreachIDLink,
- /* foreachTexLink */ NULL,
- /* freeRuntimeData */ NULL,
- /* panelRegister */ panelRegister,
- /* blendWrite */ blendWrite,
- /* blendRead */ blendRead,
-};
diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c
index 5a07c4e5e64..1930a38b825 100644
--- a/source/blender/modifiers/intern/MOD_triangulate.c
+++ b/source/blender/modifiers/intern/MOD_triangulate.c
@@ -48,11 +48,17 @@
#include "MOD_modifiertypes.h"
#include "MOD_ui_common.h"
-static Mesh *triangulate_mesh(Mesh *mesh,
- const int quad_method,
- const int ngon_method,
- const int min_vertices,
- const int flag)
+Mesh *triangulate_mesh(Mesh *mesh,
+ const int quad_method,
+ const int ngon_method,
+ const int min_vertices,
+ const int flag);
+
+Mesh *triangulate_mesh(Mesh *mesh,
+ const int quad_method,
+ const int ngon_method,
+ const int min_vertices,
+ const int flag)
{
Mesh *result;
BMesh *bm;
diff --git a/source/blender/modifiers/intern/MOD_util.c b/source/blender/modifiers/intern/MOD_util.c
index e0802dc5fb4..32d40027537 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -342,7 +342,7 @@ void modifier_type_init(ModifierTypeInfo *types[])
INIT_TYPE(MeshSequenceCache);
INIT_TYPE(SurfaceDeform);
INIT_TYPE(WeightedNormal);
- INIT_TYPE(Simulation);
+ INIT_TYPE(Nodes);
INIT_TYPE(MeshToVolume);
INIT_TYPE(VolumeDisplace);
INIT_TYPE(VolumeToMesh);
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 78b3e6236f0..9058ee965a5 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -24,7 +24,7 @@ set(INC
function
intern
shader
- simulation
+ geometry
texture
../blenkernel
../blenlib
@@ -137,6 +137,13 @@ set(SRC
function/nodes/node_fn_switch.cc
function/node_function_util.cc
+ geometry/nodes/node_geo_common.cc
+ geometry/nodes/node_geo_edge_split.cc
+ geometry/nodes/node_geo_triangulate.cc
+ geometry/node_geometry_exec.cc
+ geometry/node_geometry_tree.cc
+ geometry/node_geometry_util.cc
+
shader/nodes/node_shader_add_shader.c
shader/nodes/node_shader_ambient_occlusion.c
shader/nodes/node_shader_attribute.c
@@ -230,10 +237,6 @@ set(SRC
shader/node_shader_tree.c
shader/node_shader_util.c
- simulation/nodes/node_sim_common.cc
- simulation/node_simulation_tree.cc
- simulation/node_simulation_util.cc
-
texture/nodes/node_texture_at.c
texture/nodes/node_texture_bricks.c
texture/nodes/node_texture_checker.c
@@ -268,11 +271,12 @@ set(SRC
intern/node_tree_multi_function.cc
intern/node_tree_ref.cc
intern/node_util.c
+ intern/type_callbacks.cc
composite/node_composite_util.h
function/node_function_util.hh
shader/node_shader_util.h
- simulation/node_simulation_util.h
+ geometry/node_geometry_util.hh
texture/node_texture_util.h
NOD_common.h
@@ -283,10 +287,11 @@ set(SRC
NOD_node_tree_multi_function.hh
NOD_node_tree_ref.hh
NOD_shader.h
- NOD_simulation.h
+ NOD_geometry.h
NOD_socket.h
NOD_static_types.h
NOD_texture.h
+ NOD_type_callbacks.hh
intern/node_common.h
intern/node_exec.h
intern/node_util.h
diff --git a/source/blender/nodes/NOD_derived_node_tree.hh b/source/blender/nodes/NOD_derived_node_tree.hh
index 9c71ae79cf2..1a9f223cf6c 100644
--- a/source/blender/nodes/NOD_derived_node_tree.hh
+++ b/source/blender/nodes/NOD_derived_node_tree.hh
@@ -65,6 +65,8 @@ class DSocket : NonCopyable, NonMovable {
PointerRNA *rna() const;
StringRefNull idname() const;
StringRefNull name() const;
+ StringRefNull identifier() const;
+ bNodeSocketType *typeinfo() const;
const SocketRef &socket_ref() const;
bNodeSocket *bsocket() const;
@@ -147,6 +149,8 @@ class DNode : NonCopyable, NonMovable {
PointerRNA *rna() const;
StringRefNull idname() const;
StringRefNull name() const;
+ bNode *bnode() const;
+ bNodeType *typeinfo() const;
private:
void destruct_with_sockets();
@@ -288,6 +292,16 @@ inline StringRefNull DSocket::name() const
return socket_ref_->name();
}
+inline StringRefNull DSocket::identifier() const
+{
+ return socket_ref_->identifier();
+}
+
+inline bNodeSocketType *DSocket::typeinfo() const
+{
+ return socket_ref_->bsocket()->typeinfo;
+}
+
inline const SocketRef &DSocket::socket_ref() const
{
return *socket_ref_;
@@ -445,6 +459,16 @@ inline StringRefNull DNode::name() const
return node_ref_->name();
}
+inline bNode *DNode::bnode() const
+{
+ return node_ref_->bnode();
+}
+
+inline bNodeType *DNode::typeinfo() const
+{
+ return node_ref_->bnode()->typeinfo;
+}
+
/* --------------------------------------------------------------------
* DParentNode inline methods.
*/
diff --git a/source/blender/nodes/NOD_simulation.h b/source/blender/nodes/NOD_geometry.h
index 6b3d51b46a9..2b561c419a3 100644
--- a/source/blender/nodes/NOD_simulation.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -20,11 +20,14 @@
extern "C" {
#endif
-extern struct bNodeTreeType *ntreeType_Simulation;
+extern struct bNodeTreeType *ntreeType_Geometry;
-void register_node_tree_type_sim(void);
+void register_node_tree_type_geo(void);
-void register_node_type_sim_group(void);
+void register_node_type_geo_group(void);
+
+void register_node_type_geo_triangulate(void);
+void register_node_type_geo_edge_split(void);
#ifdef __cplusplus
}
diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh
new file mode 100644
index 00000000000..fe6dc732898
--- /dev/null
+++ b/source/blender/nodes/NOD_geometry_exec.hh
@@ -0,0 +1,92 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include "FN_generic_pointer.hh"
+
+#include "BLI_linear_allocator.hh"
+#include "BLI_map.hh"
+
+#include "BKE_geometry.hh"
+
+namespace blender::nodes {
+
+using bke::Geometry;
+using bke::GeometryPtr;
+using fn::CPPType;
+using fn::GMutablePointer;
+
+/**
+ * This container maps names to values of arbitrary type. It is used to represent the input and
+ * output values of geometry nodes.
+ *
+ * The string keys are only referenced, but the values are owned.
+ */
+class GValueByName {
+ private:
+ /* Used to allocate values owned by this container. */
+ LinearAllocator<> &allocator_;
+ Map<StringRef, GMutablePointer> values_;
+
+ public:
+ GValueByName(LinearAllocator<> &allocator) : allocator_(allocator)
+ {
+ }
+
+ ~GValueByName()
+ {
+ /* Destruct all values that have not been destructed. */
+ for (GMutablePointer value : values_.values()) {
+ value.type()->destruct(value.get());
+ }
+ }
+
+ /* Add a value to the container. */
+ void move_in(StringRef name, GMutablePointer value)
+ {
+ const CPPType &type = *value.type();
+ void *buffer = allocator_.allocate(type.size(), type.alignment());
+ type.move_to_uninitialized(value.get(), buffer);
+ values_.add_new(name, GMutablePointer{type, buffer});
+ }
+
+ /* Add a value to the container. */
+ template<typename T> void move_in(StringRef name, T &&value)
+ {
+ this->move_in(name, GMutablePointer{&value});
+ }
+
+ /* Remove the value for the given name from the container and remove it. The caller is
+ * responsible for freeing it. */
+ GMutablePointer extract(StringRef name)
+ {
+ return values_.pop(name);
+ }
+
+ /* Remove the value for the given name from the container and remove it. */
+ template<typename T> T extract(StringRef name)
+ {
+ GMutablePointer value = values_.pop(name);
+ const CPPType &type = *value.type();
+ BLI_assert(type.is<T>());
+ T return_value;
+ type.relocate_to_initialized(value.get(), &return_value);
+ return return_value;
+ }
+};
+
+} // namespace blender::nodes
diff --git a/source/blender/nodes/NOD_node_tree_multi_function.hh b/source/blender/nodes/NOD_node_tree_multi_function.hh
index 25787231afa..552ef5509fa 100644
--- a/source/blender/nodes/NOD_node_tree_multi_function.hh
+++ b/source/blender/nodes/NOD_node_tree_multi_function.hh
@@ -26,21 +26,12 @@
#include "FN_multi_function_network.hh"
#include "NOD_derived_node_tree.hh"
+#include "NOD_type_callbacks.hh"
#include "BLI_resource_collector.hh"
namespace blender::nodes {
-/* Maybe this should be moved to BKE_node.h. */
-inline bool is_multi_function_data_socket(const bNodeSocket *bsocket)
-{
- if (bsocket->typeinfo->get_mf_data_type != nullptr) {
- BLI_assert(bsocket->typeinfo->expand_in_mf_network != nullptr);
- return true;
- }
- return false;
-}
-
/**
* A MFNetworkTreeMap maps various components of a DerivedNodeTree to components of a
* fn::MFNetwork. This is necessary for further processing of a multi-function network that has
@@ -149,7 +140,7 @@ class MFNetworkTreeMap {
if (!dsocket->is_available()) {
continue;
}
- if (!is_multi_function_data_socket(dsocket->bsocket())) {
+ if (!socket_is_mf_data_socket(*dsocket->bsocket()->typeinfo)) {
continue;
}
fn::MFSocket *socket = sockets[used_sockets];
@@ -299,6 +290,11 @@ class SocketMFNetworkBuilder : public MFNetworkBuilderBase {
{
this->construct_generator_fn<fn::CustomMF_Constant<T>>(std::move(value));
}
+ void set_constant_value(const CPPType &type, const void *value)
+ {
+ /* The value has live as long as the generated mf network. */
+ this->construct_generator_fn<fn::CustomMF_GenericConstant>(type, value);
+ }
template<typename T, typename... Args> void construct_generator_fn(Args &&... args)
{
@@ -397,4 +393,37 @@ MFNetworkTreeMap insert_node_tree_into_mf_network(fn::MFNetwork &network,
const DerivedNodeTree &tree,
ResourceCollector &resources);
+using MultiFunctionByNode = Map<const DNode *, const fn::MultiFunction *>;
+MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree,
+ ResourceCollector &resources);
+
+class DataTypeConversions {
+ private:
+ Map<std::pair<fn::MFDataType, fn::MFDataType>, const fn::MultiFunction *> conversions_;
+
+ public:
+ void add(fn::MFDataType from_type, fn::MFDataType to_type, const fn::MultiFunction &fn)
+ {
+ conversions_.add_new({from_type, to_type}, &fn);
+ }
+
+ const fn::MultiFunction *get_conversion(fn::MFDataType from, fn::MFDataType to) const
+ {
+ return conversions_.lookup_default({from, to}, nullptr);
+ }
+
+ bool is_convertible(const CPPType &from_type, const CPPType &to_type) const
+ {
+ return conversions_.contains(
+ {fn::MFDataType::ForSingle(from_type), fn::MFDataType::ForSingle(to_type)});
+ }
+
+ void convert(const CPPType &from_type,
+ const CPPType &to_type,
+ const void *from_value,
+ void *to_value) const;
+};
+
+const DataTypeConversions &get_implicit_type_conversions();
+
} // namespace blender::nodes
diff --git a/source/blender/nodes/NOD_node_tree_ref.hh b/source/blender/nodes/NOD_node_tree_ref.hh
index 3b085248a39..c3fc95d98e4 100644
--- a/source/blender/nodes/NOD_node_tree_ref.hh
+++ b/source/blender/nodes/NOD_node_tree_ref.hh
@@ -101,6 +101,7 @@ class SocketRef : NonCopyable, NonMovable {
StringRefNull idname() const;
StringRefNull name() const;
+ StringRefNull identifier() const;
bNodeSocket *bsocket() const;
bNode *bnode() const;
@@ -272,6 +273,11 @@ inline StringRefNull SocketRef::name() const
return bsocket_->name;
}
+inline StringRefNull SocketRef::identifier() const
+{
+ return bsocket_->identifier;
+}
+
inline bNodeSocket *SocketRef::bsocket() const
{
return bsocket_;
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 0173706b570..cd75e8a1ff0 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -266,6 +266,9 @@ DefNode(FunctionNode, FN_NODE_COMBINE_STRINGS, 0, "COMBINE_STRINGS
DefNode(FunctionNode, FN_NODE_OBJECT_TRANSFORMS, 0, "OBJECT_TRANSFORMS", ObjectTransforms, "Object Transforms", "")
DefNode(FunctionNode, FN_NODE_RANDOM_FLOAT, 0, "RANDOM_FLOAT", RandomFloat, "Random Float", "")
+DefNode(GeometryNode, GEO_NODE_TRIANGULATE, 0, "TRIANGULATE", Triangulate, "Triangulate", "")
+DefNode(GeometryNode, GEO_NODE_EDGE_SPLIT, 0, "EDGE_SPLIT", EdgeSplit, "Edge Split", "")
+
/* undefine macros */
#undef DefNode
diff --git a/source/blender/nodes/NOD_type_callbacks.hh b/source/blender/nodes/NOD_type_callbacks.hh
new file mode 100644
index 00000000000..d1a4bd3ad7a
--- /dev/null
+++ b/source/blender/nodes/NOD_type_callbacks.hh
@@ -0,0 +1,36 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <optional>
+
+#include "BKE_node.h"
+
+#include "FN_multi_function_data_type.hh"
+
+namespace blender::nodes {
+
+using fn::CPPType;
+using fn::MFDataType;
+
+const CPPType *socket_cpp_type_get(const bNodeSocketType &stype);
+std::optional<MFDataType> socket_mf_type_get(const bNodeSocketType &stype);
+bool socket_is_mf_data_socket(const bNodeSocketType &stype);
+bool socket_cpp_value_get(const bNodeSocket &socket, void *r_value);
+void socket_expand_in_mf_network(SocketMFNetworkBuilder &builder);
+
+} // namespace blender::nodes
diff --git a/source/blender/nodes/function/node_function_util.cc b/source/blender/nodes/function/node_function_util.cc
index 342c330a8fa..05b452e61a5 100644
--- a/source/blender/nodes/function/node_function_util.cc
+++ b/source/blender/nodes/function/node_function_util.cc
@@ -20,7 +20,7 @@
bool fn_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree)
{
/* Function nodes are only supported in simulation node trees so far. */
- return STREQ(ntree->idname, "SimulationNodeTree");
+ return STREQ(ntree->idname, "GeometryNodeTree");
}
void fn_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
diff --git a/source/blender/nodes/function/nodes/node_fn_random_float.cc b/source/blender/nodes/function/nodes/node_fn_random_float.cc
index 584c544946e..f3401a2c00d 100644
--- a/source/blender/nodes/function/nodes/node_fn_random_float.cc
+++ b/source/blender/nodes/function/nodes/node_fn_random_float.cc
@@ -21,7 +21,7 @@
static bNodeSocketTemplate fn_node_random_float_in[] = {
{SOCK_FLOAT, N_("Min"), 0.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f, PROP_NONE},
{SOCK_FLOAT, N_("Max"), 1.0f, 0.0f, 0.0f, 0.0f, -10000.0f, 10000.0f, PROP_NONE},
- {SOCK_INT, N_("Seed")},
+ {SOCK_INT, N_("Seed"), 0, 0, 0, 0, -10000, 10000},
{-1, ""},
};
diff --git a/source/blender/nodes/geometry/node_geometry_exec.cc b/source/blender/nodes/geometry/node_geometry_exec.cc
new file mode 100644
index 00000000000..bca65a6609d
--- /dev/null
+++ b/source/blender/nodes/geometry/node_geometry_exec.cc
@@ -0,0 +1,23 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "NOD_geometry_exec.hh"
+
+MAKE_CPP_TYPE(GeometryPtr, blender::bke::GeometryPtr);
+
+namespace blender::nodes {
+
+}
diff --git a/source/blender/nodes/simulation/node_simulation_tree.cc b/source/blender/nodes/geometry/node_geometry_tree.cc
index eb3257d7e66..d4a9805f311 100644
--- a/source/blender/nodes/simulation/node_simulation_tree.cc
+++ b/source/blender/nodes/geometry/node_geometry_tree.cc
@@ -18,7 +18,7 @@
#include "MEM_guardedalloc.h"
-#include "NOD_simulation.h"
+#include "NOD_geometry.h"
#include "BKE_node.h"
@@ -28,18 +28,18 @@
#include "RNA_access.h"
-bNodeTreeType *ntreeType_Simulation;
+bNodeTreeType *ntreeType_Geometry;
-void register_node_tree_type_sim(void)
+void register_node_tree_type_geo(void)
{
- bNodeTreeType *tt = ntreeType_Simulation = static_cast<bNodeTreeType *>(
- MEM_callocN(sizeof(bNodeTreeType), "simulation node tree type"));
- tt->type = NTREE_SIMULATION;
- strcpy(tt->idname, "SimulationNodeTree");
- strcpy(tt->ui_name, N_("Simulation Editor"));
+ bNodeTreeType *tt = ntreeType_Geometry = static_cast<bNodeTreeType *>(
+ MEM_callocN(sizeof(bNodeTreeType), "geometry node tree type"));
+ tt->type = NTREE_GEOMETRY;
+ strcpy(tt->idname, "GeometryNodeTree");
+ strcpy(tt->ui_name, N_("Geometry Node Editor"));
tt->ui_icon = 0; /* defined in drawnode.c */
- strcpy(tt->ui_description, N_("Simulation nodes"));
- tt->rna_ext.srna = &RNA_SimulationNodeTree;
+ strcpy(tt->ui_description, N_("Geometry nodes"));
+ tt->rna_ext.srna = &RNA_GeometryNodeTree;
ntreeTypeAdd(tt);
}
diff --git a/source/blender/nodes/simulation/node_simulation_util.cc b/source/blender/nodes/geometry/node_geometry_util.cc
index ae875335da8..e8d2494f91d 100644
--- a/source/blender/nodes/simulation/node_simulation_util.cc
+++ b/source/blender/nodes/geometry/node_geometry_util.cc
@@ -14,16 +14,16 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include "node_simulation_util.h"
+#include "node_geometry_util.hh"
#include "node_util.h"
-bool sim_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree)
+bool geo_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree)
{
- return STREQ(ntree->idname, "SimulationNodeTree");
+ return STREQ(ntree->idname, "GeometryNodeTree");
}
-void sim_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
+void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass, short flag)
{
node_type_base(ntype, type, name, nclass, flag);
- ntype->poll = sim_node_poll_default;
+ ntype->poll = geo_node_poll_default;
}
diff --git a/source/blender/nodes/simulation/node_simulation_util.h b/source/blender/nodes/geometry/node_geometry_util.hh
index 76a10715cff..e0b170dd6c8 100644
--- a/source/blender/nodes/simulation/node_simulation_util.h
+++ b/source/blender/nodes/geometry/node_geometry_util.hh
@@ -28,10 +28,11 @@
#include "BLT_translation.h"
-#include "NOD_simulation.h"
+#include "NOD_geometry.h"
+#include "NOD_geometry_exec.hh"
#include "node_util.h"
-void sim_node_type_base(
+void geo_node_type_base(
struct bNodeType *ntype, int type, const char *name, short nclass, short flag);
-bool sim_node_poll_default(struct bNodeType *ntype, struct bNodeTree *ntree);
+bool geo_node_poll_default(struct bNodeType *ntype, struct bNodeTree *ntree);
diff --git a/source/blender/nodes/simulation/nodes/node_sim_common.cc b/source/blender/nodes/geometry/nodes/node_geo_common.cc
index fbc03905d4f..ee3045b9b35 100644
--- a/source/blender/nodes/simulation/nodes/node_sim_common.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_common.cc
@@ -16,23 +16,23 @@
#include "BKE_node.h"
-#include "NOD_simulation.h"
+#include "NOD_geometry.h"
#include "NOD_common.h"
#include "node_common.h"
-#include "node_simulation_util.h"
+#include "node_geometry_util.hh"
-void register_node_type_sim_group(void)
+void register_node_type_geo_group(void)
{
static bNodeType ntype;
- node_type_base_custom(&ntype, "SimulationNodeGroup", "Group", 0, 0);
+ node_type_base_custom(&ntype, "GeometryNodeGroup", "Group", 0, 0);
ntype.type = NODE_GROUP;
- ntype.poll = sim_node_poll_default;
+ ntype.poll = geo_node_poll_default;
ntype.poll_instance = node_group_poll_instance;
ntype.insert_link = node_insert_link_default;
ntype.update_internal_links = node_update_internal_links_default;
- ntype.rna_ext.srna = RNA_struct_find("SimulationNodeGroup");
+ ntype.rna_ext.srna = RNA_struct_find("GeometryNodeGroup");
BLI_assert(ntype.rna_ext.srna != NULL);
RNA_struct_blender_type_set(ntype.rna_ext.srna, &ntype);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
new file mode 100644
index 00000000000..e6cddb9db7d
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_edge_split.cc
@@ -0,0 +1,83 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "BLI_math_base.h"
+#include "BLI_math_rotation.h"
+
+#include "DNA_modifier_types.h"
+
+#include "node_geometry_util.hh"
+
+extern "C" {
+Mesh *doEdgeSplit(Mesh *mesh, EdgeSplitModifierData *emd);
+}
+
+static bNodeSocketTemplate geo_node_edge_split_in[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {SOCK_FLOAT,
+ N_("Angle"),
+ DEG2RADF(30.0f),
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ 0.0f,
+ DEG2RADF(180.0f),
+ PROP_ANGLE},
+ {SOCK_BOOLEAN, N_("Sharp Edges")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_edge_split_out[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {-1, ""},
+};
+
+namespace blender::nodes {
+static void geo_edge_split_exec(bNode *UNUSED(node), GValueByName &inputs, GValueByName &outputs)
+{
+ GeometryPtr geometry_in = inputs.extract<GeometryPtr>("Geometry");
+
+ GeometryPtr geometry_out;
+ if (geometry_in.has_value()) {
+ Mesh *mesh_in = geometry_in->mesh_get_for_read();
+ if (mesh_in != nullptr) {
+ const float split_angle = inputs.extract<float>("Angle");
+ const bool use_sharp_flag = inputs.extract<bool>("Sharp Edges");
+
+ /* Use modifier struct to pass arguments to the modifier code. */
+ EdgeSplitModifierData emd = {.split_angle = split_angle, .flags = MOD_EDGESPLIT_FROMANGLE};
+ if (use_sharp_flag) {
+ emd.flags |= MOD_EDGESPLIT_FROMFLAG;
+ }
+
+ Mesh *mesh_out = doEdgeSplit(mesh_in, &emd);
+ geometry_out = GeometryPtr{new Geometry()};
+ geometry_out->mesh_set_and_transfer_ownership(mesh_out);
+ }
+ }
+ outputs.move_in("Geometry", std::move(geometry_out));
+}
+} // namespace blender::nodes
+
+void register_node_type_geo_edge_split()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_EDGE_SPLIT, "Edge Split", 0, 0);
+ node_type_socket_templates(&ntype, geo_node_edge_split_in, geo_node_edge_split_out);
+ ntype.geometry_node_execute = blender::nodes::geo_edge_split_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
new file mode 100644
index 00000000000..cbffc943c9e
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_triangulate.cc
@@ -0,0 +1,64 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "node_geometry_util.hh"
+
+extern "C" {
+Mesh *triangulate_mesh(Mesh *mesh,
+ const int quad_method,
+ const int ngon_method,
+ const int min_vertices,
+ const int flag);
+}
+
+static bNodeSocketTemplate geo_node_triangulate_in[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {SOCK_INT, N_("Minimum Vertices"), 4, 0, 0, 0, 4, 10000},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_triangulate_out[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {-1, ""},
+};
+
+namespace blender::nodes {
+static void geo_triangulate_exec(bNode *UNUSED(node), GValueByName &inputs, GValueByName &outputs)
+{
+ GeometryPtr geometry_in = inputs.extract<GeometryPtr>("Geometry");
+ const int min_vertices = std::max(inputs.extract<int>("Minimum Vertices"), 4);
+ GeometryPtr geometry_out;
+ if (geometry_in.has_value()) {
+ Mesh *mesh_in = geometry_in->mesh_get_for_read();
+ if (mesh_in != nullptr) {
+ Mesh *mesh_out = triangulate_mesh(mesh_in, 3, 0, min_vertices, 0);
+ geometry_out = GeometryPtr{new Geometry()};
+ geometry_out->mesh_set_and_transfer_ownership(mesh_out);
+ }
+ }
+ outputs.move_in("Geometry", std::move(geometry_out));
+}
+} // namespace blender::nodes
+
+void register_node_type_geo_triangulate()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_TRIANGULATE, "Triangulate", 0, 0);
+ node_type_socket_templates(&ntype, geo_node_triangulate_in, geo_node_triangulate_out);
+ ntype.geometry_node_execute = blender::nodes::geo_triangulate_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc
index 0cedc6597c8..31bed283d6b 100644
--- a/source/blender/nodes/intern/node_socket.cc
+++ b/source/blender/nodes/intern/node_socket.cc
@@ -32,6 +32,7 @@
#include "BLI_string.h"
#include "BLI_utildefines.h"
+#include "BKE_geometry.hh"
#include "BKE_lib_id.h"
#include "BKE_node.h"
#include "BKE_persistent_data_handle.hh"
@@ -552,10 +553,9 @@ static bNodeSocketType *make_socket_type_virtual(void)
static bNodeSocketType *make_socket_type_bool()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_BOOLEAN, PROP_NONE);
- socktype->get_mf_data_type = []() { return blender::fn::MFDataType::ForSingle<bool>(); };
- socktype->expand_in_mf_network = [](blender::nodes::SocketMFNetworkBuilder &builder) {
- bool value = builder.socket_default_value<bNodeSocketValueBoolean>()->value;
- builder.set_constant_value(value);
+ socktype->get_cpp_type = []() { return &blender::fn::CPPType::get<bool>(); };
+ socktype->get_cpp_value = [](const bNodeSocket &socket, void *r_value) {
+ *(bool *)r_value = ((bNodeSocketValueBoolean *)socket.default_value)->value;
};
return socktype;
}
@@ -563,10 +563,9 @@ static bNodeSocketType *make_socket_type_bool()
static bNodeSocketType *make_socket_type_float(PropertySubType subtype)
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_FLOAT, subtype);
- socktype->get_mf_data_type = []() { return blender::fn::MFDataType::ForSingle<float>(); };
- socktype->expand_in_mf_network = [](blender::nodes::SocketMFNetworkBuilder &builder) {
- float value = builder.socket_default_value<bNodeSocketValueFloat>()->value;
- builder.set_constant_value(value);
+ socktype->get_cpp_type = []() { return &blender::fn::CPPType::get<float>(); };
+ socktype->get_cpp_value = [](const bNodeSocket &socket, void *r_value) {
+ *(float *)r_value = ((bNodeSocketValueFloat *)socket.default_value)->value;
};
return socktype;
}
@@ -574,10 +573,9 @@ static bNodeSocketType *make_socket_type_float(PropertySubType subtype)
static bNodeSocketType *make_socket_type_int(PropertySubType subtype)
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_INT, subtype);
- socktype->get_mf_data_type = []() { return blender::fn::MFDataType::ForSingle<int>(); };
- socktype->expand_in_mf_network = [](blender::nodes::SocketMFNetworkBuilder &builder) {
- int value = builder.socket_default_value<bNodeSocketValueInt>()->value;
- builder.set_constant_value(value);
+ socktype->get_cpp_type = []() { return &blender::fn::CPPType::get<int>(); };
+ socktype->get_cpp_value = [](const bNodeSocket &socket, void *r_value) {
+ *(int *)r_value = ((bNodeSocketValueInt *)socket.default_value)->value;
};
return socktype;
}
@@ -585,12 +583,9 @@ static bNodeSocketType *make_socket_type_int(PropertySubType subtype)
static bNodeSocketType *make_socket_type_vector(PropertySubType subtype)
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_VECTOR, subtype);
- socktype->get_mf_data_type = []() {
- return blender::fn::MFDataType::ForSingle<blender::float3>();
- };
- socktype->expand_in_mf_network = [](blender::nodes::SocketMFNetworkBuilder &builder) {
- blender::float3 value = builder.socket_default_value<bNodeSocketValueVector>()->value;
- builder.set_constant_value(value);
+ socktype->get_cpp_type = []() { return &blender::fn::CPPType::get<blender::float3>(); };
+ socktype->get_cpp_value = [](const bNodeSocket &socket, void *r_value) {
+ *(blender::float3 *)r_value = ((bNodeSocketValueVector *)socket.default_value)->value;
};
return socktype;
}
@@ -598,12 +593,9 @@ static bNodeSocketType *make_socket_type_vector(PropertySubType subtype)
static bNodeSocketType *make_socket_type_rgba()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_RGBA, PROP_NONE);
- socktype->get_mf_data_type = []() {
- return blender::fn::MFDataType::ForSingle<blender::Color4f>();
- };
- socktype->expand_in_mf_network = [](blender::nodes::SocketMFNetworkBuilder &builder) {
- blender::Color4f value = builder.socket_default_value<bNodeSocketValueRGBA>()->value;
- builder.set_constant_value(value);
+ socktype->get_cpp_type = []() { return &blender::fn::CPPType::get<blender::Color4f>(); };
+ socktype->get_cpp_value = [](const bNodeSocket &socket, void *r_value) {
+ *(blender::Color4f *)r_value = ((bNodeSocketValueRGBA *)socket.default_value)->value;
};
return socktype;
}
@@ -611,10 +603,9 @@ static bNodeSocketType *make_socket_type_rgba()
static bNodeSocketType *make_socket_type_string()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_STRING, PROP_NONE);
- socktype->get_mf_data_type = []() { return blender::fn::MFDataType::ForSingle<std::string>(); };
- socktype->expand_in_mf_network = [](blender::nodes::SocketMFNetworkBuilder &builder) {
- std::string value = builder.socket_default_value<bNodeSocketValueString>()->value;
- builder.set_constant_value(value);
+ socktype->get_cpp_type = []() { return &blender::fn::CPPType::get<std::string>(); };
+ socktype->get_cpp_value = [](const bNodeSocket &socket, void *r_value) {
+ new (r_value) std::string(((bNodeSocketValueString *)socket.default_value)->value);
};
return socktype;
}
@@ -661,9 +652,9 @@ MAKE_CPP_TYPE(PersistentObjectHandle, blender::bke::PersistentObjectHandle);
static bNodeSocketType *make_socket_type_object()
{
bNodeSocketType *socktype = make_standard_socket_type(SOCK_OBJECT, PROP_NONE);
- socktype->get_mf_data_type = []() {
+ socktype->get_cpp_type = []() {
/* Objects are not passed along as raw pointers, but as handles. */
- return blender::fn::MFDataType::ForSingle<blender::bke::PersistentObjectHandle>();
+ return &blender::fn::CPPType::get<blender::bke::PersistentObjectHandle>();
};
socktype->expand_in_mf_network = [](blender::nodes::SocketMFNetworkBuilder &builder) {
Object *object = builder.socket_default_value<bNodeSocketValueObject>()->value;
@@ -672,6 +663,18 @@ static bNodeSocketType *make_socket_type_object()
return socktype;
}
+static bNodeSocketType *make_socket_type_geometry()
+{
+ bNodeSocketType *socktype = make_standard_socket_type(SOCK_GEOMETRY, PROP_NONE);
+ socktype->get_cpp_type = []() {
+ return &blender::fn::CPPType::get<blender::bke::GeometryPtr>();
+ };
+ socktype->get_cpp_value = [](const bNodeSocket &UNUSED(socket), void *r_value) {
+ new (r_value) blender::bke::GeometryPtr();
+ };
+ return socktype;
+}
+
void register_standard_node_socket_types(void)
{
/* draw callbacks are set in drawnode.c to avoid bad-level calls */
@@ -708,5 +711,7 @@ void register_standard_node_socket_types(void)
nodeRegisterSocketType(make_standard_socket_type(SOCK_IMAGE, PROP_NONE));
+ nodeRegisterSocketType(make_socket_type_geometry());
+
nodeRegisterSocketType(make_socket_type_virtual());
}
diff --git a/source/blender/nodes/intern/node_tree_multi_function.cc b/source/blender/nodes/intern/node_tree_multi_function.cc
index 09a80fd23f4..8440e996651 100644
--- a/source/blender/nodes/intern/node_tree_multi_function.cc
+++ b/source/blender/nodes/intern/node_tree_multi_function.cc
@@ -16,21 +16,13 @@
#include "NOD_node_tree_multi_function.hh"
+#include "FN_multi_function_network_evaluation.hh"
+
#include "BLI_color.hh"
#include "BLI_float3.hh"
namespace blender::nodes {
-/* Maybe this should be moved to BKE_node.h. */
-static std::optional<fn::MFDataType> try_get_multi_function_data_type_of_socket(
- const bNodeSocket *bsocket)
-{
- if (bsocket->typeinfo->get_mf_data_type == nullptr) {
- return {};
- }
- return bsocket->typeinfo->get_mf_data_type();
-}
-
const fn::MultiFunction &NodeMFNetworkBuilder::get_default_fn(StringRef name)
{
Vector<fn::MFDataType, 10> input_types;
@@ -38,8 +30,7 @@ const fn::MultiFunction &NodeMFNetworkBuilder::get_default_fn(StringRef name)
for (const DInputSocket *dsocket : dnode_.inputs()) {
if (dsocket->is_available()) {
- std::optional<fn::MFDataType> data_type = try_get_multi_function_data_type_of_socket(
- dsocket->bsocket());
+ std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo);
if (data_type.has_value()) {
input_types.append(*data_type);
}
@@ -47,8 +38,7 @@ const fn::MultiFunction &NodeMFNetworkBuilder::get_default_fn(StringRef name)
}
for (const DOutputSocket *dsocket : dnode_.outputs()) {
if (dsocket->is_available()) {
- std::optional<fn::MFDataType> data_type = try_get_multi_function_data_type_of_socket(
- dsocket->bsocket());
+ std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo);
if (data_type.has_value()) {
output_types.append(*data_type);
}
@@ -70,8 +60,7 @@ static void insert_dummy_node(CommonMFNetworkBuilderData &common, const DNode &d
for (const DInputSocket *dsocket : dnode.inputs()) {
if (dsocket->is_available()) {
- std::optional<fn::MFDataType> data_type = try_get_multi_function_data_type_of_socket(
- dsocket->bsocket());
+ std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo);
if (data_type.has_value()) {
input_types.append(*data_type);
input_names.append(dsocket->name());
@@ -86,8 +75,7 @@ static void insert_dummy_node(CommonMFNetworkBuilderData &common, const DNode &d
for (const DOutputSocket *dsocket : dnode.outputs()) {
if (dsocket->is_available()) {
- std::optional<fn::MFDataType> data_type = try_get_multi_function_data_type_of_socket(
- dsocket->bsocket());
+ std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo);
if (data_type.has_value()) {
output_types.append(*data_type);
output_names.append(dsocket->name());
@@ -106,12 +94,12 @@ static void insert_dummy_node(CommonMFNetworkBuilderData &common, const DNode &d
static bool has_data_sockets(const DNode &dnode)
{
for (const DInputSocket *socket : dnode.inputs()) {
- if (is_multi_function_data_socket(socket->bsocket())) {
+ if (socket_is_mf_data_socket(*socket->bsocket()->typeinfo)) {
return true;
}
}
for (const DOutputSocket *socket : dnode.outputs()) {
- if (is_multi_function_data_socket(socket->bsocket())) {
+ if (socket_is_mf_data_socket(*socket->bsocket()->typeinfo)) {
return true;
}
}
@@ -140,7 +128,7 @@ static void insert_group_inputs(CommonMFNetworkBuilderData &common)
{
for (const DGroupInput *group_input : common.tree.group_inputs()) {
bNodeSocket *bsocket = group_input->bsocket();
- if (is_multi_function_data_socket(bsocket)) {
+ if (socket_is_mf_data_socket(*bsocket->typeinfo)) {
bNodeSocketType *socktype = bsocket->typeinfo;
BLI_assert(socktype->expand_in_mf_network != nullptr);
@@ -171,44 +159,43 @@ static fn::MFOutputSocket *try_find_origin(CommonMFNetworkBuilderData &common,
if (!from_dsocket.is_available()) {
return nullptr;
}
- if (is_multi_function_data_socket(from_dsocket.bsocket())) {
+ if (socket_is_mf_data_socket(*from_dsocket.bsocket()->typeinfo)) {
return &common.network_map.lookup(from_dsocket);
}
return nullptr;
}
const DGroupInput &from_group_input = *from_group_inputs[0];
- if (is_multi_function_data_socket(from_group_input.bsocket())) {
+ if (socket_is_mf_data_socket(*from_group_input.bsocket()->typeinfo)) {
return &common.network_map.lookup(from_group_input);
}
return nullptr;
}
-using ImplicitConversionsMap =
- Map<std::pair<fn::MFDataType, fn::MFDataType>, const fn::MultiFunction *>;
-
template<typename From, typename To>
-static void add_implicit_conversion(ImplicitConversionsMap &map)
+static void add_implicit_conversion(DataTypeConversions &conversions)
{
static fn::CustomMF_Convert<From, To> function;
- map.add({fn::MFDataType::ForSingle<From>(), fn::MFDataType::ForSingle<To>()}, &function);
+ conversions.add(fn::MFDataType::ForSingle<From>(), fn::MFDataType::ForSingle<To>(), function);
}
template<typename From, typename To, typename ConversionF>
-static void add_implicit_conversion(ImplicitConversionsMap &map,
+static void add_implicit_conversion(DataTypeConversions &conversions,
StringRef name,
ConversionF conversion)
{
static fn::CustomMF_SI_SO<From, To> function{name, conversion};
- map.add({fn::MFDataType::ForSingle<From>(), fn::MFDataType::ForSingle<To>()}, &function);
+ conversions.add(fn::MFDataType::ForSingle<From>(), fn::MFDataType::ForSingle<To>(), function);
}
-static ImplicitConversionsMap get_implicit_conversions()
+static DataTypeConversions create_implicit_conversions()
{
- ImplicitConversionsMap conversions;
+ DataTypeConversions conversions;
add_implicit_conversion<float, int32_t>(conversions);
add_implicit_conversion<float, float3>(conversions);
add_implicit_conversion<int32_t, float>(conversions);
+ add_implicit_conversion<float, bool>(conversions);
+ add_implicit_conversion<bool, float>(conversions);
add_implicit_conversion<float3, float>(
conversions, "Vector Length", [](float3 a) { return a.length(); });
add_implicit_conversion<int32_t, float3>(
@@ -220,11 +207,26 @@ static ImplicitConversionsMap get_implicit_conversions()
return conversions;
}
-static const fn::MultiFunction *try_get_conversion_function(fn::MFDataType from, fn::MFDataType to)
+const DataTypeConversions &get_implicit_type_conversions()
{
- static const ImplicitConversionsMap conversions = get_implicit_conversions();
- const fn::MultiFunction *function = conversions.lookup_default({from, to}, nullptr);
- return function;
+ static const DataTypeConversions conversions = create_implicit_conversions();
+ return conversions;
+}
+
+void DataTypeConversions::convert(const CPPType &from_type,
+ const CPPType &to_type,
+ const void *from_value,
+ void *to_value) const
+{
+ const fn::MultiFunction *fn = this->get_conversion(MFDataType::ForSingle(from_type),
+ MFDataType::ForSingle(to_type));
+ BLI_assert(fn != nullptr);
+
+ fn::MFContextBuilder context;
+ fn::MFParamsBuilder params{*fn, 1};
+ params.add_readonly_single_input(fn::GSpan(from_type, from_value, 1));
+ params.add_uninitialized_single_output(fn::GMutableSpan(to_type, to_value, 1));
+ fn->call({0}, params, context);
}
static fn::MFOutputSocket &insert_default_value_for_type(CommonMFNetworkBuilderData &common,
@@ -253,7 +255,7 @@ static void insert_links(CommonMFNetworkBuilderData &common)
if (!to_dsocket->is_linked()) {
continue;
}
- if (!is_multi_function_data_socket(to_dsocket->bsocket())) {
+ if (!socket_is_mf_data_socket(*to_dsocket->bsocket()->typeinfo)) {
continue;
}
@@ -269,7 +271,8 @@ static void insert_links(CommonMFNetworkBuilderData &common)
fn::MFDataType from_type = from_socket->data_type();
if (from_type != to_type) {
- const fn::MultiFunction *conversion_fn = try_get_conversion_function(from_type, to_type);
+ const fn::MultiFunction *conversion_fn = get_implicit_type_conversions().get_conversion(
+ from_type, to_type);
if (conversion_fn != nullptr) {
fn::MFNode &node = common.network.add_function(*conversion_fn);
common.network.add_link(*from_socket, node.input(0));
@@ -308,7 +311,7 @@ static void insert_unlinked_inputs(CommonMFNetworkBuilderData &common)
Vector<const DInputSocket *> unlinked_data_inputs;
for (const DInputSocket *dsocket : common.tree.input_sockets()) {
if (dsocket->is_available()) {
- if (is_multi_function_data_socket(dsocket->bsocket())) {
+ if (socket_is_mf_data_socket(*dsocket->bsocket()->typeinfo)) {
if (!dsocket->is_linked()) {
insert_unlinked_input(common, *dsocket);
}
@@ -340,4 +343,150 @@ MFNetworkTreeMap insert_node_tree_into_mf_network(fn::MFNetwork &network,
return network_map;
}
+/**
+ * A single node is allowed to expand into multiple nodes before evaluation. Depending on what
+ * nodes it expands to, it belongs a different type of the ones below.
+ */
+enum class NodeExpandType {
+ SingleFunctionNode,
+ MultipleFunctionNodes,
+ HasDummyNodes,
+};
+
+/**
+ * Checks how the given node expanded in the multi-function network. If it is only a single
+ * function node, the corresponding function is returned as well.
+ */
+static NodeExpandType get_node_expand_type(MFNetworkTreeMap &network_map,
+ const DNode &dnode,
+ const fn::MultiFunction **r_single_function)
+{
+ const fn::MFFunctionNode *single_function_node = nullptr;
+ bool has_multiple_nodes = false;
+ bool has_dummy_nodes = false;
+
+ auto check_mf_node = [&](fn::MFNode &mf_node) {
+ if (mf_node.is_function()) {
+ if (single_function_node == nullptr) {
+ single_function_node = &mf_node.as_function();
+ }
+ if (&mf_node != single_function_node) {
+ has_multiple_nodes = true;
+ }
+ }
+ else {
+ BLI_assert(mf_node.is_dummy());
+ has_dummy_nodes = true;
+ }
+ };
+
+ for (const DInputSocket *dsocket : dnode.inputs()) {
+ if (dsocket->is_available()) {
+ for (fn::MFInputSocket *mf_input : network_map.lookup(*dsocket)) {
+ check_mf_node(mf_input->node());
+ }
+ }
+ }
+ for (const DOutputSocket *dsocket : dnode.outputs()) {
+ if (dsocket->is_available()) {
+ fn::MFOutputSocket &mf_output = network_map.lookup(*dsocket);
+ check_mf_node(mf_output.node());
+ }
+ }
+
+ if (has_dummy_nodes) {
+ return NodeExpandType::HasDummyNodes;
+ }
+ if (has_multiple_nodes) {
+ return NodeExpandType::MultipleFunctionNodes;
+ }
+ *r_single_function = &single_function_node->function();
+ return NodeExpandType::SingleFunctionNode;
+}
+
+static const fn::MultiFunction &create_function_for_node_that_expands_into_multiple(
+ const DNode &dnode,
+ fn::MFNetwork &network,
+ MFNetworkTreeMap &network_map,
+ ResourceCollector &resources)
+{
+ Vector<const fn::MFOutputSocket *> dummy_fn_inputs;
+ for (const DInputSocket *dsocket : dnode.inputs()) {
+ if (dsocket->is_available()) {
+ MFDataType data_type = *socket_mf_type_get(*dsocket->typeinfo());
+ fn::MFOutputSocket &fn_input = network.add_input(data_type.to_string(), data_type);
+ for (fn::MFInputSocket *mf_input : network_map.lookup(*dsocket)) {
+ network.add_link(fn_input, *mf_input);
+ dummy_fn_inputs.append(&fn_input);
+ }
+ }
+ }
+ Vector<const fn::MFInputSocket *> dummy_fn_outputs;
+ for (const DOutputSocket *dsocket : dnode.outputs()) {
+ if (dsocket->is_available()) {
+ fn::MFOutputSocket &mf_output = network_map.lookup(*dsocket);
+ MFDataType data_type = mf_output.data_type();
+ fn::MFInputSocket &fn_output = network.add_output(data_type.to_string(), data_type);
+ network.add_link(mf_output, fn_output);
+ dummy_fn_outputs.append(&fn_output);
+ }
+ }
+
+ fn::MFNetworkEvaluator &fn_evaluator = resources.construct<fn::MFNetworkEvaluator>(
+ __func__, std::move(dummy_fn_inputs), std::move(dummy_fn_outputs));
+ return fn_evaluator;
+}
+
+/**
+ * Returns a single multi-function for every node that supports it. This makes it easier to reuse
+ * the multi-function implementation of nodes in different contexts.
+ */
+MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree,
+ ResourceCollector &resources)
+{
+ /* Build a network that nodes can insert themselves into. However, the individual nodes are not
+ * connected. */
+ fn::MFNetwork &network = resources.construct<fn::MFNetwork>(__func__);
+ MFNetworkTreeMap network_map{tree, network};
+ MultiFunctionByNode functions_by_node;
+
+ CommonMFNetworkBuilderData common{resources, network, network_map, tree};
+
+ for (const DNode *dnode : tree.nodes()) {
+ const bNodeType *node_type = dnode->typeinfo();
+ if (node_type->expand_in_mf_network == nullptr) {
+ /* This node does not have a multi-function implementation. */
+ continue;
+ }
+
+ NodeMFNetworkBuilder builder{common, *dnode};
+ node_type->expand_in_mf_network(builder);
+
+ const fn::MultiFunction *single_function = nullptr;
+ const NodeExpandType expand_type = get_node_expand_type(network_map, *dnode, &single_function);
+
+ switch (expand_type) {
+ case NodeExpandType::HasDummyNodes: {
+ /* Dummy nodes cannot be executed, so skip them. */
+ break;
+ }
+ case NodeExpandType::SingleFunctionNode: {
+ /* This is the common case. Most nodes just expand to a single function. */
+ functions_by_node.add_new(dnode, single_function);
+ break;
+ }
+ case NodeExpandType::MultipleFunctionNodes: {
+ /* If a node expanded into multiple functions, a new function has to be created that
+ * combines those. */
+ const fn::MultiFunction &fn = create_function_for_node_that_expands_into_multiple(
+ *dnode, network, network_map, resources);
+ functions_by_node.add_new(dnode, &fn);
+ break;
+ }
+ }
+ }
+
+ return functions_by_node;
+}
+
} // namespace blender::nodes
diff --git a/source/blender/nodes/intern/type_callbacks.cc b/source/blender/nodes/intern/type_callbacks.cc
new file mode 100644
index 00000000000..1f207f880bc
--- /dev/null
+++ b/source/blender/nodes/intern/type_callbacks.cc
@@ -0,0 +1,76 @@
+/*
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "NOD_node_tree_multi_function.hh"
+#include "NOD_type_callbacks.hh"
+
+namespace blender::nodes {
+
+const CPPType *socket_cpp_type_get(const bNodeSocketType &stype)
+{
+ if (stype.get_cpp_type != nullptr) {
+ return stype.get_cpp_type();
+ }
+ return nullptr;
+}
+
+std::optional<MFDataType> socket_mf_type_get(const bNodeSocketType &stype)
+{
+ const CPPType *cpp_type = socket_cpp_type_get(stype);
+ if (cpp_type != nullptr) {
+ return MFDataType::ForSingle(*cpp_type);
+ }
+ return {};
+}
+
+bool socket_is_mf_data_socket(const bNodeSocketType &stype)
+{
+ if (!socket_mf_type_get(stype).has_value()) {
+ return false;
+ }
+ if (stype.expand_in_mf_network == nullptr && stype.get_cpp_value == nullptr) {
+ return false;
+ }
+ return true;
+}
+
+bool socket_cpp_value_get(const bNodeSocket &socket, void *r_value)
+{
+ if (socket.typeinfo->get_cpp_value != nullptr) {
+ socket.typeinfo->get_cpp_value(socket, r_value);
+ return true;
+ }
+ return false;
+}
+
+void socket_expand_in_mf_network(SocketMFNetworkBuilder &builder)
+{
+ bNodeSocket &socket = builder.bsocket();
+ if (socket.typeinfo->expand_in_mf_network != nullptr) {
+ socket.typeinfo->expand_in_mf_network(builder);
+ }
+ else if (socket.typeinfo->get_cpp_value != nullptr) {
+ const CPPType &type = *socket_cpp_type_get(*socket.typeinfo);
+ void *buffer = builder.resources().linear_allocator().allocate(type.size(), type.alignment());
+ socket.typeinfo->get_cpp_value(socket, buffer);
+ builder.set_constant_value(type, buffer);
+ }
+ else {
+ BLI_assert(false);
+ }
+}
+
+} // namespace blender::nodes
diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.c
index 4464a61c48c..25d6aef69e5 100644
--- a/source/blender/nodes/shader/node_shader_util.c
+++ b/source/blender/nodes/shader/node_shader_util.c
@@ -34,7 +34,7 @@ bool sh_node_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree)
static bool sh_fn_poll_default(bNodeType *UNUSED(ntype), bNodeTree *ntree)
{
- return STREQ(ntree->idname, "ShaderNodeTree") || STREQ(ntree->idname, "SimulationNodeTree");
+ return STREQ(ntree->idname, "ShaderNodeTree") || STREQ(ntree->idname, "GeometryNodeTree");
}
void sh_node_type_base(