Changeset View
Changeset View
Standalone View
Standalone View
source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc
| Show All 28 Lines | |||||
| #include "NOD_math_functions.hh" | #include "NOD_math_functions.hh" | ||||
| static bNodeSocketTemplate geo_node_attribute_math_in[] = { | static bNodeSocketTemplate geo_node_attribute_math_in[] = { | ||||
| {SOCK_GEOMETRY, N_("Geometry")}, | {SOCK_GEOMETRY, N_("Geometry")}, | ||||
| {SOCK_STRING, N_("A")}, | {SOCK_STRING, N_("A")}, | ||||
| {SOCK_FLOAT, N_("A"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, | {SOCK_FLOAT, N_("A"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, | ||||
| {SOCK_STRING, N_("B")}, | {SOCK_STRING, N_("B")}, | ||||
| {SOCK_FLOAT, N_("B"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, | {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")}, | {SOCK_STRING, N_("Result")}, | ||||
| {-1, ""}, | {-1, ""}, | ||||
| }; | }; | ||||
| static bNodeSocketTemplate geo_node_attribute_math_out[] = { | static bNodeSocketTemplate geo_node_attribute_math_out[] = { | ||||
| {SOCK_GEOMETRY, N_("Geometry")}, | {SOCK_GEOMETRY, N_("Geometry")}, | ||||
| {-1, ""}, | {-1, ""}, | ||||
| }; | }; | ||||
| static void geo_node_attribute_math_init(bNodeTree *UNUSED(tree), bNode *node) | static void geo_node_attribute_math_init(bNodeTree *UNUSED(tree), bNode *node) | ||||
| { | { | ||||
| NodeAttributeMath *data = (NodeAttributeMath *)MEM_callocN(sizeof(NodeAttributeMath), | NodeAttributeMath *data = (NodeAttributeMath *)MEM_callocN(sizeof(NodeAttributeMath), | ||||
| "NodeAttributeMath"); | "NodeAttributeMath"); | ||||
| data->operation = NODE_MATH_ADD; | data->operation = NODE_MATH_ADD; | ||||
| data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE; | data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE; | ||||
| data->input_type_b = 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; | 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 { | namespace blender::nodes { | ||||
| static void geo_node_attribute_math_update(bNodeTree *UNUSED(ntree), bNode *node) | 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( | 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, | |||||
| operation_use_input_b(operation)); | |||||
| update_attribute_input_socket_availabilities( | update_attribute_input_socket_availabilities( | ||||
| *node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b); | *node, | ||||
| "C", | |||||
| (GeometryNodeAttributeInputMode)node_storage.input_type_c, | |||||
| operation_use_input_c(operation)); | |||||
| } | } | ||||
| static void do_math_operation(const FloatReadAttribute &input_a, | static void do_math_operation(Span<float> span_a, | ||||
| const FloatReadAttribute &input_b, | Span<float> span_b, | ||||
| FloatWriteAttribute result, | Span<float> span_c, | ||||
| const int operation) | MutableSpan<float> span_result, | ||||
| const NodeMathOperation operation) | |||||
| { | { | ||||
| const int size = input_a.size(); | bool success = try_dispatch_float_math_fl_fl_fl_to_fl( | ||||
| operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) { | |||||
| Span<float> span_a = input_a.get_span(); | for (const int i : IndexRange(span_result.size())) { | ||||
| Span<float> span_b = input_b.get_span(); | span_result[i] = math_function(span_a[i], span_b[i], span_c[i]); | ||||
| MutableSpan<float> span_result = result.get_span_for_write_only(); | } | ||||
| }); | |||||
| 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( | bool success = try_dispatch_float_math_fl_fl_to_fl( | ||||
| operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) { | operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) { | ||||
| for (const int i : IndexRange(size)) { | for (const int i : IndexRange(span_result.size())) { | ||||
| const float in1 = span_a[i]; | span_result[i] = math_function(span_a[i], span_b[i]); | ||||
| const float in2 = span_b[i]; | |||||
| const float out = math_function(in1, in2); | |||||
| span_result[i] = out; | |||||
| } | } | ||||
| }); | }); | ||||
| BLI_assert(success); | |||||
| UNUSED_VARS_NDEBUG(success); | |||||
| } | |||||
| result.apply_span(); | static void do_math_operation(Span<float> span_input, | ||||
| MutableSpan<float> span_result, | |||||
| /* The operation is not supported by this node currently. */ | 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); | BLI_assert(success); | ||||
| UNUSED_VARS_NDEBUG(success); | UNUSED_VARS_NDEBUG(success); | ||||
| } | } | ||||
| static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecParams ¶ms) | static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecParams ¶ms) | ||||
| { | { | ||||
| const bNode &node = params.node(); | const bNode &node = params.node(); | ||||
| const NodeAttributeMath *node_storage = (const NodeAttributeMath *)node.storage; | 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. */ | /* The result type of this node is always float. */ | ||||
| const CustomDataType result_type = CD_PROP_FLOAT; | const CustomDataType result_type = CD_PROP_FLOAT; | ||||
| /* The result domain is always point for now. */ | /* The result domain is always point for now. */ | ||||
| const AttributeDomain result_domain = ATTR_DOMAIN_POINT; | const AttributeDomain result_domain = ATTR_DOMAIN_POINT; | ||||
| /* Get result attribute first, in case it has to overwrite one of the existing attributes. */ | /* Get result attribute first, in case it has to overwrite one of the existing attributes. */ | ||||
| const std::string result_name = params.get_input<std::string>("Result"); | const std::string result_name = params.get_input<std::string>("Result"); | ||||
| OutputAttributePtr attribute_result = component.attribute_try_get_for_output( | OutputAttributePtr attribute_result = component.attribute_try_get_for_output( | ||||
| result_name, result_domain, result_type); | result_name, result_domain, result_type); | ||||
| if (!attribute_result) { | if (!attribute_result) { | ||||
| return; | return; | ||||
| } | } | ||||
| ReadAttributePtr attribute_a = params.get_input_attribute( | ReadAttributePtr attribute_a = params.get_input_attribute( | ||||
| "A", component, result_domain, result_type, nullptr); | "A", component, result_domain, result_type, nullptr); | ||||
| if (!attribute_a) { | |||||
| return; | |||||
| } | |||||
| /* 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( | ReadAttributePtr attribute_b = params.get_input_attribute( | ||||
| "B", component, result_domain, result_type, nullptr); | "B", component, result_domain, result_type, nullptr); | ||||
| if (!attribute_a || !attribute_b) { | if (!attribute_b) { | ||||
| /* Attribute wasn't found. */ | |||||
| return; | 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); | |||||
| } | |||||
| do_math_operation(*attribute_a, *attribute_b, *attribute_result, operation); | attribute_result.apply_span_and_save(); | ||||
| attribute_result.save(); | |||||
| } | } | ||||
| static void geo_node_attribute_math_exec(GeoNodeExecParams params) | static void geo_node_attribute_math_exec(GeoNodeExecParams params) | ||||
| { | { | ||||
| GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); | GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); | ||||
| if (geometry_set.has<MeshComponent>()) { | if (geometry_set.has<MeshComponent>()) { | ||||
| attribute_math_calc(geometry_set.get_component_for_write<MeshComponent>(), params); | attribute_math_calc(geometry_set.get_component_for_write<MeshComponent>(), params); | ||||
| Show All 23 Lines | |||||