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/nodes/geometry')
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.hh8
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc28
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_curve_map.cc7
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc7
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc9
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_length.cc58
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc677
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc316
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_separate.cc16
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_switch.cc48
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_transform.cc5
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc2
26 files changed, 1171 insertions, 70 deletions
diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh
index 81092798ca1..79a98c5ebf0 100644
--- a/source/blender/nodes/geometry/node_geometry_util.hh
+++ b/source/blender/nodes/geometry/node_geometry_util.hh
@@ -62,4 +62,12 @@ Mesh *create_cylinder_or_cone_mesh(const float radius_top,
Mesh *create_cube_mesh(const float size);
+/**
+ * Copies the point domain attributes from `in_component` that are in the mask to `out_component`.
+ */
+void copy_point_attributes_based_on_mask(const GeometryComponent &in_component,
+ GeometryComponent &result_component,
+ Span<bool> masks,
+ const bool invert);
+
} // namespace blender::nodes
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc
index 21538db5455..71643df1cb6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc
@@ -101,9 +101,12 @@ template<> inline float3 clamp_value(const float3 val, const float3 min, const f
return tmp;
}
-template<> inline Color4f clamp_value(const Color4f val, const Color4f min, const Color4f max)
+template<>
+inline ColorGeometry4f clamp_value(const ColorGeometry4f val,
+ const ColorGeometry4f min,
+ const ColorGeometry4f max)
{
- Color4f tmp;
+ ColorGeometry4f tmp;
tmp.r = std::min(std::max(val.r, min.r), max.r);
tmp.g = std::min(std::max(val.g, min.g), max.g);
tmp.b = std::min(std::max(val.b, min.b), max.b);
@@ -214,8 +217,8 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam
break;
}
case CD_PROP_COLOR: {
- Color4f min = params.get_input<Color4f>("Min_003");
- Color4f max = params.get_input<Color4f>("Max_003");
+ ColorGeometry4f min = params.get_input<ColorGeometry4f>("Min_003");
+ ColorGeometry4f max = params.get_input<ColorGeometry4f>("Max_003");
if (operation == NODE_CLAMP_RANGE) {
if (min.r > max.r) {
std::swap(min.r, max.r);
@@ -230,8 +233,9 @@ static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParam
std::swap(min.a, max.a);
}
}
- MutableSpan<Color4f> results = attribute_result.as_span<Color4f>();
- clamp_attribute<Color4f>(attribute_input->typed<Color4f>(), results, min, max);
+ MutableSpan<ColorGeometry4f> results = attribute_result.as_span<ColorGeometry4f>();
+ clamp_attribute<ColorGeometry4f>(
+ attribute_input->typed<ColorGeometry4f>(), results, min, max);
break;
}
default: {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc
index b13e82e676d..5293dd8c876 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_color_ramp.cc
@@ -83,8 +83,8 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
* currently. */
const AttributeDomain result_domain = get_result_domain(component, input_name, result_name);
- OutputAttribute_Typed<Color4f> attribute_result =
- component.attribute_try_get_for_output_only<Color4f>(result_name, result_domain);
+ OutputAttribute_Typed<ColorGeometry4f> attribute_result =
+ component.attribute_try_get_for_output_only<ColorGeometry4f>(result_name, result_domain);
if (!attribute_result) {
return;
}
@@ -92,7 +92,7 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
GVArray_Typed<float> attribute_in = component.attribute_get_for_read<float>(
input_name, result_domain, 0.0f);
- MutableSpan<Color4f> results = attribute_result.as_span();
+ MutableSpan<ColorGeometry4f> results = attribute_result.as_span();
ColorBand *color_ramp = &node_storage->color_ramp;
parallel_for(IndexRange(attribute_in.size()), 512, [&](IndexRange range) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc
index a2ff1668a06..57ac68b4cd4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_compare.cc
@@ -131,16 +131,16 @@ static void do_equal_operation_float3(const VArray<float3> &input_a,
}
}
-static void do_equal_operation_color4f(const VArray<Color4f> &input_a,
- const VArray<Color4f> &input_b,
+static void do_equal_operation_color4f(const VArray<ColorGeometry4f> &input_a,
+ const VArray<ColorGeometry4f> &input_b,
const float threshold,
MutableSpan<bool> span_result)
{
const float threshold_squared = pow2f(threshold);
const int size = input_a.size();
for (const int i : IndexRange(size)) {
- const Color4f a = input_a[i];
- const Color4f b = input_b[i];
+ const ColorGeometry4f a = input_a[i];
+ const ColorGeometry4f b = input_b[i];
span_result[i] = len_squared_v4v4(a, b) < threshold_squared;
}
}
@@ -185,16 +185,16 @@ static void do_not_equal_operation_float3(const VArray<float3> &input_a,
}
}
-static void do_not_equal_operation_color4f(const VArray<Color4f> &input_a,
- const VArray<Color4f> &input_b,
+static void do_not_equal_operation_color4f(const VArray<ColorGeometry4f> &input_a,
+ const VArray<ColorGeometry4f> &input_b,
const float threshold,
MutableSpan<bool> span_result)
{
const float threshold_squared = pow2f(threshold);
const int size = input_a.size();
for (const int i : IndexRange(size)) {
- const Color4f a = input_a[i];
- const Color4f b = input_b[i];
+ const ColorGeometry4f a = input_a[i];
+ const ColorGeometry4f b = input_b[i];
span_result[i] = len_squared_v4v4(a, b) >= threshold_squared;
}
}
@@ -287,8 +287,10 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx
attribute_a->typed<float3>(), attribute_b->typed<float3>(), threshold, result_span);
}
else if (input_data_type == CD_PROP_COLOR) {
- do_equal_operation_color4f(
- attribute_a->typed<Color4f>(), attribute_b->typed<Color4f>(), threshold, result_span);
+ do_equal_operation_color4f(attribute_a->typed<ColorGeometry4f>(),
+ attribute_b->typed<ColorGeometry4f>(),
+ threshold,
+ result_span);
}
else if (input_data_type == CD_PROP_BOOL) {
do_equal_operation_bool(
@@ -305,8 +307,10 @@ static void attribute_compare_calc(GeometryComponent &component, const GeoNodeEx
attribute_a->typed<float3>(), attribute_b->typed<float3>(), threshold, result_span);
}
else if (input_data_type == CD_PROP_COLOR) {
- do_not_equal_operation_color4f(
- attribute_a->typed<Color4f>(), attribute_b->typed<Color4f>(), threshold, result_span);
+ do_not_equal_operation_color4f(attribute_a->typed<ColorGeometry4f>(),
+ attribute_b->typed<ColorGeometry4f>(),
+ threshold,
+ result_span);
}
else if (input_data_type == CD_PROP_BOOL) {
do_not_equal_operation_bool(
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_curve_map.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_curve_map.cc
index 2fc86269797..599c9e58e52 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_curve_map.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_curve_map.cc
@@ -165,9 +165,10 @@ static void execute_on_component(const GeoNodeExecParams &params, GeometryCompon
}
case CD_PROP_COLOR: {
const CurveMapping *cumap = (CurveMapping *)node_storage.curve_rgb;
- GVArray_Typed<Color4f> attribute_in = component.attribute_get_for_read<Color4f>(
- input_name, result_domain, Color4f(0.0f, 0.0f, 0.0f, 1.0f));
- MutableSpan<Color4f> results = attribute_result.as_span<Color4f>();
+ GVArray_Typed<ColorGeometry4f> attribute_in =
+ component.attribute_get_for_read<ColorGeometry4f>(
+ input_name, result_domain, ColorGeometry4f(0.0f, 0.0f, 0.0f, 1.0f));
+ MutableSpan<ColorGeometry4f> results = attribute_result.as_span<ColorGeometry4f>();
parallel_for(IndexRange(attribute_in.size()), 512, [&](IndexRange range) {
for (const int i : range) {
BKE_curvemapping_evaluateRGBF(cumap, results[i], attribute_in[i]);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc
index 60522fd0f72..389abe3b2aa 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_fill.cc
@@ -110,7 +110,7 @@ static void fill_attribute(GeometryComponent &component, const GeoNodeExecParams
break;
}
case CD_PROP_COLOR: {
- const Color4f value = params.get_input<Color4f>("Value_002");
+ const ColorGeometry4f value = params.get_input<ColorGeometry4f>("Value_002");
attribute->fill(&value);
break;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc
index e502a183ef5..a6bd6c0ee32 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_mix.cc
@@ -120,16 +120,16 @@ static void do_mix_operation_float3(const int blend_mode,
static void do_mix_operation_color4f(const int blend_mode,
const VArray<float> &factors,
- const VArray<Color4f> &inputs_a,
- const VArray<Color4f> &inputs_b,
- VMutableArray<Color4f> &results)
+ const VArray<ColorGeometry4f> &inputs_a,
+ const VArray<ColorGeometry4f> &inputs_b,
+ VMutableArray<ColorGeometry4f> &results)
{
const int size = results.size();
parallel_for(IndexRange(size), 512, [&](IndexRange range) {
for (const int i : range) {
const float factor = factors[i];
- Color4f a = inputs_a[i];
- const Color4f b = inputs_b[i];
+ ColorGeometry4f a = inputs_a[i];
+ const ColorGeometry4f b = inputs_b[i];
ramp_blend(blend_mode, a, factor, b);
results.set(i, a);
}
@@ -160,9 +160,9 @@ static void do_mix_operation(const CustomDataType result_type,
else if (result_type == CD_PROP_COLOR) {
do_mix_operation_color4f(blend_mode,
attribute_factor,
- attribute_a.typed<Color4f>(),
- attribute_b.typed<Color4f>(),
- attribute_result.typed<Color4f>());
+ attribute_a.typed<ColorGeometry4f>(),
+ attribute_b.typed<ColorGeometry4f>(),
+ attribute_result.typed<ColorGeometry4f>());
}
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc
index aa558314b9e..d6b1ad3e9e0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_sample_texture.cc
@@ -79,8 +79,9 @@ static void execute_on_component(GeometryComponent &component, const GeoNodeExec
const AttributeDomain result_domain = get_result_domain(
component, result_attribute_name, mapping_name);
- OutputAttribute_Typed<Color4f> attribute_out =
- component.attribute_try_get_for_output_only<Color4f>(result_attribute_name, result_domain);
+ OutputAttribute_Typed<ColorGeometry4f> attribute_out =
+ component.attribute_try_get_for_output_only<ColorGeometry4f>(result_attribute_name,
+ result_domain);
if (!attribute_out) {
return;
}
@@ -88,7 +89,7 @@ static void execute_on_component(GeometryComponent &component, const GeoNodeExec
GVArray_Typed<float3> mapping_attribute = component.attribute_get_for_read<float3>(
mapping_name, result_domain, {0, 0, 0});
- MutableSpan<Color4f> colors = attribute_out.as_span();
+ MutableSpan<ColorGeometry4f> colors = attribute_out.as_span();
parallel_for(IndexRange(mapping_attribute.size()), 128, [&](IndexRange range) {
for (const int i : range) {
TexResult texture_result = {0};
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc
index 8877af445f9..b04e04d1cb7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_vector_math.cc
@@ -59,8 +59,11 @@ static bool operation_use_input_b(const NodeVectorMathOperation operation)
static bool operation_use_input_c(const NodeVectorMathOperation operation)
{
- return ELEM(
- operation, NODE_VECTOR_MATH_WRAP, NODE_VECTOR_MATH_REFRACT, NODE_VECTOR_MATH_FACEFORWARD);
+ return ELEM(operation,
+ NODE_VECTOR_MATH_WRAP,
+ NODE_VECTOR_MATH_REFRACT,
+ NODE_VECTOR_MATH_FACEFORWARD,
+ NODE_VECTOR_MATH_MULTIPLY_ADD);
}
static void geo_node_attribute_vector_math_layout(uiLayout *layout,
@@ -137,6 +140,7 @@ static CustomDataType operation_get_result_type(const NodeVectorMathOperation op
case NODE_VECTOR_MATH_TANGENT:
case NODE_VECTOR_MATH_REFRACT:
case NODE_VECTOR_MATH_FACEFORWARD:
+ case NODE_VECTOR_MATH_MULTIPLY_ADD:
return CD_PROP_FLOAT3;
case NODE_VECTOR_MATH_DOT_PRODUCT:
case NODE_VECTOR_MATH_DISTANCE:
@@ -495,6 +499,7 @@ static void attribute_vector_math_calc(GeometryComponent &component,
break;
case NODE_VECTOR_MATH_WRAP:
case NODE_VECTOR_MATH_FACEFORWARD:
+ case NODE_VECTOR_MATH_MULTIPLY_ADD:
do_math_operation_fl3_fl3_fl3_to_fl3(attribute_a->typed<float3>(),
attribute_b->typed<float3>(),
attribute_c->typed<float3>(),
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
new file mode 100644
index 00000000000..306085e3b75
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_length.cc
@@ -0,0 +1,58 @@
+/*
+ * 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_spline.hh"
+#include "node_geometry_util.hh"
+
+static bNodeSocketTemplate geo_node_curve_length_in[] = {
+ {SOCK_GEOMETRY, N_("Curve")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_curve_length_out[] = {
+ {SOCK_FLOAT, N_("Length")},
+ {-1, ""},
+};
+
+namespace blender::nodes {
+
+static void geo_node_curve_length_exec(GeoNodeExecParams params)
+{
+ GeometrySet curve_set = params.extract_input<GeometrySet>("Curve");
+ curve_set = bke::geometry_set_realize_instances(curve_set);
+ if (!curve_set.has_curve()) {
+ params.set_output("Length", 0.0f);
+ return;
+ }
+ const CurveEval &curve = *curve_set.get_curve_for_read();
+ float length = 0.0f;
+ for (const SplinePtr &spline : curve.splines()) {
+ length += spline->length();
+ }
+ params.set_output("Length", length);
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_curve_length()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_LENGTH, "Curve Length", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(&ntype, geo_node_curve_length_in, geo_node_curve_length_out);
+ ntype.geometry_node_execute = blender::nodes::geo_node_curve_length_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
index 1c42b9341a0..684f7d6c702 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
@@ -182,6 +182,8 @@ static std::unique_ptr<CurveEval> resample_curve(const CurveEval &input_curve,
}
}
+ output_curve->attributes.reallocate(output_curve->splines().size());
+
return output_curve;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
index f0effdc71f6..fe1b23bf6d7 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc
@@ -21,6 +21,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_spline.hh"
@@ -236,6 +237,7 @@ static Mesh *curve_to_mesh_calculate(const CurveEval &curve, const CurveEval &pr
}
Mesh *mesh = BKE_mesh_new_nomain(vert_total, edge_total, 0, corner_total, poly_total);
+ BKE_id_material_eval_ensure_default_slot(&mesh->id);
MutableSpan<MVert> verts{mesh->mvert, mesh->totvert};
MutableSpan<MEdge> edges{mesh->medge, mesh->totedge};
MutableSpan<MLoop> loops{mesh->mloop, mesh->totloop};
diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
new file mode 100644
index 00000000000..0e053a6d0e9
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
@@ -0,0 +1,677 @@
+/*
+ * 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_array.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_customdata.h"
+#include "BKE_mesh.h"
+#include "BKE_pointcloud.h"
+#include "BKE_spline.hh"
+
+#include "node_geometry_util.hh"
+
+using blender::bke::CustomDataAttributes;
+
+/* Code from the mask modifier in MOD_mask.cc. */
+extern void copy_masked_vertices_to_new_mesh(const Mesh &src_mesh,
+ Mesh &dst_mesh,
+ blender::Span<int> vertex_map);
+extern void copy_masked_edges_to_new_mesh(const Mesh &src_mesh,
+ Mesh &dst_mesh,
+ blender::Span<int> vertex_map,
+ blender::Span<int> edge_map);
+extern void copy_masked_polys_to_new_mesh(const Mesh &src_mesh,
+ Mesh &dst_mesh,
+ blender::Span<int> vertex_map,
+ blender::Span<int> edge_map,
+ blender::Span<int> masked_poly_indices,
+ blender::Span<int> new_loop_starts);
+
+static bNodeSocketTemplate geo_node_delete_geometry_in[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {SOCK_STRING, N_("Selection")},
+ {SOCK_BOOLEAN, N_("Invert")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_delete_geometry_out[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {-1, ""},
+};
+
+namespace blender::nodes {
+
+template<typename T> static void copy_data(Span<T> data, MutableSpan<T> r_data, IndexMask mask)
+{
+ for (const int i_out : mask.index_range()) {
+ r_data[i_out] = data[mask[i_out]];
+ }
+}
+
+static void spline_copy_builtin_attributes(const Spline &spline,
+ Spline &r_spline,
+ const IndexMask mask)
+{
+ copy_data(spline.positions(), r_spline.positions(), mask);
+ copy_data(spline.radii(), r_spline.radii(), mask);
+ copy_data(spline.tilts(), r_spline.tilts(), mask);
+ switch (spline.type()) {
+ case Spline::Type::Poly:
+ break;
+ case Spline::Type::Bezier: {
+ const BezierSpline &src = static_cast<const BezierSpline &>(spline);
+ BezierSpline &dst = static_cast<BezierSpline &>(r_spline);
+ copy_data(src.handle_positions_left(), dst.handle_positions_left(), mask);
+ copy_data(src.handle_positions_right(), dst.handle_positions_right(), mask);
+ copy_data(src.handle_types_left(), dst.handle_types_left(), mask);
+ copy_data(src.handle_types_right(), dst.handle_types_right(), mask);
+ break;
+ }
+ case Spline::Type::NURBS: {
+ const NURBSpline &src = static_cast<const NURBSpline &>(spline);
+ NURBSpline &dst = static_cast<NURBSpline &>(r_spline);
+ copy_data(src.weights(), dst.weights(), mask);
+ break;
+ }
+ }
+}
+
+static void copy_dynamic_attributes(const CustomDataAttributes &src,
+ CustomDataAttributes &dst,
+ const IndexMask mask)
+{
+ src.foreach_attribute(
+ [&](StringRefNull name, const AttributeMetaData &meta_data) {
+ std::optional<GSpan> src_attribute = src.get_for_read(name);
+ BLI_assert(src_attribute);
+
+ if (!dst.create(name, meta_data.data_type)) {
+ /* Since the source spline of the same type had the attribute, adding it should work. */
+ BLI_assert_unreachable();
+ }
+
+ std::optional<GMutableSpan> new_attribute = dst.get_for_write(name);
+ BLI_assert(new_attribute);
+
+ attribute_math::convert_to_static_type(new_attribute->type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ copy_data(src_attribute->typed<T>(), new_attribute->typed<T>(), mask);
+ });
+ return true;
+ },
+ ATTR_DOMAIN_POINT);
+}
+
+static SplinePtr spline_delete(const Spline &spline, const IndexMask mask)
+{
+ SplinePtr new_spline = spline.copy_settings();
+ new_spline->resize(mask.size());
+
+ spline_copy_builtin_attributes(spline, *new_spline, mask);
+ copy_dynamic_attributes(spline.attributes, new_spline->attributes, mask);
+
+ return new_spline;
+}
+
+static std::unique_ptr<CurveEval> curve_delete(const CurveEval &input_curve,
+ const StringRef name,
+ const bool invert)
+{
+ Span<SplinePtr> input_splines = input_curve.splines();
+ std::unique_ptr<CurveEval> output_curve = std::make_unique<CurveEval>();
+
+ /* Keep track of which splines were copied to the result to copy spline domain attributes. */
+ Vector<int64_t> copied_splines;
+
+ if (input_curve.attributes.get_for_read(name)) {
+ GVArray_Typed<bool> selection = input_curve.attributes.get_for_read<bool>(name, false);
+ for (const int i : input_splines.index_range()) {
+ if (selection[i] == invert) {
+ output_curve->add_spline(input_splines[i]->copy());
+ copied_splines.append(i);
+ }
+ }
+ }
+ else {
+ /* Reuse index vector for each spline. */
+ Vector<int64_t> indices_to_copy;
+
+ for (const int i : input_splines.index_range()) {
+ const Spline &spline = *input_splines[i];
+ GVArray_Typed<bool> selection = spline.attributes.get_for_read<bool>(name, false);
+
+ indices_to_copy.clear();
+ for (const int i_point : IndexRange(spline.size())) {
+ if (selection[i_point] == invert) {
+ indices_to_copy.append(i_point);
+ }
+ }
+
+ /* Avoid creating an empty spline. */
+ if (indices_to_copy.is_empty()) {
+ continue;
+ }
+
+ SplinePtr new_spline = spline_delete(spline, IndexMask(indices_to_copy));
+ output_curve->add_spline(std::move(new_spline));
+ copied_splines.append(i);
+ }
+ }
+
+ if (copied_splines.is_empty()) {
+ return {};
+ }
+
+ output_curve->attributes.reallocate(output_curve->splines().size());
+ copy_dynamic_attributes(
+ input_curve.attributes, output_curve->attributes, IndexMask(copied_splines));
+
+ return output_curve;
+}
+
+static void delete_curve_selection(const CurveComponent &in_component,
+ CurveComponent &r_component,
+ const StringRef selection_name,
+ const bool invert)
+{
+ std::unique_ptr<CurveEval> r_curve = curve_delete(
+ *in_component.get_for_read(), selection_name, invert);
+ if (r_curve) {
+ r_component.replace(r_curve.release());
+ }
+ else {
+ r_component.clear();
+ }
+}
+
+static void delete_point_cloud_selection(const PointCloudComponent &in_component,
+ PointCloudComponent &out_component,
+ const StringRef selection_name,
+ const bool invert)
+{
+ const GVArray_Typed<bool> selection_attribute = in_component.attribute_get_for_read<bool>(
+ selection_name, ATTR_DOMAIN_POINT, false);
+ VArray_Span<bool> selection{selection_attribute};
+
+ const int total = selection.count(invert);
+ if (total == 0) {
+ out_component.clear();
+ return;
+ }
+ out_component.replace(BKE_pointcloud_new_nomain(total));
+
+ /* Invert the inversion, because this deletes the selected points instead of keeping them. */
+ copy_point_attributes_based_on_mask(in_component, out_component, selection, !invert);
+}
+
+static void compute_selected_vertices_from_vertex_selection(const VArray<bool> &vertex_selection,
+ const bool invert,
+ MutableSpan<int> r_vertex_map,
+ uint *r_num_selected_vertices)
+{
+ BLI_assert(vertex_selection.size() == r_vertex_map.size());
+
+ uint num_selected_vertices = 0;
+ for (const int i : r_vertex_map.index_range()) {
+ if (vertex_selection[i] != invert) {
+ r_vertex_map[i] = num_selected_vertices;
+ num_selected_vertices++;
+ }
+ else {
+ r_vertex_map[i] = -1;
+ }
+ }
+
+ *r_num_selected_vertices = num_selected_vertices;
+}
+
+static void compute_selected_edges_from_vertex_selection(const Mesh &mesh,
+ const VArray<bool> &vertex_selection,
+ const bool invert,
+ MutableSpan<int> r_edge_map,
+ uint *r_num_selected_edges)
+{
+ BLI_assert(mesh.totedge == r_edge_map.size());
+
+ uint num_selected_edges = 0;
+ for (const int i : IndexRange(mesh.totedge)) {
+ const MEdge &edge = mesh.medge[i];
+
+ /* Only add the edge if both vertices will be in the new mesh. */
+ if (vertex_selection[edge.v1] != invert && vertex_selection[edge.v2] != invert) {
+ r_edge_map[i] = num_selected_edges;
+ num_selected_edges++;
+ }
+ else {
+ r_edge_map[i] = -1;
+ }
+ }
+
+ *r_num_selected_edges = num_selected_edges;
+}
+
+static void compute_selected_polygons_from_vertex_selection(const Mesh &mesh,
+ const VArray<bool> &vertex_selection,
+ const bool invert,
+ Vector<int> &r_selected_poly_indices,
+ Vector<int> &r_loop_starts,
+ uint *r_num_selected_polys,
+ uint *r_num_selected_loops)
+{
+ BLI_assert(mesh.totvert == vertex_selection.size());
+
+ r_selected_poly_indices.reserve(mesh.totpoly);
+ r_loop_starts.reserve(mesh.totloop);
+
+ uint num_selected_loops = 0;
+ for (const int i : IndexRange(mesh.totpoly)) {
+ const MPoly &poly_src = mesh.mpoly[i];
+
+ bool all_verts_in_selection = true;
+ Span<MLoop> loops_src(&mesh.mloop[poly_src.loopstart], poly_src.totloop);
+ for (const MLoop &loop : loops_src) {
+ if (vertex_selection[loop.v] == invert) {
+ all_verts_in_selection = false;
+ break;
+ }
+ }
+
+ if (all_verts_in_selection) {
+ r_selected_poly_indices.append_unchecked(i);
+ r_loop_starts.append_unchecked(num_selected_loops);
+ num_selected_loops += poly_src.totloop;
+ }
+ }
+
+ *r_num_selected_polys = r_selected_poly_indices.size();
+ *r_num_selected_loops = num_selected_loops;
+}
+
+/**
+ * Checks for every edge if it is in `edge_selection`. If it is, then the two vertices of the edge
+ * are kept along with the edge.
+ */
+static void compute_selected_vertices_and_edges_from_edge_selection(
+ const Mesh &mesh,
+ const VArray<bool> &edge_selection,
+ const bool invert,
+ MutableSpan<int> r_vertex_map,
+ MutableSpan<int> r_edge_map,
+ uint *r_num_selected_vertices,
+ uint *r_num_selected_edges)
+{
+ BLI_assert(mesh.totedge == edge_selection.size());
+
+ uint num_selected_edges = 0;
+ uint num_selected_vertices = 0;
+ for (const int i : IndexRange(mesh.totedge)) {
+ const MEdge &edge = mesh.medge[i];
+ if (edge_selection[i] != invert) {
+ r_edge_map[i] = num_selected_edges;
+ num_selected_edges++;
+ if (r_vertex_map[edge.v1] == -1) {
+ r_vertex_map[edge.v1] = num_selected_vertices;
+ num_selected_vertices++;
+ }
+ if (r_vertex_map[edge.v2] == -1) {
+ r_vertex_map[edge.v2] = num_selected_vertices;
+ num_selected_vertices++;
+ }
+ }
+ else {
+ r_edge_map[i] = -1;
+ }
+ }
+
+ *r_num_selected_vertices = num_selected_vertices;
+ *r_num_selected_edges = num_selected_edges;
+}
+
+/**
+ * Checks for every polygon if all the edges are in `edge_selection`. If they are, then that
+ * polygon is kept.
+ */
+static void compute_selected_polygons_from_edge_selection(const Mesh &mesh,
+ const VArray<bool> &edge_selection,
+ const bool invert,
+ Vector<int> &r_selected_poly_indices,
+ Vector<int> &r_loop_starts,
+ uint *r_num_selected_polys,
+ uint *r_num_selected_loops)
+{
+ r_selected_poly_indices.reserve(mesh.totpoly);
+ r_loop_starts.reserve(mesh.totloop);
+
+ uint num_selected_loops = 0;
+ for (const int i : IndexRange(mesh.totpoly)) {
+ const MPoly &poly_src = mesh.mpoly[i];
+
+ bool all_edges_in_selection = true;
+ Span<MLoop> loops_src(&mesh.mloop[poly_src.loopstart], poly_src.totloop);
+ for (const MLoop &loop : loops_src) {
+ if (edge_selection[loop.e] == invert) {
+ all_edges_in_selection = false;
+ break;
+ }
+ }
+
+ if (all_edges_in_selection) {
+ r_selected_poly_indices.append_unchecked(i);
+ r_loop_starts.append_unchecked(num_selected_loops);
+ num_selected_loops += poly_src.totloop;
+ }
+ }
+
+ *r_num_selected_polys = r_selected_poly_indices.size();
+ *r_num_selected_loops = num_selected_loops;
+}
+
+/**
+ * Checks for every vertex if it is in `vertex_selection`. The polygons and edges are kept if all
+ * vertices of that polygon or edge are in the selection.
+ */
+static void compute_selected_mesh_data_from_vertex_selection(const Mesh &mesh,
+ const VArray<bool> &vertex_selection,
+ const bool invert,
+ MutableSpan<int> r_vertex_map,
+ MutableSpan<int> r_edge_map,
+ Vector<int> &r_selected_poly_indices,
+ Vector<int> &r_loop_starts,
+ uint *r_num_selected_vertices,
+ uint *r_num_selected_edges,
+ uint *r_num_selected_polys,
+ uint *r_num_selected_loops)
+{
+ compute_selected_vertices_from_vertex_selection(
+ vertex_selection, invert, r_vertex_map, r_num_selected_vertices);
+
+ compute_selected_edges_from_vertex_selection(
+ mesh, vertex_selection, invert, r_edge_map, r_num_selected_edges);
+
+ compute_selected_polygons_from_vertex_selection(mesh,
+ vertex_selection,
+ invert,
+ r_selected_poly_indices,
+ r_loop_starts,
+ r_num_selected_polys,
+ r_num_selected_loops);
+}
+
+/**
+ * Checks for every edge if it is in `edge_selection`. If it is, the vertices belonging to
+ * that edge are kept as well. The polygons are kept if all edges are in the selection.
+ */
+static void compute_selected_mesh_data_from_edge_selection(const Mesh &mesh,
+ const VArray<bool> &edge_selection,
+ const bool invert,
+ MutableSpan<int> r_vertex_map,
+ MutableSpan<int> r_edge_map,
+ Vector<int> &r_selected_poly_indices,
+ Vector<int> &r_loop_starts,
+ uint *r_num_selected_vertices,
+ uint *r_num_selected_edges,
+ uint *r_num_selected_polys,
+ uint *r_num_selected_loops)
+{
+ r_vertex_map.fill(-1);
+ compute_selected_vertices_and_edges_from_edge_selection(mesh,
+ edge_selection,
+ invert,
+ r_vertex_map,
+ r_edge_map,
+ r_num_selected_vertices,
+ r_num_selected_edges);
+ compute_selected_polygons_from_edge_selection(mesh,
+ edge_selection,
+ invert,
+ r_selected_poly_indices,
+ r_loop_starts,
+ r_num_selected_polys,
+ r_num_selected_loops);
+}
+
+/**
+ * Checks for every polygon if it is in `poly_selection`. If it is, the edges and vertices
+ * belonging to that polygon are kept as well.
+ */
+static void compute_selected_mesh_data_from_poly_selection(const Mesh &mesh,
+ const VArray<bool> &poly_selection,
+ const bool invert,
+ MutableSpan<int> r_vertex_map,
+ MutableSpan<int> r_edge_map,
+ Vector<int> &r_selected_poly_indices,
+ Vector<int> &r_loop_starts,
+ uint *r_num_selected_vertices,
+ uint *r_num_selected_edges,
+ uint *r_num_selected_polys,
+ uint *r_num_selected_loops)
+{
+ BLI_assert(mesh.totpoly == poly_selection.size());
+ BLI_assert(mesh.totedge == r_edge_map.size());
+ r_vertex_map.fill(-1);
+ r_edge_map.fill(-1);
+
+ r_selected_poly_indices.reserve(mesh.totpoly);
+ r_loop_starts.reserve(mesh.totloop);
+
+ uint num_selected_loops = 0;
+ uint num_selected_vertices = 0;
+ uint num_selected_edges = 0;
+ for (const int i : IndexRange(mesh.totpoly)) {
+ const MPoly &poly_src = mesh.mpoly[i];
+ /* We keep this one. */
+ if (poly_selection[i] != invert) {
+ r_selected_poly_indices.append_unchecked(i);
+ r_loop_starts.append_unchecked(num_selected_loops);
+ num_selected_loops += poly_src.totloop;
+
+ /* Add the vertices and the edges. */
+ Span<MLoop> loops_src(&mesh.mloop[poly_src.loopstart], poly_src.totloop);
+ for (const MLoop &loop : loops_src) {
+ /* Check first if it has not yet been added. */
+ if (r_vertex_map[loop.v] == -1) {
+ r_vertex_map[loop.v] = num_selected_vertices;
+ num_selected_vertices++;
+ }
+ if (r_edge_map[loop.e] == -1) {
+ r_edge_map[loop.e] = num_selected_edges;
+ num_selected_edges++;
+ }
+ }
+ }
+ }
+ *r_num_selected_vertices = num_selected_vertices;
+ *r_num_selected_edges = num_selected_edges;
+ *r_num_selected_polys = r_selected_poly_indices.size();
+ *r_num_selected_loops = num_selected_loops;
+}
+
+using FillMapsFunction = void (*)(const Mesh &mesh,
+ const VArray<bool> &selection,
+ const bool invert,
+ MutableSpan<int> r_vertex_map,
+ MutableSpan<int> r_edge_map,
+ Vector<int> &r_selected_poly_indices,
+ Vector<int> &r_loop_starts,
+ uint *r_num_selected_vertices,
+ uint *r_num_selected_edges,
+ uint *r_num_selected_polys,
+ uint *r_num_selected_loops);
+
+/**
+ * Delete the parts of the mesh that are in the selection. The `fill_maps_function`
+ * depends on the selection type: vertices, edges or faces.
+ */
+static Mesh *delete_mesh_selection(const Mesh &mesh_in,
+ const VArray<bool> &selection,
+ const bool invert,
+ FillMapsFunction fill_maps_function)
+{
+ Array<int> vertex_map(mesh_in.totvert);
+ uint num_selected_vertices;
+
+ Array<int> edge_map(mesh_in.totedge);
+ uint num_selected_edges;
+
+ Vector<int> selected_poly_indices;
+ Vector<int> new_loop_starts;
+ uint num_selected_polys;
+ uint num_selected_loops;
+
+ /* Fill all the maps based on the selection. We delete everything
+ * in the selection instead of keeping it, so we need to invert it. */
+ fill_maps_function(mesh_in,
+ selection,
+ !invert,
+ vertex_map,
+ edge_map,
+ selected_poly_indices,
+ new_loop_starts,
+ &num_selected_vertices,
+ &num_selected_edges,
+ &num_selected_polys,
+ &num_selected_loops);
+
+ Mesh *result = BKE_mesh_new_nomain_from_template(&mesh_in,
+ num_selected_vertices,
+ num_selected_edges,
+ 0,
+ num_selected_loops,
+ num_selected_polys);
+
+ /* Copy the selected parts of the mesh over to the new mesh. */
+ copy_masked_vertices_to_new_mesh(mesh_in, *result, vertex_map);
+ copy_masked_edges_to_new_mesh(mesh_in, *result, vertex_map, edge_map);
+ copy_masked_polys_to_new_mesh(
+ mesh_in, *result, vertex_map, edge_map, selected_poly_indices, new_loop_starts);
+ BKE_mesh_calc_edges_loose(result);
+ /* Tag to recalculate normals later. */
+ result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+
+ return result;
+}
+
+static AttributeDomain get_mesh_selection_domain(MeshComponent &component, const StringRef name)
+{
+ std::optional<AttributeMetaData> selection_attribute = component.attribute_get_meta_data(name);
+ if (!selection_attribute) {
+ /* The node will not do anything in this case, but this function must return something. */
+ return ATTR_DOMAIN_POINT;
+ }
+
+ /* Corners can't be deleted separately, so interpolate corner attributes
+ * to the face domain. Note that this choice is somewhat arbitrary. */
+ if (selection_attribute->domain == ATTR_DOMAIN_CORNER) {
+ return ATTR_DOMAIN_FACE;
+ }
+
+ return selection_attribute->domain;
+}
+
+static void delete_mesh_selection(MeshComponent &component,
+ const Mesh &mesh_in,
+ const StringRef selection_name,
+ const bool invert)
+{
+ /* Figure out the best domain to use. */
+ const AttributeDomain selection_domain = get_mesh_selection_domain(component, selection_name);
+
+ /* This already checks if the attribute exists, and displays a warning in that case. */
+ GVArray_Typed<bool> selection = component.attribute_get_for_read<bool>(
+ selection_name, selection_domain, false);
+
+ /* Check if there is anything to delete. */
+ bool delete_nothing = true;
+ for (const int i : selection.index_range()) {
+ if (selection[i] != invert) {
+ delete_nothing = false;
+ break;
+ }
+ }
+ if (delete_nothing) {
+ return;
+ }
+
+ Mesh *mesh_out;
+ switch (selection_domain) {
+ case ATTR_DOMAIN_POINT:
+ mesh_out = delete_mesh_selection(
+ mesh_in, selection, invert, compute_selected_mesh_data_from_vertex_selection);
+ break;
+ case ATTR_DOMAIN_EDGE:
+ mesh_out = delete_mesh_selection(
+ mesh_in, selection, invert, compute_selected_mesh_data_from_edge_selection);
+ break;
+ case ATTR_DOMAIN_FACE:
+ mesh_out = delete_mesh_selection(
+ mesh_in, selection, invert, compute_selected_mesh_data_from_poly_selection);
+ break;
+ default:
+ BLI_assert_unreachable();
+ break;
+ }
+ component.replace_mesh_but_keep_vertex_group_names(mesh_out);
+}
+
+static void geo_node_delete_geometry_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+ geometry_set = bke::geometry_set_realize_instances(geometry_set);
+
+ const bool invert = params.extract_input<bool>("Invert");
+ const std::string selection_name = params.extract_input<std::string>("Selection");
+ if (selection_name.empty()) {
+ params.set_output("Geometry", std::move(geometry_set));
+ return;
+ }
+
+ GeometrySet out_set(geometry_set);
+ if (geometry_set.has<PointCloudComponent>()) {
+ delete_point_cloud_selection(*geometry_set.get_component_for_read<PointCloudComponent>(),
+ out_set.get_component_for_write<PointCloudComponent>(),
+ selection_name,
+ invert);
+ }
+ if (geometry_set.has<MeshComponent>()) {
+ delete_mesh_selection(out_set.get_component_for_write<MeshComponent>(),
+ *geometry_set.get_mesh_for_read(),
+ selection_name,
+ invert);
+ }
+ if (geometry_set.has<CurveComponent>()) {
+ delete_curve_selection(*geometry_set.get_component_for_read<CurveComponent>(),
+ out_set.get_component_for_write<CurveComponent>(),
+ selection_name,
+ invert);
+ }
+
+ params.set_output("Geometry", std::move(out_set));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_delete_geometry()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_DELETE_GEOMETRY, "Delete Geometry", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(&ntype, geo_node_delete_geometry_in, geo_node_delete_geometry_out);
+ ntype.geometry_node_execute = blender::nodes::geo_node_delete_geometry_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
index aace71d1d40..f19d533d0b0 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc
@@ -17,6 +17,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "BKE_material.h"
#include "BKE_mesh.h"
#include "UI_interface.h"
@@ -214,6 +215,7 @@ static void geo_node_mesh_primitive_circle_exec(GeoNodeExecParams params)
}
Mesh *mesh = create_circle_mesh(radius, verts_num, fill_type);
+ BKE_id_material_eval_ensure_default_slot(&mesh->id);
BLI_assert(BKE_mesh_is_valid(mesh));
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
index 2806472286e..4c1521aa6f1 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cone.cc
@@ -17,6 +17,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "BKE_material.h"
#include "BKE_mesh.h"
#include "UI_interface.h"
@@ -561,6 +562,7 @@ static void geo_node_mesh_primitive_cone_exec(GeoNodeExecParams params)
Mesh *mesh = create_cylinder_or_cone_mesh(
radius_top, radius_bottom, depth, verts_num, fill_type);
+ BKE_id_material_eval_ensure_default_slot(&mesh->id);
/* Transform the mesh so that the base of the cone is at the origin. */
BKE_mesh_translate(mesh, float3(0.0f, 0.0f, depth * 0.5f), false);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
index 1d31068653e..b34913df843 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cube.cc
@@ -17,6 +17,7 @@
#include "DNA_mesh_types.h"
#include "BKE_lib_id.h"
+#include "BKE_material.h"
#include "BKE_mesh.h"
#include "bmesh.h"
@@ -64,6 +65,7 @@ static void geo_node_mesh_primitive_cube_exec(GeoNodeExecParams params)
const float size = params.extract_input<float>("Size");
Mesh *mesh = create_cube_mesh(size);
+ BKE_id_material_eval_ensure_default_slot(&mesh->id);
params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc
index f443b4387d3..c7b9fb920f8 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_cylinder.cc
@@ -17,6 +17,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "BKE_material.h"
#include "BKE_mesh.h"
#include "UI_interface.h"
@@ -75,6 +76,7 @@ static void geo_node_mesh_primitive_cylinder_exec(GeoNodeExecParams params)
/* The cylinder is a special case of the cone mesh where the top and bottom radius are equal. */
Mesh *mesh = create_cylinder_or_cone_mesh(radius, radius, depth, verts_num, fill_type);
+ BKE_id_material_eval_ensure_default_slot(&mesh->id);
params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
index 5a4bab86421..ac2f5a23a4d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc
@@ -17,6 +17,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "BKE_material.h"
#include "BKE_mesh.h"
#include "UI_interface.h"
@@ -167,6 +168,7 @@ static void geo_node_mesh_primitive_grid_exec(GeoNodeExecParams params)
Mesh *mesh = create_grid_mesh(verts_x, verts_y, size_x, size_y);
BLI_assert(BKE_mesh_is_valid(mesh));
+ BKE_id_material_eval_ensure_default_slot(&mesh->id);
params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
index 242cc6ed7df..5f7d8150022 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
@@ -17,6 +17,7 @@
#include "DNA_mesh_types.h"
#include "BKE_lib_id.h"
+#include "BKE_material.h"
#include "BKE_mesh.h"
#include "bmesh.h"
@@ -67,6 +68,7 @@ static void geo_node_mesh_primitive_ico_sphere_exec(GeoNodeExecParams params)
const float radius = params.extract_input<float>("Radius");
Mesh *mesh = create_ico_sphere_mesh(subdivisions, radius);
+ BKE_id_material_eval_ensure_default_slot(&mesh->id);
params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
index 2eeb87695a8..d93c4e39fda 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_line.cc
@@ -17,6 +17,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "BKE_material.h"
#include "BKE_mesh.h"
#include "UI_interface.h"
@@ -165,6 +166,7 @@ static void geo_node_mesh_primitive_line_exec(GeoNodeExecParams params)
const int count = params.extract_input<int>("Count");
mesh = create_line_mesh(start, delta, count);
}
+ BKE_id_material_eval_ensure_default_slot(&mesh->id);
params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
index cc93e71a5dd..7d340679269 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
@@ -17,6 +17,7 @@
#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"
+#include "BKE_material.h"
#include "BKE_mesh.h"
#include "UI_interface.h"
@@ -296,6 +297,7 @@ static void geo_node_mesh_primitive_uv_sphere_exec(GeoNodeExecParams params)
const float radius = params.extract_input<float>("Radius");
Mesh *mesh = create_uv_sphere_mesh(radius, segments_num, rings_num);
+ BKE_id_material_eval_ensure_default_slot(&mesh->id);
params.set_output("Geometry", GeometrySet::create_with_mesh(mesh));
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
new file mode 100644
index 00000000000..0fb7910c904
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_to_curve.cc
@@ -0,0 +1,316 @@
+/*
+ * 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_array.hh"
+#include "BLI_task.hh"
+
+#include "DNA_mesh_types.h"
+#include "DNA_meshdata_types.h"
+
+#include "BKE_attribute_math.hh"
+#include "BKE_spline.hh"
+
+#include "node_geometry_util.hh"
+
+using blender::Array;
+
+static bNodeSocketTemplate geo_node_mesh_to_curve_in[] = {
+ {SOCK_GEOMETRY, N_("Mesh")},
+ {SOCK_STRING, N_("Selection")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_mesh_to_curve_out[] = {
+ {SOCK_GEOMETRY, N_("Curve")},
+ {-1, ""},
+};
+
+namespace blender::nodes {
+
+template<typename T>
+static void copy_attribute_to_points(const VArray<T> &source_data,
+ Span<int> map,
+ MutableSpan<T> dest_data)
+{
+ for (const int point_index : map.index_range()) {
+ const int vert_index = map[point_index];
+ dest_data[point_index] = source_data[vert_index];
+ }
+}
+
+static void copy_attributes_to_points(CurveEval &curve,
+ const MeshComponent &mesh_component,
+ Span<Vector<int>> point_to_vert_maps)
+{
+ MutableSpan<SplinePtr> splines = curve.splines();
+ Set<std::string> source_attribute_names = mesh_component.attribute_names();
+
+ /* Copy builtin control point attributes. */
+ if (source_attribute_names.contains_as("tilt")) {
+ const GVArray_Typed<float> tilt_attribute = mesh_component.attribute_get_for_read<float>(
+ "tilt", ATTR_DOMAIN_POINT, 0.0f);
+ parallel_for(splines.index_range(), 256, [&](IndexRange range) {
+ for (const int i : range) {
+ copy_attribute_to_points<float>(
+ *tilt_attribute, point_to_vert_maps[i], splines[i]->tilts());
+ }
+ });
+ source_attribute_names.remove_contained_as("tilt");
+ }
+ if (source_attribute_names.contains_as("radius")) {
+ const GVArray_Typed<float> radius_attribute = mesh_component.attribute_get_for_read<float>(
+ "radius", ATTR_DOMAIN_POINT, 1.0f);
+ parallel_for(splines.index_range(), 256, [&](IndexRange range) {
+ for (const int i : range) {
+ copy_attribute_to_points<float>(
+ *radius_attribute, point_to_vert_maps[i], splines[i]->radii());
+ }
+ });
+ source_attribute_names.remove_contained_as("radius");
+ }
+
+ /* Don't copy other builtin control point attributes. */
+ source_attribute_names.remove_as("position");
+
+ /* Copy dynamic control point attributes. */
+ for (const StringRef name : source_attribute_names) {
+ const GVArrayPtr mesh_attribute = mesh_component.attribute_try_get_for_read(name,
+ ATTR_DOMAIN_POINT);
+ /* Some attributes might not exist if they were builtin attribute on domains that don't
+ * have any elements, i.e. a face attribute on the output of the line primitive node. */
+ if (!mesh_attribute) {
+ continue;
+ }
+
+ const CustomDataType data_type = bke::cpp_type_to_custom_data_type(mesh_attribute->type());
+
+ parallel_for(splines.index_range(), 128, [&](IndexRange range) {
+ for (const int i : range) {
+ /* Create attribute on the spline points. */
+ splines[i]->attributes.create(name, data_type);
+ std::optional<GMutableSpan> spline_attribute = splines[i]->attributes.get_for_write(name);
+ BLI_assert(spline_attribute);
+
+ /* Copy attribute based on the map for this spline. */
+ attribute_math::convert_to_static_type(mesh_attribute->type(), [&](auto dummy) {
+ using T = decltype(dummy);
+ copy_attribute_to_points<T>(
+ mesh_attribute->typed<T>(), point_to_vert_maps[i], spline_attribute->typed<T>());
+ });
+ }
+ });
+ }
+
+ curve.assert_valid_point_attributes();
+}
+
+struct CurveFromEdgesOutput {
+ std::unique_ptr<CurveEval> curve;
+ Vector<Vector<int>> point_to_vert_maps;
+};
+
+static CurveFromEdgesOutput mesh_to_curve(Span<MVert> verts, Span<std::pair<int, int>> edges)
+{
+ std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
+ Vector<Vector<int>> point_to_vert_maps;
+
+ /* Compute the number of edges connecting to each vertex. */
+ Array<int> neighbor_count(verts.size(), 0);
+ for (const std::pair<int, int> &edge : edges) {
+ neighbor_count[edge.first]++;
+ neighbor_count[edge.second]++;
+ }
+
+ /* Compute an offset into the array of neighbor edges based on the counts. */
+ Array<int> neighbor_offsets(verts.size());
+ int start = 0;
+ for (const int i : verts.index_range()) {
+ neighbor_offsets[i] = start;
+ start += neighbor_count[i];
+ }
+
+ /* Use as an index into the "neighbor group" for each vertex. */
+ Array<int> used_slots(verts.size(), 0);
+ /* Calculate the indices of each vertex's neighboring edges. */
+ Array<int> neighbors(edges.size() * 2);
+ for (const int i : edges.index_range()) {
+ const int v1 = edges[i].first;
+ const int v2 = edges[i].second;
+ neighbors[neighbor_offsets[v1] + used_slots[v1]] = v2;
+ neighbors[neighbor_offsets[v2] + used_slots[v2]] = v1;
+ used_slots[v1]++;
+ used_slots[v2]++;
+ }
+
+ /* Now use the neighbor group offsets calculated above as a count used edges at each vertex. */
+ Array<int> unused_edges = std::move(used_slots);
+
+ for (const int start_vert : verts.index_range()) {
+ /* The vertex will be part of a cyclic spline. */
+ if (neighbor_count[start_vert] == 2) {
+ continue;
+ }
+
+ /* The vertex has no connected edges, or they were already used. */
+ if (unused_edges[start_vert] == 0) {
+ continue;
+ }
+
+ for (const int i : IndexRange(neighbor_count[start_vert])) {
+ int current_vert = start_vert;
+ int next_vert = neighbors[neighbor_offsets[current_vert] + i];
+
+ if (unused_edges[next_vert] == 0) {
+ continue;
+ }
+
+ std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
+ Vector<int> point_to_vert_map;
+
+ spline->add_point(verts[current_vert].co, 1.0f, 0.0f);
+ point_to_vert_map.append(current_vert);
+
+ /* Follow connected edges until we read a vertex with more than two connected edges. */
+ while (true) {
+ int last_vert = current_vert;
+ current_vert = next_vert;
+
+ spline->add_point(verts[current_vert].co, 1.0f, 0.0f);
+ point_to_vert_map.append(current_vert);
+ unused_edges[current_vert]--;
+ unused_edges[last_vert]--;
+
+ if (neighbor_count[current_vert] != 2) {
+ break;
+ }
+
+ const int offset = neighbor_offsets[current_vert];
+ const int next_a = neighbors[offset];
+ const int next_b = neighbors[offset + 1];
+ next_vert = (last_vert == next_a) ? next_b : next_a;
+ }
+
+ spline->attributes.reallocate(spline->size());
+ curve->add_spline(std::move(spline));
+ point_to_vert_maps.append(std::move(point_to_vert_map));
+ }
+ }
+
+ /* All remaining edges are part of cyclic splines (we skipped vertices with two edges before). */
+ for (const int start_vert : verts.index_range()) {
+ if (unused_edges[start_vert] != 2) {
+ continue;
+ }
+
+ int current_vert = start_vert;
+ int next_vert = neighbors[neighbor_offsets[current_vert]];
+
+ std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
+ Vector<int> point_to_vert_map;
+ spline->set_cyclic(true);
+
+ spline->add_point(verts[current_vert].co, 1.0f, 0.0f);
+ point_to_vert_map.append(current_vert);
+
+ /* Follow connected edges until we loop back to the start vertex. */
+ while (next_vert != start_vert) {
+ const int last_vert = current_vert;
+ current_vert = next_vert;
+
+ spline->add_point(verts[current_vert].co, 1.0f, 0.0f);
+ point_to_vert_map.append(current_vert);
+ unused_edges[current_vert]--;
+ unused_edges[last_vert]--;
+
+ const int offset = neighbor_offsets[current_vert];
+ const int next_a = neighbors[offset];
+ const int next_b = neighbors[offset + 1];
+ next_vert = (last_vert == next_a) ? next_b : next_a;
+ }
+
+ spline->attributes.reallocate(spline->size());
+ curve->add_spline(std::move(spline));
+ point_to_vert_maps.append(std::move(point_to_vert_map));
+ }
+
+ curve->attributes.reallocate(curve->splines().size());
+ return {std::move(curve), std::move(point_to_vert_maps)};
+}
+
+/**
+ * Get a separate array of the indices for edges in a selection (a boolean attribute).
+ * This helps to make the above algorithm simpler by removing the need to check for selection
+ * in many places.
+ */
+static Vector<std::pair<int, int>> get_selected_edges(GeoNodeExecParams params,
+ const MeshComponent &component)
+{
+ const Mesh &mesh = *component.get_for_read();
+ const std::string selection_name = params.extract_input<std::string>("Selection");
+ if (!selection_name.empty() && !component.attribute_exists(selection_name)) {
+ params.error_message_add(NodeWarningType::Error,
+ TIP_("No attribute with name \"") + selection_name + "\"");
+ }
+ GVArray_Typed<bool> selection = component.attribute_get_for_read<bool>(
+ selection_name, ATTR_DOMAIN_EDGE, true);
+
+ Vector<std::pair<int, int>> selected_edges;
+ for (const int i : IndexRange(mesh.totedge)) {
+ if (selection[i]) {
+ selected_edges.append({mesh.medge[i].v1, mesh.medge[i].v2});
+ }
+ }
+
+ return selected_edges;
+}
+
+static void geo_node_mesh_to_curve_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Mesh");
+
+ geometry_set = bke::geometry_set_realize_instances(geometry_set);
+
+ if (!geometry_set.has_mesh()) {
+ params.set_output("Curve", GeometrySet());
+ return;
+ }
+
+ const MeshComponent &component = *geometry_set.get_component_for_read<MeshComponent>();
+ const Mesh &mesh = *component.get_for_read();
+ Span<MVert> verts = Span{mesh.mvert, mesh.totvert};
+ Vector<std::pair<int, int>> selected_edges = get_selected_edges(params, component);
+ if (selected_edges.size() == 0) {
+ params.set_output("Curve", GeometrySet());
+ return;
+ }
+
+ CurveFromEdgesOutput output = mesh_to_curve(verts, selected_edges);
+ copy_attributes_to_points(*output.curve, component, output.point_to_vert_maps);
+
+ params.set_output("Curve", GeometrySet::create_with_curve(output.curve.release()));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_mesh_to_curve()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_MESH_TO_CURVE, "Mesh to Curve", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(&ntype, geo_node_mesh_to_curve_in, geo_node_mesh_to_curve_out);
+ ntype.geometry_node_execute = blender::nodes::geo_node_mesh_to_curve_exec;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc b/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc
index d2b024b208c..fc04d1e275f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_separate.cc
@@ -52,10 +52,10 @@ static void copy_data_based_on_mask(Span<T> data,
}
}
-static void copy_attributes_based_on_mask(const GeometryComponent &in_component,
- GeometryComponent &result_component,
- Span<bool> masks,
- const bool invert)
+void copy_point_attributes_based_on_mask(const GeometryComponent &in_component,
+ GeometryComponent &result_component,
+ Span<bool> masks,
+ const bool invert)
{
for (const std::string &name : in_component.attribute_names()) {
ReadAttributeLookup attribute = in_component.attribute_try_get_for_read(name);
@@ -118,7 +118,7 @@ static void separate_points_from_component(const GeometryComponent &in_component
create_component_points(out_component, total);
- copy_attributes_based_on_mask(in_component, out_component, masks, invert);
+ copy_point_attributes_based_on_mask(in_component, out_component, masks, invert);
}
static GeometrySet separate_geometry_set(const GeometrySet &set_in,
@@ -127,6 +127,10 @@ static GeometrySet separate_geometry_set(const GeometrySet &set_in,
{
GeometrySet set_out;
for (const GeometryComponent *component : set_in.get_components_for_read()) {
+ if (component->type() == GEO_COMPONENT_TYPE_CURVE) {
+ /* Don't support the curve component for now, even though it has a point domain. */
+ continue;
+ }
GeometryComponent &out_component = set_out.get_component_for_write(component->type());
separate_points_from_component(*component, out_component, mask_name, invert);
}
@@ -167,6 +171,6 @@ void register_node_type_geo_point_separate()
geo_node_type_base(&ntype, GEO_NODE_POINT_SEPARATE, "Point Separate", NODE_CLASS_GEOMETRY, 0);
node_type_socket_templates(&ntype, geo_node_point_instance_in, geo_node_point_instance_out);
ntype.geometry_node_execute = blender::nodes::geo_node_point_separate_exec;
- ntype.geometry_node_execute_supports_lazyness = true;
+ ntype.geometry_node_execute_supports_laziness = true;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_switch.cc b/source/blender/nodes/geometry/nodes/node_geo_switch.cc
index bb0a20f4561..742fafba9e6 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_switch.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_switch.cc
@@ -22,24 +22,24 @@
static bNodeSocketTemplate geo_node_switch_in[] = {
{SOCK_BOOLEAN, N_("Switch")},
- {SOCK_FLOAT, N_("A"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
- {SOCK_FLOAT, N_("B"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
- {SOCK_INT, N_("A"), 0, 0, 0, 0, -100000, 100000},
- {SOCK_INT, N_("B"), 0, 0, 0, 0, -100000, 100000},
- {SOCK_BOOLEAN, N_("A")},
- {SOCK_BOOLEAN, N_("B")},
- {SOCK_VECTOR, N_("A"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
- {SOCK_VECTOR, N_("B"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
- {SOCK_RGBA, N_("A"), 0.8, 0.8, 0.8, 1.0},
- {SOCK_RGBA, N_("B"), 0.8, 0.8, 0.8, 1.0},
- {SOCK_STRING, N_("A")},
- {SOCK_STRING, N_("B")},
- {SOCK_GEOMETRY, N_("A")},
- {SOCK_GEOMETRY, N_("B")},
- {SOCK_OBJECT, N_("A")},
- {SOCK_OBJECT, N_("B")},
- {SOCK_COLLECTION, N_("A")},
- {SOCK_COLLECTION, N_("B")},
+ {SOCK_FLOAT, N_("False"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
+ {SOCK_FLOAT, N_("True"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
+ {SOCK_INT, N_("False"), 0, 0, 0, 0, -100000, 100000},
+ {SOCK_INT, N_("True"), 0, 0, 0, 0, -100000, 100000},
+ {SOCK_BOOLEAN, N_("False")},
+ {SOCK_BOOLEAN, N_("True")},
+ {SOCK_VECTOR, N_("False"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
+ {SOCK_VECTOR, N_("True"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
+ {SOCK_RGBA, N_("False"), 0.8, 0.8, 0.8, 1.0},
+ {SOCK_RGBA, N_("True"), 0.8, 0.8, 0.8, 1.0},
+ {SOCK_STRING, N_("False")},
+ {SOCK_STRING, N_("True")},
+ {SOCK_GEOMETRY, N_("False")},
+ {SOCK_GEOMETRY, N_("True")},
+ {SOCK_OBJECT, N_("False")},
+ {SOCK_OBJECT, N_("True")},
+ {SOCK_COLLECTION, N_("False")},
+ {SOCK_COLLECTION, N_("True")},
{-1, ""},
};
@@ -64,7 +64,7 @@ static void geo_node_switch_layout(uiLayout *layout, bContext *UNUSED(C), Pointe
static void geo_node_switch_init(bNodeTree *UNUSED(tree), bNode *node)
{
NodeSwitch *data = (NodeSwitch *)MEM_callocN(sizeof(NodeSwitch), __func__);
- data->input_type = SOCK_FLOAT;
+ data->input_type = SOCK_GEOMETRY;
node->storage = data;
}
@@ -91,8 +91,8 @@ static void output_input(GeoNodeExecParams &params,
const StringRef input_suffix,
const StringRef output_identifier)
{
- const std::string name_a = "A" + input_suffix;
- const std::string name_b = "B" + input_suffix;
+ const std::string name_a = "False" + input_suffix;
+ const std::string name_b = "True" + input_suffix;
if (input) {
params.set_input_unused(name_a);
if (params.lazy_require_input(name_b)) {
@@ -134,7 +134,7 @@ static void geo_node_switch_exec(GeoNodeExecParams params)
break;
}
case SOCK_RGBA: {
- output_input<Color4f>(params, input, "_004", "Output_004");
+ output_input<ColorGeometry4f>(params, input, "_004", "Output_004");
break;
}
case SOCK_STRING: {
@@ -165,13 +165,13 @@ void register_node_type_geo_switch()
{
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_SWITCH, "Switch", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_SWITCH, "Switch", NODE_CLASS_CONVERTOR, 0);
node_type_socket_templates(&ntype, geo_node_switch_in, geo_node_switch_out);
node_type_init(&ntype, geo_node_switch_init);
node_type_update(&ntype, blender::nodes::geo_node_switch_update);
node_type_storage(&ntype, "NodeSwitch", node_free_standard_storage, node_copy_standard_storage);
ntype.geometry_node_execute = blender::nodes::geo_node_switch_exec;
- ntype.geometry_node_execute_supports_lazyness = true;
+ ntype.geometry_node_execute_supports_laziness = true;
ntype.draw_buttons = geo_node_switch_layout;
nodeRegisterType(&ntype);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform.cc b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
index 9714a4f8a80..1ad5dbea492 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc
@@ -20,6 +20,7 @@
#include "BLI_float4x4.hh"
+#include "DNA_mesh_types.h"
#include "DNA_pointcloud_types.h"
#include "DNA_volume_types.h"
@@ -72,7 +73,8 @@ void transform_mesh(Mesh *mesh,
else {
const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale);
BKE_mesh_transform(mesh, matrix.values, false);
- BKE_mesh_calc_normals(mesh);
+ mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ mesh->runtime.cd_dirty_poly |= CD_MASK_NORMAL;
}
}
@@ -158,7 +160,6 @@ static void transform_curve(CurveEval &curve,
const float3 rotation,
const float3 scale)
{
-
if (use_translate(rotation, scale)) {
curve.translate(translation);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
index c6049787970..403f4906d07 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_volume_to_mesh.cc
@@ -23,6 +23,7 @@
#include "node_geometry_util.hh"
#include "BKE_lib_id.h"
+#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_mesh_runtime.h"
#include "BKE_volume.h"
@@ -134,6 +135,7 @@ static void create_mesh_from_volume(GeometrySet &geometry_set_in,
if (mesh == nullptr) {
return;
}
+ BKE_id_material_eval_ensure_default_slot(&mesh->id);
MeshComponent &dst_component = geometry_set_out.get_component_for_write<MeshComponent>();
dst_component.replace(mesh);
}