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')
-rw-r--r--source/blender/nodes/CMakeLists.txt20
-rw-r--r--source/blender/nodes/NOD_function.h1
-rw-r--r--source/blender/nodes/NOD_geometry.h12
-rw-r--r--source/blender/nodes/NOD_geometry_exec.hh8
-rw-r--r--source/blender/nodes/NOD_geometry_nodes_eval_log.hh309
-rw-r--r--source/blender/nodes/NOD_static_types.h15
-rw-r--r--source/blender/nodes/composite/node_composite_tree.c7
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_antialiasing.c6
-rw-r--r--source/blender/nodes/composite/nodes/node_composite_zcombine.c2
-rw-r--r--source/blender/nodes/function/nodes/node_fn_float_to_int.cc95
-rw-r--r--source/blender/nodes/geometry/node_geometry_tree.cc30
-rw-r--r--source/blender/nodes/geometry/node_geometry_util.hh22
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_curve_map.cc13
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_attribute_transfer.cc6
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_endpoints.cc223
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc20
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc146
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc241
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc4
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc17
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc76
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_mesh.cc10
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc47
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_mesh_primitive_circle.cc3
-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_subdivide.cc (renamed from source/blender/nodes/geometry/nodes/node_geo_subdivide.cc)18
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc3
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_raycast.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc2
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_viewer.cc31
-rw-r--r--source/blender/nodes/intern/geometry_nodes_eval_log.cc361
-rw-r--r--source/blender/nodes/intern/node_common.c11
-rw-r--r--source/blender/nodes/intern/node_geometry_exec.cc16
-rw-r--r--source/blender/nodes/intern/node_socket.cc4
-rw-r--r--source/blender/nodes/intern/node_tree_ref.cc2
-rw-r--r--source/blender/nodes/shader/node_shader_tree.c9
-rw-r--r--source/blender/nodes/shader/nodes/node_shader_hueSatVal.c2
-rw-r--r--source/blender/nodes/texture/node_texture_tree.c7
41 files changed, 1630 insertions, 180 deletions
diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt
index d27f45c4d98..929b1c3e6b2 100644
--- a/source/blender/nodes/CMakeLists.txt
+++ b/source/blender/nodes/CMakeLists.txt
@@ -134,6 +134,7 @@ set(SRC
function/nodes/node_fn_boolean_math.cc
function/nodes/node_fn_float_compare.cc
+ function/nodes/node_fn_float_to_int.cc
function/nodes/node_fn_input_string.cc
function/nodes/node_fn_input_vector.cc
function/nodes/node_fn_random_float.cc
@@ -165,17 +166,20 @@ set(SRC
geometry/nodes/node_geo_collection_info.cc
geometry/nodes/node_geo_common.cc
geometry/nodes/node_geo_convex_hull.cc
- geometry/nodes/node_geo_curve_length.cc
+ geometry/nodes/node_geo_curve_endpoints.cc
+ geometry/nodes/node_geo_curve_length.cc
geometry/nodes/node_geo_curve_primitive_bezier_segment.cc
geometry/nodes/node_geo_curve_primitive_circle.cc
+ geometry/nodes/node_geo_curve_primitive_line.cc
geometry/nodes/node_geo_curve_primitive_quadratic_bezier.cc
+ geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
geometry/nodes/node_geo_curve_primitive_spiral.cc
geometry/nodes/node_geo_curve_primitive_star.cc
- geometry/nodes/node_geo_curve_to_mesh.cc
- geometry/nodes/node_geo_curve_to_points.cc
geometry/nodes/node_geo_curve_resample.cc
geometry/nodes/node_geo_curve_reverse.cc
geometry/nodes/node_geo_curve_subdivide.cc
+ geometry/nodes/node_geo_curve_to_mesh.cc
+ geometry/nodes/node_geo_curve_to_points.cc
geometry/nodes/node_geo_delete_geometry.cc
geometry/nodes/node_geo_edge_split.cc
geometry/nodes/node_geo_input_material.cc
@@ -191,6 +195,7 @@ set(SRC
geometry/nodes/node_geo_mesh_primitive_ico_sphere.cc
geometry/nodes/node_geo_mesh_primitive_line.cc
geometry/nodes/node_geo_mesh_primitive_uv_sphere.cc
+ geometry/nodes/node_geo_mesh_subdivide.cc
geometry/nodes/node_geo_mesh_to_curve.cc
geometry/nodes/node_geo_object_info.cc
geometry/nodes/node_geo_point_distribute.cc
@@ -203,11 +208,11 @@ set(SRC
geometry/nodes/node_geo_raycast.cc
geometry/nodes/node_geo_select_by_material.cc
geometry/nodes/node_geo_separate_components.cc
- geometry/nodes/node_geo_subdivide.cc
geometry/nodes/node_geo_subdivision_surface.cc
geometry/nodes/node_geo_switch.cc
geometry/nodes/node_geo_transform.cc
geometry/nodes/node_geo_triangulate.cc
+ geometry/nodes/node_geo_viewer.cc
geometry/nodes/node_geo_volume_to_mesh.cc
geometry/node_geometry_exec.cc
geometry/node_geometry_tree.cc
@@ -333,6 +338,7 @@ set(SRC
texture/node_texture_util.c
intern/derived_node_tree.cc
+ intern/geometry_nodes_eval_log.cc
intern/math_functions.cc
intern/attribute_ref.cc
intern/node_common.c
@@ -358,6 +364,7 @@ set(SRC
NOD_function.h
NOD_geometry.h
NOD_geometry_exec.hh
+ NOD_geometry_nodes_eval_log.hh
NOD_math_functions.hh
NOD_node_tree_multi_function.hh
NOD_node_tree_ref.hh
@@ -418,6 +425,11 @@ if(WITH_TBB)
${TBB_INCLUDE_DIRS}
)
add_definitions(-DWITH_TBB)
+ if(WIN32)
+ # TBB includes Windows.h which will define min/max macros
+ # that will collide with the stl versions.
+ add_definitions(-DNOMINMAX)
+ endif()
endif()
if(WITH_IMAGE_OPENEXR)
diff --git a/source/blender/nodes/NOD_function.h b/source/blender/nodes/NOD_function.h
index b31b5326d66..29f1a465491 100644
--- a/source/blender/nodes/NOD_function.h
+++ b/source/blender/nodes/NOD_function.h
@@ -22,6 +22,7 @@ extern "C" {
void register_node_type_fn_boolean_math(void);
void register_node_type_fn_float_compare(void);
+void register_node_type_fn_float_to_int(void);
void register_node_type_fn_input_string(void);
void register_node_type_fn_input_vector(void);
void register_node_type_fn_random_float(void);
diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h
index 788978c4246..3b546d208e4 100644
--- a/source/blender/nodes/NOD_geometry.h
+++ b/source/blender/nodes/NOD_geometry.h
@@ -43,27 +43,30 @@ void register_node_type_geo_attribute_math(void);
void register_node_type_geo_attribute_mix(void);
void register_node_type_geo_attribute_proximity(void);
void register_node_type_geo_attribute_randomize(void);
+void register_node_type_geo_attribute_remove(void);
void register_node_type_geo_attribute_separate_xyz(void);
void register_node_type_geo_attribute_transfer(void);
void register_node_type_geo_attribute_vector_math(void);
void register_node_type_geo_attribute_vector_rotate(void);
-void register_node_type_geo_attribute_remove(void);
void register_node_type_geo_attribute_set(void);
void register_node_type_geo_boolean(void);
void register_node_type_geo_bounding_box(void);
void register_node_type_geo_collection_info(void);
void register_node_type_geo_convex_hull(void);
+void register_node_type_geo_curve_endpoints(void);
void register_node_type_geo_curve_length(void);
void register_node_type_geo_curve_primitive_bezier_segment(void);
void register_node_type_geo_curve_primitive_circle(void);
+void register_node_type_geo_curve_primitive_line(void);
void register_node_type_geo_curve_primitive_quadratic_bezier(void);
+void register_node_type_geo_curve_primitive_quadrilateral(void);
void register_node_type_geo_curve_primitive_spiral(void);
void register_node_type_geo_curve_primitive_star(void);
-void register_node_type_geo_curve_to_mesh(void);
-void register_node_type_geo_curve_to_points(void);
void register_node_type_geo_curve_resample(void);
void register_node_type_geo_curve_reverse(void);
void register_node_type_geo_curve_subdivide(void);
+void register_node_type_geo_curve_to_mesh(void);
+void register_node_type_geo_curve_to_points(void);
void register_node_type_geo_delete_geometry(void);
void register_node_type_geo_edge_split(void);
void register_node_type_geo_input_material(void);
@@ -79,6 +82,7 @@ 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);
+void register_node_type_geo_mesh_subdivide(void);
void register_node_type_geo_mesh_to_curve(void);
void register_node_type_geo_object_info(void);
void register_node_type_geo_point_distribute(void);
@@ -92,11 +96,11 @@ void register_node_type_geo_raycast(void);
void register_node_type_geo_sample_texture(void);
void register_node_type_geo_select_by_material(void);
void register_node_type_geo_separate_components(void);
-void register_node_type_geo_subdivide(void);
void register_node_type_geo_subdivision_surface(void);
void register_node_type_geo_switch(void);
void register_node_type_geo_transform(void);
void register_node_type_geo_triangulate(void);
+void register_node_type_geo_viewer(void);
void register_node_type_geo_volume_to_mesh(void);
#ifdef __cplusplus
diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh
index caefccfdba0..cc01465f4e5 100644
--- a/source/blender/nodes/NOD_geometry_exec.hh
+++ b/source/blender/nodes/NOD_geometry_exec.hh
@@ -21,12 +21,12 @@
#include "BKE_attribute_access.hh"
#include "BKE_geometry_set.hh"
#include "BKE_geometry_set_instances.hh"
-#include "BKE_node_ui_storage.hh"
#include "DNA_node_types.h"
#include "NOD_attribute_ref.hh"
#include "NOD_derived_node_tree.hh"
+#include "NOD_geometry_nodes_eval_log.hh"
struct Depsgraph;
struct ModifierData;
@@ -53,10 +53,11 @@ using fn::GVMutableArray;
using fn::GVMutableArray_GSpan;
using fn::GVMutableArray_Typed;
using fn::GVMutableArrayPtr;
+using geometry_nodes_eval_log::NodeWarningType;
/**
- * This class exists to separate the memory management details of the geometry nodes evaluator from
- * the node execution functions and related utilities.
+ * This class exists to separate the memory management details of the geometry nodes evaluator
+ * from the node execution functions and related utilities.
*/
class GeoNodeExecParamsProvider {
public:
@@ -64,6 +65,7 @@ class GeoNodeExecParamsProvider {
const Object *self_object = nullptr;
const ModifierData *modifier = nullptr;
Depsgraph *depsgraph = nullptr;
+ geometry_nodes_eval_log::GeoLogger *logger = nullptr;
/**
* Returns true when the node is allowed to get/extract the input value. The identifier is
diff --git a/source/blender/nodes/NOD_geometry_nodes_eval_log.hh b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
new file mode 100644
index 00000000000..b85862a0176
--- /dev/null
+++ b/source/blender/nodes/NOD_geometry_nodes_eval_log.hh
@@ -0,0 +1,309 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+/**
+ * Many geometry nodes related UI features need access to data produced during evaluation. Not only
+ * is the final output required but also the intermediate results. Those features include
+ * attribute search, node warnings, socket inspection and the viewer node.
+ *
+ * This file provides the framework for logging data during evaluation and accessing the data after
+ * evaluation.
+ *
+ * During logging every thread gets its own local logger to avoid too much locking (logging
+ * generally happens for every socket). After geometry nodes evaluation is done, the thread-local
+ * logging information is combined and post-processed to make it easier for the UI to lookup.
+ * necessary information.
+ */
+
+#include "BLI_enumerable_thread_specific.hh"
+#include "BLI_linear_allocator.hh"
+#include "BLI_map.hh"
+
+#include "BKE_geometry_set.hh"
+
+#include "FN_generic_pointer.hh"
+
+#include "NOD_derived_node_tree.hh"
+
+struct SpaceNode;
+struct SpaceSpreadsheet;
+
+namespace blender::nodes::geometry_nodes_eval_log {
+
+using fn::GMutablePointer;
+using fn::GPointer;
+
+/** Contains information about a value that has been computed during geometry nodes evaluation. */
+class ValueLog {
+ public:
+ virtual ~ValueLog() = default;
+};
+
+/** Contains an owned copy of a value of a generic type. */
+class GenericValueLog : public ValueLog {
+ private:
+ GMutablePointer data_;
+
+ public:
+ GenericValueLog(GMutablePointer data) : data_(data)
+ {
+ }
+
+ ~GenericValueLog()
+ {
+ data_.destruct();
+ }
+
+ GPointer value() const
+ {
+ return data_;
+ }
+};
+
+struct GeometryAttributeInfo {
+ std::string name;
+ AttributeDomain domain;
+ CustomDataType data_type;
+};
+
+/** Contains information about a geometry set. In most cases this does not store the entire
+ * geometry set as this would require too much memory. */
+class GeometryValueLog : public ValueLog {
+ private:
+ Vector<GeometryAttributeInfo> attributes_;
+ Vector<GeometryComponentType> component_types_;
+ std::unique_ptr<GeometrySet> full_geometry_;
+
+ public:
+ struct MeshInfo {
+ int tot_verts, tot_edges, tot_faces;
+ };
+ struct CurveInfo {
+ int tot_splines;
+ };
+ struct PointCloudInfo {
+ int tot_points;
+ };
+ struct InstancesInfo {
+ int tot_instances;
+ };
+
+ std::optional<MeshInfo> mesh_info;
+ std::optional<CurveInfo> curve_info;
+ std::optional<PointCloudInfo> pointcloud_info;
+ std::optional<InstancesInfo> instances_info;
+
+ GeometryValueLog(const GeometrySet &geometry_set, bool log_full_geometry);
+
+ Span<GeometryAttributeInfo> attributes() const
+ {
+ return attributes_;
+ }
+
+ Span<GeometryComponentType> component_types() const
+ {
+ return component_types_;
+ }
+
+ const GeometrySet *full_geometry() const
+ {
+ return full_geometry_.get();
+ }
+};
+
+enum class NodeWarningType {
+ Error,
+ Warning,
+ Info,
+};
+
+struct NodeWarning {
+ NodeWarningType type;
+ std::string message;
+};
+
+struct NodeWithWarning {
+ DNode node;
+ NodeWarning warning;
+};
+
+/** The same value can be referenced by multiple sockets when they are linked. */
+struct ValueOfSockets {
+ Span<DSocket> sockets;
+ destruct_ptr<ValueLog> value;
+};
+
+class GeoLogger;
+class ModifierLog;
+
+/** Every thread has its own local logger to avoid having to communicate between threads during
+ * evaluation. After evaluation the individual logs are combined. */
+class LocalGeoLogger {
+ private:
+ /* Back pointer to the owner of this local logger. */
+ GeoLogger *main_logger_;
+ /* Allocator for the many small allocations during logging. This is in a `unique_ptr` so that
+ * ownership can be transferred later on. */
+ std::unique_ptr<LinearAllocator<>> allocator_;
+ Vector<ValueOfSockets> values_;
+ Vector<NodeWithWarning> node_warnings_;
+
+ friend ModifierLog;
+
+ public:
+ LocalGeoLogger(GeoLogger &main_logger) : main_logger_(&main_logger)
+ {
+ this->allocator_ = std::make_unique<LinearAllocator<>>();
+ }
+
+ void log_value_for_sockets(Span<DSocket> sockets, GPointer value);
+ void log_multi_value_socket(DSocket socket, Span<GPointer> values);
+ void log_node_warning(DNode node, NodeWarningType type, std::string message);
+};
+
+/** The root logger class. */
+class GeoLogger {
+ private:
+ /** The entire geometry of sockets in this set should be cached, because e.g. the spreadsheet
+ * displays the data. We don't log the entire geometry at all places, because that would require
+ * way too much memory. */
+ Set<DSocket> log_full_geometry_sockets_;
+ threading::EnumerableThreadSpecific<LocalGeoLogger> threadlocals_;
+
+ friend LocalGeoLogger;
+
+ public:
+ GeoLogger(Set<DSocket> log_full_geometry_sockets)
+ : log_full_geometry_sockets_(std::move(log_full_geometry_sockets)),
+ threadlocals_([this]() { return LocalGeoLogger(*this); })
+ {
+ }
+
+ LocalGeoLogger &local()
+ {
+ return threadlocals_.local();
+ }
+
+ auto begin()
+ {
+ return threadlocals_.begin();
+ }
+
+ auto end()
+ {
+ return threadlocals_.end();
+ }
+};
+
+/** Contains information that has been logged for one specific socket. */
+class SocketLog {
+ private:
+ ValueLog *value_ = nullptr;
+
+ friend ModifierLog;
+
+ public:
+ const ValueLog *value() const
+ {
+ return value_;
+ }
+};
+
+/** Contains information that has been logged for one specific node. */
+class NodeLog {
+ private:
+ Vector<SocketLog> input_logs_;
+ Vector<SocketLog> output_logs_;
+ Vector<NodeWarning, 0> warnings_;
+
+ friend ModifierLog;
+
+ public:
+ const SocketLog *lookup_socket_log(eNodeSocketInOut in_out, int index) const;
+ const SocketLog *lookup_socket_log(const bNode &node, const bNodeSocket &socket) const;
+
+ Span<SocketLog> input_logs() const
+ {
+ return input_logs_;
+ }
+
+ Span<SocketLog> output_logs() const
+ {
+ return output_logs_;
+ }
+
+ Span<NodeWarning> warnings() const
+ {
+ return warnings_;
+ }
+
+ Vector<const GeometryAttributeInfo *> lookup_available_attributes() const;
+};
+
+/** Contains information that has been logged for one specific tree. */
+class TreeLog {
+ private:
+ Map<std::string, destruct_ptr<NodeLog>> node_logs_;
+ Map<std::string, destruct_ptr<TreeLog>> child_logs_;
+
+ friend ModifierLog;
+
+ public:
+ const NodeLog *lookup_node_log(StringRef node_name) const;
+ const NodeLog *lookup_node_log(const bNode &node) const;
+ const TreeLog *lookup_child_log(StringRef node_name) const;
+};
+
+/** Contains information about an entire geometry nodes evaluation. */
+class ModifierLog {
+ private:
+ LinearAllocator<> allocator_;
+ /* Allocators of the individual loggers. */
+ Vector<std::unique_ptr<LinearAllocator<>>> logger_allocators_;
+ destruct_ptr<TreeLog> root_tree_logs_;
+ Vector<destruct_ptr<ValueLog>> logged_values_;
+
+ public:
+ ModifierLog(GeoLogger &logger);
+
+ const TreeLog &root_tree() const
+ {
+ return *root_tree_logs_;
+ }
+
+ /* Utilities to find logged information for a specific context. */
+ static const ModifierLog *find_root_by_node_editor_context(const SpaceNode &snode);
+ static const TreeLog *find_tree_by_node_editor_context(const SpaceNode &snode);
+ static const NodeLog *find_node_by_node_editor_context(const SpaceNode &snode,
+ const bNode &node);
+ static const SocketLog *find_socket_by_node_editor_context(const SpaceNode &snode,
+ const bNode &node,
+ const bNodeSocket &socket);
+ static const NodeLog *find_node_by_spreadsheet_editor_context(
+ const SpaceSpreadsheet &sspreadsheet);
+
+ private:
+ using LogByTreeContext = Map<const DTreeContext *, TreeLog *>;
+
+ TreeLog &lookup_or_add_tree_log(LogByTreeContext &log_by_tree_context,
+ const DTreeContext &tree_context);
+ NodeLog &lookup_or_add_node_log(LogByTreeContext &log_by_tree_context, DNode node);
+ SocketLog &lookup_or_add_socket_log(LogByTreeContext &log_by_tree_context, DSocket socket);
+};
+
+} // namespace blender::nodes::geometry_nodes_eval_log
diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h
index f5f8f77f2a1..60a10d2c508 100644
--- a/source/blender/nodes/NOD_static_types.h
+++ b/source/blender/nodes/NOD_static_types.h
@@ -210,7 +210,7 @@ DefNode(CompositorNode, CMP_NODE_MASK_ELLIPSE, def_cmp_ellipsemask, "ELLIPS
DefNode(CompositorNode, CMP_NODE_BOKEHIMAGE, def_cmp_bokehimage, "BOKEHIMAGE", BokehImage, "Bokeh Image", "" )
DefNode(CompositorNode, CMP_NODE_BOKEHBLUR, def_cmp_bokehblur, "BOKEHBLUR", BokehBlur, "Bokeh Blur", "" )
DefNode(CompositorNode, CMP_NODE_SWITCH, def_cmp_switch, "SWITCH", Switch, "Switch", "" )
-DefNode(CompositorNode, CMP_NODE_SWITCH_VIEW, def_cmp_switch_view, "VIEWSWITCH", SwitchView, "View Switch", "" )
+DefNode(CompositorNode, CMP_NODE_SWITCH_VIEW, def_cmp_switch_view, "VIEWSWITCH", SwitchView, "Switch View", "" )
DefNode(CompositorNode, CMP_NODE_COLORCORRECTION,def_cmp_colorcorrection,"COLORCORRECTION",ColorCorrection, "Color Correction", "" )
DefNode(CompositorNode, CMP_NODE_MASK, def_cmp_mask, "MASK", Mask, "Mask", "" )
DefNode(CompositorNode, CMP_NODE_KEYINGSCREEN, def_cmp_keyingscreen, "KEYINGSCREEN", KeyingScreen, "Keying Screen", "" )
@@ -263,6 +263,7 @@ DefNode(TextureNode, TEX_NODE_PROC+TEX_DISTNOISE, 0, "TEX_DI
DefNode(FunctionNode, FN_NODE_BOOLEAN_MATH, def_boolean_math, "BOOLEAN_MATH", BooleanMath, "Boolean Math", "")
DefNode(FunctionNode, FN_NODE_FLOAT_COMPARE, def_float_compare, "FLOAT_COMPARE", FloatCompare, "Float Compare", "")
+DefNode(FunctionNode, FN_NODE_FLOAT_TO_INT, def_float_to_int, "FLOAT_TO_INT", FloatToInt, "Float to Integer", "")
DefNode(FunctionNode, FN_NODE_INPUT_STRING, def_fn_input_string, "INPUT_STRING", InputString, "String", "")
DefNode(FunctionNode, FN_NODE_INPUT_VECTOR, def_fn_input_vector, "INPUT_VECTOR", InputVector, "Vector", "")
DefNode(FunctionNode, FN_NODE_RANDOM_FLOAT, 0, "RANDOM_FLOAT", RandomFloat, "Random Float", "")
@@ -294,7 +295,9 @@ DefNode(GeometryNode, GEO_NODE_COLLECTION_INFO, def_geo_collection_info, "COLLEC
DefNode(GeometryNode, GEO_NODE_CONVEX_HULL, 0, "CONVEX_HULL", ConvexHull, "Convex Hull", "")
DefNode(GeometryNode, GEO_NODE_CURVE_LENGTH, 0, "CURVE_LENGTH", CurveLength, "Curve Length", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_BEZIER_SEGMENT, def_geo_curve_primitive_bezier_segment, "CURVE_PRIMITIVE_BEZIER_SEGMENT", CurvePrimitiveBezierSegment, "Bezier Segment", "")
-DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, def_geo_curve_primitive_circle, "CURVE_PRIMITIVE_CIRCLE", CurvePrimitiveCircle, "Circle", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, def_geo_curve_primitive_circle, "CURVE_PRIMITIVE_CIRCLE", CurvePrimitiveCircle, "Curve Circle", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_LINE, def_geo_curve_primitive_line, "CURVE_PRIMITIVE_LINE", CurvePrimitiveLine, "Curve Line", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL, def_geo_curve_primitive_quadrilateral, "CURVE_PRIMITIVE_QUADRILATERAL", CurvePrimitiveQuadrilateral, "Quadrilateral", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_QUADRATIC_BEZIER, 0, "CURVE_PRIMITIVE_QUADRATIC_BEZIER", CurveQuadraticBezier, "Quadratic Bezier", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_STAR, 0, "CURVE_PRIMITIVE_STAR", CurveStar, "Star", "")
DefNode(GeometryNode, GEO_NODE_CURVE_PRIMITIVE_SPIRAL, 0, "CURVE_PRIMITIVE_SPIRAL", CurveSpiral, "Curve Spiral", "")
@@ -303,6 +306,7 @@ DefNode(GeometryNode, GEO_NODE_CURVE_SUBDIVIDE, def_geo_curve_subdivide, "CURVE_
DefNode(GeometryNode, GEO_NODE_CURVE_TO_MESH, 0, "CURVE_TO_MESH", CurveToMesh, "Curve to Mesh", "")
DefNode(GeometryNode, GEO_NODE_CURVE_REVERSE, 0, "CURVE_REVERSE", CurveReverse, "Curve Reverse", "")
DefNode(GeometryNode, GEO_NODE_CURVE_TO_POINTS, def_geo_curve_to_points, "CURVE_TO_POINTS", CurveToPoints, "Curve to Points", "")
+DefNode(GeometryNode, GEO_NODE_CURVE_ENDPOINTS, 0, "CURVE_ENDPOINTS", CurveEndpoints, "Curve Endpoints", "")
DefNode(GeometryNode, GEO_NODE_DELETE_GEOMETRY, 0, "DELETE_GEOMETRY", DeleteGeometry, "Delete Geometry", "")
DefNode(GeometryNode, GEO_NODE_EDGE_SPLIT, 0, "EDGE_SPLIT", EdgeSplit, "Edge Split", "")
DefNode(GeometryNode, GEO_NODE_INPUT_MATERIAL, def_geo_input_material, "INPUT_MATERIAL", InputMaterial, "Material", "")
@@ -310,13 +314,13 @@ DefNode(GeometryNode, GEO_NODE_IS_VIEWPORT, 0, "IS_VIEWPORT", IsViewport, "Is Vi
DefNode(GeometryNode, GEO_NODE_JOIN_GEOMETRY, 0, "JOIN_GEOMETRY", JoinGeometry, "Join Geometry", "")
DefNode(GeometryNode, GEO_NODE_MATERIAL_ASSIGN, 0, "MATERIAL_ASSIGN", MaterialAssign, "Material Assign", "")
DefNode(GeometryNode, GEO_NODE_MATERIAL_REPLACE, 0, "MATERIAL_REPLACE", MaterialReplace, "Material Replace", "")
-DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CIRCLE, def_geo_mesh_circle, "MESH_PRIMITIVE_CIRCLE", MeshCircle, "Circle", "")
+DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CIRCLE, def_geo_mesh_circle, "MESH_PRIMITIVE_CIRCLE", MeshCircle, "Mesh Circle", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CONE, def_geo_mesh_cone, "MESH_PRIMITIVE_CONE", MeshCone, "Cone", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CUBE, 0, "MESH_PRIMITIVE_CUBE", MeshCube, "Cube", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_CYLINDER, def_geo_mesh_cylinder, "MESH_PRIMITIVE_CYLINDER", MeshCylinder, "Cylinder", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_GRID, 0, "MESH_PRIMITIVE_GRID", MeshGrid, "Grid", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_ICO_SPHERE, 0, "MESH_PRIMITIVE_ICO_SPHERE", MeshIcoSphere, "Ico Sphere", "")
-DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_LINE, def_geo_mesh_line, "MESH_PRIMITIVE_LINE", MeshLine, "Line", "")
+DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_LINE, def_geo_mesh_line, "MESH_PRIMITIVE_LINE", MeshLine, "Mesh Line", "")
DefNode(GeometryNode, GEO_NODE_MESH_PRIMITIVE_UV_SPHERE, 0, "MESH_PRIMITIVE_UV_SPHERE", MeshUVSphere, "UV Sphere", "")
DefNode(GeometryNode, GEO_NODE_MESH_TO_CURVE, 0, "MESH_TO_CURVE", MeshToCurve, "Mesh to Curve", "")
DefNode(GeometryNode, GEO_NODE_OBJECT_INFO, def_geo_object_info, "OBJECT_INFO", ObjectInfo, "Object Info", "")
@@ -330,11 +334,12 @@ DefNode(GeometryNode, GEO_NODE_POINTS_TO_VOLUME, def_geo_points_to_volume, "POIN
DefNode(GeometryNode, GEO_NODE_RAYCAST, def_geo_raycast, "RAYCAST", Raycast, "Raycast", "")
DefNode(GeometryNode, GEO_NODE_SELECT_BY_MATERIAL, 0, "SELECT_BY_MATERIAL", SelectByMaterial, "Select by Material", "")
DefNode(GeometryNode, GEO_NODE_SEPARATE_COMPONENTS, 0, "SEPARATE_COMPONENTS", SeparateComponents, "Separate Components", "")
-DefNode(GeometryNode, GEO_NODE_SUBDIVIDE, 0, "SUBDIVIDE", Subdivide, "Subdivide", "")
+DefNode(GeometryNode, GEO_NODE_MESH_SUBDIVIDE, 0, "MESH_SUBDIVIDE", MeshSubdivide, "Mesh Subdivide", "")
DefNode(GeometryNode, GEO_NODE_SUBDIVISION_SURFACE, 0, "SUBDIVISION_SURFACE", SubdivisionSurface, "Subdivision Surface", "")
DefNode(GeometryNode, GEO_NODE_SWITCH, def_geo_switch, "SWITCH", Switch, "Switch", "")
DefNode(GeometryNode, GEO_NODE_TRANSFORM, 0, "TRANSFORM", Transform, "Transform", "")
DefNode(GeometryNode, GEO_NODE_TRIANGULATE, def_geo_triangulate, "TRIANGULATE", Triangulate, "Triangulate", "")
+DefNode(GeometryNode, GEO_NODE_VIEWER, 0, "VIEWER", Viewer, "Viewer", "")
DefNode(GeometryNode, GEO_NODE_VOLUME_TO_MESH, def_geo_volume_to_mesh, "VOLUME_TO_MESH", VolumeToMesh, "Volume to Mesh", "")
/* undefine macros */
diff --git a/source/blender/nodes/composite/node_composite_tree.c b/source/blender/nodes/composite/node_composite_tree.c
index 19815d01278..013d196e1c8 100644
--- a/source/blender/nodes/composite/node_composite_tree.c
+++ b/source/blender/nodes/composite/node_composite_tree.c
@@ -205,10 +205,11 @@ static void composite_node_add_init(bNodeTree *UNUSED(bnodetree), bNode *bnode)
}
}
-static bool composite_node_tree_socket_type_valid(eNodeSocketDatatype socket_type,
- bNodeTreeType *UNUSED(ntreetype))
+static bool composite_node_tree_socket_type_valid(bNodeTreeType *UNUSED(ntreetype),
+ bNodeSocketType *socket_type)
{
- return ELEM(socket_type, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA);
+ return nodeIsStaticSocketType(socket_type) &&
+ ELEM(socket_type->type, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA);
}
bNodeTreeType *ntreeType_Composite;
diff --git a/source/blender/nodes/composite/nodes/node_composite_antialiasing.c b/source/blender/nodes/composite/nodes/node_composite_antialiasing.c
index 7437496d878..fa276e9a794 100644
--- a/source/blender/nodes/composite/nodes/node_composite_antialiasing.c
+++ b/source/blender/nodes/composite/nodes/node_composite_antialiasing.c
@@ -42,9 +42,9 @@ static void node_composit_init_antialiasing(bNodeTree *UNUSED(ntree), bNode *nod
{
NodeAntiAliasingData *data = MEM_callocN(sizeof(NodeAntiAliasingData), "node antialiasing data");
- data->threshold = 1.0f;
- data->contrast_limit = 0.2f;
- data->corner_rounding = 0.25f;
+ data->threshold = CMP_DEFAULT_SMAA_THRESHOLD;
+ data->contrast_limit = CMP_DEFAULT_SMAA_CONTRAST_LIMIT;
+ data->corner_rounding = CMP_DEFAULT_SMAA_CORNER_ROUNDING;
node->storage = data;
}
diff --git a/source/blender/nodes/composite/nodes/node_composite_zcombine.c b/source/blender/nodes/composite/nodes/node_composite_zcombine.c
index be1359f795f..5041b16c303 100644
--- a/source/blender/nodes/composite/nodes/node_composite_zcombine.c
+++ b/source/blender/nodes/composite/nodes/node_composite_zcombine.c
@@ -24,7 +24,7 @@
#include "node_composite_util.h"
/* **************** Z COMBINE ******************** */
-/* lazy coder note: node->custom2 is abused to send signal */
+/* lazy coder NOTE: node->custom2 is abused to send signal. */
static bNodeSocketTemplate cmp_node_zcombine_in[] = {
{SOCK_RGBA, N_("Image"), 1.0f, 1.0f, 1.0f, 1.0f},
{SOCK_FLOAT, N_("Z"), 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 10000.0f, PROP_NONE},
diff --git a/source/blender/nodes/function/nodes/node_fn_float_to_int.cc b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc
new file mode 100644
index 00000000000..26cde576400
--- /dev/null
+++ b/source/blender/nodes/function/nodes/node_fn_float_to_int.cc
@@ -0,0 +1,95 @@
+/*
+ * 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 <cmath>
+
+#include "BLI_string.h"
+
+#include "RNA_enum_types.h"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_function_util.hh"
+
+static bNodeSocketTemplate fn_node_float_to_int_in[] = {
+ {SOCK_FLOAT, N_("Float"), 0.0, 0.0, 0.0, 0.0, -FLT_MAX, FLT_MAX},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate fn_node_float_to_int_out[] = {
+ {SOCK_INT, N_("Integer")},
+ {-1, ""},
+};
+
+static void fn_node_float_to_int_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "rounding_mode", 0, "", ICON_NONE);
+}
+
+static void node_float_to_int_label(bNodeTree *UNUSED(ntree), bNode *node, char *label, int maxlen)
+{
+ const char *name;
+ bool enum_label = RNA_enum_name(rna_enum_node_float_to_int_items, node->custom1, &name);
+ if (!enum_label) {
+ name = "Unknown";
+ }
+ BLI_strncpy(label, IFACE_(name), maxlen);
+}
+
+static const blender::fn::MultiFunction &get_multi_function(bNode &bnode)
+{
+ static blender::fn::CustomMF_SI_SO<float, int> round_fn{"Round",
+ [](float a) { return (int)round(a); }};
+ static blender::fn::CustomMF_SI_SO<float, int> floor_fn{"Floor",
+ [](float a) { return (int)floor(a); }};
+ static blender::fn::CustomMF_SI_SO<float, int> ceil_fn{"Ceiling",
+ [](float a) { return (int)ceil(a); }};
+ static blender::fn::CustomMF_SI_SO<float, int> trunc_fn{"Truncate",
+ [](float a) { return (int)trunc(a); }};
+
+ switch (static_cast<FloatToIntRoundingMode>(bnode.custom1)) {
+ case FN_NODE_FLOAT_TO_INT_ROUND:
+ return round_fn;
+ case FN_NODE_FLOAT_TO_INT_FLOOR:
+ return floor_fn;
+ case FN_NODE_FLOAT_TO_INT_CEIL:
+ return ceil_fn;
+ case FN_NODE_FLOAT_TO_INT_TRUNCATE:
+ return trunc_fn;
+ }
+
+ BLI_assert_unreachable();
+ return blender::fn::dummy_multi_function;
+}
+
+static void node_float_to_int_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder)
+{
+ const blender::fn::MultiFunction &fn = get_multi_function(builder.bnode());
+ builder.set_matching_fn(fn);
+}
+
+void register_node_type_fn_float_to_int()
+{
+ static bNodeType ntype;
+
+ fn_node_type_base(&ntype, FN_NODE_FLOAT_TO_INT, "Float to Integer", NODE_CLASS_CONVERTOR, 0);
+ node_type_socket_templates(&ntype, fn_node_float_to_int_in, fn_node_float_to_int_out);
+ node_type_label(&ntype, node_float_to_int_label);
+ ntype.expand_in_mf_network = node_float_to_int_expand_in_mf_network;
+ ntype.draw_buttons = fn_node_float_to_int_layout;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/node_geometry_tree.cc b/source/blender/nodes/geometry/node_geometry_tree.cc
index f36d5b3c9ca..5f10cd87049 100644
--- a/source/blender/nodes/geometry/node_geometry_tree.cc
+++ b/source/blender/nodes/geometry/node_geometry_tree.cc
@@ -108,22 +108,22 @@ static bool geometry_node_tree_validate_link(bNodeTree *UNUSED(ntree), bNodeLink
return (link->tosock->type == link->fromsock->type);
}
-static bool geometry_node_tree_socket_type_valid(eNodeSocketDatatype socket_type,
- bNodeTreeType *UNUSED(ntreetype))
+static bool geometry_node_tree_socket_type_valid(bNodeTreeType *UNUSED(ntreetype),
+ bNodeSocketType *socket_type)
{
- return ELEM(socket_type,
- SOCK_FLOAT,
- SOCK_VECTOR,
- SOCK_RGBA,
- SOCK_BOOLEAN,
- SOCK_INT,
- SOCK_STRING,
- SOCK_OBJECT,
- SOCK_GEOMETRY,
- SOCK_COLLECTION,
- SOCK_TEXTURE,
- SOCK_MATERIAL,
- SOCK_ATTRIBUTE);
+ return nodeIsStaticSocketType(socket_type) && ELEM(socket_type->type,
+ SOCK_FLOAT,
+ SOCK_VECTOR,
+ SOCK_RGBA,
+ SOCK_BOOLEAN,
+ SOCK_INT,
+ SOCK_STRING,
+ SOCK_OBJECT,
+ SOCK_GEOMETRY,
+ SOCK_COLLECTION,
+ SOCK_TEXTURE,
+ SOCK_MATERIAL,
+ SOCK_ATTRIBUTE);
}
void register_node_tree_type_geo(void)
diff --git a/source/blender/nodes/geometry/node_geometry_util.hh b/source/blender/nodes/geometry/node_geometry_util.hh
index 67d32d540a8..98c92eac98f 100644
--- a/source/blender/nodes/geometry/node_geometry_util.hh
+++ b/source/blender/nodes/geometry/node_geometry_util.hh
@@ -79,4 +79,26 @@ void copy_point_attributes_based_on_mask(const GeometryComponent &in_component,
Span<bool> masks,
const bool invert);
+struct CurveToPointsResults {
+ int result_size;
+ MutableSpan<float3> positions;
+ MutableSpan<float> radii;
+ MutableSpan<float> tilts;
+
+ Map<std::string, GMutableSpan> point_attributes;
+
+ MutableSpan<float3> tangents;
+ MutableSpan<float3> normals;
+ MutableSpan<float3> rotations;
+};
+/**
+ * Create references for all result point cloud attributes to simplify accessing them later on.
+ */
+CurveToPointsResults curve_to_points_create_result_attributes(PointCloudComponent &points,
+ const CurveEval &curve);
+
+void curve_create_default_rotation_attribute(Span<float3> tangents,
+ Span<float3> normals,
+ MutableSpan<float3> rotations);
+
} // namespace blender::nodes
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 06a4327a6c5..3b951bda95e 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
@@ -108,15 +108,14 @@ static AttributeDomain get_result_domain(const GeometryComponent &component,
StringRef result_name)
{
/* Use the domain of the result attribute if it already exists. */
- ReadAttributeLookup result_attribute = component.attribute_try_get_for_read(result_name);
- if (result_attribute) {
- return result_attribute.domain;
+ std::optional<AttributeMetaData> result_info = component.attribute_get_meta_data(result_name);
+ if (result_info) {
+ return result_info->domain;
}
-
/* Otherwise use the input attribute's domain if it exists. */
- ReadAttributeLookup input_attribute = component.attribute_try_get_for_read(input_name);
- if (input_attribute) {
- return input_attribute.domain;
+ std::optional<AttributeMetaData> input_info = component.attribute_get_meta_data(input_name);
+ if (input_info) {
+ return input_info->domain;
}
return ATTR_DOMAIN_POINT;
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc
index b7863d38fc2..d71cb09f1bd 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_proximity.cc
@@ -143,8 +143,7 @@ static bool bvh_from_mesh(const Mesh *target_mesh,
break;
}
- /* This only updates a cache and can be considered to be logically const. */
- BKE_bvhtree_from_mesh_get(&r_tree_data_mesh, const_cast<Mesh *>(target_mesh), bvh_type, 2);
+ BKE_bvhtree_from_mesh_get(&r_tree_data_mesh, target_mesh, bvh_type, 2);
if (r_tree_data_mesh.tree == nullptr) {
return false;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_transfer.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_transfer.cc
index d1114713672..756f93f154f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_attribute_transfer.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_transfer.cc
@@ -162,7 +162,7 @@ static void get_closest_mesh_points(const Mesh &mesh,
{
BLI_assert(mesh.totvert > 0);
BVHTreeFromMesh tree_data;
- BKE_bvhtree_from_mesh_get(&tree_data, const_cast<Mesh *>(&mesh), BVHTREE_FROM_VERTS, 2);
+ BKE_bvhtree_from_mesh_get(&tree_data, &mesh, BVHTREE_FROM_VERTS, 2);
get_closest_in_bvhtree(tree_data, positions, r_point_indices, r_distances_sq, r_positions);
free_bvhtree_from_mesh(&tree_data);
}
@@ -175,7 +175,7 @@ static void get_closest_mesh_edges(const Mesh &mesh,
{
BLI_assert(mesh.totedge > 0);
BVHTreeFromMesh tree_data;
- BKE_bvhtree_from_mesh_get(&tree_data, const_cast<Mesh *>(&mesh), BVHTREE_FROM_EDGES, 2);
+ BKE_bvhtree_from_mesh_get(&tree_data, &mesh, BVHTREE_FROM_EDGES, 2);
get_closest_in_bvhtree(tree_data, positions, r_edge_indices, r_distances_sq, r_positions);
free_bvhtree_from_mesh(&tree_data);
}
@@ -188,7 +188,7 @@ static void get_closest_mesh_looptris(const Mesh &mesh,
{
BLI_assert(mesh.totpoly > 0);
BVHTreeFromMesh tree_data;
- BKE_bvhtree_from_mesh_get(&tree_data, const_cast<Mesh *>(&mesh), BVHTREE_FROM_LOOPTRI, 2);
+ BKE_bvhtree_from_mesh_get(&tree_data, &mesh, BVHTREE_FROM_LOOPTRI, 2);
get_closest_in_bvhtree(tree_data, positions, r_looptri_indices, r_distances_sq, r_positions);
free_bvhtree_from_mesh(&tree_data);
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
index b1b17a321b8..4286db52115 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_convex_hull.cc
@@ -82,7 +82,7 @@ static Mesh *hull_from_bullet(const Mesh *mesh, Span<float3> coords)
copy_v3_v3(result->mvert[i].co, co);
}
else {
- BLI_assert(!"Unexpected new vertex in hull output");
+ BLI_assert_msg(0, "Unexpected new vertex in hull output");
}
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_endpoints.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoints.cc
new file mode 100644
index 00000000000..1f878259f30
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_endpoints.cc
@@ -0,0 +1,223 @@
+/*
+ * 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_task.hh"
+#include "BLI_timeit.hh"
+
+#include "BKE_pointcloud.h"
+#include "BKE_spline.hh"
+
+#include "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+static bNodeSocketTemplate geo_node_curve_endpoints_in[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_curve_endpoints_out[] = {
+ {SOCK_GEOMETRY, N_("Start Points")},
+ {SOCK_GEOMETRY, N_("End Points")},
+ {-1, ""},
+};
+
+namespace blender::nodes {
+
+/**
+ * Evaluate splines in parallel to speed up the rest of the node's execution.
+ */
+static void evaluate_splines(Span<SplinePtr> splines)
+{
+ threading::parallel_for_each(splines, [](const SplinePtr &spline) {
+ /* These functions fill the corresponding caches on each spline. */
+ spline->evaluated_positions();
+ spline->evaluated_tangents();
+ spline->evaluated_normals();
+ spline->evaluated_lengths();
+ });
+}
+
+/**
+ * \note Use attributes from the curve component rather than the attribute data directly on the
+ * attribute storage to allow reading the virtual spline attributes like "cyclic" and "resolution".
+ */
+static void copy_spline_domain_attributes(const CurveComponent &curve_component,
+ Span<int> offsets,
+ PointCloudComponent &points)
+{
+ curve_component.attribute_foreach([&](StringRefNull name, const AttributeMetaData &meta_data) {
+ if (meta_data.domain != ATTR_DOMAIN_CURVE) {
+ return true;
+ }
+ GVArrayPtr spline_attribute = curve_component.attribute_get_for_read(
+ name, ATTR_DOMAIN_CURVE, meta_data.data_type);
+
+ OutputAttribute result_attribute = points.attribute_try_get_for_output_only(
+ name, ATTR_DOMAIN_POINT, meta_data.data_type);
+ GMutableSpan result = result_attribute.as_span();
+
+ /* Only copy the attributes of splines in the offsets. */
+ for (const int i : offsets.index_range()) {
+ spline_attribute->get(offsets[i], result[i]);
+ }
+
+ result_attribute.save();
+ return true;
+ });
+}
+
+/**
+ * Get the offsets for the splines whose endpoints we want to output.
+ * Filter those which are cyclic, or that evaluate to empty.
+ * Could be easily adapted to include a selection argument to support attribute selection.
+ */
+static blender::Vector<int> get_endpoint_spline_offsets(Span<SplinePtr> splines)
+{
+ blender::Vector<int> spline_offsets;
+ spline_offsets.reserve(splines.size());
+
+ for (const int i : splines.index_range()) {
+ if (!(splines[i]->is_cyclic() || splines[i]->evaluated_points_size() == 0)) {
+ spline_offsets.append(i);
+ }
+ }
+
+ return spline_offsets;
+}
+
+/**
+ * Copy the endpoint attributes from the correct positions at the splines at the offsets to
+ * the start and end attributes.
+ */
+static void copy_endpoint_attributes(Span<SplinePtr> splines,
+ Span<int> offsets,
+ CurveToPointsResults &start_data,
+ CurveToPointsResults &end_data)
+{
+ threading::parallel_for(offsets.index_range(), 64, [&](IndexRange range) {
+ for (const int i : range) {
+ const Spline &spline = *splines[offsets[i]];
+
+ /* Copy the start and end point data over. */
+ start_data.positions[i] = spline.evaluated_positions().first();
+ start_data.tangents[i] = spline.evaluated_tangents().first();
+ start_data.normals[i] = spline.evaluated_normals().first();
+ start_data.radii[i] = spline.radii().first();
+ start_data.tilts[i] = spline.tilts().first();
+
+ end_data.positions[i] = spline.evaluated_positions().last();
+ end_data.tangents[i] = spline.evaluated_tangents().last();
+ end_data.normals[i] = spline.evaluated_normals().last();
+ end_data.radii[i] = spline.radii().last();
+ end_data.tilts[i] = spline.tilts().last();
+
+ /* Copy the point attribute data over. */
+ for (const auto &item : start_data.point_attributes.items()) {
+ const StringRef name = item.key;
+ GMutableSpan point_span = item.value;
+
+ BLI_assert(spline.attributes.get_for_read(name));
+ GSpan spline_span = *spline.attributes.get_for_read(name);
+ blender::fn::GVArray_For_GSpan(spline_span).get(0, point_span[i]);
+ }
+
+ for (const auto &item : end_data.point_attributes.items()) {
+ const StringRef name = item.key;
+ GMutableSpan point_span = item.value;
+
+ BLI_assert(spline.attributes.get_for_read(name));
+ GSpan spline_span = *spline.attributes.get_for_read(name);
+ blender::fn::GVArray_For_GSpan(spline_span).get(spline.size() - 1, point_span[i]);
+ }
+ }
+ });
+}
+
+static void geo_node_curve_endpoints_exec(GeoNodeExecParams params)
+{
+ GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
+
+ geometry_set = bke::geometry_set_realize_instances(geometry_set);
+
+ if (!geometry_set.has_curve()) {
+ params.set_output("Start Points", GeometrySet());
+ params.set_output("End Points", GeometrySet());
+ return;
+ }
+
+ const CurveComponent &curve_component = *geometry_set.get_component_for_read<CurveComponent>();
+ const CurveEval &curve = *curve_component.get_for_read();
+ const Span<SplinePtr> splines = curve.splines();
+ curve.assert_valid_point_attributes();
+
+ evaluate_splines(splines);
+
+ const Vector<int> offsets = get_endpoint_spline_offsets(splines);
+ const int total_size = offsets.size();
+
+ if (total_size == 0) {
+ params.set_output("Start Points", GeometrySet());
+ params.set_output("End Points", GeometrySet());
+ return;
+ }
+
+ GeometrySet start_result = GeometrySet::create_with_pointcloud(
+ BKE_pointcloud_new_nomain(total_size));
+ GeometrySet end_result = GeometrySet::create_with_pointcloud(
+ BKE_pointcloud_new_nomain(total_size));
+ PointCloudComponent &start_point_component =
+ start_result.get_component_for_write<PointCloudComponent>();
+ PointCloudComponent &end_point_component =
+ end_result.get_component_for_write<PointCloudComponent>();
+
+ CurveToPointsResults start_attributes = curve_to_points_create_result_attributes(
+ start_point_component, curve);
+ CurveToPointsResults end_attributes = curve_to_points_create_result_attributes(
+ end_point_component, curve);
+
+ copy_endpoint_attributes(splines, offsets.as_span(), start_attributes, end_attributes);
+ copy_spline_domain_attributes(curve_component, offsets.as_span(), start_point_component);
+ curve_create_default_rotation_attribute(
+ start_attributes.tangents, start_attributes.normals, start_attributes.rotations);
+ curve_create_default_rotation_attribute(
+ end_attributes.tangents, end_attributes.normals, end_attributes.rotations);
+
+ /* The default radius is way too large for points, divide by 10. */
+ for (float &radius : start_attributes.radii) {
+ radius *= 0.1f;
+ }
+ for (float &radius : end_attributes.radii) {
+ radius *= 0.1f;
+ }
+
+ params.set_output("Start Points", std::move(start_result));
+ params.set_output("End Points", std::move(end_result));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_curve_endpoints()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_ENDPOINTS, "Curve Endpoints", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(&ntype, geo_node_curve_endpoints_in, geo_node_curve_endpoints_out);
+ ntype.geometry_node_execute = blender::nodes::geo_node_curve_endpoints_exec;
+
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
index 963c48b7536..ae947b7aeed 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_circle.cc
@@ -83,9 +83,10 @@ static bool colinear_f3_f3_f3(const float3 p1, const float3 p2, const float3 p3)
}
static std::unique_ptr<CurveEval> create_point_circle_curve(
- const float3 p1, const float3 p2, const float3 p3, const int resolution, float center_out[3])
+ const float3 p1, const float3 p2, const float3 p3, const int resolution, float3 &r_center)
{
if (colinear_f3_f3_f3(p1, p2, p3)) {
+ r_center = float3(0);
return nullptr;
}
@@ -118,6 +119,7 @@ static std::unique_ptr<CurveEval> create_point_circle_curve(
/* If the 3 planes do not intersect at one point, just return empty geometry. */
if (!isect_plane_plane_plane_v3(plane_1, plane_2, plane_3, center)) {
+ r_center = float3(0);
return nullptr;
}
@@ -126,7 +128,7 @@ static std::unique_ptr<CurveEval> create_point_circle_curve(
const float theta_step = ((2 * M_PI) / (float)resolution);
for (const int i : IndexRange(resolution)) {
- /* Formula for a circle around a point and 2 unit vectors perpendicular.
+ /* Formula for a circle around a point and 2 unit vectors perpendicular
* to each other and the axis of the circle from:
* https://math.stackexchange.com/questions/73237/parametric-equation-of-a-circle-in-3d-space
*/
@@ -141,7 +143,7 @@ static std::unique_ptr<CurveEval> create_point_circle_curve(
curve->add_spline(std::move(spline));
curve->attributes.reallocate(curve->splines().size());
- copy_v3_v3(center_out, center);
+ r_center = center;
return curve;
}
@@ -179,18 +181,13 @@ static void geo_node_curve_primitive_circle_exec(GeoNodeExecParams params)
std::unique_ptr<CurveEval> curve;
if (mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_POINTS) {
- float center_point[3];
+ float3 center_point;
curve = create_point_circle_curve(params.extract_input<float3>("Point 1"),
params.extract_input<float3>("Point 2"),
params.extract_input<float3>("Point 3"),
std::max(params.extract_input<int>("Resolution"), 3),
center_point);
- if (curve) {
- params.set_output("Center", float3(center_point));
- }
- else {
- params.set_output("Center", float3(0, 0, 0));
- }
+ params.set_output("Center", center_point);
}
else if (mode == GEO_NODE_CURVE_PRIMITIVE_CIRCLE_TYPE_RADIUS) {
curve = create_radius_circle_curve(std::max(params.extract_input<int>("Resolution"), 3),
@@ -210,7 +207,8 @@ static void geo_node_curve_primitive_circle_exec(GeoNodeExecParams params)
void register_node_type_geo_curve_primitive_circle()
{
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, "Circle", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(
+ &ntype, GEO_NODE_CURVE_PRIMITIVE_CIRCLE, "Curve Circle", NODE_CLASS_GEOMETRY, 0);
node_type_socket_templates(
&ntype, geo_node_curve_primitive_circle_in, geo_node_curve_primitive_circle_out);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
new file mode 100644
index 00000000000..eed3a998ef6
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_line.cc
@@ -0,0 +1,146 @@
+/*
+ * 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 "UI_interface.h"
+#include "UI_resources.h"
+
+#include "node_geometry_util.hh"
+
+static bNodeSocketTemplate geo_node_curve_primitive_line_in[] = {
+ {SOCK_VECTOR, N_("Start"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
+ {SOCK_VECTOR, N_("End"), 0.0f, 0.0f, 1.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_TRANSLATION},
+ {SOCK_VECTOR, N_("Direction"), 0.0f, 0.0f, 1.0f, 0.0f, -FLT_MAX, FLT_MAX},
+ {SOCK_FLOAT, N_("Length"), 1.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_DISTANCE},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_curve_primitive_line_out[] = {
+ {SOCK_GEOMETRY, N_("Curve")},
+ {-1, ""},
+};
+
+static void geo_node_curve_primitive_line_layout(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", UI_ITEM_R_EXPAND, nullptr, ICON_NONE);
+}
+
+namespace blender::nodes {
+
+static void geo_node_curve_primitive_line_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryCurvePrimitiveLine *data = (NodeGeometryCurvePrimitiveLine *)MEM_callocN(
+ sizeof(NodeGeometryCurvePrimitiveLine), __func__);
+
+ data->mode = GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_POINTS;
+ node->storage = data;
+}
+
+static void geo_node_curve_primitive_line_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ const NodeGeometryCurvePrimitiveLine *node_storage = (NodeGeometryCurvePrimitiveLine *)
+ node->storage;
+ const GeometryNodeCurvePrimitiveLineMode mode = (const GeometryNodeCurvePrimitiveLineMode)
+ node_storage->mode;
+
+ bNodeSocket *p2_socket = ((bNodeSocket *)node->inputs.first)->next;
+ bNodeSocket *direction_socket = p2_socket->next;
+ bNodeSocket *length_socket = direction_socket->next;
+
+ nodeSetSocketAvailability(p2_socket, mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_POINTS);
+ nodeSetSocketAvailability(direction_socket,
+ mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION);
+ nodeSetSocketAvailability(length_socket, mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION);
+}
+
+static std::unique_ptr<CurveEval> create_point_line_curve(const float3 start, const float3 end)
+{
+ std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
+ std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
+
+ spline->resize(2);
+ MutableSpan<float3> positions = spline->positions();
+ positions[0] = start;
+ positions[1] = end;
+ spline->radii().fill(1.0f);
+ spline->tilts().fill(0.0f);
+ curve->add_spline(std::move(spline));
+ curve->attributes.reallocate(curve->splines().size());
+ return curve;
+}
+
+static std::unique_ptr<CurveEval> create_direction_line_curve(const float3 start,
+ const float3 direction,
+ const float length)
+{
+ std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
+ std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
+
+ spline->resize(2);
+ MutableSpan<float3> positions = spline->positions();
+ positions[0] = start;
+ positions[1] = direction.normalized() * length + start;
+
+ spline->radii().fill(1.0f);
+ spline->tilts().fill(0.0f);
+ curve->add_spline(std::move(spline));
+ curve->attributes.reallocate(curve->splines().size());
+ return curve;
+}
+
+static void geo_node_curve_primitive_line_exec(GeoNodeExecParams params)
+{
+
+ const NodeGeometryCurvePrimitiveLine *node_storage =
+ (NodeGeometryCurvePrimitiveLine *)params.node().storage;
+
+ GeometryNodeCurvePrimitiveLineMode mode = (GeometryNodeCurvePrimitiveLineMode)node_storage->mode;
+
+ std::unique_ptr<CurveEval> curve;
+ if (mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_POINTS) {
+ curve = create_point_line_curve(params.extract_input<float3>("Start"),
+ params.extract_input<float3>("End"));
+ }
+ else if (mode == GEO_NODE_CURVE_PRIMITIVE_LINE_MODE_DIRECTION) {
+ curve = create_direction_line_curve(params.extract_input<float3>("Start"),
+ params.extract_input<float3>("Direction"),
+ params.extract_input<float>("Length"));
+ }
+
+ params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_curve_primitive_line()
+{
+ static bNodeType ntype;
+ geo_node_type_base(&ntype, GEO_NODE_CURVE_PRIMITIVE_LINE, "Curve Line", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(
+ &ntype, geo_node_curve_primitive_line_in, geo_node_curve_primitive_line_out);
+ node_type_init(&ntype, blender::nodes::geo_node_curve_primitive_line_init);
+ node_type_update(&ntype, blender::nodes::geo_node_curve_primitive_line_update);
+ node_type_storage(&ntype,
+ "NodeGeometryCurvePrimitiveLine",
+ node_free_standard_storage,
+ node_copy_standard_storage);
+ ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_line_exec;
+ ntype.draw_buttons = geo_node_curve_primitive_line_layout;
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
new file mode 100644
index 00000000000..5f3f159c305
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_quadrilateral.cc
@@ -0,0 +1,241 @@
+/*
+ * 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 "UI_interface.h"
+#include "UI_resources.h"
+#include "node_geometry_util.hh"
+
+static bNodeSocketTemplate geo_node_curve_primitive_quadrilateral_in[] = {
+ {SOCK_FLOAT, N_("Width"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
+ {SOCK_FLOAT, N_("Height"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
+ {SOCK_FLOAT, N_("Bottom Width"), 4.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
+ {SOCK_FLOAT, N_("Top Width"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
+ {SOCK_FLOAT, N_("Offset"), 1.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_DISTANCE},
+ {SOCK_FLOAT, N_("Bottom Height"), 3.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
+ {SOCK_FLOAT, N_("Top Height"), 1.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_DISTANCE},
+ {SOCK_VECTOR, N_("Point 1"), -1.0f, 1.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_DISTANCE},
+ {SOCK_VECTOR, N_("Point 2"), 1.0f, 1.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_DISTANCE},
+ {SOCK_VECTOR, N_("Point 3"), 1.0f, -1.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_DISTANCE},
+ {SOCK_VECTOR, N_("Point 4"), -1.0f, -1.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_DISTANCE},
+ {-1, ""},
+};
+
+static bNodeSocketTemplate geo_node_curve_primitive_quadrilateral_out[] = {
+ {SOCK_GEOMETRY, N_("Curve")},
+ {-1, ""},
+};
+
+static void geo_node_curve_primitive_quadrilateral_layout(uiLayout *layout,
+ bContext *UNUSED(C),
+ PointerRNA *ptr)
+{
+ uiItemR(layout, ptr, "mode", 0, "", ICON_NONE);
+}
+
+static void geo_node_curve_primitive_quadrilateral_init(bNodeTree *UNUSED(tree), bNode *node)
+{
+ NodeGeometryCurvePrimitiveQuad *data = (NodeGeometryCurvePrimitiveQuad *)MEM_callocN(
+ sizeof(NodeGeometryCurvePrimitiveQuad), __func__);
+ data->mode = GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE;
+ node->storage = data;
+}
+
+namespace blender::nodes {
+
+static void geo_node_curve_primitive_quadrilateral_update(bNodeTree *UNUSED(ntree), bNode *node)
+{
+ NodeGeometryCurvePrimitiveQuad &node_storage = *(NodeGeometryCurvePrimitiveQuad *)node->storage;
+ GeometryNodeCurvePrimitiveQuadMode mode = static_cast<GeometryNodeCurvePrimitiveQuadMode>(
+ node_storage.mode);
+
+ bNodeSocket *width = ((bNodeSocket *)node->inputs.first);
+ bNodeSocket *height = width->next;
+ bNodeSocket *bottom = height->next;
+ bNodeSocket *top = bottom->next;
+ bNodeSocket *offset = top->next;
+ bNodeSocket *bottom_height = offset->next;
+ bNodeSocket *top_height = bottom_height->next;
+ bNodeSocket *p1 = top_height->next;
+ bNodeSocket *p2 = p1->next;
+ bNodeSocket *p3 = p2->next;
+ bNodeSocket *p4 = p3->next;
+
+ LISTBASE_FOREACH (bNodeSocket *, sock, &node->inputs) {
+ nodeSetSocketAvailability(sock, false);
+ }
+
+ if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE) {
+ nodeSetSocketAvailability(width, true);
+ nodeSetSocketAvailability(height, true);
+ }
+ else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_PARALLELOGRAM) {
+ nodeSetSocketAvailability(width, true);
+ nodeSetSocketAvailability(height, true);
+ nodeSetSocketAvailability(offset, true);
+ }
+ else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_TRAPEZOID) {
+ nodeSetSocketAvailability(bottom, true);
+ nodeSetSocketAvailability(top, true);
+ nodeSetSocketAvailability(offset, true);
+ nodeSetSocketAvailability(height, true);
+ }
+ else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_KITE) {
+ nodeSetSocketAvailability(width, true);
+ nodeSetSocketAvailability(bottom_height, true);
+ nodeSetSocketAvailability(top_height, true);
+ }
+ else if (mode == GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_POINTS) {
+ nodeSetSocketAvailability(p1, true);
+ nodeSetSocketAvailability(p2, true);
+ nodeSetSocketAvailability(p3, true);
+ nodeSetSocketAvailability(p4, true);
+ }
+}
+
+static void create_rectangle_curve(MutableSpan<float3> positions,
+ const float height,
+ const float width)
+{
+ positions[0] = float3(width / 2.0f, -height / 2.0f, 0.0f);
+ positions[1] = float3(-width / 2.0f, -height / 2.0f, 0.0f);
+ positions[2] = float3(-width / 2.0f, height / 2.0f, 0.0f);
+ positions[3] = float3(width / 2.0f, height / 2.0f, 0.0f);
+}
+
+static void create_points_curve(MutableSpan<float3> positions,
+ const float3 &p1,
+ const float3 &p2,
+ const float3 &p3,
+ const float3 &p4)
+{
+ positions[0] = p1;
+ positions[1] = p2;
+ positions[2] = p3;
+ positions[3] = p4;
+}
+
+static void create_parallelogram_curve(MutableSpan<float3> positions,
+ const float height,
+ const float width,
+ const float offset)
+{
+ positions[0] = float3(width / 2.0f - offset / 2.0f, -height / 2.0f, 0.0f);
+ positions[1] = float3(-width / 2.0f - offset / 2.0f, -height / 2.0f, 0.0f);
+ positions[2] = float3(-width / 2.0f + offset / 2.0f, height / 2.0f, 0.0f);
+ positions[3] = float3(width / 2.0f + offset / 2.0f, height / 2.0f, 0.0f);
+}
+static void create_trapezoid_curve(MutableSpan<float3> positions,
+ const float bottom,
+ const float top,
+ const float offset,
+ const float height)
+{
+ positions[0] = float3(bottom / 2.0f, -height / 2.0f, 0.0f);
+ positions[1] = float3(-bottom / 2.0f, -height / 2.0f, 0.0f);
+ positions[2] = float3(-top / 2.0f + offset, height / 2.0f, 0.0f);
+ positions[3] = float3(top / 2.0f + offset, height / 2.0f, 0.0f);
+}
+
+static void create_kite_curve(MutableSpan<float3> positions,
+ const float width,
+ const float bottom_height,
+ const float top_height)
+{
+ positions[0] = float3(-width / 2.0f, 0, 0);
+ positions[1] = float3(0, top_height, 0);
+ positions[2] = float3(width / 2, 0, 0);
+ positions[3] = float3(0, -bottom_height, 0);
+}
+
+static void geo_node_curve_primitive_quadrilateral_exec(GeoNodeExecParams params)
+{
+ const NodeGeometryCurvePrimitiveQuad &node_storage =
+ *(NodeGeometryCurvePrimitiveQuad *)(params.node()).storage;
+ const GeometryNodeCurvePrimitiveQuadMode mode = static_cast<GeometryNodeCurvePrimitiveQuadMode>(
+ node_storage.mode);
+
+ std::unique_ptr<CurveEval> curve = std::make_unique<CurveEval>();
+ std::unique_ptr<PolySpline> spline = std::make_unique<PolySpline>();
+ spline->resize(4);
+ spline->radii().fill(1.0f);
+ spline->tilts().fill(0.0f);
+ spline->set_cyclic(true);
+ MutableSpan<float3> positions = spline->positions();
+
+ switch (mode) {
+ case GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_RECTANGLE:
+ create_rectangle_curve(positions,
+ std::max(params.extract_input<float>("Height"), 0.0f),
+ std::max(params.extract_input<float>("Width"), 0.0f));
+ break;
+
+ case GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_PARALLELOGRAM:
+ create_parallelogram_curve(positions,
+ std::max(params.extract_input<float>("Height"), 0.0f),
+ std::max(params.extract_input<float>("Width"), 0.0f),
+ params.extract_input<float>("Offset"));
+ break;
+ case GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_TRAPEZOID:
+ create_trapezoid_curve(positions,
+ std::max(params.extract_input<float>("Bottom Width"), 0.0f),
+ std::max(params.extract_input<float>("Top Width"), 0.0f),
+ params.extract_input<float>("Offset"),
+ std::max(params.extract_input<float>("Height"), 0.0f));
+ break;
+ case GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_KITE:
+ create_kite_curve(positions,
+ std::max(params.extract_input<float>("Width"), 0.0f),
+ std::max(params.extract_input<float>("Bottom Height"), 0.0f),
+ params.extract_input<float>("Top Height"));
+ break;
+ case GEO_NODE_CURVE_PRIMITIVE_QUAD_MODE_POINTS:
+ create_points_curve(positions,
+ params.extract_input<float3>("Point 1"),
+ params.extract_input<float3>("Point 2"),
+ params.extract_input<float3>("Point 3"),
+ params.extract_input<float3>("Point 4"));
+ break;
+ default:
+ params.set_output("Curve", GeometrySet());
+ return;
+ }
+
+ curve->add_spline(std::move(spline));
+ curve->attributes.reallocate(curve->splines().size());
+ params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
+}
+
+} // namespace blender::nodes
+
+void register_node_type_geo_curve_primitive_quadrilateral()
+{
+ static bNodeType ntype;
+ geo_node_type_base(
+ &ntype, GEO_NODE_CURVE_PRIMITIVE_QUADRILATERAL, "Quadrilateral", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(&ntype,
+ geo_node_curve_primitive_quadrilateral_in,
+ geo_node_curve_primitive_quadrilateral_out);
+ ntype.geometry_node_execute = blender::nodes::geo_node_curve_primitive_quadrilateral_exec;
+ ntype.draw_buttons = geo_node_curve_primitive_quadrilateral_layout;
+ node_type_update(&ntype, blender::nodes::geo_node_curve_primitive_quadrilateral_update);
+ node_type_init(&ntype, geo_node_curve_primitive_quadrilateral_init);
+ node_type_storage(&ntype,
+ "NodeGeometryCurvePrimitiveQuad",
+ node_free_standard_storage,
+ node_copy_standard_storage);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
index 367da3bc3c2..2e2bb247e2b 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_primitive_star.cc
@@ -19,7 +19,7 @@
#include "node_geometry_util.hh"
static bNodeSocketTemplate geo_node_curve_primitive_star_in[] = {
- {SOCK_INT, N_("Points"), 8.0f, 0.0f, 0.0f, 0.0f, 4, 256, PROP_UNSIGNED},
+ {SOCK_INT, N_("Points"), 8.0f, 0.0f, 0.0f, 0.0f, 3, 256, PROP_UNSIGNED},
{SOCK_FLOAT, N_("Inner Radius"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
{SOCK_FLOAT, N_("Outer Radius"), 2.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX, PROP_DISTANCE},
{SOCK_FLOAT, N_("Twist"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX, PROP_ANGLE},
@@ -64,7 +64,7 @@ static void geo_node_curve_primitive_star_exec(GeoNodeExecParams params)
std::max(params.extract_input<float>("Inner Radius"), 0.0f),
std::max(params.extract_input<float>("Outer Radius"), 0.0f),
params.extract_input<float>("Twist"),
- std::max(params.extract_input<int>("Points"), 4));
+ std::max(params.extract_input<int>("Points"), 3));
params.set_output("Curve", GeometrySet::create_with_curve(curve.release()));
}
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 fc65d1754e9..ad0c453c2af 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_resample.cc
@@ -87,6 +87,23 @@ static SplinePtr resample_spline(const Spline &input_spline, const int count)
input_spline.tilts().first(),
input_spline.radii().first());
output_spline->attributes.reallocate(1);
+ input_spline.attributes.foreach_attribute(
+ [&](StringRefNull name, const AttributeMetaData &meta_data) {
+ std::optional<GSpan> src = input_spline.attributes.get_for_read(name);
+ BLI_assert(src);
+ if (!output_spline->attributes.create(name, meta_data.data_type)) {
+ BLI_assert_unreachable();
+ return false;
+ }
+ std::optional<GMutableSpan> dst = output_spline->attributes.get_for_write(name);
+ if (!dst) {
+ BLI_assert_unreachable();
+ return false;
+ }
+ src->type().copy_assign(src->data(), dst->data());
+ return true;
+ },
+ ATTR_DOMAIN_POINT);
return output_spline;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
index 3de2604cd0a..7908c26e2dc 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_subdivide.cc
@@ -116,38 +116,6 @@ static void subdivide_attribute(Span<T> src,
}
/**
- * De Casteljau Bezier subdivision.
- *
- * <pre>
- * handle_prev handle_next
- * O----------------O
- * / \
- * / x---O---x \
- * / new_* \
- * / \
- * O O
- * point_prev point_next
- * </pre>
- */
-static void calculate_new_bezier_point(const float3 &point_prev,
- float3 &handle_prev,
- float3 &new_left_handle,
- float3 &new_position,
- float3 &new_right_handle,
- float3 &handle_next,
- const float3 &point_next,
- const float parameter)
-{
- const float3 center_point = float3::interpolate(handle_prev, handle_next, parameter);
-
- handle_prev = float3::interpolate(point_prev, handle_prev, parameter);
- handle_next = float3::interpolate(handle_next, point_next, parameter);
- new_left_handle = float3::interpolate(handle_prev, center_point, parameter);
- new_right_handle = float3::interpolate(center_point, handle_next, parameter);
- new_position = float3::interpolate(new_left_handle, new_right_handle, parameter);
-}
-
-/**
* In order to generate a Bezier spline with the same shape as the input spline, apply the
* De Casteljau algorithm iteratively for the provided number of cuts, constantly updating the
* previous result point's right handle and the left handle at the end of the segment.
@@ -171,6 +139,10 @@ static void subdivide_bezier_segment(const BezierSpline &src,
{
const bool is_last_cyclic_segment = index == (src.size() - 1);
const int next_index = is_last_cyclic_segment ? 0 : index + 1;
+
+ /* The first point in the segment is always copied. */
+ dst_positions[offset] = src_positions[index];
+
if (src.segment_is_vector(index)) {
if (is_last_cyclic_segment) {
dst_type_left.first() = BezierSpline::HandleType::Vector;
@@ -178,7 +150,6 @@ static void subdivide_bezier_segment(const BezierSpline &src,
dst_type_left.slice(offset + 1, result_size).fill(BezierSpline::HandleType::Vector);
dst_type_right.slice(offset, result_size).fill(BezierSpline::HandleType::Vector);
- dst_positions[offset] = src_positions[index];
const float factor_delta = 1.0f / result_size;
for (const int cut : IndexRange(result_size)) {
const float factor = cut * factor_delta;
@@ -194,21 +165,38 @@ static void subdivide_bezier_segment(const BezierSpline &src,
dst_type_right.slice(offset, result_size).fill(BezierSpline::HandleType::Free);
const int i_segment_last = is_last_cyclic_segment ? 0 : offset + result_size;
- dst_positions[offset] = src_positions[index];
- dst_handles_right[offset] = src_handles_right[index];
- dst_handles_left[i_segment_last] = src_handles_left[next_index];
+
+ /* Create a Bezier segment to update iteratively for every subdivision
+ * and references to the meaningful values for ease of use. */
+ BezierSpline temp;
+ temp.resize(2);
+ float3 &segment_start = temp.positions().first();
+ float3 &segment_end = temp.positions().last();
+ float3 &handle_prev = temp.handle_positions_right().first();
+ float3 &handle_next = temp.handle_positions_left().last();
+ segment_start = src_positions[index];
+ segment_end = src_positions[next_index];
+ handle_prev = src_handles_right[index];
+ handle_next = src_handles_left[next_index];
for (const int cut : IndexRange(result_size - 1)) {
const float parameter = 1.0f / (result_size - cut);
- calculate_new_bezier_point(dst_positions[offset + cut],
- dst_handles_right[offset + cut],
- dst_handles_left[offset + cut + 1],
- dst_positions[offset + cut + 1],
- dst_handles_right[offset + cut + 1],
- dst_handles_left[i_segment_last],
- src_positions[next_index],
- parameter);
+ const BezierSpline::InsertResult insert = temp.calculate_segment_insertion(0, 1, parameter);
+
+ /* Copy relevant temporary data to the result. */
+ dst_handles_right[offset + cut] = insert.handle_prev;
+ dst_handles_left[offset + cut + 1] = insert.left_handle;
+ dst_positions[offset + cut + 1] = insert.position;
+
+ /* Update the segment to prepare it for the next subdivision. */
+ segment_start = insert.position;
+ handle_prev = insert.right_handle;
+ handle_next = insert.handle_next;
}
+
+ /* Copy the handles for the last segment from the temporary spline. */
+ dst_handles_right[offset + result_size - 1] = handle_prev;
+ dst_handles_left[i_segment_last] = handle_next;
}
}
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 c0d817385e2..f1bcb4ed47f 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
@@ -337,7 +337,17 @@ static void geo_node_curve_to_mesh_exec(GeoNodeExecParams params)
curve_set = bke::geometry_set_realize_instances(curve_set);
profile_set = bke::geometry_set_realize_instances(profile_set);
+ /* NOTE: Theoretically an "is empty" check would be more correct for errors. */
+ if (profile_set.has_mesh() && !profile_set.has_curve()) {
+ params.error_message_add(NodeWarningType::Warning,
+ TIP_("No curve data available in profile input"));
+ }
+
if (!curve_set.has_curve()) {
+ if (curve_set.has_mesh()) {
+ params.error_message_add(NodeWarningType::Warning,
+ TIP_("No curve data available in curve input"));
+ }
params.set_output("Mesh", GeometrySet());
return;
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
index e37822bd262..bb8f560f92d 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_curve_to_points.cc
@@ -118,22 +118,6 @@ static Array<int> calculate_spline_point_offsets(GeoNodeExecParams &params,
return {0};
}
-/**
- * \note This doesn't store a map for spline domain attributes.
- */
-struct ResultAttributes {
- int result_size;
- MutableSpan<float3> positions;
- MutableSpan<float> radii;
- MutableSpan<float> tilts;
-
- Map<std::string, GMutableSpan> point_attributes;
-
- MutableSpan<float3> tangents;
- MutableSpan<float3> normals;
- MutableSpan<float3> rotations;
-};
-
static GMutableSpan create_attribute_and_retrieve_span(PointCloudComponent &points,
const StringRef name,
const CustomDataType data_type)
@@ -153,13 +137,10 @@ static MutableSpan<T> create_attribute_and_retrieve_span(PointCloudComponent &po
return attribute.typed<T>();
}
-/**
- * Create references for all result point cloud attributes to simplify accessing them later on.
- */
-static ResultAttributes create_point_attributes(PointCloudComponent &points,
- const CurveEval &curve)
+CurveToPointsResults curve_to_points_create_result_attributes(PointCloudComponent &points,
+ const CurveEval &curve)
{
- ResultAttributes attributes;
+ CurveToPointsResults attributes;
attributes.result_size = points.attribute_domain_size(ATTR_DOMAIN_POINT);
@@ -190,7 +171,7 @@ static ResultAttributes create_point_attributes(PointCloudComponent &points,
*/
static void copy_evaluated_point_attributes(Span<SplinePtr> splines,
Span<int> offsets,
- ResultAttributes &data)
+ CurveToPointsResults &data)
{
threading::parallel_for(splines.index_range(), 64, [&](IndexRange range) {
for (const int i : range) {
@@ -221,7 +202,7 @@ static void copy_evaluated_point_attributes(Span<SplinePtr> splines,
static void copy_uniform_sample_point_attributes(Span<SplinePtr> splines,
Span<int> offsets,
- ResultAttributes &data)
+ CurveToPointsResults &data)
{
threading::parallel_for(splines.index_range(), 64, [&](IndexRange range) {
for (const int i : range) {
@@ -307,13 +288,14 @@ static void copy_spline_domain_attributes(const CurveComponent &curve_component,
});
}
-static void create_default_rotation_attribute(ResultAttributes &data)
+void curve_create_default_rotation_attribute(Span<float3> tangents,
+ Span<float3> normals,
+ MutableSpan<float3> rotations)
{
- threading::parallel_for(IndexRange(data.result_size), 512, [&](IndexRange range) {
+ threading::parallel_for(IndexRange(rotations.size()), 512, [&](IndexRange range) {
for (const int i : range) {
- data.rotations[i] = float4x4::from_normalized_axis_data(
- {0, 0, 0}, data.normals[i], data.tangents[i])
- .to_euler();
+ rotations[i] =
+ float4x4::from_normalized_axis_data({0, 0, 0}, normals[i], tangents[i]).to_euler();
}
});
}
@@ -348,8 +330,8 @@ static void geo_node_curve_to_points_exec(GeoNodeExecParams params)
GeometrySet result = GeometrySet::create_with_pointcloud(BKE_pointcloud_new_nomain(total_size));
PointCloudComponent &point_component = result.get_component_for_write<PointCloudComponent>();
- ResultAttributes new_attributes = create_point_attributes(point_component, curve);
-
+ CurveToPointsResults new_attributes = curve_to_points_create_result_attributes(point_component,
+ curve);
switch (mode) {
case GEO_NODE_CURVE_SAMPLE_COUNT:
case GEO_NODE_CURVE_SAMPLE_LENGTH:
@@ -361,7 +343,8 @@ static void geo_node_curve_to_points_exec(GeoNodeExecParams params)
}
copy_spline_domain_attributes(curve_component, offsets, point_component);
- create_default_rotation_attribute(new_attributes);
+ curve_create_default_rotation_attribute(
+ new_attributes.tangents, new_attributes.normals, new_attributes.rotations);
/* The default radius is way too large for points, divide by 10. */
for (float &radius : new_attributes.radii) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
index b1da2dcd3c4..8c697275f88 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_delete_geometry.cc
@@ -627,7 +627,7 @@ static void delete_mesh_selection(MeshComponent &component,
mesh_out = nullptr;
break;
}
- component.replace_mesh_but_keep_vertex_group_names(mesh_out);
+ component.replace(mesh_out);
}
static void geo_node_delete_geometry_exec(GeoNodeExecParams params)
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 2915a17d2c8..667e1c931bd 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
@@ -228,7 +228,8 @@ void register_node_type_geo_mesh_primitive_circle()
{
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_CIRCLE, "Circle", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(
+ &ntype, GEO_NODE_MESH_PRIMITIVE_CIRCLE, "Mesh Circle", NODE_CLASS_GEOMETRY, 0);
node_type_socket_templates(
&ntype, geo_node_mesh_primitive_circle_in, geo_node_mesh_primitive_circle_out);
node_type_init(&ntype, geo_node_mesh_primitive_circle_init);
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 e841455e58c..a193c05daa1 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
@@ -177,7 +177,7 @@ void register_node_type_geo_mesh_primitive_line()
{
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_LINE, "Line", NODE_CLASS_GEOMETRY, 0);
+ geo_node_type_base(&ntype, GEO_NODE_MESH_PRIMITIVE_LINE, "Mesh Line", NODE_CLASS_GEOMETRY, 0);
node_type_socket_templates(
&ntype, geo_node_mesh_primitive_line_in, geo_node_mesh_primitive_line_out);
node_type_init(&ntype, geo_node_mesh_primitive_line_init);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivide.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
index a4c6522c57a..245d7800621 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_subdivide.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_subdivide.cc
@@ -14,8 +14,6 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-// #include "MEM_guardedalloc.h"
-
#include "BKE_mesh.h"
#include "BKE_subdiv.h"
#include "BKE_subdiv_mesh.h"
@@ -25,20 +23,20 @@
#include "node_geometry_util.hh"
-static bNodeSocketTemplate geo_node_subdivide_in[] = {
+static bNodeSocketTemplate geo_node_mesh_subdivide_in[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{SOCK_INT, N_("Level"), 1, 0, 0, 0, 0, 6},
{-1, ""},
};
-static bNodeSocketTemplate geo_node_subdivide_out[] = {
+static bNodeSocketTemplate geo_node_mesh_subdivide_out[] = {
{SOCK_GEOMETRY, N_("Geometry")},
{-1, ""},
};
namespace blender::nodes {
-static void geo_node_subdivide_exec(GeoNodeExecParams params)
+static void geo_node_mesh_subdivide_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");
geometry_set = geometry_set_realize_instances(geometry_set);
@@ -93,7 +91,7 @@ static void geo_node_subdivide_exec(GeoNodeExecParams params)
BKE_mesh_calc_normals(mesh_out);
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
- mesh_component.replace_mesh_but_keep_vertex_group_names(mesh_out);
+ mesh_component.replace(mesh_out);
BKE_subdiv_free(subdiv);
@@ -102,12 +100,12 @@ static void geo_node_subdivide_exec(GeoNodeExecParams params)
} // namespace blender::nodes
-void register_node_type_geo_subdivide()
+void register_node_type_geo_mesh_subdivide()
{
static bNodeType ntype;
- geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE, "Subdivide", NODE_CLASS_GEOMETRY, 0);
- node_type_socket_templates(&ntype, geo_node_subdivide_in, geo_node_subdivide_out);
- ntype.geometry_node_execute = blender::nodes::geo_node_subdivide_exec;
+ geo_node_type_base(&ntype, GEO_NODE_MESH_SUBDIVIDE, "Mesh Subdivide", NODE_CLASS_GEOMETRY, 0);
+ node_type_socket_templates(&ntype, geo_node_mesh_subdivide_in, geo_node_mesh_subdivide_out);
+ ntype.geometry_node_execute = blender::nodes::geo_node_mesh_subdivide_exec;
nodeRegisterType(&ntype);
}
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 772bd8a1080..d456c72744f 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc
@@ -83,8 +83,7 @@ static float3 normal_to_euler_rotation(const float3 normal)
static Span<MLoopTri> get_mesh_looptris(const Mesh &mesh)
{
- /* This only updates a cache and can be considered to be logically const. */
- const MLoopTri *looptris = BKE_mesh_runtime_looptri_ensure(const_cast<Mesh *>(&mesh));
+ const MLoopTri *looptris = BKE_mesh_runtime_looptri_ensure(&mesh);
const int looptris_len = BKE_mesh_runtime_looptri_len(&mesh);
return {looptris, looptris_len};
}
diff --git a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
index bfd6027e0fc..0c1d8645411 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_raycast.cc
@@ -95,7 +95,7 @@ static void raycast_to_mesh(const Mesh *mesh,
BLI_assert(ray_origins.size() == r_hit_distances.size() || r_hit_distances.is_empty());
BVHTreeFromMesh tree_data;
- BKE_bvhtree_from_mesh_get(&tree_data, const_cast<Mesh *>(mesh), BVHTREE_FROM_LOOPTRI, 4);
+ BKE_bvhtree_from_mesh_get(&tree_data, mesh, BVHTREE_FROM_LOOPTRI, 4);
if (tree_data.tree != nullptr) {
for (const int i : ray_origins.index_range()) {
diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
index 20ffcdb516d..f0f032ed8f4 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc
@@ -96,7 +96,7 @@ static void geo_node_subdivision_surface_exec(GeoNodeExecParams params)
BKE_mesh_calc_normals(mesh_out);
MeshComponent &mesh_component = geometry_set.get_component_for_write<MeshComponent>();
- mesh_component.replace_mesh_but_keep_vertex_group_names(mesh_out);
+ mesh_component.replace(mesh_out);
// BKE_subdiv_stats_print(&subdiv->stats);
BKE_subdiv_free(subdiv);
diff --git a/source/blender/nodes/geometry/nodes/node_geo_viewer.cc b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
new file mode 100644
index 00000000000..f0b91f49f52
--- /dev/null
+++ b/source/blender/nodes/geometry/nodes/node_geo_viewer.cc
@@ -0,0 +1,31 @@
+/*
+ * 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"
+
+static bNodeSocketTemplate geo_node_viewer_in[] = {
+ {SOCK_GEOMETRY, N_("Geometry")},
+ {-1, ""},
+};
+
+void register_node_type_geo_viewer()
+{
+ static bNodeType ntype;
+
+ geo_node_type_base(&ntype, GEO_NODE_VIEWER, "Viewer", NODE_CLASS_OUTPUT, 0);
+ node_type_socket_templates(&ntype, geo_node_viewer_in, nullptr);
+ nodeRegisterType(&ntype);
+}
diff --git a/source/blender/nodes/intern/geometry_nodes_eval_log.cc b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
new file mode 100644
index 00000000000..3024cc51cad
--- /dev/null
+++ b/source/blender/nodes/intern/geometry_nodes_eval_log.cc
@@ -0,0 +1,361 @@
+/*
+ * 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 "NOD_geometry_nodes_eval_log.hh"
+
+#include "BKE_geometry_set_instances.hh"
+
+#include "DNA_modifier_types.h"
+#include "DNA_space_types.h"
+
+namespace blender::nodes::geometry_nodes_eval_log {
+
+using fn::CPPType;
+
+ModifierLog::ModifierLog(GeoLogger &logger)
+{
+ root_tree_logs_ = allocator_.construct<TreeLog>();
+
+ LogByTreeContext log_by_tree_context;
+
+ /* Combine all the local loggers that have been used by separate threads. */
+ for (LocalGeoLogger &local_logger : logger) {
+ /* Take ownership of the allocator. */
+ logger_allocators_.append(std::move(local_logger.allocator_));
+
+ for (ValueOfSockets &value_of_sockets : local_logger.values_) {
+ ValueLog *value_log = value_of_sockets.value.get();
+
+ /* Take centralized ownership of the logged value. It might be referenced by multiple
+ * sockets. */
+ logged_values_.append(std::move(value_of_sockets.value));
+
+ for (const DSocket &socket : value_of_sockets.sockets) {
+ SocketLog &socket_log = this->lookup_or_add_socket_log(log_by_tree_context, socket);
+ socket_log.value_ = value_log;
+ }
+ }
+
+ for (NodeWithWarning &node_with_warning : local_logger.node_warnings_) {
+ NodeLog &node_log = this->lookup_or_add_node_log(log_by_tree_context,
+ node_with_warning.node);
+ node_log.warnings_.append(node_with_warning.warning);
+ }
+ }
+}
+
+TreeLog &ModifierLog::lookup_or_add_tree_log(LogByTreeContext &log_by_tree_context,
+ const DTreeContext &tree_context)
+{
+ TreeLog *tree_log = log_by_tree_context.lookup_default(&tree_context, nullptr);
+ if (tree_log != nullptr) {
+ return *tree_log;
+ }
+
+ const DTreeContext *parent_context = tree_context.parent_context();
+ if (parent_context == nullptr) {
+ return *root_tree_logs_.get();
+ }
+ TreeLog &parent_log = this->lookup_or_add_tree_log(log_by_tree_context, *parent_context);
+ destruct_ptr<TreeLog> owned_tree_log = allocator_.construct<TreeLog>();
+ tree_log = owned_tree_log.get();
+ log_by_tree_context.add_new(&tree_context, tree_log);
+ parent_log.child_logs_.add_new(tree_context.parent_node()->name(), std::move(owned_tree_log));
+ return *tree_log;
+}
+
+NodeLog &ModifierLog::lookup_or_add_node_log(LogByTreeContext &log_by_tree_context, DNode node)
+{
+ TreeLog &tree_log = this->lookup_or_add_tree_log(log_by_tree_context, *node.context());
+ NodeLog &node_log = *tree_log.node_logs_.lookup_or_add_cb(node->name(), [&]() {
+ destruct_ptr<NodeLog> node_log = allocator_.construct<NodeLog>();
+ node_log->input_logs_.resize(node->inputs().size());
+ node_log->output_logs_.resize(node->outputs().size());
+ return node_log;
+ });
+ return node_log;
+}
+
+SocketLog &ModifierLog::lookup_or_add_socket_log(LogByTreeContext &log_by_tree_context,
+ DSocket socket)
+{
+ NodeLog &node_log = this->lookup_or_add_node_log(log_by_tree_context, socket.node());
+ MutableSpan<SocketLog> socket_logs = socket->is_input() ? node_log.input_logs_ :
+ node_log.output_logs_;
+ SocketLog &socket_log = socket_logs[socket->index()];
+ return socket_log;
+}
+
+const NodeLog *TreeLog::lookup_node_log(StringRef node_name) const
+{
+ const destruct_ptr<NodeLog> *node_log = node_logs_.lookup_ptr_as(node_name);
+ if (node_log == nullptr) {
+ return nullptr;
+ }
+ return node_log->get();
+}
+
+const NodeLog *TreeLog::lookup_node_log(const bNode &node) const
+{
+ return this->lookup_node_log(node.name);
+}
+
+const TreeLog *TreeLog::lookup_child_log(StringRef node_name) const
+{
+ const destruct_ptr<TreeLog> *tree_log = child_logs_.lookup_ptr_as(node_name);
+ if (tree_log == nullptr) {
+ return nullptr;
+ }
+ return tree_log->get();
+}
+
+const SocketLog *NodeLog::lookup_socket_log(eNodeSocketInOut in_out, int index) const
+{
+ BLI_assert(index >= 0);
+ Span<SocketLog> socket_logs = (in_out == SOCK_IN) ? input_logs_ : output_logs_;
+ if (index >= socket_logs.size()) {
+ return nullptr;
+ }
+ return &socket_logs[index];
+}
+
+const SocketLog *NodeLog::lookup_socket_log(const bNode &node, const bNodeSocket &socket) const
+{
+ ListBase sockets = socket.in_out == SOCK_IN ? node.inputs : node.outputs;
+ int index = BLI_findindex(&sockets, &socket);
+ return this->lookup_socket_log((eNodeSocketInOut)socket.in_out, index);
+}
+
+GeometryValueLog::GeometryValueLog(const GeometrySet &geometry_set, bool log_full_geometry)
+{
+ bke::geometry_set_instances_attribute_foreach(
+ geometry_set,
+ [&](StringRefNull attribute_name, const AttributeMetaData &meta_data) {
+ this->attributes_.append({attribute_name, meta_data.domain, meta_data.data_type});
+ return true;
+ },
+ 8);
+ for (const GeometryComponent *component : geometry_set.get_components_for_read()) {
+ component_types_.append(component->type());
+ switch (component->type()) {
+ case GEO_COMPONENT_TYPE_MESH: {
+ const MeshComponent &mesh_component = *(const MeshComponent *)component;
+ MeshInfo &info = this->mesh_info.emplace();
+ info.tot_verts = mesh_component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ info.tot_edges = mesh_component.attribute_domain_size(ATTR_DOMAIN_EDGE);
+ info.tot_faces = mesh_component.attribute_domain_size(ATTR_DOMAIN_FACE);
+ break;
+ }
+ case GEO_COMPONENT_TYPE_CURVE: {
+ const CurveComponent &curve_component = *(const CurveComponent *)component;
+ CurveInfo &info = this->curve_info.emplace();
+ info.tot_splines = curve_component.attribute_domain_size(ATTR_DOMAIN_CURVE);
+ break;
+ }
+ case GEO_COMPONENT_TYPE_POINT_CLOUD: {
+ const PointCloudComponent &pointcloud_component = *(const PointCloudComponent *)component;
+ PointCloudInfo &info = this->pointcloud_info.emplace();
+ info.tot_points = pointcloud_component.attribute_domain_size(ATTR_DOMAIN_POINT);
+ break;
+ }
+ case GEO_COMPONENT_TYPE_INSTANCES: {
+ const InstancesComponent &instances_component = *(const InstancesComponent *)component;
+ InstancesInfo &info = this->instances_info.emplace();
+ info.tot_instances = instances_component.instances_amount();
+ break;
+ }
+ case GEO_COMPONENT_TYPE_VOLUME: {
+ break;
+ }
+ }
+ }
+ if (log_full_geometry) {
+ full_geometry_ = std::make_unique<GeometrySet>(geometry_set);
+ full_geometry_->ensure_owns_direct_data();
+ }
+}
+
+Vector<const GeometryAttributeInfo *> NodeLog::lookup_available_attributes() const
+{
+ Vector<const GeometryAttributeInfo *> attributes;
+ Set<StringRef> names;
+ for (const SocketLog &socket_log : input_logs_) {
+ const ValueLog *value_log = socket_log.value();
+ if (const GeometryValueLog *geo_value_log = dynamic_cast<const GeometryValueLog *>(
+ value_log)) {
+ for (const GeometryAttributeInfo &attribute : geo_value_log->attributes()) {
+ if (names.add(attribute.name)) {
+ attributes.append(&attribute);
+ }
+ }
+ }
+ }
+ return attributes;
+}
+
+const ModifierLog *ModifierLog::find_root_by_node_editor_context(const SpaceNode &snode)
+{
+ if (snode.id == nullptr) {
+ return nullptr;
+ }
+ if (GS(snode.id->name) != ID_OB) {
+ return nullptr;
+ }
+ Object *object = (Object *)snode.id;
+ LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
+ if (md->type == eModifierType_Nodes) {
+ NodesModifierData *nmd = (NodesModifierData *)md;
+ if (nmd->node_group == snode.nodetree) {
+ return (ModifierLog *)nmd->runtime_eval_log;
+ }
+ }
+ }
+ return nullptr;
+}
+
+const TreeLog *ModifierLog::find_tree_by_node_editor_context(const SpaceNode &snode)
+{
+ const ModifierLog *eval_log = ModifierLog::find_root_by_node_editor_context(snode);
+ if (eval_log == nullptr) {
+ return nullptr;
+ }
+ Vector<bNodeTreePath *> tree_path_vec = snode.treepath;
+ if (tree_path_vec.is_empty()) {
+ return nullptr;
+ }
+ TreeLog *current = eval_log->root_tree_logs_.get();
+ for (bNodeTreePath *path : tree_path_vec.as_span().drop_front(1)) {
+ destruct_ptr<TreeLog> *tree_log = current->child_logs_.lookup_ptr_as(path->node_name);
+ if (tree_log == nullptr) {
+ return nullptr;
+ }
+ current = tree_log->get();
+ }
+ return current;
+}
+
+const NodeLog *ModifierLog::find_node_by_node_editor_context(const SpaceNode &snode,
+ const bNode &node)
+{
+ const TreeLog *tree_log = ModifierLog::find_tree_by_node_editor_context(snode);
+ if (tree_log == nullptr) {
+ return nullptr;
+ }
+ return tree_log->lookup_node_log(node);
+}
+
+const SocketLog *ModifierLog::find_socket_by_node_editor_context(const SpaceNode &snode,
+ const bNode &node,
+ const bNodeSocket &socket)
+{
+ const NodeLog *node_log = ModifierLog::find_node_by_node_editor_context(snode, node);
+ if (node_log == nullptr) {
+ return nullptr;
+ }
+ return node_log->lookup_socket_log(node, socket);
+}
+
+const NodeLog *ModifierLog::find_node_by_spreadsheet_editor_context(
+ const SpaceSpreadsheet &sspreadsheet)
+{
+ Vector<SpreadsheetContext *> context_path = sspreadsheet.context_path;
+ if (context_path.size() <= 2) {
+ return nullptr;
+ }
+ if (context_path[0]->type != SPREADSHEET_CONTEXT_OBJECT) {
+ return nullptr;
+ }
+ if (context_path[1]->type != SPREADSHEET_CONTEXT_MODIFIER) {
+ return nullptr;
+ }
+ for (SpreadsheetContext *context : context_path.as_span().drop_front(2)) {
+ if (context->type != SPREADSHEET_CONTEXT_NODE) {
+ return nullptr;
+ }
+ }
+ Span<SpreadsheetContextNode *> node_contexts =
+ context_path.as_span().drop_front(2).cast<SpreadsheetContextNode *>();
+
+ Object *object = ((SpreadsheetContextObject *)context_path[0])->object;
+ StringRefNull modifier_name = ((SpreadsheetContextModifier *)context_path[1])->modifier_name;
+ if (object == nullptr) {
+ return nullptr;
+ }
+
+ const ModifierLog *eval_log = nullptr;
+ LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
+ if (md->type == eModifierType_Nodes) {
+ if (md->name == modifier_name) {
+ NodesModifierData *nmd = (NodesModifierData *)md;
+ eval_log = (const ModifierLog *)nmd->runtime_eval_log;
+ break;
+ }
+ }
+ }
+ if (eval_log == nullptr) {
+ return nullptr;
+ }
+
+ const TreeLog *tree_log = &eval_log->root_tree();
+ for (SpreadsheetContextNode *context : node_contexts.drop_back(1)) {
+ tree_log = tree_log->lookup_child_log(context->node_name);
+ if (tree_log == nullptr) {
+ return nullptr;
+ }
+ }
+ const NodeLog *node_log = tree_log->lookup_node_log(node_contexts.last()->node_name);
+ return node_log;
+}
+
+void LocalGeoLogger::log_value_for_sockets(Span<DSocket> sockets, GPointer value)
+{
+ const CPPType &type = *value.type();
+ Span<DSocket> copied_sockets = allocator_->construct_array_copy(sockets);
+ if (type.is<GeometrySet>()) {
+ bool log_full_geometry = false;
+ for (const DSocket &socket : sockets) {
+ if (main_logger_->log_full_geometry_sockets_.contains(socket)) {
+ log_full_geometry = true;
+ break;
+ }
+ }
+
+ const GeometrySet &geometry_set = *value.get<GeometrySet>();
+ destruct_ptr<GeometryValueLog> value_log = allocator_->construct<GeometryValueLog>(
+ geometry_set, log_full_geometry);
+ values_.append({copied_sockets, std::move(value_log)});
+ }
+ else {
+ void *buffer = allocator_->allocate(type.size(), type.alignment());
+ type.copy_construct(value.get(), buffer);
+ destruct_ptr<GenericValueLog> value_log = allocator_->construct<GenericValueLog>(
+ GMutablePointer{type, buffer});
+ values_.append({copied_sockets, std::move(value_log)});
+ }
+}
+
+void LocalGeoLogger::log_multi_value_socket(DSocket socket, Span<GPointer> values)
+{
+ /* Doesn't have to be logged currently. */
+ UNUSED_VARS(socket, values);
+}
+
+void LocalGeoLogger::log_node_warning(DNode node, NodeWarningType type, std::string message)
+{
+ node_warnings_.append({node, {type, std::move(message)}});
+}
+
+} // namespace blender::nodes::geometry_nodes_eval_log
diff --git a/source/blender/nodes/intern/node_common.c b/source/blender/nodes/intern/node_common.c
index 7fc9f664df0..b8c89d1db37 100644
--- a/source/blender/nodes/intern/node_common.c
+++ b/source/blender/nodes/intern/node_common.c
@@ -127,7 +127,7 @@ static bNodeSocket *group_verify_socket(
bNodeSocket *sock;
for (sock = verify_lb->first; sock; sock = sock->next) {
- if (sock->typeinfo == iosock->typeinfo && STREQ(sock->identifier, iosock->identifier)) {
+ if (STREQ(sock->identifier, iosock->identifier)) {
break;
}
}
@@ -137,6 +137,13 @@ static bNodeSocket *group_verify_socket(
const int mask = SOCK_HIDE_VALUE;
sock->flag = (sock->flag & ~mask) | (iosock->flag & mask);
+ /* Update socket type if necessary */
+ if (sock->typeinfo != iosock->typeinfo) {
+ nodeModifySocketType(ntree, gnode, sock, iosock->idname);
+ /* Flag the tree to make sure link validity is updated after type changes. */
+ ntree->update |= NTREE_UPDATE_LINKS;
+ }
+
if (iosock->typeinfo->interface_verify_socket) {
iosock->typeinfo->interface_verify_socket(ntree, iosock, gnode, sock, "interface");
}
@@ -259,7 +266,7 @@ static void node_reroute_update_internal_links(bNodeTree *ntree, bNode *node)
static void node_reroute_init(bNodeTree *ntree, bNode *node)
{
- /* Note: Cannot use socket templates for this, since it would reset the socket type
+ /* NOTE: Cannot use socket templates for this, since it would reset the socket type
* on each file read via the template verification procedure.
*/
nodeAddStaticSocket(ntree, node, SOCK_IN, SOCK_RGBA, PROP_NONE, "Input", "Input");
diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc
index 8b61758a673..1e39aa5214d 100644
--- a/source/blender/nodes/intern/node_geometry_exec.cc
+++ b/source/blender/nodes/intern/node_geometry_exec.cc
@@ -16,8 +16,6 @@
#include "DNA_modifier_types.h"
-#include "BKE_node_ui_storage.hh"
-
#include "DEG_depsgraph_query.h"
#include "NOD_geometry_exec.hh"
@@ -26,21 +24,17 @@
#include "node_geometry_util.hh"
+using blender::nodes::geometry_nodes_eval_log::LocalGeoLogger;
+
namespace blender::nodes {
void GeoNodeExecParams::error_message_add(const NodeWarningType type, std::string message) const
{
- bNodeTree *btree_cow = provider_->dnode->btree();
- BLI_assert(btree_cow != nullptr);
- if (btree_cow == nullptr) {
+ if (provider_->logger == nullptr) {
return;
}
- bNodeTree *btree_original = (bNodeTree *)DEG_get_original_id((ID *)btree_cow);
-
- const NodeTreeEvaluationContext context(*provider_->self_object, *provider_->modifier);
-
- BKE_nodetree_error_message_add(
- *btree_original, context, *provider_->dnode->bnode(), type, std::move(message));
+ LocalGeoLogger &local_logger = provider_->logger->local();
+ local_logger.log_node_warning(provider_->dnode, type, std::move(message));
}
const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name) const
diff --git a/source/blender/nodes/intern/node_socket.cc b/source/blender/nodes/intern/node_socket.cc
index c0a8382a661..e2568fd8f85 100644
--- a/source/blender/nodes/intern/node_socket.cc
+++ b/source/blender/nodes/intern/node_socket.cc
@@ -131,7 +131,7 @@ static bNodeSocket *verify_socket_template(bNodeTree *ntree,
}
if (sock) {
if (sock->type != stemp->type) {
- nodeModifySocketType(ntree, node, sock, stemp->type, stemp->subtype);
+ nodeModifySocketTypeStatic(ntree, node, sock, stemp->type, stemp->subtype);
}
sock->flag |= stemp->flag;
}
@@ -563,12 +563,14 @@ static bNodeSocketType *make_standard_socket_type(int type, int subtype)
{
const char *socket_idname = nodeStaticSocketType(type, subtype);
const char *interface_idname = nodeStaticSocketInterfaceType(type, subtype);
+ const char *socket_label = nodeStaticSocketLabel(type, subtype);
bNodeSocketType *stype;
StructRNA *srna;
stype = (bNodeSocketType *)MEM_callocN(sizeof(bNodeSocketType), "node socket C type");
stype->free_self = (void (*)(bNodeSocketType * stype)) MEM_freeN;
BLI_strncpy(stype->idname, socket_idname, sizeof(stype->idname));
+ BLI_strncpy(stype->label, socket_label, sizeof(stype->label));
/* set the RNA type
* uses the exact same identifier as the socket type idname */
diff --git a/source/blender/nodes/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc
index bed4d60382d..9ce9d6fc273 100644
--- a/source/blender/nodes/intern/node_tree_ref.cc
+++ b/source/blender/nodes/intern/node_tree_ref.cc
@@ -461,7 +461,7 @@ bool NodeTreeRef::has_undefined_nodes_or_sockets() const
return true;
}
}
- return true;
+ return false;
}
std::string NodeTreeRef::to_dot() const
diff --git a/source/blender/nodes/shader/node_shader_tree.c b/source/blender/nodes/shader/node_shader_tree.c
index e23e2ac3b9d..7367f73d171 100644
--- a/source/blender/nodes/shader/node_shader_tree.c
+++ b/source/blender/nodes/shader/node_shader_tree.c
@@ -184,10 +184,11 @@ static bool shader_validate_link(bNodeTree *UNUSED(ntree), bNodeLink *link)
return true;
}
-static bool shader_node_tree_socket_type_valid(eNodeSocketDatatype socket_type,
- bNodeTreeType *UNUSED(ntreetype))
+static bool shader_node_tree_socket_type_valid(bNodeTreeType *UNUSED(ntreetype),
+ bNodeSocketType *socket_type)
{
- return ELEM(socket_type, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_SHADER);
+ return nodeIsStaticSocketType(socket_type) &&
+ ELEM(socket_type->type, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA, SOCK_SHADER);
}
bNodeTreeType *ntreeType_Shader;
@@ -790,7 +791,7 @@ static void ntree_shader_relink_displacement(bNodeTree *ntree, bNode *output_nod
*/
nodeAddLink(ntree, displacement_node, displacement_socket, bump_node, bump_input_socket);
- /* Tag as part of the new displacmeent tree. */
+ /* Tag as part of the new displacement tree. */
dot_node->tmp_flag = -2;
geo_node->tmp_flag = -2;
bump_node->tmp_flag = -2;
diff --git a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
index 7a05fc95eec..50eb5bf32c9 100644
--- a/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
+++ b/source/blender/nodes/shader/nodes/node_shader_hueSatVal.c
@@ -37,7 +37,7 @@ static bNodeSocketTemplate sh_node_hue_sat_out[] = {
{-1, ""},
};
-/* note: it would be possible to use CMP version for both nodes */
+/* NOTE: it would be possible to use CMP version for both nodes. */
static void do_hue_sat_fac(
bNode *UNUSED(node), float *out, float hue, float sat, float val, const float in[4], float fac)
{
diff --git a/source/blender/nodes/texture/node_texture_tree.c b/source/blender/nodes/texture/node_texture_tree.c
index 2ae722e3cd8..f771b4934b2 100644
--- a/source/blender/nodes/texture/node_texture_tree.c
+++ b/source/blender/nodes/texture/node_texture_tree.c
@@ -152,10 +152,11 @@ static void update(bNodeTree *ntree)
}
}
-static bool texture_node_tree_socket_type_valid(eNodeSocketDatatype socket_type,
- bNodeTreeType *UNUSED(ntreetype))
+static bool texture_node_tree_socket_type_valid(bNodeTreeType *UNUSED(ntreetype),
+ bNodeSocketType *socket_type)
{
- return ELEM(socket_type, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA);
+ return nodeIsStaticSocketType(socket_type) &&
+ ELEM(socket_type->type, SOCK_FLOAT, SOCK_VECTOR, SOCK_RGBA);
}
bNodeTreeType *ntreeType_Texture;