diff options
Diffstat (limited to 'source/blender/nodes')
23 files changed, 920 insertions, 179 deletions
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 271f4e5c5e4..07380addaff 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -46,6 +46,7 @@ set(INC set(SRC composite/nodes/node_composite_alphaOver.c + composite/nodes/node_composite_antialiasing.c composite/nodes/node_composite_bilateralblur.c composite/nodes/node_composite_blur.c composite/nodes/node_composite_bokehblur.c @@ -139,19 +140,21 @@ set(SRC function/node_function_util.cc geometry/nodes/node_geo_align_rotation_to_vector.cc + geometry/nodes/node_geo_attribute_clamp.cc geometry/nodes/node_geo_attribute_color_ramp.cc geometry/nodes/node_geo_attribute_combine_xyz.cc geometry/nodes/node_geo_attribute_compare.cc geometry/nodes/node_geo_attribute_convert.cc geometry/nodes/node_geo_attribute_fill.cc + geometry/nodes/node_geo_attribute_map_range.cc geometry/nodes/node_geo_attribute_math.cc geometry/nodes/node_geo_attribute_mix.cc geometry/nodes/node_geo_attribute_proximity.cc geometry/nodes/node_geo_attribute_randomize.cc + geometry/nodes/node_geo_attribute_remove.cc geometry/nodes/node_geo_attribute_sample_texture.cc geometry/nodes/node_geo_attribute_separate_xyz.cc geometry/nodes/node_geo_attribute_vector_math.cc - geometry/nodes/node_geo_attribute_remove.cc geometry/nodes/node_geo_boolean.cc geometry/nodes/node_geo_collection_info.cc geometry/nodes/node_geo_common.cc @@ -162,9 +165,9 @@ set(SRC geometry/nodes/node_geo_mesh_primitive_cone.cc geometry/nodes/node_geo_mesh_primitive_cube.cc geometry/nodes/node_geo_mesh_primitive_cylinder.cc + geometry/nodes/node_geo_mesh_primitive_grid.cc geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc geometry/nodes/node_geo_mesh_primitive_line.cc - geometry/nodes/node_geo_mesh_primitive_plane.cc geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc geometry/nodes/node_geo_object_info.cc geometry/nodes/node_geo_point_distribute.cc diff --git a/source/blender/nodes/NOD_composite.h b/source/blender/nodes/NOD_composite.h index b0dd0edeec5..258e4c961c9 100644 --- a/source/blender/nodes/NOD_composite.h +++ b/source/blender/nodes/NOD_composite.h @@ -79,6 +79,7 @@ void register_node_type_cmp_inpaint(void); void register_node_type_cmp_despeckle(void); void register_node_type_cmp_defocus(void); void register_node_type_cmp_denoise(void); +void register_node_type_cmp_antialiasing(void); void register_node_type_cmp_valtorgb(void); void register_node_type_cmp_rgbtobw(void); diff --git a/source/blender/nodes/NOD_derived_node_tree.hh b/source/blender/nodes/NOD_derived_node_tree.hh index e47774bb25a..c29de611e18 100644 --- a/source/blender/nodes/NOD_derived_node_tree.hh +++ b/source/blender/nodes/NOD_derived_node_tree.hh @@ -261,7 +261,7 @@ inline const NodeRef *DNode::operator->() const inline uint64_t DNode::hash() const { - return DefaultHash<const DTreeContext *>{}(context_) ^ DefaultHash<const NodeRef *>{}(node_ref_); + return get_default_hash_2(context_, node_ref_); } /* -------------------------------------------------------------------- @@ -316,8 +316,7 @@ inline const SocketRef *DSocket::operator->() const inline uint64_t DSocket::hash() const { - return DefaultHash<const DTreeContext *>{}(context_) ^ - DefaultHash<const SocketRef *>{}(socket_ref_); + return get_default_hash_2(context_, socket_ref_); } /* -------------------------------------------------------------------- diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index 03115852d80..3a26f38d6ba 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -27,11 +27,13 @@ void register_node_tree_type_geo(void); void register_node_type_geo_group(void); void register_node_type_geo_align_rotation_to_vector(void); +void register_node_type_geo_attribute_clamp(void); void register_node_type_geo_attribute_color_ramp(void); void register_node_type_geo_attribute_combine_xyz(void); void register_node_type_geo_attribute_compare(void); void register_node_type_geo_attribute_convert(void); void register_node_type_geo_attribute_fill(void); +void register_node_type_geo_attribute_map_range(void); void register_node_type_geo_attribute_math(void); void register_node_type_geo_attribute_mix(void); void register_node_type_geo_attribute_proximity(void); @@ -47,8 +49,8 @@ void register_node_type_geo_join_geometry(void); void register_node_type_geo_mesh_primitive_circle(void); void register_node_type_geo_mesh_primitive_cone(void); void register_node_type_geo_mesh_primitive_cube(void); -void register_node_type_geo_mesh_primitive_plane(void); void register_node_type_geo_mesh_primitive_cylinder(void); +void register_node_type_geo_mesh_primitive_grid(void); void register_node_type_geo_mesh_primitive_ico_sphere(void); void register_node_type_geo_mesh_primitive_line(void); void register_node_type_geo_mesh_primitive_uv_sphere(void); diff --git a/source/blender/nodes/NOD_math_functions.hh b/source/blender/nodes/NOD_math_functions.hh index 08496e044c5..45de1816549 100644 --- a/source/blender/nodes/NOD_math_functions.hh +++ b/source/blender/nodes/NOD_math_functions.hh @@ -379,7 +379,8 @@ inline bool try_dispatch_float_math_fl3_fl3_fl_to_fl3(const NodeVectorMathOperat switch (operation) { case NODE_VECTOR_MATH_REFRACT: - return dispatch([](float3 a, float3 b, float c) { return float3::refract(a, b.normalized(), c); }); + return dispatch( + [](float3 a, float3 b, float c) { return float3::refract(a, b.normalized(), c); }); default: return false; } diff --git a/source/blender/nodes/NOD_socket.h b/source/blender/nodes/NOD_socket.h index 3344a25bdea..6bcfda70d04 100644 --- a/source/blender/nodes/NOD_socket.h +++ b/source/blender/nodes/NOD_socket.h @@ -41,7 +41,7 @@ extern "C" { struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocketTemplate *stemp, - int in_out); + eNodeSocketInOut in_out); void node_verify_socket_templates(struct bNodeTree *ntree, struct bNode *node); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index ec687ae6b70..0b1efaca502 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -224,6 +224,7 @@ DefNode(CompositorNode, CMP_NODE_CRYPTOMATTE, def_cmp_cryptomatte, "CRYPTO DefNode(CompositorNode, CMP_NODE_CRYPTOMATTE_LEGACY, def_cmp_cryptomatte_legacy, "CRYPTOMATTE", Cryptomatte, "Cryptomatte (Legacy)", "" ) DefNode(CompositorNode, CMP_NODE_DENOISE, def_cmp_denoise, "DENOISE", Denoise, "Denoise", "" ) DefNode(CompositorNode, CMP_NODE_EXPOSURE, 0, "EXPOSURE", Exposure, "Exposure", "" ) +DefNode(CompositorNode, CMP_NODE_ANTIALIASING, def_cmp_antialiasing, "ANTIALIASING", AntiAliasing, "Anti-Aliasing", "" ) DefNode(TextureNode, TEX_NODE_OUTPUT, def_tex_output, "OUTPUT", Output, "Output", "" ) DefNode(TextureNode, TEX_NODE_CHECKER, 0, "CHECKER", Checker, "Checker", "" ) @@ -305,7 +306,9 @@ DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CYLINDER, def_geo_mesh_cylinder, " DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, 0, "MESH_PRIMITIVE_ICO_SPHERE", MeshIcoSphere, "Ico Sphere", "") DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CONE, def_geo_mesh_cone, "MESH_PRIMITIVE_CONE", MeshCone, "Cone", "") DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_LINE, def_geo_mesh_line, "MESH_PRIMITIVE_LINE", MeshLine, "Line", "") -DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_PLANE, 0, "MESH_PRIMITIVE_PLANE", MeshPlane, "Plane", "") +DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_GRID, 0, "MESH_PRIMITIVE_GRID", MeshGrid, "Grid", "") +DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_MAP_RANGE, def_geo_attribute_map_range, "ATTRIBUTE_MAP_RANGE", AttributeMapRange, "Attribute Map Range", "") +DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_CLAMP, def_geo_attribute_clamp, "ATTRIBUTE_CLAMP", AttributeClamp, "Attribute Clamp", "") /* undefine macros */ #undef DefNode diff --git a/source/blender/nodes/composite/nodes/node_composite_antialiasing.c b/source/blender/nodes/composite/nodes/node_composite_antialiasing.c new file mode 100644 index 00000000000..7437496d878 --- /dev/null +++ b/source/blender/nodes/composite/nodes/node_composite_antialiasing.c @@ -0,0 +1,65 @@ +/* + * ***** BEGIN GPL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2017 Blender Foundation. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): IRIE Shinsuke + * + * ***** END GPL LICENSE BLOCK ***** + */ + +/** \file blender/nodes/composite/nodes/node_composite_antialiasing.c + * \ingroup cmpnodes + */ + +#include "node_composite_util.h" + +/* **************** Anti-Aliasing (SMAA 1x) ******************** */ + +static bNodeSocketTemplate cmp_node_antialiasing_in[] = { + {SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f}, {-1, ""}}; + +static bNodeSocketTemplate cmp_node_antialiasing_out[] = {{SOCK_RGBA, N_("Image")}, {-1, ""}}; + +static void node_composit_init_antialiasing(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodeAntiAliasingData *data = MEM_callocN(sizeof(NodeAntiAliasingData), "node antialiasing data"); + + data->threshold = 1.0f; + data->contrast_limit = 0.2f; + data->corner_rounding = 0.25f; + + node->storage = data; +} + +void register_node_type_cmp_antialiasing(void) +{ + static bNodeType ntype; + + cmp_node_type_base( + &ntype, CMP_NODE_ANTIALIASING, "Anti-Aliasing", NODE_CLASS_OP_FILTER, NODE_PREVIEW); + node_type_socket_templates(&ntype, cmp_node_antialiasing_in, cmp_node_antialiasing_out); + node_type_size(&ntype, 170, 140, 200); + node_type_init(&ntype, node_composit_init_antialiasing); + node_type_storage( + &ntype, "NodeAntiAliasingData", node_free_standard_storage, node_copy_standard_storage); + + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc new file mode 100644 index 00000000000..93e4124bd70 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_clamp.cc @@ -0,0 +1,278 @@ + +/* + * 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 "node_geometry_util.hh" + +#include "UI_interface.h" +#include "UI_resources.h" + +static bNodeSocketTemplate geo_node_attribute_clamp_in[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {SOCK_STRING, N_("Attribute")}, + {SOCK_STRING, N_("Result")}, + {SOCK_VECTOR, N_("Min"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_VECTOR, N_("Max"), 1.0f, 1.0f, 1.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_FLOAT, N_("Min"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_FLOAT, N_("Max"), 1.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_INT, N_("Min"), 0.0f, 0.0f, 0.0f, 0.0f, -100000, 100000}, + {SOCK_INT, N_("Max"), 100.0f, 0.0f, 0.0f, 0.0f, -100000, 100000}, + {SOCK_RGBA, N_("Min"), 0.5, 0.5, 0.5, 1.0}, + {SOCK_RGBA, N_("Max"), 0.5, 0.5, 0.5, 1.0}, + {-1, ""}, +}; + +static bNodeSocketTemplate geo_node_attribute_clamp_out[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {-1, ""}, +}; + +static void geo_node_attribute_clamp_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "operation", 0, "", ICON_NONE); +} + +static void geo_node_attribute_clamp_init(bNodeTree *UNUSED(tree), bNode *node) +{ + NodeAttributeClamp *data = (NodeAttributeClamp *)MEM_callocN(sizeof(NodeAttributeClamp), + __func__); + data->data_type = CD_PROP_FLOAT; + data->operation = NODE_CLAMP_MINMAX; + node->storage = data; +} + +static void geo_node_attribute_clamp_update(bNodeTree *UNUSED(ntree), bNode *node) +{ + bNodeSocket *sock_min_vector = (bNodeSocket *)BLI_findlink(&node->inputs, 3); + bNodeSocket *sock_max_vector = sock_min_vector->next; + bNodeSocket *sock_min_float = sock_max_vector->next; + bNodeSocket *sock_max_float = sock_min_float->next; + bNodeSocket *sock_min_int = sock_max_float->next; + bNodeSocket *sock_max_int = sock_min_int->next; + bNodeSocket *sock_min_color = sock_max_int->next; + bNodeSocket *sock_max_color = sock_min_color->next; + + const NodeAttributeClamp &storage = *(const NodeAttributeClamp *)node->storage; + const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); + nodeSetSocketAvailability(sock_min_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(sock_max_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(sock_min_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(sock_max_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(sock_min_int, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(sock_max_int, data_type == CD_PROP_INT32); + nodeSetSocketAvailability(sock_min_color, data_type == CD_PROP_COLOR); + nodeSetSocketAvailability(sock_max_color, data_type == CD_PROP_COLOR); +} + +namespace blender::nodes { + +template<typename T> T clamp_value(const T val, const T min, const T max); + +template<> inline float clamp_value(const float val, const float min, const float max) +{ + return std::min(std::max(val, min), max); +} + +template<> inline int clamp_value(const int val, const int min, const int max) +{ + return std::min(std::max(val, min), max); +} + +template<> inline float3 clamp_value(const float3 val, const float3 min, const float3 max) +{ + float3 tmp; + tmp.x = std::min(std::max(val.x, min.x), max.x); + tmp.y = std::min(std::max(val.y, min.y), max.y); + tmp.z = std::min(std::max(val.z, min.z), max.z); + return tmp; +} + +template<> inline Color4f clamp_value(const Color4f val, const Color4f min, const Color4f max) +{ + Color4f 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); + tmp.a = std::min(std::max(val.a, min.a), max.a); + return tmp; +} + +template<typename T> +static void clamp_attribute(Span<T> read_span, MutableSpan<T> span, const T min, const T max) +{ + for (const int i : span.index_range()) { + span[i] = clamp_value<T>(read_span[i], min, max); + } +} + +static AttributeDomain get_result_domain(const GeometryComponent &component, + StringRef source_name, + StringRef result_name) +{ + ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name); + if (result_attribute) { + return result_attribute->domain(); + } + ReadAttributePtr source_attribute = component.attribute_try_get_for_read(source_name); + if (source_attribute) { + return source_attribute->domain(); + } + return ATTR_DOMAIN_POINT; +} + +static void clamp_attribute(GeometryComponent &component, const GeoNodeExecParams ¶ms) +{ + const std::string attribute_name = params.get_input<std::string>("Attribute"); + const std::string result_name = params.get_input<std::string>("Result"); + + if (attribute_name.empty() || result_name.empty()) { + return; + } + + if (!component.attribute_exists(attribute_name)) { + params.error_message_add(NodeWarningType::Error, + TIP_("No attribute with name \"") + attribute_name + "\""); + return; + } + + const NodeAttributeClamp &storage = *(const NodeAttributeClamp *)params.node().storage; + const CustomDataType data_type = static_cast<CustomDataType>(storage.data_type); + const AttributeDomain domain = get_result_domain(component, attribute_name, result_name); + const int operation = static_cast<int>(storage.operation); + + ReadAttributePtr attribute_input = component.attribute_try_get_for_read( + attribute_name, domain, data_type); + + OutputAttributePtr attribute_result = component.attribute_try_get_for_output( + result_name, domain, data_type); + + if (!attribute_result) { + params.error_message_add(NodeWarningType::Error, + TIP_("Could not find or create attribute with name \"") + + result_name + "\""); + return; + } + + switch (data_type) { + case CD_PROP_FLOAT3: { + Span<float3> read_span = attribute_input->get_span<float3>(); + MutableSpan<float3> span = attribute_result->get_span_for_write_only<float3>(); + float3 min = params.get_input<float3>("Min"); + float3 max = params.get_input<float3>("Max"); + if (operation == NODE_CLAMP_RANGE) { + if (min.x > max.x) { + std::swap(min.x, max.x); + } + if (min.y > max.y) { + std::swap(min.y, max.y); + } + if (min.z > max.z) { + std::swap(min.z, max.z); + } + } + clamp_attribute<float3>(read_span, span, min, max); + break; + } + case CD_PROP_FLOAT: { + Span<float> read_span = attribute_input->get_span<float>(); + MutableSpan<float> span = attribute_result->get_span_for_write_only<float>(); + const float min = params.get_input<float>("Min_001"); + const float max = params.get_input<float>("Max_001"); + if (operation == NODE_CLAMP_RANGE && min > max) { + clamp_attribute<float>(read_span, span, max, min); + } + else { + clamp_attribute<float>(read_span, span, min, max); + } + break; + } + case CD_PROP_INT32: { + Span<int> read_span = attribute_input->get_span<int>(); + MutableSpan<int> span = attribute_result->get_span_for_write_only<int>(); + const int min = params.get_input<int>("Min_002"); + const int max = params.get_input<int>("Max_002"); + if (operation == NODE_CLAMP_RANGE && min > max) { + clamp_attribute<int>(read_span, span, max, min); + } + else { + clamp_attribute<int>(read_span, span, min, max); + } + break; + } + case CD_PROP_COLOR: { + Span<Color4f> read_span = attribute_input->get_span<Color4f>(); + MutableSpan<Color4f> span = attribute_result->get_span_for_write_only<Color4f>(); + Color4f min = params.get_input<Color4f>("Min_003"); + Color4f max = params.get_input<Color4f>("Max_003"); + if (operation == NODE_CLAMP_RANGE) { + if (min.r > max.r) { + std::swap(min.r, max.r); + } + if (min.g > max.g) { + std::swap(min.g, max.g); + } + if (min.b > max.b) { + std::swap(min.b, max.b); + } + if (min.a > max.a) { + std::swap(min.a, max.a); + } + } + clamp_attribute<Color4f>(read_span, span, min, max); + break; + } + default: { + BLI_assert(false); + break; + } + } + + attribute_result.apply_span_and_save(); +} + +static void geo_node_attribute_clamp_exec(GeoNodeExecParams params) +{ + GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); + + geometry_set = geometry_set_realize_instances(geometry_set); + + if (geometry_set.has<MeshComponent>()) { + clamp_attribute(geometry_set.get_component_for_write<MeshComponent>(), params); + } + if (geometry_set.has<PointCloudComponent>()) { + clamp_attribute(geometry_set.get_component_for_write<PointCloudComponent>(), params); + } + + params.set_output("Geometry", geometry_set); +} + +} // namespace blender::nodes + +void register_node_type_geo_attribute_clamp() +{ + static bNodeType ntype; + + geo_node_type_base(&ntype, GEO_NODE_ATTRIBUTE_CLAMP, "Attribute Clamp", NODE_CLASS_ATTRIBUTE, 0); + node_type_socket_templates(&ntype, geo_node_attribute_clamp_in, geo_node_attribute_clamp_out); + node_type_init(&ntype, geo_node_attribute_clamp_init); + node_type_update(&ntype, geo_node_attribute_clamp_update); + ntype.geometry_node_execute = blender::nodes::geo_node_attribute_clamp_exec; + ntype.draw_buttons = geo_node_attribute_clamp_layout; + node_type_storage( + &ntype, "NodeAttributeClamp", node_free_standard_storage, node_copy_standard_storage); + nodeRegisterType(&ntype); +} diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc new file mode 100644 index 00000000000..4e0dfd3a636 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_map_range.cc @@ -0,0 +1,417 @@ +/* + * 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 "node_geometry_util.hh" + +#include "BLI_math_base_safe.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +static bNodeSocketTemplate geo_node_attribute_map_range_in[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {SOCK_STRING, N_("Attribute")}, + {SOCK_STRING, N_("Result")}, + {SOCK_FLOAT, N_("From Min"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_FLOAT, N_("From Max"), 1.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_FLOAT, N_("To Min"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_FLOAT, N_("To Max"), 1.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_FLOAT, N_("Steps"), 4.0f, 4.0f, 4.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_VECTOR, N_("From Min"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_VECTOR, N_("From Max"), 1.0f, 1.0f, 1.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_VECTOR, N_("To Min"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_VECTOR, N_("To Max"), 1.0f, 1.0f, 1.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_VECTOR, N_("Steps"), 4.0f, 4.0f, 4.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_BOOLEAN, N_("Clamp")}, + {-1, ""}, +}; + +static bNodeSocketTemplate geo_node_attribute_map_range_out[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {-1, ""}, +}; + +static void fn_attribute_map_range_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) +{ + uiItemR(layout, ptr, "data_type", 0, "", ICON_NONE); + uiItemR(layout, ptr, "interpolation_type", 0, "", ICON_NONE); +} + +static void geo_node_attribute_map_range_init(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodeAttributeMapRange *data = (NodeAttributeMapRange *)MEM_callocN(sizeof(NodeAttributeMapRange), + __func__); + data->data_type = CD_PROP_FLOAT; + data->interpolation_type = NODE_MAP_RANGE_LINEAR; + + node->storage = data; +} +static void geo_node_attribute_map_range_update(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodeAttributeMapRange &node_storage = *(NodeAttributeMapRange *)node->storage; + + bNodeSocket *sock_from_min_float = (bNodeSocket *)BLI_findlink(&node->inputs, 3); + bNodeSocket *sock_from_max_float = sock_from_min_float->next; + bNodeSocket *sock_to_min_float = sock_from_max_float->next; + bNodeSocket *sock_to_max_float = sock_to_min_float->next; + bNodeSocket *sock_steps_float = sock_to_max_float->next; + + bNodeSocket *sock_from_min_vector = sock_steps_float->next; + bNodeSocket *sock_from_max_vector = sock_from_min_vector->next; + bNodeSocket *sock_to_min_vector = sock_from_max_vector->next; + bNodeSocket *sock_to_max_vector = sock_to_min_vector->next; + bNodeSocket *sock_steps_vector = sock_to_max_vector->next; + + bNodeSocket *sock_clamp = sock_steps_vector->next; + + const CustomDataType data_type = static_cast<CustomDataType>(node_storage.data_type); + + nodeSetSocketAvailability(sock_clamp, + node_storage.interpolation_type == NODE_MAP_RANGE_LINEAR || + node_storage.interpolation_type == NODE_MAP_RANGE_STEPPED); + + nodeSetSocketAvailability(sock_from_min_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(sock_from_max_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(sock_to_min_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(sock_to_max_float, data_type == CD_PROP_FLOAT); + nodeSetSocketAvailability(sock_steps_float, + data_type == CD_PROP_FLOAT && + node_storage.interpolation_type == NODE_MAP_RANGE_STEPPED); + + nodeSetSocketAvailability(sock_from_min_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(sock_from_max_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(sock_to_min_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(sock_to_max_vector, data_type == CD_PROP_FLOAT3); + nodeSetSocketAvailability(sock_steps_vector, + data_type == CD_PROP_FLOAT3 && + node_storage.interpolation_type == NODE_MAP_RANGE_STEPPED); +} + +namespace blender::nodes { + +static float map_linear(const float value, + const float min_from, + const float max_from, + const float min_to, + const float max_to) +{ + /* First we calculate a fraction that measures how far along + * the [min_from, max_from] interval the value lies. + * + * value + * min_from [------>|------------------------] max_from + * factor (e.g. 0.25) + * + * Then to find where the value is mapped, we add the same fraction + * of the [min_to, max_to] interval to min_to. + * + * min_to [--->|-----------] max_to + * v + * min_to + (max_to - min_to) * factor + */ + const float factor = safe_divide(value - min_from, max_from - min_from); + return min_to + factor * (max_to - min_to); +} + +static float map_stepped(const float value, + const float min_from, + const float max_from, + const float min_to, + const float max_to, + const float steps) +{ + /* First the factor is calculated here in the same way as for the linear mapping. + * + * Then the factor is mapped to multiples of 1.0 / steps. + * This is best understood with a few examples. Assume steps == 3. + * ____________________________________ + * | factor | * 4.0 | floor() | / 3.0 | + * |--------|-------|---------|-------| + * | 0.0 | 0.0 | 0.0 | 0.0 | + * | 0.1 | 0.4 | 0.0 | 0.0 | + * | 0.25 | 1.0 | 1.0 | 0.333 | + * | 0.45 | 1.8 | 1.0 | 0.333 | + * | 0.5 | 2.0 | 2.0 | 0.666 | + * | 0.55 | 2.2 | 2.0 | 0.666 | + * | 0.999 | 3.999 | 3.0 | 1.0 | + * | 1.0 | 4.0 | 4.0 | 1.333 | + * ------------------------------------ + * Note that the factor is not always mapped the closest multiple of 1.0 /steps. + */ + const float factor = safe_divide(value - min_from, max_from - min_from); + const float factor_mapped = safe_divide(floorf(factor * (steps + 1.0f)), steps); + return min_to + factor_mapped * (max_to - min_to); +} + +static float smoothstep_polynomial(float x) +{ + /* This polynomial is only meant to be used for the [0, 1] range. */ + return (3.0f - 2.0f * x) * (x * x); +} + +static float map_smoothstep(const float value, + const float min_from, + const float max_from, + const float min_to, + const float max_to) +{ + const float factor = safe_divide(value - min_from, max_from - min_from); + const float factor_clamped = std::clamp(factor, 0.0f, 1.0f); + const float factor_mapped = smoothstep_polynomial(factor_clamped); + return min_to + factor_mapped * (max_to - min_to); +} + +static float smootherstep_polynomial(float x) +{ + /* This polynomial is only meant to be used for the [0, 1] range. */ + return x * x * x * (x * (x * 6.0f - 15.0f) + 10.0f); +} + +static float map_smootherstep(const float value, + const float min_from, + const float max_from, + const float min_to, + const float max_to) +{ + const float factor = safe_divide(value - min_from, max_from - min_from); + const float factor_clamped = std::clamp(factor, 0.0f, 1.0f); + const float factor_mapped = smootherstep_polynomial(factor_clamped); + return min_to + factor_mapped * (max_to - min_to); +} + +static void map_range_float(FloatReadAttribute attribute_input, + FloatWriteAttribute attribute_result, + const GeoNodeExecParams ¶ms) +{ + const bNode &node = params.node(); + NodeAttributeMapRange &node_storage = *(NodeAttributeMapRange *)node.storage; + const int interpolation_type = node_storage.interpolation_type; + const float min_from = params.get_input<float>("From Min"); + const float max_from = params.get_input<float>("From Max"); + const float min_to = params.get_input<float>("To Min"); + const float max_to = params.get_input<float>("To Max"); + + Span<float> span = attribute_input.get_span(); + MutableSpan<float> result_span = attribute_result.get_span(); + + switch (interpolation_type) { + case NODE_MAP_RANGE_LINEAR: { + for (int i : span.index_range()) { + result_span[i] = map_linear(span[i], min_from, max_from, min_to, max_to); + } + break; + } + case NODE_MAP_RANGE_STEPPED: { + const float steps = params.get_input<float>("Steps"); + for (int i : span.index_range()) { + result_span[i] = map_stepped(span[i], min_from, max_from, min_to, max_to, steps); + } + break; + } + case NODE_MAP_RANGE_SMOOTHSTEP: { + for (int i : span.index_range()) { + result_span[i] = map_smoothstep(span[i], min_from, max_from, min_to, max_to); + } + break; + } + case NODE_MAP_RANGE_SMOOTHERSTEP: { + for (int i : span.index_range()) { + result_span[i] = map_smootherstep(span[i], min_from, max_from, min_to, max_to); + } + break; + } + } + + if (ELEM(interpolation_type, NODE_MAP_RANGE_LINEAR, NODE_MAP_RANGE_STEPPED) && + params.get_input<bool>("Clamp")) { + /* Users can specify min_to > max_to, but clamping expects min < max. */ + const float clamp_min = min_to < max_to ? min_to : max_to; + const float clamp_max = min_to < max_to ? max_to : min_to; + + for (int i : result_span.index_range()) { + result_span[i] = std::clamp(result_span[i], clamp_min, clamp_max); + } + } +} + +static void map_range_float3(Float3ReadAttribute attribute_input, + Float3WriteAttribute attribute_result, + const GeoNodeExecParams ¶ms) +{ + const bNode &node = params.node(); + NodeAttributeMapRange &node_storage = *(NodeAttributeMapRange *)node.storage; + const int interpolation_type = node_storage.interpolation_type; + const float3 min_from = params.get_input<float3>("From Min_001"); + const float3 max_from = params.get_input<float3>("From Max_001"); + const float3 min_to = params.get_input<float3>("To Min_001"); + const float3 max_to = params.get_input<float3>("To Max_001"); + + Span<float3> span = attribute_input.get_span(); + MutableSpan<float3> result_span = attribute_result.get_span(); + + switch (interpolation_type) { + case NODE_MAP_RANGE_LINEAR: { + for (int i : span.index_range()) { + result_span[i].x = map_linear(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x); + result_span[i].y = map_linear(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y); + result_span[i].z = map_linear(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z); + } + break; + } + case NODE_MAP_RANGE_STEPPED: { + const float3 steps = params.get_input<float3>("Steps_001"); + for (int i : span.index_range()) { + result_span[i].x = map_stepped( + span[i].x, min_from.x, max_from.x, min_to.x, max_to.x, steps.x); + result_span[i].y = map_stepped( + span[i].y, min_from.y, max_from.y, min_to.y, max_to.y, steps.y); + result_span[i].z = map_stepped( + span[i].z, min_from.z, max_from.z, min_to.z, max_to.z, steps.z); + } + break; + } + case NODE_MAP_RANGE_SMOOTHSTEP: { + for (int i : span.index_range()) { + result_span[i].x = map_smoothstep(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x); + result_span[i].y = map_smoothstep(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y); + result_span[i].z = map_smoothstep(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z); + } + break; + } + case NODE_MAP_RANGE_SMOOTHERSTEP: { + for (int i : span.index_range()) { + result_span[i].x = map_smootherstep(span[i].x, min_from.x, max_from.x, min_to.x, max_to.x); + result_span[i].y = map_smootherstep(span[i].y, min_from.y, max_from.y, min_to.y, max_to.y); + result_span[i].z = map_smootherstep(span[i].z, min_from.z, max_from.z, min_to.z, max_to.z); + } + break; + } + } + + if (ELEM(interpolation_type, NODE_MAP_RANGE_LINEAR, NODE_MAP_RANGE_STEPPED) && + params.get_input<bool>("Clamp")) { + /* Users can specify min_to > max_to, but clamping expects min < max. */ + float3 clamp_min; + float3 clamp_max; + clamp_min.x = min_to.x < max_to.x ? min_to.x : max_to.x; + clamp_max.x = min_to.x < max_to.x ? max_to.x : min_to.x; + clamp_min.y = min_to.y < max_to.y ? min_to.y : max_to.y; + clamp_max.y = min_to.y < max_to.y ? max_to.y : min_to.y; + clamp_min.z = min_to.z < max_to.z ? min_to.z : max_to.z; + clamp_max.z = min_to.z < max_to.z ? max_to.z : min_to.z; + + for (int i : result_span.index_range()) { + clamp_v3_v3v3(result_span[i], clamp_min, clamp_max); + } + } +} + +static AttributeDomain get_result_domain(const GeometryComponent &component, + StringRef source_name, + StringRef result_name) +{ + ReadAttributePtr result_attribute = component.attribute_try_get_for_read(result_name); + if (result_attribute) { + return result_attribute->domain(); + } + ReadAttributePtr source_attribute = component.attribute_try_get_for_read(source_name); + if (source_attribute) { + return source_attribute->domain(); + } + return ATTR_DOMAIN_POINT; +} + +static void map_range_attribute(GeometryComponent &component, const GeoNodeExecParams ¶ms) +{ + const std::string input_name = params.get_input<std::string>("Attribute"); + const std::string result_name = params.get_input<std::string>("Result"); + + if (input_name.empty() || result_name.empty()) { + return; + } + + const bNode &node = params.node(); + NodeAttributeMapRange &node_storage = *(NodeAttributeMapRange *)node.storage; + const CustomDataType data_type = static_cast<CustomDataType>(node_storage.data_type); + + const AttributeDomain domain = get_result_domain(component, input_name, result_name); + + ReadAttributePtr attribute_input = component.attribute_try_get_for_read( + input_name, domain, data_type); + + if (!attribute_input) { + params.error_message_add(NodeWarningType::Error, + TIP_("No attribute with name \"") + input_name + "\""); + return; + } + + OutputAttributePtr attribute_result = component.attribute_try_get_for_output( + result_name, domain, data_type); + if (!attribute_result) { + params.error_message_add(NodeWarningType::Error, + TIP_("Could not find or create attribute with name \"") + + result_name + "\""); + return; + } + + switch (data_type) { + case CD_PROP_FLOAT: { + map_range_float(*attribute_input, *attribute_result, params); + break; + } + case CD_PROP_FLOAT3: { + map_range_float3(*attribute_input, *attribute_result, params); + break; + } + default: + BLI_assert_unreachable(); + } + + attribute_result.apply_span_and_save(); +} + +static void geo_node_attribute_map_range_exec(GeoNodeExecParams params) +{ + GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); + + if (geometry_set.has<MeshComponent>()) { + map_range_attribute(geometry_set.get_component_for_write<MeshComponent>(), params); + } + if (geometry_set.has<PointCloudComponent>()) { + map_range_attribute(geometry_set.get_component_for_write<PointCloudComponent>(), params); + } + + params.set_output("Geometry", geometry_set); +} + +} // namespace blender::nodes + +void register_node_type_geo_attribute_map_range() +{ + static bNodeType ntype; + + geo_node_type_base( + &ntype, GEO_NODE_ATTRIBUTE_MAP_RANGE, "Attribute Map Range", NODE_CLASS_ATTRIBUTE, 0); + node_type_socket_templates( + &ntype, geo_node_attribute_map_range_in, geo_node_attribute_map_range_out); + ntype.geometry_node_execute = blender::nodes::geo_node_attribute_map_range_exec; + node_type_init(&ntype, geo_node_attribute_map_range_init); + node_type_update(&ntype, geo_node_attribute_map_range_update); + node_type_storage( + &ntype, "NodeAttributeMapRange", node_free_standard_storage, node_copy_standard_storage); + ntype.draw_buttons = fn_attribute_map_range_layout; + nodeRegisterType(&ntype); +} 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 9c48e7c44ba..0c970f0d2e2 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 @@ -223,8 +223,10 @@ Mesh *create_cylinder_or_cone_mesh(const float radius_top, transform.values, true); + BMeshToMeshParams params{}; + params.calc_object_remap = false; Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr); - BM_mesh_bm_to_me_for_eval(bm, mesh, nullptr); + BM_mesh_bm_to_me(nullptr, bm, mesh, ¶ms); BM_mesh_free(bm); return mesh; 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 1803a13f651..f8a9bfd2ed1 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 @@ -50,8 +50,10 @@ static Mesh *create_cube_mesh(const float size) size, true); + BMeshToMeshParams params{}; + params.calc_object_remap = false; Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr); - BM_mesh_bm_to_me_for_eval(bm, mesh, nullptr); + BM_mesh_bm_to_me(nullptr, bm, mesh, ¶ms); BM_mesh_free(bm); return mesh; diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_plane.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc index eff84d7d1ad..1b9ec91a2f6 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_plane.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_grid.cc @@ -27,14 +27,14 @@ #include "node_geometry_util.hh" -static bNodeSocketTemplate geo_node_mesh_primitive_plane_in[] = { +static bNodeSocketTemplate geo_node_mesh_primitive_grid_in[] = { {SOCK_FLOAT, N_("Size"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE}, - {SOCK_INT, N_("Vertices X"), 10, 0.0f, 0.0f, 0.0f, 2, 1000}, - {SOCK_INT, N_("Vertices Y"), 10, 0.0f, 0.0f, 0.0f, 2, 1000}, + {SOCK_INT, N_("Vertices X"), 3, 0.0f, 0.0f, 0.0f, 2, 1000}, + {SOCK_INT, N_("Vertices Y"), 3, 0.0f, 0.0f, 0.0f, 2, 1000}, {-1, ""}, }; -static bNodeSocketTemplate geo_node_mesh_primitive_plane_out[] = { +static bNodeSocketTemplate geo_node_mesh_primitive_grid_out[] = { {SOCK_GEOMETRY, N_("Geometry")}, {-1, ""}, }; @@ -51,14 +51,14 @@ static void calculate_uvs(Mesh *mesh, Span<MVert> verts, Span<MLoop> loops, cons for (const int i : loops.index_range()) { const float3 &co = verts[loops[i].v].co; - uvs[i].x = (co.x + size) / (size * 2.0f); - uvs[i].y = (co.y + size) / (size * 2.0f); + uvs[i].x = (co.x + (size * 0.5)) / size; + uvs[i].y = (co.y + (size * 0.5)) / size; } uv_attribute.apply_span_and_save(); } -static Mesh *create_plane_mesh(const int verts_x, const int verts_y, const float size) +static Mesh *create_grid_mesh(const int verts_x, const int verts_y, const float size) { const int edges_x = verts_x - 1; const int edges_y = verts_y - 1; @@ -75,9 +75,9 @@ static Mesh *create_plane_mesh(const int verts_x, const int verts_y, const float { const float dx = size / edges_x; const float dy = size / edges_y; - float x = -size; + float x = -size * 0.5; for (const int x_index : IndexRange(verts_x)) { - float y = -size; + float y = -size * 0.5; for (const int y_index : IndexRange(verts_y)) { const int vert_index = x_index * verts_y + y_index; verts[vert_index].co[0] = x; @@ -147,7 +147,7 @@ static Mesh *create_plane_mesh(const int verts_x, const int verts_y, const float return mesh; } -static void geo_node_mesh_primitive_plane_exec(GeoNodeExecParams params) +static void geo_node_mesh_primitive_grid_exec(GeoNodeExecParams params) { const float size = params.extract_input<float>("Size"); const int verts_x = params.extract_input<int>("Vertices X"); @@ -157,7 +157,7 @@ static void geo_node_mesh_primitive_plane_exec(GeoNodeExecParams params) return; } - Mesh *mesh = create_plane_mesh(verts_x, verts_y, size); + Mesh *mesh = create_grid_mesh(verts_x, verts_y, size); BLI_assert(BKE_mesh_is_valid(mesh)); params.set_output("Geometry", GeometrySet::create_with_mesh(mesh)); @@ -165,13 +165,13 @@ static void geo_node_mesh_primitive_plane_exec(GeoNodeExecParams params) } // namespace blender::nodes -void register_node_type_geo_mesh_primitive_plane() +void register_node_type_geo_mesh_primitive_grid() { static bNodeType ntype; - geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_PLANE, "Plane", NODE_CLASS_GEOMETRY, 0); + geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_GRID, "Grid", NODE_CLASS_GEOMETRY, 0); node_type_socket_templates( - &ntype, geo_node_mesh_primitive_plane_in, geo_node_mesh_primitive_plane_out); - ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_plane_exec; + &ntype, geo_node_mesh_primitive_grid_in, geo_node_mesh_primitive_grid_out); + ntype.geometry_node_execute = blender::nodes::geo_node_mesh_primitive_grid_exec; nodeRegisterType(&ntype); } 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 f16b37fe977..242cc6ed7df 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 @@ -52,8 +52,10 @@ static Mesh *create_ico_sphere_mesh(const int subdivisions, const float radius) transform.values, true); + BMeshToMeshParams params{}; + params.calc_object_remap = false; Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr); - BM_mesh_bm_to_me_for_eval(bm, mesh, nullptr); + BM_mesh_bm_to_me(nullptr, bm, mesh, ¶ms); BM_mesh_free(bm); return 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 b7d249c18bc..8efba91da1a 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 @@ -85,8 +85,10 @@ static Mesh *create_uv_sphere_mesh_bmesh(const float radius, const int segments, transform.values, true); + BMeshToMeshParams params{}; + params.calc_object_remap = false; Mesh *mesh = (Mesh *)BKE_id_new_nomain(ID_ME, nullptr); - BM_mesh_bm_to_me_for_eval(bm, mesh, nullptr); + BM_mesh_bm_to_me(nullptr, bm, mesh, ¶ms); BM_mesh_free(bm); return mesh; diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc index 4795970377a..1e1f5e9d085 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc @@ -310,10 +310,10 @@ BLI_NOINLINE static void interpolate_attribute_corner(const Mesh &mesh, } template<typename T> -BLI_NOINLINE static void interpolate_attribute_polygon(const Mesh &mesh, - const Span<int> looptri_indices, - const Span<T> data_in, - MutableSpan<T> data_out) +BLI_NOINLINE static void interpolate_attribute_face(const Mesh &mesh, + const Span<int> looptri_indices, + const Span<T> data_in, + MutableSpan<T> data_out) { BLI_assert(data_in.size() == mesh.totpoly); Span<MLoopTri> looptris = get_mesh_looptris(mesh); @@ -344,8 +344,8 @@ BLI_NOINLINE static void interpolate_attribute(const Mesh &mesh, mesh, bary_coords, looptri_indices, source_span, output_span); break; } - case ATTR_DOMAIN_POLYGON: { - interpolate_attribute_polygon<T>(mesh, looptri_indices, source_span, output_span); + case ATTR_DOMAIN_FACE: { + interpolate_attribute_face<T>(mesh, looptri_indices, source_span, output_span); break; } default: { @@ -636,7 +636,8 @@ static void geo_node_point_distribute_exec(GeoNodeExecParams params) return; } - Vector<GeometryInstanceGroup> set_groups = bke::geometry_set_gather_instances(geometry_set); + Vector<GeometryInstanceGroup> set_groups; + geometry_set_gather_instances(geometry_set, set_groups); if (set_groups.is_empty()) { params.set_output("Geometry", GeometrySet()); return; diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc index dbbb73bd36d..5d8f0a76719 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc @@ -188,9 +188,8 @@ static void add_instances_from_geometry_component(InstancesComponent &instances, for (const int i : IndexRange(domain_size)) { if (instances_data[i].has_value()) { - float transform[4][4]; - loc_eul_size_to_mat4(transform, positions[i], rotations[i], scales[i]); - instances.add_instance(*instances_data[i], transform, ids[i]); + const float4x4 matrix = float4x4::from_loc_eul_scale(positions[i], rotations[i], scales[i]); + instances.add_instance(*instances_data[i], matrix, ids[i]); } } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc index b79ca0a6197..eb441a0a568 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc @@ -38,7 +38,7 @@ static bNodeSocketTemplate geo_node_points_to_volume_in[] = { {-1, ""}, }; -static bNodeSocketTemplate geo_node_point_translate_out[] = { +static bNodeSocketTemplate geo_node_points_to_volume_out[] = { {SOCK_GEOMETRY, N_("Geometry")}, {-1, ""}, }; @@ -262,7 +262,7 @@ void register_node_type_geo_points_to_volume() geo_node_type_base( &ntype, GEO_NODE_POINTS_TO_VOLUME, "Points to Volume", NODE_CLASS_GEOMETRY, 0); - node_type_socket_templates(&ntype, geo_node_points_to_volume_in, geo_node_point_translate_out); + node_type_socket_templates(&ntype, geo_node_points_to_volume_in, geo_node_points_to_volume_out); node_type_storage(&ntype, "NodeGeometryPointsToVolume", node_free_standard_storage, diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform.cc b/source/blender/nodes/geometry/nodes/node_geo_transform.cc index ef6f0be40f2..2c05c98c9ba 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc @@ -18,7 +18,7 @@ # include <openvdb/openvdb.h> #endif -#include "BLI_math_matrix.h" +#include "BLI_float4x4.hh" #include "DNA_pointcloud_types.h" #include "DNA_volume_types.h" @@ -65,13 +65,12 @@ void transform_mesh(Mesh *mesh, /* Use only translation if rotation and scale are zero. */ if (use_translate(rotation, scale)) { if (!translation.is_zero()) { - BKE_mesh_translate(mesh, translation, true); + BKE_mesh_translate(mesh, translation, false); } } else { - float mat[4][4]; - loc_eul_size_to_mat4(mat, translation, rotation, scale); - BKE_mesh_transform(mesh, mat, true); + const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale); + BKE_mesh_transform(mesh, matrix.values, false); BKE_mesh_calc_normals(mesh); } } @@ -83,15 +82,15 @@ static void transform_pointcloud(PointCloud *pointcloud, { /* Use only translation if rotation and scale don't apply. */ if (use_translate(rotation, scale)) { - for (int i = 0; i < pointcloud->totpoint; i++) { + for (const int i : IndexRange(pointcloud->totpoint)) { add_v3_v3(pointcloud->co[i], translation); } } else { - float mat[4][4]; - loc_eul_size_to_mat4(mat, translation, rotation, scale); - for (int i = 0; i < pointcloud->totpoint; i++) { - mul_m4_v3(mat, pointcloud->co[i]); + const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale); + for (const int i : IndexRange(pointcloud->totpoint)) { + float3 &co = *(float3 *)pointcloud->co[i]; + co = matrix * co; } } } @@ -110,11 +109,9 @@ static void transform_instances(InstancesComponent &instances, } } else { - float mat[4][4]; - - loc_eul_size_to_mat4(mat, translation, rotation, scale); + const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, scale); for (float4x4 &transform : transforms) { - mul_m4_m4_pre(transform.ptr(), mat); + transform = matrix * transform; } } } @@ -136,8 +133,7 @@ static void transform_volume(Volume *volume, Main *bmain = DEG_get_bmain(params.depsgraph()); BKE_volume_load(volume, bmain); - float matrix[4][4]; - loc_eul_size_to_mat4(matrix, translation, rotation, limited_scale); + const float4x4 matrix = float4x4::from_loc_eul_scale(translation, rotation, limited_scale); openvdb::Mat4s vdb_matrix; memcpy(vdb_matrix.asPointer(), matrix, sizeof(float[4][4])); 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 54dccb613a1..1c0e7106b19 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 @@ -36,7 +36,7 @@ static bNodeSocketTemplate geo_node_volume_to_mesh_in[] = { {SOCK_GEOMETRY, N_("Geometry")}, - {SOCK_STRING, N_("Grid")}, + {SOCK_STRING, N_("Density")}, {SOCK_FLOAT, N_("Voxel Size"), 0.3f, 0.0f, 0.0f, 0.0f, 0.01f, FLT_MAX}, {SOCK_FLOAT, N_("Voxel Amount"), 64.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX}, {SOCK_FLOAT, N_("Threshold"), 0.1f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX}, @@ -64,7 +64,7 @@ static void geo_node_volume_to_mesh_init(bNodeTree *UNUSED(ntree), bNode *node) sizeof(NodeGeometryVolumeToMesh), __func__); data->resolution_mode = VOLUME_TO_MESH_RESOLUTION_MODE_GRID; - bNodeSocket *grid_socket = nodeFindSocket(node, SOCK_IN, "Grid"); + bNodeSocket *grid_socket = nodeFindSocket(node, SOCK_IN, "Density"); bNodeSocketValueString *grid_socket_value = (bNodeSocketValueString *)grid_socket->default_value; STRNCPY(grid_socket_value->value, "density"); @@ -120,7 +120,7 @@ static void create_mesh_from_volume(GeometrySet &geometry_set_in, Main *bmain = DEG_get_bmain(params.depsgraph()); BKE_volume_load(const_cast<Volume *>(volume), bmain); - const std::string grid_name = params.get_input<std::string>("Grid"); + const std::string grid_name = params.get_input<std::string>("Density"); VolumeGrid *volume_grid = BKE_volume_grid_find(volume, grid_name.c_str()); if (volume_grid == nullptr) { return; diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc index 26df3f77738..b583523da98 100644 --- a/source/blender/nodes/intern/node_socket.cc +++ b/source/blender/nodes/intern/node_socket.cc @@ -52,7 +52,7 @@ struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree, struct bNode *node, struct bNodeSocketTemplate *stemp, - int in_out) + eNodeSocketInOut in_out) { bNodeSocket *sock = nodeAddStaticSocket( ntree, node, in_out, stemp->type, stemp->subtype, stemp->identifier, stemp->name); @@ -102,8 +102,11 @@ struct bNodeSocket *node_add_socket_from_template(struct bNodeTree *ntree, return sock; } -static bNodeSocket *verify_socket_template( - bNodeTree *ntree, bNode *node, int in_out, ListBase *socklist, bNodeSocketTemplate *stemp) +static bNodeSocket *verify_socket_template(bNodeTree *ntree, + bNode *node, + eNodeSocketInOut in_out, + ListBase *socklist, + bNodeSocketTemplate *stemp) { bNodeSocket *sock; @@ -132,7 +135,7 @@ static bNodeSocket *verify_socket_template( static void verify_socket_template_list(bNodeTree *ntree, bNode *node, - int in_out, + eNodeSocketInOut in_out, ListBase *socklist, bNodeSocketTemplate *stemp_first) { diff --git a/source/blender/nodes/intern/node_tree_multi_function.cc b/source/blender/nodes/intern/node_tree_multi_function.cc index b973350becd..c77a6b42f97 100644 --- a/source/blender/nodes/intern/node_tree_multi_function.cc +++ b/source/blender/nodes/intern/node_tree_multi_function.cc @@ -164,7 +164,8 @@ static DataTypeConversions create_implicit_conversions() add_implicit_conversion<float, float2>(conversions); add_implicit_conversion<float, float3>(conversions); add_implicit_conversion<float, int32_t>(conversions); - add_implicit_conversion<float, bool>(conversions); + add_implicit_conversion<float, bool>( + conversions, "float to boolean", [](float a) { return a > 0.0f; }); add_implicit_conversion<float, Color4f>( conversions, "float to Color4f", [](float a) { return Color4f(a, a, a, 1.0f); }); @@ -189,7 +190,8 @@ static DataTypeConversions create_implicit_conversions() add_implicit_conversion<float3, Color4f>( conversions, "float3 to Color4f", [](float3 a) { return Color4f(a.x, a.y, a.z, 1.0f); }); - add_implicit_conversion<int32_t, bool>(conversions); + add_implicit_conversion<int32_t, bool>( + conversions, "int32 to boolean", [](int32_t a) { return a > 0; }); add_implicit_conversion<int32_t, float>(conversions); add_implicit_conversion<int32_t, float2>( conversions, "int32 to float2", [](int32_t a) { return float2((float)a); }); @@ -209,9 +211,8 @@ static DataTypeConversions create_implicit_conversions() return (a) ? Color4f(1.0f, 1.0f, 1.0f, 1.0f) : Color4f(0.0f, 0.0f, 0.0f, 1.0f); }); - add_implicit_conversion<Color4f, bool>(conversions, "Color4f to boolean", [](Color4f a) { - return a.r != 0.0f && a.g != 0.0f && a.b != 0.0f; - }); + add_implicit_conversion<Color4f, bool>( + conversions, "Color4f to boolean", [](Color4f a) { return rgb_to_grayscale(a) > 0.0f; }); add_implicit_conversion<Color4f, float>( conversions, "Color4f to float", [](Color4f a) { return rgb_to_grayscale(a); }); add_implicit_conversion<Color4f, float2>( diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc index 3a9822fbc8e..472f903e1a5 100644 --- a/source/blender/nodes/shader/nodes/node_shader_vector_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_vector_math.cc @@ -23,6 +23,8 @@ #include "node_shader_util.h" +#include "NOD_math_functions.hh" + /* **************** VECTOR MATH ******************** */ static bNodeSocketTemplate sh_node_vector_math_in[] = { {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 1.0f, -10000.0f, 10000.0f, PROP_NONE}, @@ -177,117 +179,79 @@ static const blender::fn::MultiFunction &get_multi_function( { using blender::float3; - const int mode = builder.bnode().custom1; - switch (mode) { - case NODE_VECTOR_MATH_ADD: { - static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{ - "Add", [](float3 a, float3 b) { return a + b; }}; - return fn; - } - case NODE_VECTOR_MATH_SUBTRACT: { - static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{ - "Subtract", [](float3 a, float3 b) { return a - b; }}; - return fn; - } - case NODE_VECTOR_MATH_MULTIPLY: { - static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{ - "Multiply", [](float3 a, float3 b) { return a * b; }}; - return fn; - } - case NODE_VECTOR_MATH_DIVIDE: { - static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{ - "Divide", [](float3 a, float3 b) { return float3::safe_divide(a, b); }}; - return fn; - } - case NODE_VECTOR_MATH_CROSS_PRODUCT: { - static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{ - "Cross Product", float3::cross_high_precision}; - return fn; - } - case NODE_VECTOR_MATH_PROJECT: { - static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{"Project", float3::project}; - return fn; - } - case NODE_VECTOR_MATH_REFLECT: { - static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{ - "Reflect", [](float3 a, float3 b) { return a.reflected(b); }}; - return fn; - } - case NODE_VECTOR_MATH_DOT_PRODUCT: { - static blender::fn::CustomMF_SI_SI_SO<float3, float3, float> fn{"Dot Product", float3::dot}; - return fn; - } - case NODE_VECTOR_MATH_DISTANCE: { - static blender::fn::CustomMF_SI_SI_SO<float3, float3, float> fn{"Distance", - float3::distance}; - return fn; - } - case NODE_VECTOR_MATH_LENGTH: { - static blender::fn::CustomMF_SI_SO<float3, float> fn{"Length", - [](float3 a) { return a.length(); }}; - return fn; - } - case NODE_VECTOR_MATH_SCALE: { - static blender::fn::CustomMF_SI_SI_SO<float3, float, float3> fn{ - "Scale", [](float3 a, float factor) { return a * factor; }}; - return fn; - } - case NODE_VECTOR_MATH_NORMALIZE: { - static blender::fn::CustomMF_SI_SO<float3, float3> fn{ - "Normalize", [](float3 a) { return a.normalized(); }}; - return fn; - } - case NODE_VECTOR_MATH_REFRACT: { - static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{ - "Refract", - [](float3 a, float3 b, float c) { return float3::refract(a, b.normalized(), c); }}; - return fn; - } - case NODE_VECTOR_MATH_FACEFORWARD: { - static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{ - "Faceforward", float3::faceforward}; - return fn; - } - case NODE_VECTOR_MATH_SNAP: { - return builder.get_not_implemented_fn(); - } - case NODE_VECTOR_MATH_FLOOR: { - return builder.get_not_implemented_fn(); - } - case NODE_VECTOR_MATH_CEIL: { - return builder.get_not_implemented_fn(); - } - case NODE_VECTOR_MATH_MODULO: { - return builder.get_not_implemented_fn(); - } - case NODE_VECTOR_MATH_FRACTION: { - return builder.get_not_implemented_fn(); - } - case NODE_VECTOR_MATH_ABSOLUTE: { - return builder.get_not_implemented_fn(); - } - case NODE_VECTOR_MATH_MINIMUM: { - return builder.get_not_implemented_fn(); - } - case NODE_VECTOR_MATH_MAXIMUM: { - return builder.get_not_implemented_fn(); - } - case NODE_VECTOR_MATH_WRAP: { - return builder.get_not_implemented_fn(); - } - case NODE_VECTOR_MATH_SINE: { - return builder.get_not_implemented_fn(); - } - case NODE_VECTOR_MATH_COSINE: { - return builder.get_not_implemented_fn(); - } - case NODE_VECTOR_MATH_TANGENT: { - return builder.get_not_implemented_fn(); - } - default: - BLI_assert_unreachable(); - return builder.get_not_implemented_fn(); - }; + NodeVectorMathOperation operation = NodeVectorMathOperation(builder.bnode().custom1); + + const blender::fn::MultiFunction *multi_fn = nullptr; + + blender::nodes::try_dispatch_float_math_fl3_fl3_to_fl3( + operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { + static blender::fn::CustomMF_SI_SI_SO<float3, float3, float3> fn{info.title_case_name, + function}; + multi_fn = &fn; + }); + if (multi_fn != nullptr) { + return *multi_fn; + } + + blender::nodes::try_dispatch_float_math_fl3_fl3_fl3_to_fl3( + operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { + static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{ + info.title_case_name, function}; + multi_fn = &fn; + }); + if (multi_fn != nullptr) { + return *multi_fn; + } + + blender::nodes::try_dispatch_float_math_fl3_fl3_fl_to_fl3( + operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { + static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{ + info.title_case_name, function}; + multi_fn = &fn; + }); + if (multi_fn != nullptr) { + return *multi_fn; + } + + blender::nodes::try_dispatch_float_math_fl3_fl3_to_fl( + operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { + static blender::fn::CustomMF_SI_SI_SO<float3, float3, float> fn{info.title_case_name, + function}; + multi_fn = &fn; + }); + if (multi_fn != nullptr) { + return *multi_fn; + } + + blender::nodes::try_dispatch_float_math_fl3_fl_to_fl3( + operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { + static blender::fn::CustomMF_SI_SI_SO<float3, float, float3> fn{info.title_case_name, + function}; + multi_fn = &fn; + }); + if (multi_fn != nullptr) { + return *multi_fn; + } + + blender::nodes::try_dispatch_float_math_fl3_to_fl3( + operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { + static blender::fn::CustomMF_SI_SO<float3, float3> fn{info.title_case_name, function}; + multi_fn = &fn; + }); + if (multi_fn != nullptr) { + return *multi_fn; + } + + blender::nodes::try_dispatch_float_math_fl3_to_fl( + operation, [&](auto function, const blender::nodes::FloatMathOperationInfo &info) { + static blender::fn::CustomMF_SI_SO<float3, float> fn{info.title_case_name, function}; + multi_fn = &fn; + }); + if (multi_fn != nullptr) { + return *multi_fn; + } + + return builder.get_not_implemented_fn(); } static void sh_node_vector_math_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) |