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
path: root/source
diff options
context:
space:
mode:
authorFabian Schempp <fabianschempp@googlemail.com>2021-08-17 23:32:46 +0300
committerFabian Schempp <fabianschempp@googlemail.com>2021-08-17 23:32:46 +0300
commit7649b8446278cb3db4409267afd90b39fef6de2b (patch)
treea6703d9825e9f3e3e20c97d0cd8b3b3aa016c114 /source
parent809dce5bdeeb193a160b2961bf069eab76c2ce01 (diff)
parentec0ebcdcc49da24fd91b7fae0eda87903f1a8cb2 (diff)
Merge branch 'soc-2021-porting-modifiers-to-nodes-decimate' into soc-2021-porting-modifiers-to-nodes
Diffstat (limited to 'source')
-rw-r--r--source/blender/blenkernel/BKE_node.h4
-rw-r--r--source/blender/blenkernel/intern/node.cc3
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.c74
-rw-r--r--source/blender/bmesh/intern/bmesh_mesh.h6
-rw-r--r--source/blender/bmesh/intern/bmesh_operator_api.h3
-rw-r--r--source/blender/bmesh/tools/bmesh_decimate_dissolve.c16
-rw-r--r--source/blender/makesdna/DNA_node_types.h23
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c52
-rw-r--r--source/blender/nodes/CMakeLists.txt3
-rw-r--r--source/blender/nodes/NOD_geometry.h3
-rw-r--r--source/blender/nodes/NOD_static_types.h3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_collapse.cc122
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_dissolve.cc137
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_unsubdivide.cc87
14 files changed, 535 insertions, 1 deletions
diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h
index caa7ab6de0a..14448bd7c85 100644
--- a/source/blender/blenkernel/BKE_node.h
+++ b/source/blender/blenkernel/BKE_node.h
@@ -1477,7 +1477,9 @@ int ntreeTexExecTree(struct bNodeTree *ntree,
#define GEO_NODE_CURVE_SET_HANDLES 1072
#define GEO_NODE_CURVE_SPLINE_TYPE 1073
#define GEO_NODE_CURVE_SELECT_HANDLES 1074
-
+#define GEO_NODE_COLLAPSE 1075
+#define GEO_NODE_UNSUBDIVIDE 1076
+#define GEO_NODE_DISSOLVE 1077
/** \} */
/* -------------------------------------------------------------------- */
diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc
index bd22f049a8b..8a8fb7561b6 100644
--- a/source/blender/blenkernel/intern/node.cc
+++ b/source/blender/blenkernel/intern/node.cc
@@ -5136,6 +5136,7 @@ static void registerGeometryNodes()
register_node_type_geo_attribute_vector_rotate();
register_node_type_geo_boolean();
register_node_type_geo_bounding_box();
+ register_node_type_geo_collapse();
register_node_type_geo_collection_info();
register_node_type_geo_convex_hull();
register_node_type_geo_curve_endpoints();
@@ -5156,6 +5157,7 @@ static void registerGeometryNodes()
register_node_type_geo_curve_to_points();
register_node_type_geo_curve_trim();
register_node_type_geo_delete_geometry();
+ register_node_type_geo_dissolve();
register_node_type_geo_edge_split();
register_node_type_geo_input_material();
register_node_type_geo_is_viewport();
@@ -5189,6 +5191,7 @@ static void registerGeometryNodes()
register_node_type_geo_switch();
register_node_type_geo_transform();
register_node_type_geo_triangulate();
+ register_node_type_geo_unsubdivide();
register_node_type_geo_viewer();
register_node_type_geo_volume_to_mesh();
}
diff --git a/source/blender/bmesh/intern/bmesh_mesh.c b/source/blender/bmesh/intern/bmesh_mesh.c
index b2958a9e744..ef89451a587 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.c
+++ b/source/blender/bmesh/intern/bmesh_mesh.c
@@ -1446,4 +1446,78 @@ void BM_mesh_vert_coords_apply_with_mat4(BMesh *bm,
}
}
+/**
+ * Use to select bmesh vertex data based on an array of bool.
+ */
+void BM_select_vertices(BMesh *bm, const bool *mask)
+{
+ BMIter iter;
+ BMVert *v;
+ int i;
+ BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
+ BM_elem_flag_set(v, BM_ELEM_SELECT, mask[i]);
+ }
+}
+
+/**
+ * Use to select bmesh edge data based on an array of bool.
+ */
+void BM_select_edges(BMesh *bm, const bool *mask)
+{
+ BMIter iter;
+ BMEdge *e;
+ int i;
+ BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
+ BM_elem_flag_set(e, BM_ELEM_SELECT, mask[i]);
+ }
+}
+
+/**
+ * Use to select bmesh face data based on an array of bool.
+ */
+void BM_select_faces(BMesh *bm, const bool *mask)
+{
+ BMIter iter;
+ BMFace *f;
+ int i;
+ BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) {
+ BM_elem_flag_set(f, BM_ELEM_SELECT, mask[i]);
+ }
+}
+
+void BM_tag_vertices(BMesh *bm, const bool *mask)
+{
+ BMIter iter;
+ BMVert *v;
+ int i;
+ BM_ITER_MESH_INDEX (v, &iter, bm, BM_VERTS_OF_MESH, i) {
+ BM_elem_flag_set(v, BM_ELEM_TAG, mask[i]);
+ }
+}
+
+/**
+ * Use to temporary tag bmesh edge data based on an array of bool.
+ */
+void BM_tag_edges(BMesh *bm, const bool *mask)
+{
+ BMIter iter;
+ BMEdge *e;
+ int i;
+ BM_ITER_MESH_INDEX (e, &iter, bm, BM_EDGES_OF_MESH, i) {
+ BM_elem_flag_set(e, BM_ELEM_TAG, mask[i]);
+ }
+}
+
+/**
+ * Use to temporary tag bmesh face data based on an array of bool.
+ */
+void BM_tag_faces(BMesh *bm, const bool *mask)
+{
+ BMIter iter;
+ BMFace *f;
+ int i;
+ BM_ITER_MESH_INDEX (f, &iter, bm, BM_FACES_OF_MESH, i) {
+ BM_elem_flag_set(f, BM_ELEM_TAG, mask[i]);
+ }
+}
/** \} */
diff --git a/source/blender/bmesh/intern/bmesh_mesh.h b/source/blender/bmesh/intern/bmesh_mesh.h
index bd0504b038a..5928da51d1e 100644
--- a/source/blender/bmesh/intern/bmesh_mesh.h
+++ b/source/blender/bmesh/intern/bmesh_mesh.h
@@ -134,3 +134,9 @@ void BM_mesh_vert_coords_apply(BMesh *bm, const float (*vert_coords)[3]);
void BM_mesh_vert_coords_apply_with_mat4(BMesh *bm,
const float (*vert_coords)[3],
const float mat[4][4]);
+void BM_select_vertices(BMesh *bm, const bool *mask);
+void BM_select_edges(BMesh *bm, const bool *mask);
+void BM_select_faces(BMesh *bm, const bool *mask);
+void BM_tag_vertices(BMesh *bm, const bool *mask);
+void BM_tag_edges(BMesh *bm, const bool *mask);
+void BM_tag_faces(BMesh *bm, const bool *mask); \ No newline at end of file
diff --git a/source/blender/bmesh/intern/bmesh_operator_api.h b/source/blender/bmesh/intern/bmesh_operator_api.h
index 0f9488bd091..06f82e21c9c 100644
--- a/source/blender/bmesh/intern/bmesh_operator_api.h
+++ b/source/blender/bmesh/intern/bmesh_operator_api.h
@@ -428,6 +428,9 @@ typedef enum {
BMO_DELIM_SEAM = 1 << 2,
BMO_DELIM_SHARP = 1 << 3,
BMO_DELIM_UV = 1 << 4,
+ BMO_DELIM_EDGE_SELECTION_INVSE = 1 << 5,
+ BMO_DELIM_EDGE_SELECTION = 1 << 6,
+ BMO_DELIM_FACE_SELECTION = 1 << 7,
} BMO_Delimit;
void BMO_op_flag_enable(BMesh *bm, BMOperator *op, const int op_flag);
diff --git a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
index d8a586acee5..349b89d4340 100644
--- a/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
+++ b/source/blender/bmesh/tools/bmesh_decimate_dissolve.c
@@ -104,6 +104,22 @@ static bool bm_edge_is_delimiter(const BMEdge *e,
BLI_assert(BM_edge_is_manifold(e));
if (delimit != 0) {
+ if (delimit & BMO_DELIM_EDGE_SELECTION_INVSE) {
+ if (!BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ return true;
+ }
+ }
+ if (delimit & BMO_DELIM_EDGE_SELECTION) {
+ if (BM_elem_flag_test(e, BM_ELEM_SELECT)) {
+ return true;
+ }
+ }
+ if (delimit & BMO_DELIM_FACE_SELECTION) {
+ if (BM_elem_flag_test(e->l->f, BM_ELEM_TAG) !=
+ BM_elem_flag_test(e->l->radial_next->f, BM_ELEM_TAG)) {
+ return true;
+ }
+ }
if (delimit & BMO_DELIM_SEAM) {
if (BM_elem_flag_test(e, BM_ELEM_SEAM)) {
return true;
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index fd794ed1b21..65016674436 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -1437,6 +1437,16 @@ typedef struct NodeGeometryRaycast {
char _pad[1];
} NodeGeometryRaycast;
+typedef struct NodeGeometryCollapse {
+ /* GeometryNodeCollapseSymmetryAxis. */
+ int8_t symmetry_axis;
+} NodeGeometryCollapse;
+
+typedef struct NodeGeometryDissolve {
+ /* GeometryNodeDissolveDelimiter */
+ int8_t selection_type;
+} NodeGeometryDissolve;
+
/* script node mode */
#define NODE_SCRIPT_INTERNAL 0
#define NODE_SCRIPT_EXTERNAL 1
@@ -2008,6 +2018,19 @@ typedef enum GeometryNodeRaycastMapMode {
GEO_NODE_RAYCAST_NEAREST = 1,
} GeometryNodeRaycastMapMode;
+typedef enum GeometryNodeCollapseSymmetryAxis {
+ GEO_NODE_COLLAPSE_SYMMETRY_AXIS_NONE = -1,
+ GEO_NODE_COLLAPSE_SYMMETRY_AXIS_X = 0,
+ GEO_NODE_COLLAPSE_SYMMETRY_AXIS_Y = 1,
+ GEO_NODE_COLLAPSE_SYMMETRY_AXIS_Z = 2,
+} GeometryNodeCollapseSymmetryAxis;
+
+typedef enum GeometryNodeDissolveDelimiter {
+ GEO_NODE_DISSOLVE_DELIMITTER_UNSELECTED = 0,
+ GEO_NODE_DISSOLVE_DELIMITTER_LIMIT = 1,
+ GEO_NODE_DISSOLVE_DELIMITTER_SELECTION_BORDER = 2,
+} GeometryNodeDissolveDelimiter;
+
#ifdef __cplusplus
}
#endif
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index 7d5fffcc6c9..0b144b7f5bc 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -10094,6 +10094,58 @@ static void def_geo_curve_resample(StructRNA *srna)
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
+static void def_geo_collapse(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ static EnumPropertyItem symmetry_axis_items[] = {
+ {GEO_NODE_COLLAPSE_SYMMETRY_AXIS_NONE, "NONE", 0, "None", "No Symmetry is applied"},
+ {GEO_NODE_COLLAPSE_SYMMETRY_AXIS_X, "X", 0, "X", "Symmetry is applied on X axis"},
+ {GEO_NODE_COLLAPSE_SYMMETRY_AXIS_Y, "Y", 0, "Y", "Symmetry is applied on Y axis"},
+ {GEO_NODE_COLLAPSE_SYMMETRY_AXIS_Z, "Z", 0, "Z", "Symmetry is applied on Z axis"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryCollapse", "storage");
+
+ prop = RNA_def_property(srna, "symmetry_axis", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, symmetry_axis_items);
+ RNA_def_property_ui_text(
+ prop, "Symmetry", "Set if and on what axis symmetry is applied by the operation");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
+static void def_geo_dissolve(StructRNA *srna)
+{
+ PropertyRNA *prop;
+
+ static EnumPropertyItem delimiter_items[] = {
+ {GEO_NODE_DISSOLVE_DELIMITTER_UNSELECTED,
+ "SELECTION",
+ 0,
+ "Selection",
+ "Only dissolve selected"},
+ {GEO_NODE_DISSOLVE_DELIMITTER_LIMIT,
+ "LIMIT",
+ 0,
+ "Limit",
+ "Only dissolve unselected. Use especially for attributes on edge domain e.g. crease"},
+ {GEO_NODE_DISSOLVE_DELIMITTER_SELECTION_BORDER,
+ "BORDER",
+ 0,
+ "Border as Limit",
+ "Use border of selection as delimiter"},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ RNA_def_struct_sdna_from(srna, "NodeGeometryDissolve", "storage");
+
+ prop = RNA_def_property(srna, "selection_type", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_items(prop, delimiter_items);
+ RNA_def_property_ui_text(prop, "Selection", "Define how selection is applied");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+}
+
static void def_geo_curve_subdivide(StructRNA *srna)
{
PropertyRNA *prop;
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index 46fb9f54bfe..d8041b646f2 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -161,6 +161,7 @@ set(SRC
geometry/nodes/node_geo_attribute_vector_rotate.cc
geometry/nodes/node_geo_boolean.cc
geometry/nodes/node_geo_bounding_box.cc
+ geometry/nodes/node_geo_collapse.cc
geometry/nodes/node_geo_collection_info.cc
geometry/nodes/node_geo_common.cc
geometry/nodes/node_geo_convex_hull.cc
@@ -183,6 +184,7 @@ set(SRC
geometry/nodes/node_geo_curve_to_points.cc
geometry/nodes/node_geo_curve_trim.cc
geometry/nodes/node_geo_delete_geometry.cc
+ geometry/nodes/node_geo_dissolve.cc
geometry/nodes/node_geo_edge_split.cc
geometry/nodes/node_geo_input_material.cc
geometry/nodes/node_geo_is_viewport.cc
@@ -214,6 +216,7 @@ set(SRC
geometry/nodes/node_geo_switch.cc
geometry/nodes/node_geo_transform.cc
geometry/nodes/node_geo_triangulate.cc
+ geometry/nodes/node_geo_unsubdivide.cc
geometry/nodes/node_geo_viewer.cc
geometry/nodes/node_geo_volume_to_mesh.cc
geometry/node_geometry_exec.cc
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index 856d787c8d0..176c3eac289 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -49,6 +49,7 @@ void register_node_type_geo_attribute_vector_math(void);
void register_node_type_geo_attribute_vector_rotate(void);
void register_node_type_geo_boolean(void);
void register_node_type_geo_bounding_box(void);
+void register_node_type_geo_collapse(void);
void register_node_type_geo_collection_info(void);
void register_node_type_geo_convex_hull(void);
void register_node_type_geo_curve_endpoints(void);
@@ -69,6 +70,7 @@ void register_node_type_geo_curve_to_mesh(void);
void register_node_type_geo_curve_to_points(void);
void register_node_type_geo_curve_trim(void);
void register_node_type_geo_delete_geometry(void);
+void register_node_type_geo_dissolve(void);
void register_node_type_geo_edge_split(void);
void register_node_type_geo_input_material(void);
void register_node_type_geo_is_viewport(void);
@@ -102,6 +104,7 @@ void register_node_type_geo_subdivision_surface(void);
void register_node_type_geo_switch(void);
void register_node_type_geo_transform(void);
void register_node_type_geo_triangulate(void);
+void register_node_type_geo_unsubdivide(void);
void register_node_type_geo_viewer(void);
void register_node_type_geo_volume_to_mesh(void);
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index 4da8648173d..40a0d60fc51 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -289,6 +289,7 @@ DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_VECTOR_MATH, def_geo_attribute_vector_m
DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_VECTOR_ROTATE, def_geo_attribute_vector_rotate, "ATTRIBUTE_VECTOR_ROTATE", AttributeVectorRotate, "Attribute Vector Rotate", "")
DefNode(GeometryNode, GEO_NODE_BOOLEAN, def_geo_boolean, "BOOLEAN", Boolean, "Boolean", "")
DefNode(GeometryNode, GEO_NODE_BOUNDING_BOX, 0, "BOUNDING_BOX", BoundBox, "Bounding Box", "")
+DefNode(GeometryNode, GEO_NODE_COLLAPSE, def_geo_collapse, "COLLAPSE", Collapse, "Collapse", "")
DefNode(GeometryNode, GEO_NODE_COLLECTION_INFO, def_geo_collection_info, "COLLECTION_INFO", CollectionInfo, "Collection Info", "")
DefNode(GeometryNode, GEO_NODE_CONVEX_HULL, 0, "CONVEX_HULL", ConvexHull, "Convex Hull", "")
DefNode(GeometryNode, GEO_NODE_CURVE_ENDPOINTS, 0, "CURVE_ENDPOINTS", CurveEndpoints, "Curve Endpoints", "")
@@ -310,6 +311,7 @@ DefNode(GeometryNode, GEO_NODE_CURVE_TO_MESH, 0, "CURVE_TO_MESH", CurveToMesh, "
DefNode(GeometryNode, GEO_NODE_CURVE_TO_POINTS, def_geo_curve_to_points, "CURVE_TO_POINTS", CurveToPoints, "Curve to Points", "")
DefNode(GeometryNode, GEO_NODE_CURVE_TRIM, def_geo_curve_trim, "CURVE_TRIM", CurveTrim, "Curve Trim", "")
DefNode(GeometryNode, GEO_NODE_DELETE_GEOMETRY, 0, "DELETE_GEOMETRY", DeleteGeometry, "Delete Geometry", "")
+DefNode(GeometryNode, GEO_NODE_DISSOLVE, def_geo_dissolve, "DISSOLVE", Dissolve, "Dissolve", "")
DefNode(GeometryNode, GEO_NODE_EDGE_SPLIT, 0, "EDGE_SPLIT", EdgeSplit, "Edge Split", "")
DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL, def_geo_input_material, "INPUT_MATERIAL", InputMaterial, "Material", "")
DefNode(GeometryNode, GEO_NODE_IS_VIEWPORT, 0, "IS_VIEWPORT", IsViewport, "Is Viewport", "")
@@ -341,6 +343,7 @@ DefNode(GeometryNode, GEO_NODE_SUBDIVISION_SURFACE, def_geo_subdivision_surface,
DefNode(GeometryNode, GEO_NODE_SWITCH, def_geo_switch, "SWITCH", Switch, "Switch", "")
DefNode(GeometryNode, GEO_NODE_TRANSFORM, 0, "TRANSFORM", Transform, "Transform", "")
DefNode(GeometryNode, GEO_NODE_TRIANGULATE, def_geo_triangulate, "TRIANGULATE", Triangulate, "Triangulate", "")
+DefNode(GeometryNode, GEO_NODE_UNSUBDIVIDE, 0, "UNSUBDIVIDE", Unsubdivide, "Unsubdivide", "")
DefNode(GeometryNode, GEO_NODE_VIEWER, 0, "VIEWER", Viewer, "Viewer", "")
DefNode(GeometryNode, GEO_NODE_VOLUME_TO_MESH, def_geo_volume_to_mesh, "VOLUME_TO_MESH", VolumeToMesh, "Volume to Mesh", "")
diff --git a/source/blender/nodes/geometry/nodes/node_geo_collapse.cc b/source/blender/nodes/geometry/nodes/node_geo_collapse.cc
new file mode 100644
index 00000000000..c13ab362f17
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_collapse.cc
@@ -0,0 +1,122 @@
+/*
+ * 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_mesh.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+
+#include "node_geometry_util.hh"
+
+static bNodeSocketTemplate geo_node_collapse_in[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {SOCK_FLOAT, N_("Factor"), 1.0f, 0.0f, 0.0f, 0.0f, 0, 1.0f, PROP_FACTOR},
+ {SOCK_STRING, N_("Selection")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_collapse_out[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {-1, ""},
+};
+
+static void geo_node_collapse_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+ uiItemR(layout, ptr, "symmetry_axis", 0, nullptr, ICON_NONE);
+}
+
+static void geo_node_collapse_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryCollapse *node_storage = (NodeGeometryCollapse *)MEM_callocN(
+ sizeof(NodeGeometryCollapse), __func__);
+
+ node->storage = node_storage;
+ node_storage->symmetry_axis = GEO_NODE_COLLAPSE_SYMMETRY_AXIS_NONE;
+}
+
+namespace blender::nodes {
+
+static Mesh *collapse_mesh(const float factor,
+ const VArray<float> &selection,
+ const bool triangulate,
+ const int symmetry_axis,
+ const Mesh *mesh)
+{
+ const BMeshCreateParams bmesh_create_params = {0};
+ const BMeshFromMeshParams bmesh_from_mesh_params = {
+ true, 0, 0, 0, {CD_MASK_ORIGINDEX, CD_MASK_ORIGINDEX, CD_MASK_ORIGINDEX}};
+ BMesh *bm = BKE_mesh_to_bmesh_ex(mesh, &bmesh_create_params, &bmesh_from_mesh_params);
+
+ const float symmetry_eps = 0.00002f;
+ Array<float> mask(selection.size());
+ selection.materialize(mask);
+
+ BM_mesh_decimate_collapse(
+ bm, factor, mask.data(), 1.0f, triangulate, symmetry_axis, symmetry_eps);
+ Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
+ BM_mesh_free(bm);
+
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ return result;
+}
+
+static void geo_node_collapse_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ const float factor = params.extract_input<float>("Factor");
+
+ if (factor < 1.0f && geometry_set.has_mesh()) {
+ MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
+
+ const float default_factor = 1.0f;
+ GVArray_Typed<float> selection_attribute = params.get_input_attribute<float>(
+ "Selection", mesh_component, ATTR_DOMAIN_POINT, default_factor);
+ // VArray<float> selection(selection_attribute.to);
+ const Mesh *input_mesh = mesh_component.get_for_read();
+
+ const bNode &node = params.node();
+ const NodeGeometryCollapse &node_storage = *(NodeGeometryCollapse *)node.storage;
+ Mesh *result = collapse_mesh(
+ factor, selection_attribute, false, node_storage.symmetry_axis, input_mesh);
+ geometry_set.replace_mesh(result);
+ }
+
+ params.set_output("Geometry", std::move(geometry_set));
+}
+} // namespace blender::nodes
+
+void register_node_type_geo_collapse()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_COLLAPSE, "Collapse", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(&ntype, geo_node_collapse_in, geo_node_collapse_out);
+ node_type_storage(
+ &ntype, "NodeGeometryCollapse", node_free_standard_storage, node_copy_standard_storage);
+ node_type_init(&ntype, geo_node_collapse_init);
+ ntype.geometry_node_execute = blender::nodes::geo_node_collapse_exec;
+ ntype.draw_buttons = geo_node_collapse_layout;
+ ntype.width = 180;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_dissolve.cc b/source/blender/nodes/geometry/nodes/node_geo_dissolve.cc
new file mode 100644
index 00000000000..3d41fa80e75
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_dissolve.cc
@@ -0,0 +1,137 @@
+/*
+ * 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_mesh.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+#include "math.h"
+#include "node_geometry_util.hh"
+
+static bNodeSocketTemplate geo_node_dissolve_in[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {SOCK_FLOAT, N_("Angle"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, M_PI, PROP_ANGLE},
+ {SOCK_BOOLEAN, N_("All Boundaries"), false},
+ {SOCK_STRING, N_("Selection")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_dissolve_out[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {-1, ""},
+};
+
+static void geo_node_dissolve_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiLayoutSetPropSep(layout, true);
+ uiLayoutSetPropDecorate(layout, false);
+ uiItemR(layout, ptr, "selection_type", 0, nullptr, ICON_NONE);
+}
+
+static void geo_node_dissolve_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryDissolve *node_storage = (NodeGeometryDissolve *)MEM_callocN(
+ sizeof(NodeGeometryDissolve), __func__);
+
+ node->storage = node_storage;
+ node_storage->selection_type = GEO_NODE_DISSOLVE_DELIMITTER_UNSELECTED;
+}
+
+namespace blender::nodes {
+static Mesh *dissolve_mesh(const float angle,
+ const bool all_boundaries,
+ const int delimiter,
+ const Span<bool> selection,
+ const Mesh *mesh)
+{
+ const BMeshCreateParams bmesh_create_params = {0};
+ const BMeshFromMeshParams bmesh_from_mesh_params = {
+ true, 0, 0, 0, {CD_MASK_ORIGINDEX, CD_MASK_ORIGINDEX, CD_MASK_ORIGINDEX}};
+ BMesh *bm = BKE_mesh_to_bmesh_ex(mesh, &bmesh_create_params, &bmesh_from_mesh_params);
+ if (delimiter & BMO_DELIM_FACE_SELECTION) {
+ BM_tag_faces(bm, selection.data());
+ }
+ else {
+ BM_select_edges(bm, selection.data());
+ }
+
+ BM_mesh_decimate_dissolve(bm, angle, all_boundaries, (BMO_Delimit)delimiter);
+
+ Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
+ BM_mesh_free(bm);
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ return result;
+}
+
+static void geo_node_dissolve_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ const float angle = params.extract_input<float>("Angle");
+
+ if (angle > 0.0f && geometry_set.has_mesh()) {
+ const MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
+ const Mesh *input_mesh = mesh_component.get_for_read();
+
+ const bool all_boundaries = params.extract_input<bool>("All Boundaries");
+ const bNode &node = params.node();
+ const NodeGeometryDissolve &node_storage = *(NodeGeometryDissolve *)node.storage;
+
+ bool default_selection = false;
+ AttributeDomain selection_domain = ATTR_DOMAIN_FACE;
+ BMO_Delimit delimiter = BMO_DELIM_FACE_SELECTION;
+
+ if (node_storage.selection_type == GEO_NODE_DISSOLVE_DELIMITTER_UNSELECTED) {
+ selection_domain = ATTR_DOMAIN_EDGE;
+ delimiter = BMO_DELIM_EDGE_SELECTION_INVSE;
+ }
+ else if (node_storage.selection_type == GEO_NODE_DISSOLVE_DELIMITTER_LIMIT) {
+ selection_domain = ATTR_DOMAIN_EDGE;
+ delimiter = BMO_DELIM_EDGE_SELECTION;
+ default_selection = true;
+ };
+
+ GVArray_Typed<bool> selection_attribute = params.get_input_attribute<bool>(
+ "Selection", mesh_component, selection_domain, default_selection);
+ VArray_Span<bool> selection{selection_attribute};
+
+ Mesh *result = dissolve_mesh(angle, all_boundaries, delimiter, selection, input_mesh);
+ geometry_set.replace_mesh(result);
+ }
+
+ params.set_output("Geometry", std::move(geometry_set));
+}
+} // namespace blender::nodes
+
+void register_node_type_geo_dissolve()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_DISSOLVE, "Dissolve", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(&ntype, geo_node_dissolve_in, geo_node_dissolve_out);
+ node_type_storage(
+ &ntype, "NodeGeometryDissolve", node_free_standard_storage, node_copy_standard_storage);
+ node_type_init(&ntype, geo_node_dissolve_init);
+ ntype.geometry_node_execute = blender::nodes::geo_node_dissolve_exec;
+ ntype.draw_buttons = geo_node_dissolve_layout;
+ ntype.width = 165;
+ nodeRegisterType(&ntype);
+} \ No newline at end of file
diff --git a/source/blender/nodes/geometry/nodes/node_geo_unsubdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_unsubdivide.cc
new file mode 100644
index 00000000000..7f0fc66ff28
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_unsubdivide.cc
@@ -0,0 +1,87 @@
+/*
+ * 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_mesh.h"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "bmesh.h"
+#include "bmesh_tools.h"
+#include "node_geometry_util.hh"
+
+static bNodeSocketTemplate geo_node_unsubdivide_in[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {SOCK_INT, N_("Iterations"), 1, 0, 0, 0, 0, 10},
+ {SOCK_STRING, N_("Selection")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_unsubdivide_out[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {-1, ""},
+};
+
+namespace blender::nodes {
+
+static Mesh *unsubdivide_mesh(const int iterations, const Array<bool> &selection, const Mesh *mesh)
+{
+ const BMeshCreateParams bmesh_create_params = {0};
+ const BMeshFromMeshParams bmesh_from_mesh_params = {
+ true, 0, 0, 0, {CD_MASK_ORIGINDEX, CD_MASK_ORIGINDEX, CD_MASK_ORIGINDEX}};
+ BMesh *bm = BKE_mesh_to_bmesh_ex(mesh, &bmesh_create_params, &bmesh_from_mesh_params);
+ BM_tag_vertices(bm, selection.data());
+ BM_mesh_decimate_unsubdivide_ex(bm, iterations, true);
+
+ Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh);
+ BM_mesh_free(bm);
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+
+ return result;
+}
+
+static void geo_node_unsubdivide_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ const int iterations = params.extract_input<int>("Iterations");
+ if (iterations > 0 && geometry_set.has_mesh()) {
+ const MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
+ const Mesh *input_mesh = mesh_component.get_for_read();
+
+ const bool default_selection = true;
+ GVArray_Typed<bool> selection_attribute = params.get_input_attribute<bool>(
+ "Selection", mesh_component, ATTR_DOMAIN_POINT, default_selection);
+ VArray_Span<bool> selection{selection_attribute};
+
+ Mesh *result = unsubdivide_mesh(iterations, selection, input_mesh);
+ if (result != input_mesh) {
+ geometry_set.replace_mesh(result);
+ }
+ }
+ params.set_output("Geometry", std::move(geometry_set));
+}
+} // namespace blender::nodes
+
+void register_node_type_geo_unsubdivide()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_UNSUBDIVIDE, "Unsubdivide", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(&ntype, geo_node_unsubdivide_in, geo_node_unsubdivide_out);
+ ntype.geometry_node_execute = blender::nodes::geo_node_unsubdivide_exec;
+ ntype.width = 165;
+ nodeRegisterType(&ntype);
+}