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

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/blender/blenkernel/BKE_blender_version.h2
-rw-r--r--source/blender/blenloader/intern/versioning_290.c15
-rw-r--r--source/blender/editors/space_node/drawnode.c69
-rw-r--r--source/blender/makesdna/DNA_node_types.h9
-rw-r--r--source/blender/makesrna/intern/rna_nodetree.c25
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc172
6 files changed, 241 insertions, 51 deletions
diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h
index 8854949fa11..7c77c6a8f86 100644
--- a/source/blender/blenkernel/BKE_blender_version.h
+++ b/source/blender/blenkernel/BKE_blender_version.h
@@ -39,7 +39,7 @@ extern "C" {
/* Blender file format version. */
#define BLENDER_FILE_VERSION BLENDER_VERSION
-#define BLENDER_FILE_SUBVERSION 3
+#define BLENDER_FILE_SUBVERSION 4
/* Minimum Blender version that supports reading file written with the current
* version. Older Blender versions will test this and show a warning if the file
diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c
index d1cbf05c0ba..b389c5ed210 100644
--- a/source/blender/blenloader/intern/versioning_290.c
+++ b/source/blender/blenloader/intern/versioning_290.c
@@ -1630,6 +1630,21 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain)
FOREACH_NODETREE_END;
}
+ if (!MAIN_VERSION_ATLEAST(bmain, 293, 4)) {
+ /* Add support for all operations to the "Attribute Math" node. */
+ FOREACH_NODETREE_BEGIN (bmain, ntree, id) {
+ if (ntree->type == NTREE_GEOMETRY) {
+ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) {
+ if (node->type == GEO_NODE_ATTRIBUTE_MATH) {
+ NodeAttributeMath *data = (NodeAttributeMath *)node->storage;
+ data->input_type_c = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
+ }
+ }
+ }
+ }
+ FOREACH_NODETREE_END;
+ }
+
/**
* Versioning code until next subversion bump goes here.
*
diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c
index 8f3602c8d50..7905483fac9 100644
--- a/source/blender/editors/space_node/drawnode.c
+++ b/source/blender/editors/space_node/drawnode.c
@@ -3166,13 +3166,80 @@ static void node_geometry_buts_random_attribute(uiLayout *layout,
uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE);
}
+static bool node_attribute_math_operation_use_input_b(const NodeMathOperation operation)
+{
+ switch (operation) {
+ case NODE_MATH_ADD:
+ case NODE_MATH_SUBTRACT:
+ case NODE_MATH_MULTIPLY:
+ case NODE_MATH_DIVIDE:
+ case NODE_MATH_POWER:
+ case NODE_MATH_LOGARITHM:
+ case NODE_MATH_MINIMUM:
+ case NODE_MATH_MAXIMUM:
+ case NODE_MATH_LESS_THAN:
+ case NODE_MATH_GREATER_THAN:
+ case NODE_MATH_MODULO:
+ case NODE_MATH_ARCTAN2:
+ case NODE_MATH_SNAP:
+ case NODE_MATH_WRAP:
+ case NODE_MATH_COMPARE:
+ case NODE_MATH_MULTIPLY_ADD:
+ case NODE_MATH_PINGPONG:
+ case NODE_MATH_SMOOTH_MIN:
+ case NODE_MATH_SMOOTH_MAX:
+ return true;
+ case NODE_MATH_SINE:
+ case NODE_MATH_COSINE:
+ case NODE_MATH_TANGENT:
+ case NODE_MATH_ARCSINE:
+ case NODE_MATH_ARCCOSINE:
+ case NODE_MATH_ARCTANGENT:
+ case NODE_MATH_ROUND:
+ case NODE_MATH_ABSOLUTE:
+ case NODE_MATH_FLOOR:
+ case NODE_MATH_CEIL:
+ case NODE_MATH_FRACTION:
+ case NODE_MATH_SQRT:
+ case NODE_MATH_INV_SQRT:
+ case NODE_MATH_SIGN:
+ case NODE_MATH_EXPONENT:
+ case NODE_MATH_RADIANS:
+ case NODE_MATH_DEGREES:
+ case NODE_MATH_SINH:
+ case NODE_MATH_COSH:
+ case NODE_MATH_TANH:
+ case NODE_MATH_TRUNC:
+ return false;
+ }
+ BLI_assert(false);
+ return false;
+}
+
static void node_geometry_buts_attribute_math(uiLayout *layout,
bContext *UNUSED(C),
PointerRNA *ptr)
{
+ bNode *node = (bNode *)ptr->data;
+ NodeAttributeMath *node_storage = (NodeAttributeMath *)node->storage;
+ NodeMathOperation operation = (NodeMathOperation)node_storage->operation;
+
uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE);
uiItemR(layout, ptr, "input_type_a", DEFAULT_FLAGS, IFACE_("Type A"), ICON_NONE);
- uiItemR(layout, ptr, "input_type_b", DEFAULT_FLAGS, IFACE_("Type B"), ICON_NONE);
+
+ /* These "use input b / c" checks are copied from the node's code.
+ * They could be de-duplicated if the drawing code was moved to the node's file. */
+ if (node_attribute_math_operation_use_input_b(operation)) {
+ uiItemR(layout, ptr, "input_type_b", DEFAULT_FLAGS, IFACE_("Type B"), ICON_NONE);
+ }
+ if (ELEM(operation,
+ NODE_MATH_MULTIPLY_ADD,
+ NODE_MATH_SMOOTH_MIN,
+ NODE_MATH_SMOOTH_MAX,
+ NODE_MATH_WRAP,
+ NODE_MATH_COMPARE)) {
+ uiItemR(layout, ptr, "input_type_c", DEFAULT_FLAGS, IFACE_("Type C"), ICON_NONE);
+ }
}
static void node_geometry_buts_attribute_vector_math(uiLayout *layout,
diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h
index e26a2861f04..0c92099e23b 100644
--- a/source/blender/makesdna/DNA_node_types.h
+++ b/source/blender/makesdna/DNA_node_types.h
@@ -1089,14 +1089,15 @@ typedef struct NodeAttributeCompare {
} NodeAttributeCompare;
typedef struct NodeAttributeMath {
- /* e.g. NODE_MATH_ADD. */
+ /* NodeMathOperation. */
uint8_t operation;
/* GeometryNodeAttributeInputMode */
uint8_t input_type_a;
uint8_t input_type_b;
+ uint8_t input_type_c;
- char _pad[5];
+ char _pad[4];
} NodeAttributeMath;
typedef struct NodeAttributeMix {
@@ -1387,7 +1388,7 @@ enum {
#define SHD_MATH_CLAMP 1
/* Math node operations. */
-enum {
+typedef enum NodeMathOperation {
NODE_MATH_ADD = 0,
NODE_MATH_SUBTRACT = 1,
NODE_MATH_MULTIPLY = 2,
@@ -1428,7 +1429,7 @@ enum {
NODE_MATH_PINGPONG = 37,
NODE_MATH_SMOOTH_MIN = 38,
NODE_MATH_SMOOTH_MAX = 39,
-};
+} NodeMathOperation;
/* Vector Math node operations. */
typedef enum NodeVectorMathOperation {
diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c
index db9c774bf9b..90badae2e8e 100644
--- a/source/blender/makesrna/intern/rna_nodetree.c
+++ b/source/blender/makesrna/intern/rna_nodetree.c
@@ -1980,22 +1980,6 @@ static const EnumPropertyItem *rna_GeometryNodeAttributeFill_domain_itemf(
return itemf_function_check(rna_enum_attribute_domain_items, attribute_fill_domain_supported);
}
-static bool attribute_math_operation_supported(const EnumPropertyItem *item)
-{
- return ELEM(item->value,
- NODE_MATH_ADD,
- NODE_MATH_SUBTRACT,
- NODE_MATH_MULTIPLY,
- NODE_MATH_DIVIDE) &&
- (item->identifier[0] != '\0');
-}
-static const EnumPropertyItem *rna_GeometryNodeAttributeMath_operation_itemf(
- bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free)
-{
- *r_free = true;
- return itemf_function_check(rna_enum_node_math_items, attribute_math_operation_supported);
-}
-
/**
* This bit of ugly code makes sure the float / attribute option shows up instead of
* vector / attribute if the node uses an operation that uses a float for input B.
@@ -8579,10 +8563,9 @@ static void def_geo_attribute_math(StructRNA *srna)
prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_sdna(prop, NULL, "operation");
RNA_def_property_enum_items(prop, rna_enum_node_math_items);
- RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeMath_operation_itemf");
RNA_def_property_enum_default(prop, NODE_MATH_ADD);
RNA_def_property_ui_text(prop, "Operation", "");
- RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
prop = RNA_def_property(srna, "input_type_a", PROP_ENUM, PROP_NONE);
RNA_def_property_enum_bitflag_sdna(prop, NULL, "input_type_a");
@@ -8595,6 +8578,12 @@ static void def_geo_attribute_math(StructRNA *srna)
RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float);
RNA_def_property_ui_text(prop, "Input Type B", "");
RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
+
+ prop = RNA_def_property(srna, "input_type_c", PROP_ENUM, PROP_NONE);
+ RNA_def_property_enum_bitflag_sdna(prop, NULL, "input_type_c");
+ RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float);
+ RNA_def_property_ui_text(prop, "Input Type C", "");
+ RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update");
}
static void def_geo_attribute_vector_math(StructRNA *srna)
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc
index f8ec9124db3..f3fc45fc1be 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc
@@ -34,6 +34,8 @@ static bNodeSocketTemplate geo_node_attribute_math_in[] = {
{SOCK_FLOAT, N_("A"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
{SOCK_STRING, N_("B")},
{SOCK_FLOAT, N_("B"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
+ {SOCK_STRING, N_("C")},
+ {SOCK_FLOAT, N_("C"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX},
{SOCK_STRING, N_("Result")},
{-1, ""},
};
@@ -51,45 +53,132 @@ static void geo_node_attribute_math_init(bNodeTree *UNUSED(tree), bNode *node)
data->operation = NODE_MATH_ADD;
data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
data->input_type_b = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
+ data->input_type_c = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE;
node->storage = data;
}
+static bool operation_use_input_c(const NodeMathOperation operation)
+{
+ return ELEM(operation,
+ NODE_MATH_MULTIPLY_ADD,
+ NODE_MATH_SMOOTH_MIN,
+ NODE_MATH_SMOOTH_MAX,
+ NODE_MATH_WRAP,
+ NODE_MATH_COMPARE);
+}
+
+static bool operation_use_input_b(const NodeMathOperation operation)
+{
+ switch (operation) {
+ case NODE_MATH_ADD:
+ case NODE_MATH_SUBTRACT:
+ case NODE_MATH_MULTIPLY:
+ case NODE_MATH_DIVIDE:
+ case NODE_MATH_POWER:
+ case NODE_MATH_LOGARITHM:
+ case NODE_MATH_MINIMUM:
+ case NODE_MATH_MAXIMUM:
+ case NODE_MATH_LESS_THAN:
+ case NODE_MATH_GREATER_THAN:
+ case NODE_MATH_MODULO:
+ case NODE_MATH_ARCTAN2:
+ case NODE_MATH_SNAP:
+ case NODE_MATH_WRAP:
+ case NODE_MATH_COMPARE:
+ case NODE_MATH_MULTIPLY_ADD:
+ case NODE_MATH_PINGPONG:
+ case NODE_MATH_SMOOTH_MIN:
+ case NODE_MATH_SMOOTH_MAX:
+ return true;
+ case NODE_MATH_SINE:
+ case NODE_MATH_COSINE:
+ case NODE_MATH_TANGENT:
+ case NODE_MATH_ARCSINE:
+ case NODE_MATH_ARCCOSINE:
+ case NODE_MATH_ARCTANGENT:
+ case NODE_MATH_ROUND:
+ case NODE_MATH_ABSOLUTE:
+ case NODE_MATH_FLOOR:
+ case NODE_MATH_CEIL:
+ case NODE_MATH_FRACTION:
+ case NODE_MATH_SQRT:
+ case NODE_MATH_INV_SQRT:
+ case NODE_MATH_SIGN:
+ case NODE_MATH_EXPONENT:
+ case NODE_MATH_RADIANS:
+ case NODE_MATH_DEGREES:
+ case NODE_MATH_SINH:
+ case NODE_MATH_COSH:
+ case NODE_MATH_TANH:
+ case NODE_MATH_TRUNC:
+ return false;
+ }
+ BLI_assert(false);
+ return false;
+}
+
namespace blender::nodes {
static void geo_node_attribute_math_update(bNodeTree *UNUSED(ntree), bNode *node)
{
- NodeAttributeMath *node_storage = (NodeAttributeMath *)node->storage;
+ NodeAttributeMath &node_storage = *(NodeAttributeMath *)node->storage;
+ NodeMathOperation operation = static_cast<NodeMathOperation>(node_storage.operation);
update_attribute_input_socket_availabilities(
- *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a);
+ *node, "A", (GeometryNodeAttributeInputMode)node_storage.input_type_a);
update_attribute_input_socket_availabilities(
- *node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b);
+ *node,
+ "B",
+ (GeometryNodeAttributeInputMode)node_storage.input_type_b,
+ operation_use_input_b(operation));
+ update_attribute_input_socket_availabilities(
+ *node,
+ "C",
+ (GeometryNodeAttributeInputMode)node_storage.input_type_c,
+ operation_use_input_c(operation));
}
-static void do_math_operation(const FloatReadAttribute &input_a,
- const FloatReadAttribute &input_b,
- FloatWriteAttribute result,
- const int operation)
+static void do_math_operation(Span<float> span_a,
+ Span<float> span_b,
+ Span<float> span_c,
+ MutableSpan<float> span_result,
+ const NodeMathOperation operation)
{
- const int size = input_a.size();
-
- Span<float> span_a = input_a.get_span();
- Span<float> span_b = input_b.get_span();
- MutableSpan<float> span_result = result.get_span_for_write_only();
+ bool success = try_dispatch_float_math_fl_fl_fl_to_fl(
+ operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
+ for (const int i : IndexRange(span_result.size())) {
+ span_result[i] = math_function(span_a[i], span_b[i], span_c[i]);
+ }
+ });
+ BLI_assert(success);
+ UNUSED_VARS_NDEBUG(success);
+}
+static void do_math_operation(Span<float> span_a,
+ Span<float> span_b,
+ MutableSpan<float> span_result,
+ const NodeMathOperation operation)
+{
bool success = try_dispatch_float_math_fl_fl_to_fl(
operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
- for (const int i : IndexRange(size)) {
- const float in1 = span_a[i];
- const float in2 = span_b[i];
- const float out = math_function(in1, in2);
- span_result[i] = out;
+ for (const int i : IndexRange(span_result.size())) {
+ span_result[i] = math_function(span_a[i], span_b[i]);
}
});
+ BLI_assert(success);
+ UNUSED_VARS_NDEBUG(success);
+}
- result.apply_span();
-
- /* The operation is not supported by this node currently. */
+static void do_math_operation(Span<float> span_input,
+ MutableSpan<float> span_result,
+ const NodeMathOperation operation)
+{
+ bool success = try_dispatch_float_math_fl_to_fl(
+ operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) {
+ for (const int i : IndexRange(span_result.size())) {
+ span_result[i] = math_function(span_input[i]);
+ }
+ });
BLI_assert(success);
UNUSED_VARS_NDEBUG(success);
}
@@ -98,7 +187,7 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP
{
const bNode &node = params.node();
const NodeAttributeMath *node_storage = (const NodeAttributeMath *)node.storage;
- const int operation = node_storage->operation;
+ const NodeMathOperation operation = static_cast<NodeMathOperation>(node_storage->operation);
/* The result type of this node is always float. */
const CustomDataType result_type = CD_PROP_FLOAT;
@@ -115,15 +204,44 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP
ReadAttributePtr attribute_a = params.get_input_attribute(
"A", component, result_domain, result_type, nullptr);
- ReadAttributePtr attribute_b = params.get_input_attribute(
- "B", component, result_domain, result_type, nullptr);
- if (!attribute_a || !attribute_b) {
- /* Attribute wasn't found. */
+ if (!attribute_a) {
return;
}
- do_math_operation(*attribute_a, *attribute_b, *attribute_result, operation);
- attribute_result.save();
+ /* Note that passing the data with `get_span<float>()` works
+ * because the attributes were accessed with #CD_PROP_FLOAT. */
+ if (operation_use_input_b(operation)) {
+ ReadAttributePtr attribute_b = params.get_input_attribute(
+ "B", component, result_domain, result_type, nullptr);
+ if (!attribute_b) {
+ return;
+ }
+ if (operation_use_input_c(operation)) {
+ ReadAttributePtr attribute_c = params.get_input_attribute(
+ "C", component, result_domain, result_type, nullptr);
+ if (!attribute_c) {
+ return;
+ }
+ do_math_operation(attribute_a->get_span<float>(),
+ attribute_b->get_span<float>(),
+ attribute_c->get_span<float>(),
+ attribute_result->get_span_for_write_only<float>(),
+ operation);
+ }
+ else {
+ do_math_operation(attribute_a->get_span<float>(),
+ attribute_b->get_span<float>(),
+ attribute_result->get_span_for_write_only<float>(),
+ operation);
+ }
+ }
+ else {
+ do_math_operation(attribute_a->get_span<float>(),
+ attribute_result->get_span_for_write_only<float>(),
+ operation);
+ }
+
+ attribute_result.apply_span_and_save();
}
static void geo_node_attribute_math_exec(GeoNodeExecParams params)