diff options
Diffstat (limited to 'source')
56 files changed, 1907 insertions, 461 deletions
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( |