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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/modifiers/intern')
-rw-r--r--source/blender/modifiers/intern/MOD_edgesplit.c5
-rw-r--r--source/blender/modifiers/intern/MOD_nodes.cc1088
-rw-r--r--source/blender/modifiers/intern/MOD_simulation.cc194
-rw-r--r--source/blender/modifiers/intern/MOD_triangulate.c16
-rw-r--r--source/blender/modifiers/intern/MOD_util.c2
5 files changed, 1104 insertions, 201 deletions
diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c
index 882d080c08d..30c38623f68 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(const Mesh *mesh, EdgeSplitModifierData *emd);
+
+Mesh *doEdgeSplit(const 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..b1849b3dbf2
--- /dev/null
+++ b/source/blender/modifiers/intern/MOD_nodes.cc
@@ -0,0 +1,1088 @@
+/*
+ * 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_set.hh"
+#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_idprop.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 "RNA_enum_types.h"
+
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_query.h"
+
+#include "MOD_modifiertypes.h"
+#include "MOD_nodes.h"
+#include "MOD_ui_common.h"
+
+#include "NOD_derived_node_tree.hh"
+#include "NOD_geometry.h"
+#include "NOD_geometry_exec.hh"
+#include "NOD_node_tree_multi_function.hh"
+#include "NOD_type_callbacks.hh"
+
+using blender::float3;
+using blender::IndexRange;
+using blender::Map;
+using blender::Set;
+using blender::Span;
+using blender::StringRef;
+using blender::Vector;
+using blender::fn::GMutablePointer;
+using blender::fn::GValueMap;
+using blender::nodes::GeoNodeExecParams;
+using namespace blender::nodes::derived_node_tree_types;
+using namespace blender::fn::multi_function_types;
+
+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 addIdsUsedBySocket(const ListBase *sockets, Set<ID *> &ids)
+{
+ LISTBASE_FOREACH (const bNodeSocket *, socket, sockets) {
+ if (socket->type == SOCK_OBJECT) {
+ Object *object = ((bNodeSocketValueObject *)socket->default_value)->value;
+ if (object != nullptr) {
+ ids.add(&object->id);
+ }
+ }
+ }
+}
+
+static void findUsedIds(const bNodeTree &tree, Set<ID *> &ids)
+{
+ Set<const bNodeTree *> handled_groups;
+
+ LISTBASE_FOREACH (const bNode *, node, &tree.nodes) {
+ addIdsUsedBySocket(&node->inputs, ids);
+ addIdsUsedBySocket(&node->outputs, ids);
+
+ if (node->type == NODE_GROUP) {
+ const bNodeTree *group = (bNodeTree *)node->id;
+ if (group != nullptr && handled_groups.add(group)) {
+ findUsedIds(*group, ids);
+ }
+ }
+ }
+}
+
+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");
+
+ Set<ID *> used_ids;
+ findUsedIds(*nmd->node_group, used_ids);
+ for (ID *id : used_ids) {
+ if (GS(id->name) == ID_OB) {
+ Object *object = reinterpret_cast<Object *>(id);
+ DEG_add_object_relation(ctx->node, object, DEG_OB_COMP_TRANSFORM, "Nodes Modifier");
+ if (id != &ctx->object->id) {
+ if (object->type != OB_EMPTY) {
+ DEG_add_object_relation(
+ ctx->node, (Object *)id, DEG_OB_COMP_GEOMETRY, "Nodes Modifier");
+ }
+ }
+ }
+ }
+ }
+
+ /* TODO: Add relations for IDs in settings. */
+}
+
+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);
+
+ struct ForeachSettingData {
+ IDWalkFunc walk;
+ void *userData;
+ Object *ob;
+ } settings = {walk, userData, ob};
+
+ IDP_foreach_property(
+ nmd->settings.properties,
+ IDP_TYPE_FILTER_ID,
+ [](IDProperty *id_prop, void *user_data) {
+ ForeachSettingData *settings = (ForeachSettingData *)user_data;
+ settings->walk(
+ settings->userData, settings->ob, (ID **)&id_prop->data.pointer, IDWALK_CB_USER);
+ },
+ &settings);
+}
+
+static bool isDisabled(const struct Scene *UNUSED(scene),
+ ModifierData *md,
+ bool UNUSED(useRenderParams))
+{
+ NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
+
+ if (nmd->node_group == nullptr) {
+ return true;
+ }
+
+ return false;
+}
+
+class GeometryNodesEvaluator {
+ private:
+ blender::LinearAllocator<> allocator_;
+ Map<const DInputSocket *, GMutablePointer> value_by_input_;
+ Vector<const DInputSocket *> group_outputs_;
+ blender::nodes::MultiFunctionByNode &mf_by_node_;
+ const blender::nodes::DataTypeConversions &conversions_;
+ const blender::bke::PersistentDataHandleMap &handle_map_;
+ const Object *self_object_;
+
+ public:
+ GeometryNodesEvaluator(const Map<const DOutputSocket *, GMutablePointer> &group_input_data,
+ Vector<const DInputSocket *> group_outputs,
+ blender::nodes::MultiFunctionByNode &mf_by_node,
+ const blender::bke::PersistentDataHandleMap &handle_map,
+ const Object *self_object)
+ : group_outputs_(std::move(group_outputs)),
+ mf_by_node_(mf_by_node),
+ conversions_(blender::nodes::get_implicit_type_conversions()),
+ handle_map_(handle_map),
+ self_object_(self_object)
+ {
+ for (auto item : group_input_data.items()) {
+ this->forward_to_inputs(*item.key, item.value);
+ }
+ }
+
+ Vector<GMutablePointer> execute()
+ {
+ Vector<GMutablePointer> results;
+ for (const DInputSocket *group_output : group_outputs_) {
+ GMutablePointer result = this->get_input_value(*group_output);
+ results.append(result);
+ }
+ for (GMutablePointer value : value_by_input_.values()) {
+ value.destruct();
+ }
+ return results;
+ }
+
+ private:
+ GMutablePointer get_input_value(const DInputSocket &socket_to_compute)
+ {
+ std::optional<GMutablePointer> value = value_by_input_.pop_try(&socket_to_compute);
+ if (value.has_value()) {
+ /* This input has been computed before, return it directly. */
+ return *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) {
+ /* The input is not connected, use the value from the socket itself. */
+ return get_unlinked_input_value(socket_to_compute);
+ }
+ if (from_group_inputs.size() == 1) {
+ /* The input gets its value from the input of a group that is not further connected. */
+ return get_unlinked_input_value(socket_to_compute);
+ }
+
+ /* Compute the socket now. */
+ const DOutputSocket &from_socket = *from_sockets[0];
+ this->compute_output_and_forward(from_socket);
+ return value_by_input_.pop(&socket_to_compute);
+ }
+
+ void compute_output_and_forward(const DOutputSocket &socket_to_compute)
+ {
+ const DNode &node = socket_to_compute.node();
+ const bNode &bnode = *node.bnode();
+
+ if (!socket_to_compute.is_available()) {
+ /* If the output is not available, use a default value. */
+ const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute.typeinfo());
+ void *buffer = allocator_.allocate(type.size(), type.alignment());
+ type.copy_to_uninitialized(type.default_value(), buffer);
+ this->forward_to_inputs(socket_to_compute, {type, buffer});
+ return;
+ }
+
+ /* Prepare inputs required to execute the node. */
+ GValueMap<StringRef> node_inputs_map{allocator_};
+ for (const DInputSocket *input_socket : node.inputs()) {
+ if (input_socket->is_available()) {
+ GMutablePointer value = this->get_input_value(*input_socket);
+ node_inputs_map.add_new_direct(input_socket->identifier(), value);
+ }
+ }
+
+ /* Execute the node. */
+ GValueMap<StringRef> node_outputs_map{allocator_};
+ GeoNodeExecParams params{bnode, node_inputs_map, node_outputs_map, handle_map_, self_object_};
+ this->execute_node(node, params);
+
+ /* Forward computed outputs to linked input sockets. */
+ for (const DOutputSocket *output_socket : node.outputs()) {
+ if (output_socket->is_available()) {
+ GMutablePointer value = node_outputs_map.extract(output_socket->identifier());
+ this->forward_to_inputs(*output_socket, value);
+ }
+ }
+ }
+
+ void execute_node(const DNode &node, GeoNodeExecParams params)
+ {
+ const bNode &bnode = params.node();
+ if (bnode.typeinfo->geometry_node_execute != nullptr) {
+ bnode.typeinfo->geometry_node_execute(params);
+ return;
+ }
+
+ /* Use the multi-function implementation of the node. */
+ const MultiFunction &fn = *mf_by_node_.lookup(&node);
+ MFContextBuilder fn_context;
+ MFParamsBuilder fn_params{fn, 1};
+ Vector<GMutablePointer> input_data;
+ for (const DInputSocket *dsocket : node.inputs()) {
+ if (dsocket->is_available()) {
+ GMutablePointer data = params.extract_input(dsocket->identifier());
+ fn_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 = *blender::nodes::socket_cpp_type_get(*dsocket->typeinfo());
+ void *buffer = allocator_.allocate(type.size(), type.alignment());
+ fn_params.add_uninitialized_single_output(GMutableSpan(type, buffer, 1));
+ output_data.append(GMutablePointer(type, buffer));
+ }
+ }
+ fn.call(IndexRange(1), fn_params, fn_context);
+ for (GMutablePointer value : input_data) {
+ value.destruct();
+ }
+ int output_index = 0;
+ for (const int i : node.outputs().index_range()) {
+ if (node.output(i).is_available()) {
+ GMutablePointer value = output_data[output_index];
+ params.set_output_by_move(node.output(i).identifier(), value);
+ value.destruct();
+ output_index++;
+ }
+ }
+ }
+
+ void forward_to_inputs(const DOutputSocket &from_socket, GMutablePointer value_to_forward)
+ {
+ Span<const DInputSocket *> to_sockets_all = from_socket.linked_sockets();
+
+ const CPPType &from_type = *value_to_forward.type();
+
+ Vector<const DInputSocket *> to_sockets_same_type;
+ for (const DInputSocket *to_socket : to_sockets_all) {
+ const CPPType &to_type = *blender::nodes::socket_cpp_type_get(*to_socket->typeinfo());
+ if (from_type == to_type) {
+ to_sockets_same_type.append(to_socket);
+ }
+ else {
+ void *buffer = allocator_.allocate(to_type.size(), to_type.alignment());
+ if (conversions_.is_convertible(from_type, to_type)) {
+ conversions_.convert(from_type, to_type, value_to_forward.get(), buffer);
+ }
+ else {
+ to_type.copy_to_uninitialized(to_type.default_value(), buffer);
+ }
+ value_by_input_.add_new(to_socket, GMutablePointer{to_type, buffer});
+ }
+ }
+
+ if (to_sockets_same_type.size() == 0) {
+ /* This value is not further used, so destruct it. */
+ value_to_forward.destruct();
+ }
+ else if (to_sockets_same_type.size() == 1) {
+ /* This value is only used on one input socket, no need to copy it. */
+ const DInputSocket *to_socket = to_sockets_same_type[0];
+ value_by_input_.add_new(to_socket, value_to_forward);
+ }
+ else {
+ /* Multiple inputs use the value, make a copy for every input except for one. */
+ const DInputSocket *first_to_socket = to_sockets_same_type[0];
+ Span<const DInputSocket *> other_to_sockets = to_sockets_same_type.as_span().drop_front(1);
+ const CPPType &type = *value_to_forward.type();
+
+ value_by_input_.add_new(first_to_socket, value_to_forward);
+ for (const DInputSocket *to_socket : other_to_sockets) {
+ void *buffer = allocator_.allocate(type.size(), type.alignment());
+ type.copy_to_uninitialized(value_to_forward.get(), buffer);
+ value_by_input_.add_new(to_socket, GMutablePointer{type, buffer});
+ }
+ }
+ }
+
+ GMutablePointer get_unlinked_input_value(const DInputSocket &socket)
+ {
+ bNodeSocket *bsocket;
+ if (socket.linked_group_inputs().size() == 0) {
+ bsocket = socket.bsocket();
+ }
+ else {
+ bsocket = socket.linked_group_inputs()[0]->bsocket();
+ }
+ const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket.typeinfo());
+ void *buffer = allocator_.allocate(type.size(), type.alignment());
+
+ if (bsocket->type == SOCK_OBJECT) {
+ Object *object = ((bNodeSocketValueObject *)bsocket->default_value)->value;
+ blender::bke::PersistentObjectHandle object_handle = handle_map_.lookup(object);
+ new (buffer) blender::bke::PersistentObjectHandle(object_handle);
+ }
+ else {
+ blender::nodes::socket_cpp_value_get(*bsocket, buffer);
+ }
+
+ return {type, buffer};
+ }
+};
+
+/**
+ * This code is responsible for creating the new property and also creating the group of
+ * properties in the prop_ui_container group for the UI info, the mapping for which is
+ * scattered about in RNA_access.c.
+ *
+ * TODO(Hans): Codify this with some sort of table or refactor IDProperty use in RNA_access.c.
+ */
+struct SocketPropertyType {
+ /* Create the actual propery used to store the data for the modifier. */
+ IDProperty *(*create_prop)(const bNodeSocket &socket, const char *name);
+ /* Reused to build the "soft_min" property too. */
+ IDProperty *(*create_min_ui_prop)(const bNodeSocket &socket, const char *name);
+ /* Reused to build the "soft_max" property too. */
+ IDProperty *(*create_max_ui_prop)(const bNodeSocket &socket, const char *name);
+ /* This uses the same values as #create_prop, but sometimes the type is different, so it can't
+ * be the same function. */
+ IDProperty *(*create_default_ui_prop)(const bNodeSocket &socket, const char *name);
+ PropertyType (*rna_subtype_get)(const bNodeSocket &socket);
+ bool (*is_correct_type)(const IDProperty &property);
+ void (*init_cpp_value)(const IDProperty &property, void *r_value);
+};
+
+static IDProperty *socket_add_property(IDProperty *settings_prop_group,
+ IDProperty *ui_container,
+ const SocketPropertyType &property_type,
+ const bNodeSocket &socket)
+{
+ const char *new_prop_name = socket.identifier;
+ /* Add the property actually storing the data to the modifier's group. */
+ IDProperty *prop = property_type.create_prop(socket, new_prop_name);
+ IDP_AddToGroup(settings_prop_group, prop);
+
+ /* Make the group in the ui container group to hold the property's UI settings. */
+ IDProperty *prop_ui_group;
+ {
+ IDPropertyTemplate idprop = {0};
+ prop_ui_group = IDP_New(IDP_GROUP, &idprop, new_prop_name);
+ IDP_AddToGroup(ui_container, prop_ui_group);
+ }
+
+ /* Create the properties for the socket's UI settings. */
+ if (property_type.create_min_ui_prop != nullptr) {
+ IDP_AddToGroup(prop_ui_group, property_type.create_min_ui_prop(socket, "min"));
+ IDP_AddToGroup(prop_ui_group, property_type.create_min_ui_prop(socket, "soft_min"));
+ }
+ if (property_type.create_max_ui_prop != nullptr) {
+ IDP_AddToGroup(prop_ui_group, property_type.create_max_ui_prop(socket, "max"));
+ IDP_AddToGroup(prop_ui_group, property_type.create_max_ui_prop(socket, "soft_max"));
+ }
+ if (property_type.create_default_ui_prop != nullptr) {
+ IDP_AddToGroup(prop_ui_group, property_type.create_default_ui_prop(socket, "default"));
+ }
+ if (property_type.rna_subtype_get != nullptr) {
+ const char *subtype_identifier = nullptr;
+ RNA_enum_identifier(rna_enum_property_subtype_items,
+ property_type.rna_subtype_get(socket),
+ &subtype_identifier);
+
+ if (subtype_identifier != nullptr) {
+ IDPropertyTemplate idprop = {0};
+ idprop.string.str = subtype_identifier;
+ idprop.string.len = BLI_strnlen(subtype_identifier, MAX_NAME) + 1;
+ IDP_AddToGroup(prop_ui_group, IDP_New(IDP_STRING, &idprop, "subtype"));
+ }
+ }
+
+ return prop;
+}
+
+static const SocketPropertyType *get_socket_property_type(const bNodeSocket &bsocket)
+{
+ switch (bsocket.type) {
+ case SOCK_FLOAT: {
+ static const SocketPropertyType float_type = {
+ [](const bNodeSocket &socket, const char *name) {
+ bNodeSocketValueFloat *value = (bNodeSocketValueFloat *)socket.default_value;
+ IDPropertyTemplate idprop = {0};
+ idprop.f = value->value;
+ return IDP_New(IDP_FLOAT, &idprop, name);
+ },
+ [](const bNodeSocket &socket, const char *name) {
+ bNodeSocketValueFloat *value = (bNodeSocketValueFloat *)socket.default_value;
+ IDPropertyTemplate idprop = {0};
+ idprop.d = value->min;
+ return IDP_New(IDP_DOUBLE, &idprop, name);
+ },
+ [](const bNodeSocket &socket, const char *name) {
+ bNodeSocketValueFloat *value = (bNodeSocketValueFloat *)socket.default_value;
+ IDPropertyTemplate idprop = {0};
+ idprop.d = value->max;
+ return IDP_New(IDP_DOUBLE, &idprop, name);
+ },
+ [](const bNodeSocket &socket, const char *name) {
+ bNodeSocketValueFloat *value = (bNodeSocketValueFloat *)socket.default_value;
+ IDPropertyTemplate idprop = {0};
+ idprop.d = value->value;
+ return IDP_New(IDP_DOUBLE, &idprop, name);
+ },
+ [](const bNodeSocket &socket) {
+ return (PropertyType)((bNodeSocketValueFloat *)socket.default_value)->subtype;
+ },
+ [](const IDProperty &property) { return property.type == IDP_FLOAT; },
+ [](const IDProperty &property, void *r_value) {
+ *(float *)r_value = IDP_Float(&property);
+ },
+ };
+ return &float_type;
+ }
+ case SOCK_INT: {
+ static const SocketPropertyType int_type = {
+ [](const bNodeSocket &socket, const char *name) {
+ bNodeSocketValueInt *value = (bNodeSocketValueInt *)socket.default_value;
+ IDPropertyTemplate idprop = {0};
+ idprop.i = value->value;
+ return IDP_New(IDP_INT, &idprop, name);
+ },
+ [](const bNodeSocket &socket, const char *name) {
+ bNodeSocketValueInt *value = (bNodeSocketValueInt *)socket.default_value;
+ IDPropertyTemplate idprop = {0};
+ idprop.i = value->min;
+ return IDP_New(IDP_INT, &idprop, name);
+ },
+ [](const bNodeSocket &socket, const char *name) {
+ bNodeSocketValueInt *value = (bNodeSocketValueInt *)socket.default_value;
+ IDPropertyTemplate idprop = {0};
+ idprop.i = value->max;
+ return IDP_New(IDP_INT, &idprop, name);
+ },
+ [](const bNodeSocket &socket, const char *name) {
+ bNodeSocketValueInt *value = (bNodeSocketValueInt *)socket.default_value;
+ IDPropertyTemplate idprop = {0};
+ idprop.i = value->value;
+ return IDP_New(IDP_INT, &idprop, name);
+ },
+ [](const bNodeSocket &socket) {
+ return (PropertyType)((bNodeSocketValueInt *)socket.default_value)->subtype;
+ },
+ [](const IDProperty &property) { return property.type == IDP_INT; },
+ [](const IDProperty &property, void *r_value) { *(int *)r_value = IDP_Int(&property); },
+ };
+ return &int_type;
+ }
+ case SOCK_VECTOR: {
+ static const SocketPropertyType vector_type = {
+ [](const bNodeSocket &socket, const char *name) {
+ bNodeSocketValueVector *value = (bNodeSocketValueVector *)socket.default_value;
+ IDPropertyTemplate idprop = {0};
+ idprop.array.len = 3;
+ idprop.array.type = IDP_FLOAT;
+ IDProperty *property = IDP_New(IDP_ARRAY, &idprop, name);
+ copy_v3_v3((float *)IDP_Array(property), value->value);
+ return property;
+ },
+ [](const bNodeSocket &socket, const char *name) {
+ bNodeSocketValueVector *value = (bNodeSocketValueVector *)socket.default_value;
+ IDPropertyTemplate idprop = {0};
+ idprop.d = value->min;
+ return IDP_New(IDP_DOUBLE, &idprop, name);
+ },
+ [](const bNodeSocket &socket, const char *name) {
+ bNodeSocketValueVector *value = (bNodeSocketValueVector *)socket.default_value;
+ IDPropertyTemplate idprop = {0};
+ idprop.d = value->max;
+ return IDP_New(IDP_DOUBLE, &idprop, name);
+ },
+ [](const bNodeSocket &socket, const char *name) {
+ bNodeSocketValueVector *value = (bNodeSocketValueVector *)socket.default_value;
+ IDPropertyTemplate idprop = {0};
+ idprop.array.len = 3;
+ idprop.array.type = IDP_FLOAT;
+ IDProperty *property = IDP_New(IDP_ARRAY, &idprop, name);
+ copy_v3_v3((float *)IDP_Array(property), value->value);
+ return property;
+ },
+ [](const bNodeSocket &socket) {
+ return (PropertyType)((bNodeSocketValueVector *)socket.default_value)->subtype;
+ },
+ [](const IDProperty &property) {
+ return property.type == IDP_ARRAY && property.subtype == IDP_FLOAT &&
+ property.len == 3;
+ },
+ [](const IDProperty &property, void *r_value) {
+ copy_v3_v3((float *)r_value, (const float *)IDP_Array(&property));
+ },
+ };
+ return &vector_type;
+ }
+ case SOCK_BOOLEAN: {
+ static const SocketPropertyType boolean_type = {
+ [](const bNodeSocket &socket, const char *name) {
+ bNodeSocketValueBoolean *value = (bNodeSocketValueBoolean *)socket.default_value;
+ IDPropertyTemplate idprop = {0};
+ idprop.i = value->value != 0;
+ return IDP_New(IDP_INT, &idprop, name);
+ },
+ [](const bNodeSocket &UNUSED(socket), const char *name) {
+ IDPropertyTemplate idprop = {0};
+ idprop.i = 0;
+ return IDP_New(IDP_INT, &idprop, name);
+ },
+ [](const bNodeSocket &UNUSED(socket), const char *name) {
+ IDPropertyTemplate idprop = {0};
+ idprop.i = 1;
+ return IDP_New(IDP_INT, &idprop, name);
+ },
+ [](const bNodeSocket &socket, const char *name) {
+ bNodeSocketValueBoolean *value = (bNodeSocketValueBoolean *)socket.default_value;
+ IDPropertyTemplate idprop = {0};
+ idprop.i = value->value != 0;
+ return IDP_New(IDP_INT, &idprop, name);
+ },
+ nullptr,
+ [](const IDProperty &property) { return property.type == IDP_INT; },
+ [](const IDProperty &property, void *r_value) {
+ *(bool *)r_value = IDP_Int(&property) != 0;
+ },
+ };
+ return &boolean_type;
+ }
+ case SOCK_STRING: {
+ static const SocketPropertyType string_type = {
+ [](const bNodeSocket &socket, const char *name) {
+ bNodeSocketValueString *value = (bNodeSocketValueString *)socket.default_value;
+ return IDP_NewString(
+ value->value, name, BLI_strnlen(value->value, sizeof(value->value)) + 1);
+ },
+ nullptr,
+ nullptr,
+ [](const bNodeSocket &socket, const char *name) {
+ bNodeSocketValueString *value = (bNodeSocketValueString *)socket.default_value;
+ return IDP_NewString(
+ value->value, name, BLI_strnlen(value->value, sizeof(value->value)) + 1);
+ },
+ nullptr,
+ [](const IDProperty &property) { return property.type == IDP_STRING; },
+ [](const IDProperty &property, void *r_value) {
+ new (r_value) std::string(IDP_String(&property));
+ },
+ };
+ return &string_type;
+ }
+ default: {
+ return nullptr;
+ }
+ }
+}
+
+/**
+ * Rebuild the list of properties based on the sockets exposed as the modifier's node group
+ * inputs. If any properties correspond to the old properties by name and type, carry over
+ * the values.
+ */
+void MOD_nodes_update_interface(Object *object, NodesModifierData *nmd)
+{
+ if (nmd->node_group == nullptr) {
+ return;
+ }
+
+ IDProperty *old_properties = nmd->settings.properties;
+
+ {
+ IDPropertyTemplate idprop = {0};
+ nmd->settings.properties = IDP_New(IDP_GROUP, &idprop, "Nodes Modifier Settings");
+ }
+
+ IDProperty *ui_container_group;
+ {
+ IDPropertyTemplate idprop = {0};
+ ui_container_group = IDP_New(IDP_GROUP, &idprop, "_RNA_UI");
+ IDP_AddToGroup(nmd->settings.properties, ui_container_group);
+ }
+
+ LISTBASE_FOREACH (bNodeSocket *, socket, &nmd->node_group->inputs) {
+ const SocketPropertyType *property_type = get_socket_property_type(*socket);
+ if (property_type == nullptr) {
+ continue;
+ }
+
+ IDProperty *new_prop = socket_add_property(
+ nmd->settings.properties, ui_container_group, *property_type, *socket);
+
+ if (old_properties != nullptr) {
+ IDProperty *old_prop = IDP_GetPropertyFromGroup(old_properties, socket->identifier);
+ if (old_prop != nullptr && property_type->is_correct_type(*old_prop)) {
+ IDP_CopyPropertyContent(new_prop, old_prop);
+ }
+ }
+ }
+
+ if (old_properties != nullptr) {
+ IDP_FreeProperty(old_properties);
+ }
+
+ DEG_id_tag_update(&object->id, ID_RECALC_GEOMETRY);
+}
+
+void MOD_nodes_init(Main *bmain, NodesModifierData *nmd)
+{
+ bNodeTree *ntree = ntreeAddTree(bmain, "Geometry Nodes", ntreeType_Geometry->idname);
+ nmd->node_group = ntree;
+
+ ntreeAddSocketInterface(ntree, SOCK_IN, "NodeSocketGeometry", "Geometry");
+ ntreeAddSocketInterface(ntree, SOCK_OUT, "NodeSocketGeometry", "Geometry");
+
+ bNode *group_input_node = nodeAddStaticNode(nullptr, ntree, NODE_GROUP_INPUT);
+ bNode *group_output_node = nodeAddStaticNode(nullptr, ntree, NODE_GROUP_OUTPUT);
+
+ group_input_node->locx = -200 - group_input_node->width;
+ group_output_node->locx = 200;
+ group_output_node->flag |= NODE_DO_OUTPUT;
+
+ nodeAddLink(ntree,
+ group_output_node,
+ (bNodeSocket *)group_output_node->inputs.first,
+ group_input_node,
+ (bNodeSocket *)group_input_node->outputs.first);
+
+ ntreeUpdateTree(bmain, ntree);
+}
+
+static void initialize_group_input(NodesModifierData &nmd,
+ const bNodeSocket &socket,
+ const CPPType &cpp_type,
+ void *r_value)
+{
+ const SocketPropertyType *property_type = get_socket_property_type(socket);
+ if (property_type == nullptr) {
+ cpp_type.copy_to_uninitialized(cpp_type.default_value(), r_value);
+ return;
+ }
+ if (nmd.settings.properties == nullptr) {
+ blender::nodes::socket_cpp_value_get(socket, r_value);
+ return;
+ }
+ const IDProperty *property = IDP_GetPropertyFromGroup(nmd.settings.properties,
+ socket.identifier);
+ if (property == nullptr) {
+ blender::nodes::socket_cpp_value_get(socket, r_value);
+ return;
+ }
+ if (!property_type->is_correct_type(*property)) {
+ blender::nodes::socket_cpp_value_get(socket, r_value);
+ }
+ property_type->init_cpp_value(*property, r_value);
+}
+
+static void fill_data_handle_map(const DerivedNodeTree &tree,
+ blender::bke::PersistentDataHandleMap &handle_map)
+{
+ Set<ID *> used_ids;
+ findUsedIds(*tree.btree(), used_ids);
+
+ int current_handle = 0;
+ for (ID *id : used_ids) {
+ handle_map.add(current_handle, *id);
+ current_handle++;
+ }
+}
+
+/**
+ * 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 GeometrySet compute_geometry(const DerivedNodeTree &tree,
+ Span<const DOutputSocket *> group_input_sockets,
+ const DInputSocket &socket_to_compute,
+ GeometrySet input_geometry_set,
+ NodesModifierData *nmd,
+ const ModifierEvalContext *ctx)
+{
+ blender::ResourceCollector resources;
+ blender::LinearAllocator<> &allocator = resources.linear_allocator();
+ blender::nodes::MultiFunctionByNode mf_by_node = get_multi_function_per_node(tree, resources);
+
+ Map<const DOutputSocket *, GMutablePointer> group_inputs;
+
+ if (group_input_sockets.size() > 0) {
+ Span<const DOutputSocket *> remaining_input_sockets = group_input_sockets;
+
+ /* If the group expects a geometry as first input, use the geometry that has been passed to
+ * modifier. */
+ const DOutputSocket *first_input_socket = group_input_sockets[0];
+ if (first_input_socket->bsocket()->type == SOCK_GEOMETRY) {
+ GeometrySet *geometry_set_in = allocator.construct<GeometrySet>(
+ std::move(input_geometry_set));
+ group_inputs.add_new(first_input_socket, geometry_set_in);
+ remaining_input_sockets = remaining_input_sockets.drop_front(1);
+ }
+
+ /* Initialize remaining group inputs. */
+ for (const DOutputSocket *socket : remaining_input_sockets) {
+ const CPPType &cpp_type = *blender::nodes::socket_cpp_type_get(*socket->typeinfo());
+ void *value_in = allocator.allocate(cpp_type.size(), cpp_type.alignment());
+ initialize_group_input(*nmd, *socket->bsocket(), cpp_type, value_in);
+ group_inputs.add_new(socket, {cpp_type, value_in});
+ }
+ }
+
+ Vector<const DInputSocket *> group_outputs;
+ group_outputs.append(&socket_to_compute);
+
+ blender::bke::PersistentDataHandleMap handle_map;
+ fill_data_handle_map(tree, handle_map);
+
+ GeometryNodesEvaluator evaluator{
+ group_inputs, group_outputs, mf_by_node, handle_map, ctx->object};
+ Vector<GMutablePointer> results = evaluator.execute();
+ BLI_assert(results.size() == 1);
+ GMutablePointer result = results[0];
+
+ GeometrySet output_geometry = std::move(*(GeometrySet *)result.get());
+ return output_geometry;
+}
+
+/**
+ * \note This could be done in #initialize_group_input, though that would require adding the
+ * the object as a parameter, so it's likely better to this check as a separate step.
+ */
+static void check_property_socket_sync(const Object *ob, ModifierData *md)
+{
+ NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
+
+ int i = 0;
+ LISTBASE_FOREACH_INDEX (const bNodeSocket *, socket, &nmd->node_group->inputs, i) {
+ /* The first socket is the special geometry socket for the modifier object. */
+ if (i == 0 && socket->type == SOCK_GEOMETRY) {
+ continue;
+ }
+
+ IDProperty *property = IDP_GetPropertyFromGroup(nmd->settings.properties, socket->identifier);
+ if (property == nullptr) {
+ if (socket->type == SOCK_STRING) {
+ BKE_modifier_set_error(ob, md, "String socket can not be exposed in the modifier");
+ }
+ else if (socket->type == SOCK_OBJECT) {
+ BKE_modifier_set_error(ob, md, "Object socket can not be exposed in the modifier");
+ }
+ else if (socket->type == SOCK_GEOMETRY) {
+ BKE_modifier_set_error(ob, md, "Node group can only have one geometry input");
+ }
+ else {
+ BKE_modifier_set_error(ob, md, "Missing property for input socket \"%s\"", socket->name);
+ }
+ continue;
+ }
+
+ const SocketPropertyType *property_type = get_socket_property_type(*socket);
+ if (!property_type->is_correct_type(*property)) {
+ BKE_modifier_set_error(
+ ob, md, "Property type does not match input socket \"(%s)\"", socket->name);
+ continue;
+ }
+ }
+
+ bool has_geometry_output = false;
+ LISTBASE_FOREACH (const bNodeSocket *, socket, &nmd->node_group->outputs) {
+ if (socket->type == SOCK_GEOMETRY) {
+ has_geometry_output = true;
+ }
+ }
+
+ if (!has_geometry_output) {
+ BKE_modifier_set_error(ob, md, "Node group must have a geometry output");
+ }
+}
+
+static void modifyGeometry(ModifierData *md,
+ const ModifierEvalContext *ctx,
+ GeometrySet &geometry_set)
+{
+ NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
+ if (nmd->node_group == nullptr) {
+ return;
+ }
+
+ check_property_socket_sync(ctx->object, md);
+
+ blender::nodes::NodeTreeRefMap tree_refs;
+ DerivedNodeTree tree{nmd->node_group, tree_refs};
+
+ if (tree.has_link_cycles()) {
+ BKE_modifier_set_error(ctx->object, md, "Node group has cycles");
+ return;
+ }
+
+ 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;
+ }
+ if (output_nodes.size() != 1) {
+ return;
+ }
+
+ 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() == 0) {
+ return;
+ }
+
+ const DInputSocket *group_output = group_outputs[0];
+ if (group_output->idname() != "NodeSocketGeometry") {
+ return;
+ }
+
+ geometry_set = compute_geometry(
+ tree, group_inputs, *group_outputs[0], std::move(geometry_set), nmd, ctx);
+}
+
+static Mesh *modifyMesh(ModifierData *md, const ModifierEvalContext *ctx, Mesh *mesh)
+{
+ GeometrySet geometry_set = GeometrySet::create_with_mesh(mesh, GeometryOwnershipType::Editable);
+ geometry_set.get_component_for_write<MeshComponent>().copy_vertex_group_names_from_object(
+ *ctx->object);
+ modifyGeometry(md, ctx, geometry_set);
+ Mesh *new_mesh = geometry_set.get_component_for_write<MeshComponent>().release();
+ if (new_mesh == nullptr) {
+ return BKE_mesh_new_nomain(0, 0, 0, 0, 0);
+ }
+ return new_mesh;
+}
+
+static void modifyPointCloud(ModifierData *md,
+ const ModifierEvalContext *ctx,
+ GeometrySet *geometry_set)
+{
+ modifyGeometry(md, ctx, *geometry_set);
+}
+
+/* Drawing the properties manually with #uiItemR instead of #uiDefAutoButsRNA allows using
+ * the node socket identifier for the property names, since they are unique, but also having
+ * the correct label displayed in the UI. */
+static void draw_property_for_socket(uiLayout *layout,
+ PointerRNA *settings_ptr,
+ const IDProperty *modifier_props,
+ const bNodeSocket &socket)
+{
+ const SocketPropertyType *property_type = get_socket_property_type(socket);
+ if (property_type == nullptr) {
+ return;
+ }
+
+ /* The property should be created in #MOD_nodes_update_interface with the correct type. */
+ IDProperty *property = IDP_GetPropertyFromGroup(modifier_props, socket.identifier);
+
+ /* IDProperties can be removed with python, so there could be a situation where
+ * there isn't a property for a socket or it doesn't have the correct type. */
+ if (property != nullptr && property_type->is_correct_type(*property)) {
+ char rna_path[128];
+ BLI_snprintf(rna_path, ARRAY_SIZE(rna_path), "[\"%s\"]", socket.identifier);
+ uiItemR(layout, settings_ptr, rna_path, 0, socket.name, ICON_NONE);
+ }
+}
+
+static void panel_draw(const bContext *C, Panel *panel)
+{
+#ifdef WITH_GEOMETRY_NODES
+ uiLayout *layout = panel->layout;
+
+ PointerRNA *ptr = modifier_panel_get_property_pointers(panel, nullptr);
+ NodesModifierData *nmd = static_cast<NodesModifierData *>(ptr->data);
+
+ uiLayoutSetPropSep(layout, true);
+ /* This should be removed, but animation currently doesn't work with the IDProperties. */
+ uiLayoutSetPropDecorate(layout, false);
+
+ uiTemplateID(layout,
+ C,
+ ptr,
+ "node_group",
+ "node.new_geometry_node_group_assign",
+ nullptr,
+ nullptr,
+ 0,
+ false,
+ nullptr);
+
+ if (nmd->node_group != nullptr && nmd->settings.properties != nullptr) {
+ PointerRNA settings_ptr;
+ RNA_pointer_create(ptr->owner_id, &RNA_NodesModifierSettings, &nmd->settings, &settings_ptr);
+
+ LISTBASE_FOREACH (bNodeSocket *, socket, &nmd->node_group->inputs) {
+ draw_property_for_socket(layout, &settings_ptr, nmd->settings.properties, *socket);
+ }
+ }
+
+ modifier_panel_end(layout, ptr);
+#endif
+}
+
+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);
+ if (nmd->settings.properties != nullptr) {
+ /* Note that the property settings are based on the socket type info
+ * and don't necessarily need to be written, but we can't just free them. */
+ IDP_BlendWrite(writer, nmd->settings.properties);
+ }
+}
+
+static void blendRead(BlendDataReader *reader, ModifierData *md)
+{
+ NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
+ BLO_read_data_address(reader, &nmd->settings.properties);
+ IDP_BlendDataRead(reader, &nmd->settings.properties);
+}
+
+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);
+
+ BKE_modifier_copydata_generic(md, target, flag);
+
+ if (nmd->settings.properties != nullptr) {
+ tnmd->settings.properties = IDP_CopyProperty_ex(nmd->settings.properties, flag);
+ }
+}
+
+static void freeData(ModifierData *md)
+{
+ NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
+ if (nmd->settings.properties != nullptr) {
+ IDP_FreeProperty_ex(nmd->settings.properties, false);
+ nmd->settings.properties = nullptr;
+ }
+}
+
+ModifierTypeInfo modifierType_Nodes = {
+ /* name */ "GeometryNodes",
+ /* structName */ "NodesModifierData",
+ /* structSize */ sizeof(NodesModifierData),
+#ifdef WITH_GEOMETRY_NODES
+ /* srna */ &RNA_NodesModifier,
+#else
+ /* srna */ &RNA_Modifier,
+#endif
+ /* type */ eModifierTypeType_Constructive,
+ /* flags */
+ static_cast<ModifierTypeFlag>(eModifierTypeFlag_AcceptsMesh |
+ eModifierTypeFlag_SupportsEditmode |
+ eModifierTypeFlag_EnableInEditmode),
+ /* icon */ ICON_MESH_DATA, /* TODO: Use correct icon. */
+
+ /* copyData */ copyData,
+
+ /* deformVerts */ nullptr,
+ /* deformMatrices */ nullptr,
+ /* deformVertsEM */ nullptr,
+ /* deformMatricesEM */ nullptr,
+ /* modifyMesh */ modifyMesh,
+ /* modifyHair */ nullptr,
+ /* modifyPointCloud */ modifyPointCloud,
+ /* modifyVolume */ nullptr,
+
+ /* initData */ initData,
+ /* requiredDataMask */ nullptr,
+ /* freeData */ freeData,
+ /* isDisabled */ isDisabled,
+ /* updateDepsgraph */ updateDepsgraph,
+ /* dependsOnTime */ nullptr,
+ /* dependsOnNormals */ nullptr,
+ /* foreachIDLink */ foreachIDLink,
+ /* foreachTexLink */ nullptr,
+ /* freeRuntimeData */ nullptr,
+ /* 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 0766c59cda6..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 */ nullptr,
- /* deformMatrices */ nullptr,
- /* deformVertsEM */ nullptr,
- /* deformMatricesEM */ nullptr,
- /* modifyMesh */ nullptr,
- /* modifyHair */ nullptr,
- /* modifyPointCloud */ modifyPointCloud,
- /* modifyVolume */ nullptr,
-
- /* initData */ initData,
- /* requiredDataMask */ nullptr,
- /* freeData */ freeData,
- /* isDisabled */ isDisabled,
- /* updateDepsgraph */ updateDepsgraph,
- /* dependsOnTime */ nullptr,
- /* dependsOnNormals */ nullptr,
- /* foreachIDLink */ foreachIDLink,
- /* foreachTexLink */ nullptr,
- /* freeRuntimeData */ nullptr,
- /* 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..55409cba114 100644
--- a/source/blender/modifiers/intern/MOD_util.c
+++ b/source/blender/modifiers/intern/MOD_util.c
@@ -342,9 +342,9 @@ void modifier_type_init(ModifierTypeInfo *types[])
INIT_TYPE(MeshSequenceCache);
INIT_TYPE(SurfaceDeform);
INIT_TYPE(WeightedNormal);
- INIT_TYPE(Simulation);
INIT_TYPE(MeshToVolume);
INIT_TYPE(VolumeDisplace);
INIT_TYPE(VolumeToMesh);
+ INIT_TYPE(Nodes);
#undef INIT_TYPE
}