Eevee-Next: World Reflective Light #108149

Merged
Jeroen Bakker merged 33 commits from Jeroen-Bakker/blender:eevee-next-world-shader into main 2023-06-29 15:25:04 +02:00
130 changed files with 1655 additions and 1204 deletions
Showing only changes of commit 9463720cff - Show all commits

View File

@ -928,6 +928,27 @@ elseif(CMAKE_C_COMPILER_ID MATCHES "Clang")
unset(MOLD_BIN) unset(MOLD_BIN)
endif() endif()
if(WITH_LINKER_LLD AND _IS_LINKER_DEFAULT)
find_program(LLD_BIN "ld.lld")
mark_as_advanced(LLD_BIN)
if(NOT LLD_BIN)
message(STATUS "The \"ld.lld\" binary could not be found, using system linker.")
set(WITH_LINKER_LLD OFF)
else()
if(CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 12.0)
string(APPEND CMAKE_EXE_LINKER_FLAGS " --ld-path=\"${LLD_BIN}\"")
string(APPEND CMAKE_SHARED_LINKER_FLAGS " --ld-path=\"${LLD_BIN}\"")
string(APPEND CMAKE_MODULE_LINKER_FLAGS " --ld-path=\"${LLD_BIN}\"")
else()
string(APPEND CMAKE_EXE_LINKER_FLAGS " -fuse-ld=\"${LLD_BIN}\"")
string(APPEND CMAKE_SHARED_LINKER_FLAGS " -fuse-ld=\"${LLD_BIN}\"")
string(APPEND CMAKE_MODULE_LINKER_FLAGS " -fuse-ld=\"${LLD_BIN}\"")
endif()
set(_IS_LINKER_DEFAULT OFF)
endif()
unset(LLD_BIN)
endif()
# Intel C++ Compiler # Intel C++ Compiler
elseif(CMAKE_C_COMPILER_ID MATCHES "Intel") elseif(CMAKE_C_COMPILER_ID MATCHES "Intel")
# think these next two are broken # think these next two are broken

View File

@ -398,7 +398,7 @@ def lightmap_uvpack(
# Since the boxes are sized in powers of 2, we can neatly group them into bigger squares # Since the boxes are sized in powers of 2, we can neatly group them into bigger squares
# this is done hierarchically, so that we may avoid running the pack function # this is done hierarchically, so that we may avoid running the pack function
# on many thousands of boxes, (under 1k is best) because it would get slow. # on many thousands of boxes, (under 1k is best) because it would get slow.
# Using an off and even dict us useful because they are packed differently # Using an odd and even dict is useful because they are packed differently
# where w/h are the same, their packed in groups of 4 # where w/h are the same, their packed in groups of 4
# where they are different they are packed in pairs # where they are different they are packed in pairs
# #

View File

@ -3592,9 +3592,6 @@ class VIEW3D_MT_face_sets_init(Menu):
props = layout.operator("sculpt.face_sets_init", text="By Sharp Edges") props = layout.operator("sculpt.face_sets_init", text="By Sharp Edges")
props.mode = 'SHARP_EDGES' props.mode = 'SHARP_EDGES'
props = layout.operator("sculpt.face_sets_init", text="By Face Maps")
props.mode = 'FACE_MAPS'
class VIEW3D_MT_random_mask(Menu): class VIEW3D_MT_random_mask(Menu):
bl_label = "Random Mask" bl_label = "Random Mask"

View File

@ -258,12 +258,9 @@ class CurvesGeometry : public ::CurvesGeometry {
MutableSpan<float2> surface_uv_coords_for_write(); MutableSpan<float2> surface_uv_coords_for_write();
/** /**
* Calculate the largest and smallest position values, only including control points * The largest and smallest position values of evaluated points.
* (rather than evaluated points). The existing values of `min` and `max` are taken into account.
*
* \return Whether there are any points. If the curve is empty, the inputs will be unaffected.
*/ */
bool bounds_min_max(float3 &min, float3 &max) const; std::optional<Bounds<float3>> bounds_min_max() const;
private: private:
/* -------------------------------------------------------------------- /* --------------------------------------------------------------------

View File

@ -8,13 +8,12 @@
* \ingroup bke * \ingroup bke
*/ */
#include <atomic>
#include <iostream> #include <iostream>
#include <mutex> #include <mutex>
#include "BLI_bounds_types.hh"
#include "BLI_function_ref.hh" #include "BLI_function_ref.hh"
#include "BLI_map.hh" #include "BLI_map.hh"
#include "BLI_vector_set.hh"
#include "BKE_attribute.hh" #include "BKE_attribute.hh"
@ -194,7 +193,7 @@ struct GeometrySet {
*/ */
Vector<const GeometryComponent *> get_components_for_read() const; Vector<const GeometryComponent *> get_components_for_read() const;
bool compute_boundbox_without_instances(float3 *r_min, float3 *r_max) const; std::optional<Bounds<float3>> compute_boundbox_without_instances() const;
friend std::ostream &operator<<(std::ostream &stream, const GeometrySet &geometry_set); friend std::ostream &operator<<(std::ostream &stream, const GeometrySet &geometry_set);

View File

@ -265,7 +265,6 @@ void BKE_mesh_nomain_to_meshkey(struct Mesh *mesh_src, struct Mesh *mesh_dst, st
/* vertex level transformations & checks (no derived mesh) */ /* vertex level transformations & checks (no derived mesh) */
/* basic vertex data functions */ /* basic vertex data functions */
bool BKE_mesh_minmax(const struct Mesh *me, float r_min[3], float r_max[3]);
void BKE_mesh_transform(struct Mesh *me, const float mat[4][4], bool do_keys); void BKE_mesh_transform(struct Mesh *me, const float mat[4][4], bool do_keys);
void BKE_mesh_translate(struct Mesh *me, const float offset[3], bool do_keys); void BKE_mesh_translate(struct Mesh *me, const float offset[3], bool do_keys);
@ -512,7 +511,6 @@ bool BKE_mesh_center_median(const struct Mesh *me, float r_cent[3]);
* use when we want to ignore vertex locations that don't have connected faces. * use when we want to ignore vertex locations that don't have connected faces.
*/ */
bool BKE_mesh_center_median_from_polys(const struct Mesh *me, float r_cent[3]); bool BKE_mesh_center_median_from_polys(const struct Mesh *me, float r_cent[3]);
bool BKE_mesh_center_bounds(const struct Mesh *me, float r_cent[3]);
bool BKE_mesh_center_of_surface(const struct Mesh *me, float r_cent[3]); bool BKE_mesh_center_of_surface(const struct Mesh *me, float r_cent[3]);
/** /**
* \note Mesh must be manifold with consistent face-winding, * \note Mesh must be manifold with consistent face-winding,

View File

@ -576,17 +576,15 @@ int ntreeGetPanelIndex(const bNodeTree *ntree, const bNodePanel *panel);
/** /**
* Add a new panel to the node tree. * Add a new panel to the node tree.
* \param name: Name of the new panel. * \param name: Name of the new panel.
* \param flag: Flags of the new panel.
*/ */
bNodePanel *ntreeAddPanel(bNodeTree *ntree, const char *name, int flag); bNodePanel *ntreeAddPanel(bNodeTree *ntree, const char *name);
/** /**
* Insert a new panel in the node tree. * Insert a new panel in the node tree.
* \param name: Name of the new panel. * \param name: Name of the new panel.
* \param flag: Flags of the new panel.
* \param index: Index at which to insert the panel. * \param index: Index at which to insert the panel.
*/ */
bNodePanel *ntreeInsertPanel(bNodeTree *ntree, const char *name, int flag, int index); bNodePanel *ntreeInsertPanel(bNodeTree *ntree, const char *name, int index);
/** Remove a panel from the node tree. */ /** Remove a panel from the node tree. */
void ntreeRemovePanel(bNodeTree *ntree, bNodePanel *panel); void ntreeRemovePanel(bNodeTree *ntree, bNodePanel *panel);

View File

@ -291,6 +291,9 @@ class bNodeRuntime : NonCopyable, NonMovable {
bool has_available_linked_outputs = false; bool has_available_linked_outputs = false;
Vector<bNode *> direct_children_in_frame; Vector<bNode *> direct_children_in_frame;
bNodeTree *owner_tree = nullptr; bNodeTree *owner_tree = nullptr;
/** Can be used to toposort a subset of nodes. */
int toposort_left_to_right_index = -1;
int toposort_right_to_left_index = -1;
}; };
namespace node_tree_runtime { namespace node_tree_runtime {
@ -515,6 +518,18 @@ inline blender::Span<bNode *> bNodeTree::root_frames() const
return this->runtime->root_frames; return this->runtime->root_frames;
} }
inline blender::Span<bNodeLink *> bNodeTree::all_links()
{
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
return this->runtime->links;
}
inline blender::Span<const bNodeLink *> bNodeTree::all_links() const
{
BLI_assert(blender::bke::node_tree_runtime::topology_cache_is_available(*this));
return this->runtime->links;
}
inline blender::Span<const bNodePanel *> bNodeTree::panels() const inline blender::Span<const bNodePanel *> bNodeTree::panels() const
{ {
return blender::Span(panels_array, panels_num); return blender::Span(panels_array, panels_num);
@ -525,6 +540,8 @@ inline blender::MutableSpan<bNodePanel *> bNodeTree::panels_for_write()
return blender::MutableSpan(panels_array, panels_num); return blender::MutableSpan(panels_array, panels_num);
} }
/** \} */
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */
/** \name #bNode Inline Methods /** \name #bNode Inline Methods
* \{ */ * \{ */

View File

@ -28,16 +28,31 @@ struct TreeZone {
TreeZone *parent_zone = nullptr; TreeZone *parent_zone = nullptr;
/** Direct children zones. Does not contain recursively nested zones. */ /** Direct children zones. Does not contain recursively nested zones. */
Vector<TreeZone *> child_zones; Vector<TreeZone *> child_zones;
/** Direct children nodes. Does not contain recursively nested nodes. */ /** Direct children nodes excluding nodes that belong to child zones. */
Vector<const bNode *> child_nodes; Vector<const bNode *> child_nodes;
/** Links that enter the zone through the zone border. */
Vector<const bNodeLink *> border_links;
bool contains_node_recursively(const bNode &node) const; bool contains_node_recursively(const bNode &node) const;
bool contains_zone_recursively(const TreeZone &other_zone) const;
}; };
class TreeZones { class TreeZones {
public: public:
Vector<std::unique_ptr<TreeZone>> zones; Vector<std::unique_ptr<TreeZone>> zones;
Map<int, int> parent_zone_by_node_id; Vector<TreeZone *> root_zones;
Vector<const bNode *> nodes_outside_zones;
/**
* Zone index by node. Nodes that are in no zone, are not included. Nodes that are at the border
* of a zone (e.g. Simulation Input) are mapped to the zone they create.
*/
Map<int, int> zone_by_node_id;
/**
* Get the deepest zone that a socket is in. Note that the inputs of a Simulation Input node are
* in a different zone than its output sockets.
*/
const TreeZone *get_zone_by_socket(const bNodeSocket &socket) const;
}; };
const TreeZones *get_tree_zones(const bNodeTree &tree); const TreeZones *get_tree_zones(const bNodeTree &tree);

View File

@ -151,6 +151,9 @@ struct StatesAroundFrame {
class ModifierSimulationCache { class ModifierSimulationCache {
private: private:
mutable std::mutex states_at_frames_mutex_; mutable std::mutex states_at_frames_mutex_;
/**
* All simulation states, sorted by frame.
*/
Vector<std::unique_ptr<ModifierSimulationStateAtFrame>> states_at_frames_; Vector<std::unique_ptr<ModifierSimulationStateAtFrame>> states_at_frames_;
/** /**
* Used for baking to deduplicate arrays when writing and writing from storage. Sharing info * Used for baking to deduplicate arrays when writing and writing from storage. Sharing info

View File

@ -39,7 +39,7 @@ typedef struct bMovieHandle {
void (*end_movie)(void *context_v); void (*end_movie)(void *context_v);
/* Optional function. */ /* Optional function. */
void (*get_movie_path)(char *filepath, void (*get_movie_path)(char filepath[/*FILE_MAX*/ 1024],
const struct RenderData *rd, const struct RenderData *rd,
bool preview, bool preview,
const char *suffix); const char *suffix);
@ -53,7 +53,7 @@ bMovieHandle *BKE_movie_handle_get(char imtype);
/** /**
* \note Similar to #BKE_image_path_from_imformat() * \note Similar to #BKE_image_path_from_imformat()
*/ */
void BKE_movie_filepath_get(char *filepath, void BKE_movie_filepath_get(char filepath[/*FILE_MAX*/ 1024],
const struct RenderData *rd, const struct RenderData *rd,
bool preview, bool preview,
const char *suffix); const char *suffix);

View File

@ -65,7 +65,7 @@ int BKE_ffmpeg_append(void *context_v,
int recty, int recty,
const char *suffix, const char *suffix,
struct ReportList *reports); struct ReportList *reports);
void BKE_ffmpeg_filepath_get(char *filepath, void BKE_ffmpeg_filepath_get(char filepath[/*FILE_MAX*/ 1024],
const struct RenderData *rd, const struct RenderData *rd,
bool preview, bool preview,
const char *suffix); const char *suffix);

View File

@ -235,6 +235,7 @@ set(SRC
intern/node.cc intern/node.cc
intern/node_runtime.cc intern/node_runtime.cc
intern/node_tree_anonymous_attributes.cc intern/node_tree_anonymous_attributes.cc
intern/node_tree_dot_export.cc
intern/node_tree_field_inferencing.cc intern/node_tree_field_inferencing.cc
intern/node_tree_update.cc intern/node_tree_update.cc
intern/node_tree_zones.cc intern/node_tree_zones.cc

View File

@ -192,6 +192,7 @@ void *BKE_curves_add(Main *bmain, const char *name)
BoundBox *BKE_curves_boundbox_get(Object *ob) BoundBox *BKE_curves_boundbox_get(Object *ob)
{ {
using namespace blender;
BLI_assert(ob->type == OB_CURVES); BLI_assert(ob->type == OB_CURVES);
const Curves *curves_id = static_cast<const Curves *>(ob->data); const Curves *curves_id = static_cast<const Curves *>(ob->data);
@ -201,17 +202,13 @@ BoundBox *BKE_curves_boundbox_get(Object *ob)
if (ob->runtime.bb == nullptr) { if (ob->runtime.bb == nullptr) {
ob->runtime.bb = MEM_cnew<BoundBox>(__func__); ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
const bke::CurvesGeometry &curves = curves_id->geometry.wrap();
const blender::bke::CurvesGeometry &curves = curves_id->geometry.wrap(); if (const std::optional<Bounds<float3>> bounds = curves.bounds_min_max()) {
BKE_boundbox_init_from_minmax(ob->runtime.bb, bounds->min, bounds->max);
float3 min(FLT_MAX); }
float3 max(-FLT_MAX); else {
if (!curves.bounds_min_max(min, max)) { BKE_boundbox_init_from_minmax(ob->runtime.bb, float3(-1), float3(1));
min = float3(-1);
max = float3(1);
} }
BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
} }
return ob->runtime.bb; return ob->runtime.bb;

View File

@ -1096,19 +1096,14 @@ void CurvesGeometry::transform(const float4x4 &matrix)
this->tag_positions_changed(); this->tag_positions_changed();
} }
bool CurvesGeometry::bounds_min_max(float3 &min, float3 &max) const std::optional<Bounds<float3>> CurvesGeometry::bounds_min_max() const
{ {
if (this->points_num() == 0) { if (this->points_num() == 0) {
return false; return std::nullopt;
} }
this->runtime->bounds_cache.ensure( this->runtime->bounds_cache.ensure(
[&](Bounds<float3> &r_bounds) { r_bounds = *bounds::min_max(this->evaluated_positions()); }); [&](Bounds<float3> &r_bounds) { r_bounds = *bounds::min_max(this->evaluated_positions()); });
return this->runtime->bounds_cache.data();
const Bounds<float3> &bounds = this->runtime->bounds_cache.data();
min = math::min(bounds.min, min);
max = math::max(bounds.max, max);
return true;
} }
CurvesGeometry curves_copy_point_selection( CurvesGeometry curves_copy_point_selection(

View File

@ -33,9 +33,7 @@ TEST(curves_geometry, Empty)
{ {
CurvesGeometry empty(0, 0); CurvesGeometry empty(0, 0);
empty.cyclic(); empty.cyclic();
float3 min; EXPECT_FALSE(empty.bounds_min_max());
float3 max;
EXPECT_FALSE(empty.bounds_min_max(min, max));
} }
TEST(curves_geometry, Move) TEST(curves_geometry, Move)
@ -52,9 +50,7 @@ TEST(curves_geometry, Move)
EXPECT_EQ(curves.curve_offsets, nullptr); /* NOLINT: bugprone-use-after-move */ EXPECT_EQ(curves.curve_offsets, nullptr); /* NOLINT: bugprone-use-after-move */
/* Just a basic check that the new curves work okay. */ /* Just a basic check that the new curves work okay. */
float3 min; EXPECT_TRUE(other.bounds_min_max());
float3 max;
EXPECT_TRUE(other.bounds_min_max(min, max));
curves = std::move(other); curves = std::move(other);

View File

@ -196,24 +196,30 @@ Vector<const GeometryComponent *> GeometrySet::get_components_for_read() const
return components; return components;
} }
bool GeometrySet::compute_boundbox_without_instances(float3 *r_min, float3 *r_max) const std::optional<Bounds<float3>> GeometrySet::compute_boundbox_without_instances() const
{ {
using namespace blender; std::optional<Bounds<float3>> bounds;
bool have_minmax = false;
if (const PointCloud *pointcloud = this->get_pointcloud_for_read()) { if (const PointCloud *pointcloud = this->get_pointcloud_for_read()) {
have_minmax |= pointcloud->bounds_min_max(*r_min, *r_max); bounds = bounds::merge(bounds, pointcloud->bounds_min_max());
} }
if (const Mesh *mesh = this->get_mesh_for_read()) { if (const Mesh *mesh = this->get_mesh_for_read()) {
have_minmax |= BKE_mesh_wrapper_minmax(mesh, *r_min, *r_max); Bounds<float3> mesh_bounds{float3(std::numeric_limits<float>::max()),
float3(std::numeric_limits<float>::min())};
if (BKE_mesh_wrapper_minmax(mesh, mesh_bounds.min, mesh_bounds.max)) {
bounds = bounds::merge(bounds, {mesh_bounds});
}
} }
if (const Volume *volume = this->get_volume_for_read()) { if (const Volume *volume = this->get_volume_for_read()) {
have_minmax |= BKE_volume_min_max(volume, *r_min, *r_max); Bounds<float3> volume_bounds{float3(std::numeric_limits<float>::max()),
float3(std::numeric_limits<float>::min())};
if (BKE_volume_min_max(volume, volume_bounds.min, volume_bounds.max)) {
bounds = bounds::merge(bounds, {volume_bounds});
}
} }
if (const Curves *curves_id = this->get_curves_for_read()) { if (const Curves *curves_id = this->get_curves_for_read()) {
const bke::CurvesGeometry &curves = curves_id->geometry.wrap(); bounds = bounds::merge(bounds, curves_id->geometry.wrap().bounds_min_max());
have_minmax |= curves.bounds_min_max(*r_min, *r_max);
} }
return have_minmax; return bounds;
} }
std::ostream &operator<<(std::ostream &stream, const GeometrySet &geometry_set) std::ostream &operator<<(std::ostream &stream, const GeometrySet &geometry_set)

View File

@ -17,6 +17,7 @@
#include "BKE_material.h" #include "BKE_material.h"
#include "BKE_object.h" #include "BKE_object.h"
#include "BLI_bounds.hh"
#include "BLI_map.hh" #include "BLI_map.hh"
#include "BLI_math_vector_types.hh" #include "BLI_math_vector_types.hh"
#include "BLI_memarena.h" #include "BLI_memarena.h"
@ -699,25 +700,21 @@ GreasePencil *BKE_grease_pencil_new_nomain()
BoundBox *BKE_grease_pencil_boundbox_get(Object *ob) BoundBox *BKE_grease_pencil_boundbox_get(Object *ob)
{ {
using namespace blender;
BLI_assert(ob->type == OB_GREASE_PENCIL); BLI_assert(ob->type == OB_GREASE_PENCIL);
const GreasePencil *grease_pencil = static_cast<const GreasePencil *>(ob->data); const GreasePencil *grease_pencil = static_cast<const GreasePencil *>(ob->data);
if (ob->runtime.bb != nullptr && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) { if (ob->runtime.bb != nullptr && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) {
return ob->runtime.bb; return ob->runtime.bb;
} }
if (ob->runtime.bb == nullptr) { if (ob->runtime.bb == nullptr) {
ob->runtime.bb = MEM_cnew<BoundBox>(__func__); ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
float3 min(FLT_MAX);
float3 max(-FLT_MAX);
if (!grease_pencil->bounds_min_max(min, max)) {
min = float3(-1);
max = float3(1);
} }
BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max); if (const std::optional<Bounds<float3>> bounds = grease_pencil->bounds_min_max()) {
BKE_boundbox_init_from_minmax(ob->runtime.bb, bounds->min, bounds->max);
}
else {
BKE_boundbox_init_from_minmax(ob->runtime.bb, float3(-1), float3(1));
} }
return ob->runtime.bb; return ob->runtime.bb;
@ -1109,21 +1106,19 @@ void GreasePencil::foreach_editable_drawing(
foreach_drawing_ex(*this, frame, EDITABLE, function); foreach_drawing_ex(*this, frame, EDITABLE, function);
} }
bool GreasePencil::bounds_min_max(float3 &min, float3 &max) const std::optional<blender::Bounds<blender::float3>> GreasePencil::bounds_min_max() const
{ {
bool found = false; using namespace blender;
/* FIXME: this should somehow go through the visible drawings. We don't have access to the /* FIXME: this should somehow go through the visible drawings. We don't have access to the
* scene time here, so we probably need to cache the visible drawing for each layer somehow. */ * scene time here, so we probably need to cache the visible drawing for each layer somehow. */
std::optional<Bounds<float3>> bounds;
for (int i = 0; i < this->drawing_array_num; i++) { for (int i = 0; i < this->drawing_array_num; i++) {
GreasePencilDrawingBase *drawing_base = this->drawing_array[i]; GreasePencilDrawingBase *drawing_base = this->drawing_array[i];
switch (drawing_base->type) { switch (drawing_base->type) {
case GP_DRAWING: { case GP_DRAWING: {
GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_base); GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_base);
const blender::bke::CurvesGeometry &curves = drawing->geometry.wrap(); const bke::CurvesGeometry &curves = drawing->geometry.wrap();
bounds = bounds::merge(bounds, curves.bounds_min_max());
if (curves.bounds_min_max(min, max)) {
found = true;
}
break; break;
} }
case GP_DRAWING_REFERENCE: { case GP_DRAWING_REFERENCE: {
@ -1133,7 +1128,7 @@ bool GreasePencil::bounds_min_max(float3 &min, float3 &max) const
} }
} }
return found; return bounds;
} }
blender::Span<const blender::bke::greasepencil::Layer *> GreasePencil::layers() const blender::Span<const blender::bke::greasepencil::Layer *> GreasePencil::layers() const

View File

@ -244,32 +244,7 @@ MetaElem *BKE_mball_element_add(MetaBall *mb, const int type)
BoundBox *BKE_mball_boundbox_get(Object *ob) BoundBox *BKE_mball_boundbox_get(Object *ob)
{ {
BLI_assert(ob->type == OB_MBALL); BLI_assert(ob->type == OB_MBALL);
if (ob->runtime.bb != nullptr && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) { BKE_object_boundbox_calc_from_evaluated_geometry(ob);
return ob->runtime.bb;
}
if (ob->runtime.bb == nullptr) {
ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
}
/* Expect that this function is only called for evaluated objects. */
const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob);
float min[3];
float max[3];
if (mesh_eval) {
INIT_MINMAX(min, max);
if (!BKE_mesh_minmax(mesh_eval, min, max)) {
copy_v3_fl(min, -1.0f);
copy_v3_fl(max, 1.0f);
}
}
else {
copy_v3_fl(min, 0.0f);
copy_v3_fl(max, 0.0f);
}
BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;
return ob->runtime.bb; return ob->runtime.bb;
} }
@ -704,14 +679,5 @@ void BKE_mball_data_update(Depsgraph *depsgraph, Scene *scene, Object *ob)
ob->runtime.geometry_set_eval = new GeometrySet(GeometrySet::create_with_mesh(mesh)); ob->runtime.geometry_set_eval = new GeometrySet(GeometrySet::create_with_mesh(mesh));
if (ob->runtime.bb == nullptr) { BKE_object_boundbox_calc_from_evaluated_geometry(ob);
ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
}
float3 min(std::numeric_limits<float>::max());
float3 max(-std::numeric_limits<float>::max());
if (!ob->runtime.geometry_set_eval->compute_boundbox_without_instances(&min, &max)) {
min = float3(0);
max = float3(0);
}
BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
}; };

View File

@ -1502,21 +1502,15 @@ void BKE_mesh_looptri_get_real_edges(const blender::int2 *edges,
} }
} }
bool BKE_mesh_minmax(const Mesh *me, float r_min[3], float r_max[3]) std::optional<blender::Bounds<blender::float3>> Mesh::bounds_min_max() const
{ {
using namespace blender; using namespace blender;
if (me->totvert == 0) { if (this->totvert == 0) {
return false; return std::nullopt;
} }
this->runtime->bounds_cache.ensure(
me->runtime->bounds_cache.ensure( [&](Bounds<float3> &r_bounds) { r_bounds = *bounds::min_max(this->vert_positions()); });
[me](Bounds<float3> &r_bounds) { r_bounds = *bounds::min_max(me->vert_positions()); }); return this->runtime->bounds_cache.data();
const Bounds<float3> &bounds = me->runtime->bounds_cache.data();
copy_v3_v3(r_min, math::min(bounds.min, float3(r_min)));
copy_v3_v3(r_max, math::max(bounds.max, float3(r_max)));
return true;
} }
void Mesh::bounds_set_eager(const blender::Bounds<float3> &bounds) void Mesh::bounds_set_eager(const blender::Bounds<float3> &bounds)

View File

@ -276,18 +276,6 @@ bool BKE_mesh_center_median_from_polys(const Mesh *me, float r_cent[3])
return (me->totpoly != 0); return (me->totpoly != 0);
} }
bool BKE_mesh_center_bounds(const Mesh *me, float r_cent[3])
{
float min[3], max[3];
INIT_MINMAX(min, max);
if (BKE_mesh_minmax(me, min, max)) {
mid_v3_v3v3(r_cent, min, max);
return true;
}
return false;
}
bool BKE_mesh_center_of_surface(const Mesh *me, float r_cent[3]) bool BKE_mesh_center_of_surface(const Mesh *me, float r_cent[3])
{ {
float poly_area; float poly_area;

View File

@ -29,6 +29,7 @@
#include "BLI_ghash.h" #include "BLI_ghash.h"
#include "BLI_math.h" #include "BLI_math.h"
#include "BLI_math_vector.hh"
#include "BLI_task.hh" #include "BLI_task.hh"
#include "BLI_threads.h" #include "BLI_threads.h"
#include "BLI_utildefines.h" #include "BLI_utildefines.h"
@ -153,12 +154,19 @@ void BKE_mesh_wrapper_ensure_mdata(Mesh *me)
bool BKE_mesh_wrapper_minmax(const Mesh *me, float min[3], float max[3]) bool BKE_mesh_wrapper_minmax(const Mesh *me, float min[3], float max[3])
{ {
using namespace blender;
switch (me->runtime->wrapper_type) { switch (me->runtime->wrapper_type) {
case ME_WRAPPER_TYPE_BMESH: case ME_WRAPPER_TYPE_BMESH:
return BKE_editmesh_cache_calc_minmax(me->edit_mesh, me->runtime->edit_data, min, max); return BKE_editmesh_cache_calc_minmax(me->edit_mesh, me->runtime->edit_data, min, max);
case ME_WRAPPER_TYPE_MDATA: case ME_WRAPPER_TYPE_MDATA:
case ME_WRAPPER_TYPE_SUBD: case ME_WRAPPER_TYPE_SUBD: {
return BKE_mesh_minmax(me, min, max); if (const std::optional<Bounds<float3>> bounds = me->bounds_min_max()) {
copy_v3_v3(min, math::min(bounds->min, float3(min)));
copy_v3_v3(max, math::max(bounds->max, float3(max)));
return true;
}
return false;
}
} }
BLI_assert_unreachable(); BLI_assert_unreachable();
return false; return false;

View File

@ -3854,7 +3854,7 @@ int ntreeGetPanelIndex(const bNodeTree *ntree, const bNodePanel *panel)
return ntree->panels().first_index_try(const_cast<bNodePanel *>(panel)); return ntree->panels().first_index_try(const_cast<bNodePanel *>(panel));
} }
bNodePanel *ntreeAddPanel(bNodeTree *ntree, const char *name, int flag) bNodePanel *ntreeAddPanel(bNodeTree *ntree, const char *name)
{ {
bNodePanel **old_panels_array = ntree->panels_array; bNodePanel **old_panels_array = ntree->panels_array;
const Span<const bNodePanel *> old_panels = ntree->panels(); const Span<const bNodePanel *> old_panels = ntree->panels();
@ -3867,7 +3867,7 @@ bNodePanel *ntreeAddPanel(bNodeTree *ntree, const char *name, int flag)
new_panels.data()); new_panels.data());
bNodePanel *new_panel = MEM_cnew<bNodePanel>(__func__); bNodePanel *new_panel = MEM_cnew<bNodePanel>(__func__);
*new_panel = {BLI_strdup(name), flag, ntree->next_panel_identifier++}; *new_panel = {BLI_strdup(name)};
new_panels[new_panels.size() - 1] = new_panel; new_panels[new_panels.size() - 1] = new_panel;
MEM_SAFE_FREE(old_panels_array); MEM_SAFE_FREE(old_panels_array);
@ -3877,7 +3877,7 @@ bNodePanel *ntreeAddPanel(bNodeTree *ntree, const char *name, int flag)
return new_panel; return new_panel;
} }
bNodePanel *ntreeInsertPanel(bNodeTree *ntree, const char *name, int flag, int index) bNodePanel *ntreeInsertPanel(bNodeTree *ntree, const char *name, int index)
{ {
if (!blender::IndexRange(ntree->panels().size() + 1).contains(index)) { if (!blender::IndexRange(ntree->panels().size() + 1).contains(index)) {
return nullptr; return nullptr;
@ -3899,7 +3899,7 @@ bNodePanel *ntreeInsertPanel(bNodeTree *ntree, const char *name, int flag, int i
new_panels.drop_front(index + 1).data()); new_panels.drop_front(index + 1).data());
bNodePanel *new_panel = MEM_cnew<bNodePanel>(__func__); bNodePanel *new_panel = MEM_cnew<bNodePanel>(__func__);
*new_panel = {BLI_strdup(name), flag, ntree->next_panel_identifier++}; *new_panel = {BLI_strdup(name)};
new_panels[index] = new_panel; new_panels[index] = new_panel;
MEM_SAFE_FREE(old_panels_array); MEM_SAFE_FREE(old_panels_array);

View File

@ -506,11 +506,19 @@ static void ensure_topology_cache(const bNodeTree &ntree)
ToposortDirection::LeftToRight, ToposortDirection::LeftToRight,
tree_runtime.toposort_left_to_right, tree_runtime.toposort_left_to_right,
tree_runtime.has_available_link_cycle); tree_runtime.has_available_link_cycle);
for (const int i : tree_runtime.toposort_left_to_right.index_range()) {
const bNode &node = *tree_runtime.toposort_left_to_right[i];
node.runtime->toposort_left_to_right_index = i;
}
}, },
[&]() { [&]() {
bool dummy; bool dummy;
update_toposort( update_toposort(
ntree, ToposortDirection::RightToLeft, tree_runtime.toposort_right_to_left, dummy); ntree, ToposortDirection::RightToLeft, tree_runtime.toposort_right_to_left, dummy);
for (const int i : tree_runtime.toposort_right_to_left.index_range()) {
const bNode &node = *tree_runtime.toposort_right_to_left[i];
node.runtime->toposort_right_to_left_index = i;
}
}, },
[&]() { update_root_frames(ntree); }, [&]() { update_root_frames(ntree); },
[&]() { update_direct_frames_childrens(ntree); }); [&]() { update_direct_frames_childrens(ntree); });

View File

@ -57,7 +57,7 @@ std::string node_tree_to_dot(const bNodeTree &tree, const bNodeTreeToDotOptions
dot_nodes.add_new(node, dot::NodeWithSocketsRef(dot_node, dot_node_with_sockets)); dot_nodes.add_new(node, dot::NodeWithSocketsRef(dot_node, dot_node_with_sockets));
} }
LISTBASE_FOREACH (const bNodeLink *, link, &tree.links) { for (const bNodeLink *link : tree.all_links()) {
const dot::NodeWithSocketsRef &from_dot_node = dot_nodes.lookup(link->fromnode); const dot::NodeWithSocketsRef &from_dot_node = dot_nodes.lookup(link->fromnode);
const dot::NodeWithSocketsRef &to_dot_node = dot_nodes.lookup(link->tonode); const dot::NodeWithSocketsRef &to_dot_node = dot_nodes.lookup(link->tonode);
const dot::NodePort from_dot_port = from_dot_node.output(link->fromsock->index()); const dot::NodePort from_dot_port = from_dot_node.output(link->fromsock->index());

View File

@ -107,10 +107,12 @@ static Vector<ZoneRelation> get_direct_zone_relations(
return zone_relations; return zone_relations;
} }
static void update_parent_zone_per_node(const Span<const bNode *> all_nodes, static void update_zone_per_node(const Span<const bNode *> all_nodes,
const Span<std::unique_ptr<TreeZone>> all_zones, const Span<std::unique_ptr<TreeZone>> all_zones,
const BitGroupVector<> &depend_on_input_flag_array, const BitGroupVector<> &depend_on_input_flag_array,
Map<int, int> &r_parent_zone_by_node_id) const Map<const bNode *, TreeZone *> &zone_by_inout_node,
Map<int, int> &r_zone_by_node_id,
Vector<const bNode *> &r_node_outside_zones)
{ {
for (const int node_i : all_nodes.index_range()) { for (const int node_i : all_nodes.index_range()) {
const bNode &node = *all_nodes[node_i]; const bNode &node = *all_nodes[node_i];
@ -125,8 +127,37 @@ static void update_parent_zone_per_node(const Span<const bNode *> all_nodes,
parent_zone = zone; parent_zone = zone;
} }
}); });
if (parent_zone != nullptr) { if (parent_zone == nullptr) {
r_parent_zone_by_node_id.add(node.identifier, parent_zone->index); if (!zone_by_inout_node.contains(&node)) {
r_node_outside_zones.append(&node);
}
}
else {
r_zone_by_node_id.add(node.identifier, parent_zone->index);
}
}
for (const MapItem<const bNode *, TreeZone *> item : zone_by_inout_node.items()) {
r_zone_by_node_id.add_overwrite(item.key->identifier, item.value->index);
}
}
static void update_zone_border_links(const bNodeTree &tree, TreeZones &tree_zones)
{
for (const bNodeLink *link : tree.all_links()) {
if (!link->is_available()) {
continue;
}
if (link->is_muted()) {
continue;
}
TreeZone *from_zone = const_cast<TreeZone *>(tree_zones.get_zone_by_socket(*link->fromsock));
TreeZone *to_zone = const_cast<TreeZone *>(tree_zones.get_zone_by_socket(*link->tosock));
if (from_zone == to_zone) {
continue;
}
BLI_assert(from_zone == nullptr || from_zone->contains_zone_recursively(*to_zone));
for (TreeZone *zone = to_zone; zone != from_zone; zone = zone->parent_zone) {
zone->border_links.append(link);
} }
} }
} }
@ -212,19 +243,33 @@ static std::unique_ptr<TreeZones> discover_tree_zones(const bNodeTree &tree)
update_zone_depths(*zone); update_zone_depths(*zone);
} }
update_parent_zone_per_node(all_nodes, for (std::unique_ptr<TreeZone> &zone : tree_zones->zones) {
if (zone->depth == 0) {
tree_zones->root_zones.append(zone.get());
}
}
update_zone_per_node(all_nodes,
tree_zones->zones, tree_zones->zones,
depend_on_input_flag_array, depend_on_input_flag_array,
tree_zones->parent_zone_by_node_id); zone_by_inout_node,
tree_zones->zone_by_node_id,
tree_zones->nodes_outside_zones);
for (const int node_i : all_nodes.index_range()) { for (const int node_i : all_nodes.index_range()) {
const bNode *node = all_nodes[node_i]; const bNode *node = all_nodes[node_i];
const int parent_zone_i = tree_zones->parent_zone_by_node_id.lookup_default(node->identifier, const int zone_i = tree_zones->zone_by_node_id.lookup_default(node->identifier, -1);
-1); if (zone_i == -1) {
if (parent_zone_i != -1) { continue;
tree_zones->zones[parent_zone_i]->child_nodes.append(node);
} }
const TreeZone &zone = *tree_zones->zones[zone_i];
if (ELEM(node, zone.input_node, zone.output_node)) {
continue;
} }
tree_zones->zones[zone_i]->child_nodes.append(node);
}
update_zone_border_links(tree, *tree_zones);
return tree_zones; return tree_zones;
} }
@ -239,11 +284,11 @@ const TreeZones *get_tree_zones(const bNodeTree &tree)
bool TreeZone::contains_node_recursively(const bNode &node) const bool TreeZone::contains_node_recursively(const bNode &node) const
{ {
const TreeZones *zones = this->owner; const TreeZones *zones = this->owner;
const int parent_zone_i = zones->parent_zone_by_node_id.lookup_default(node.identifier, -1); const int zone_i = zones->zone_by_node_id.lookup_default(node.identifier, -1);
if (parent_zone_i == -1) { if (zone_i == -1) {
return false; return false;
} }
for (const TreeZone *zone = zones->zones[parent_zone_i].get(); zone; zone = zone->parent_zone) { for (const TreeZone *zone = zones->zones[zone_i].get(); zone; zone = zone->parent_zone) {
if (zone == this) { if (zone == this) {
return true; return true;
} }
@ -251,4 +296,35 @@ bool TreeZone::contains_node_recursively(const bNode &node) const
return false; return false;
} }
bool TreeZone::contains_zone_recursively(const TreeZone &other_zone) const
{
for (const TreeZone *zone = other_zone.parent_zone; zone; zone = zone->parent_zone) {
if (zone == this) {
return true;
}
}
return false;
}
const TreeZone *TreeZones::get_zone_by_socket(const bNodeSocket &socket) const
{
const bNode &node = socket.owner_node();
const int zone_i = this->zone_by_node_id.lookup_default(node.identifier, -1);
if (zone_i == -1) {
return nullptr;
}
const TreeZone &zone = *this->zones[zone_i];
if (zone.input_node == &node) {
if (socket.is_input()) {
return zone.parent_zone;
}
}
if (zone.output_node == &node) {
if (socket.is_output()) {
return zone.parent_zone;
}
}
return &zone;
}
} // namespace blender::bke::node_tree_zones } // namespace blender::bke::node_tree_zones

View File

@ -52,6 +52,7 @@
#include "DNA_world_types.h" #include "DNA_world_types.h"
#include "BLI_blenlib.h" #include "BLI_blenlib.h"
#include "BLI_bounds.hh"
#include "BLI_kdtree.h" #include "BLI_kdtree.h"
#include "BLI_linklist.h" #include "BLI_linklist.h"
#include "BLI_listbase.h" #include "BLI_listbase.h"
@ -615,7 +616,7 @@ static void object_blend_write(BlendWriter *writer, ID *id, const void *id_addre
BLO_write_struct(writer, LightgroupMembership, ob->lightgroup); BLO_write_struct(writer, LightgroupMembership, ob->lightgroup);
} }
if (ob->light_linking) { if (ob->light_linking) {
BLO_write_struct(writer, LightgroupMembership, ob->light_linking); BLO_write_struct(writer, LightLinking, ob->light_linking);
} }
if (ob->lightprobe_cache) { if (ob->lightprobe_cache) {
@ -3847,24 +3848,19 @@ void BKE_object_boundbox_calc_from_mesh(Object *ob, const Mesh *me_eval)
bool BKE_object_boundbox_calc_from_evaluated_geometry(Object *ob) bool BKE_object_boundbox_calc_from_evaluated_geometry(Object *ob)
{ {
float3 min(FLT_MAX); using namespace blender;
float3 max(-FLT_MAX);
std::optional<Bounds<float3>> bounds;
if (ob->runtime.geometry_set_eval) { if (ob->runtime.geometry_set_eval) {
if (!ob->runtime.geometry_set_eval->compute_boundbox_without_instances(&min, &max)) { bounds = ob->runtime.geometry_set_eval->compute_boundbox_without_instances();
min = float3(0);
max = float3(0);
}
} }
else if (const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob)) { else if (const Mesh *mesh_eval = BKE_object_get_evaluated_mesh(ob)) {
if (!BKE_mesh_wrapper_minmax(mesh_eval, min, max)) { Bounds<float3> mesh_bounds{float3(std::numeric_limits<float>::max()),
min = float3(0); float3(std::numeric_limits<float>::min())};
max = float3(0); if (BKE_mesh_wrapper_minmax(mesh_eval, mesh_bounds.min, mesh_bounds.max)) {
bounds = bounds::merge(bounds, {mesh_bounds});
} }
} }
else if (ob->runtime.curve_cache) {
BKE_displist_minmax(&ob->runtime.curve_cache->disp, min, max);
}
else { else {
return false; return false;
} }
@ -3872,8 +3868,12 @@ bool BKE_object_boundbox_calc_from_evaluated_geometry(Object *ob)
if (ob->runtime.bb == nullptr) { if (ob->runtime.bb == nullptr) {
ob->runtime.bb = MEM_cnew<BoundBox>(__func__); ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
} }
if (bounds) {
BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max); BKE_boundbox_init_from_minmax(ob->runtime.bb, bounds->min, bounds->max);
}
else {
BKE_boundbox_init_from_minmax(ob->runtime.bb, float3(0), float3(0));
}
ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY; ob->runtime.bb->flag &= ~BOUNDBOX_DIRTY;

View File

@ -263,12 +263,12 @@ void BKE_pointcloud_nomain_to_pointcloud(PointCloud *pointcloud_src, PointCloud
BKE_id_free(nullptr, pointcloud_src); BKE_id_free(nullptr, pointcloud_src);
} }
bool PointCloud::bounds_min_max(blender::float3 &min, blender::float3 &max) const std::optional<blender::Bounds<blender::float3>> PointCloud::bounds_min_max() const
{ {
using namespace blender; using namespace blender;
using namespace blender::bke; using namespace blender::bke;
if (this->totpoint == 0) { if (this->totpoint == 0) {
return false; return std::nullopt;
} }
this->runtime->bounds_cache.ensure([&](Bounds<float3> &r_bounds) { this->runtime->bounds_cache.ensure([&](Bounds<float3> &r_bounds) {
const AttributeAccessor attributes = this->attributes(); const AttributeAccessor attributes = this->attributes();
@ -281,34 +281,35 @@ bool PointCloud::bounds_min_max(blender::float3 &min, blender::float3 &max) cons
r_bounds = *bounds::min_max(positions); r_bounds = *bounds::min_max(positions);
} }
}); });
const Bounds<float3> &bounds = this->runtime->bounds_cache.data(); return this->runtime->bounds_cache.data();
min = math::min(bounds.min, min);
max = math::max(bounds.max, max);
return true;
} }
BoundBox *BKE_pointcloud_boundbox_get(Object *ob) BoundBox *BKE_pointcloud_boundbox_get(Object *ob)
{ {
using namespace blender;
BLI_assert(ob->type == OB_POINTCLOUD); BLI_assert(ob->type == OB_POINTCLOUD);
if (ob->runtime.bb != nullptr && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) { if (ob->runtime.bb != nullptr && (ob->runtime.bb->flag & BOUNDBOX_DIRTY) == 0) {
return ob->runtime.bb; return ob->runtime.bb;
} }
if (ob->runtime.bb == nullptr) { if (ob->runtime.bb == nullptr) {
ob->runtime.bb = static_cast<BoundBox *>(MEM_callocN(sizeof(BoundBox), "pointcloud boundbox")); ob->runtime.bb = MEM_cnew<BoundBox>(__func__);
} }
float3 min, max; std::optional<Bounds<float3>> bounds;
INIT_MINMAX(min, max); if (ob->runtime.geometry_set_eval) {
if (ob->runtime.geometry_set_eval != nullptr) { bounds = ob->runtime.geometry_set_eval->compute_boundbox_without_instances();
ob->runtime.geometry_set_eval->compute_boundbox_without_instances(&min, &max);
} }
else { else {
const PointCloud *pointcloud = static_cast<PointCloud *>(ob->data); const PointCloud *pointcloud = static_cast<PointCloud *>(ob->data);
pointcloud->bounds_min_max(min, max); bounds = pointcloud->bounds_min_max();
}
if (bounds) {
BKE_boundbox_init_from_minmax(ob->runtime.bb, bounds->min, bounds->max);
}
else {
BKE_boundbox_init_from_minmax(ob->runtime.bb, float3(-1), float3(1));
} }
BKE_boundbox_init_from_minmax(ob->runtime.bb, min, max);
return ob->runtime.bb; return ob->runtime.bb;
} }

View File

@ -11,6 +11,7 @@
#include "DNA_node_types.h" #include "DNA_node_types.h"
#include "DNA_pointcloud_types.h" #include "DNA_pointcloud_types.h"
#include "BLI_binary_search.hh"
#include "BLI_fileops.hh" #include "BLI_fileops.hh"
#include "BLI_hash_md5.h" #include "BLI_hash_md5.h"
#include "BLI_path_util.h" #include "BLI_path_util.h"
@ -94,15 +95,34 @@ void ModifierSimulationCache::try_discover_bake(const StringRefNull absolute_bak
} }
} }
static int64_t find_state_at_frame(
const Span<std::unique_ptr<ModifierSimulationStateAtFrame>> states, const SubFrame &frame)
{
const int64_t i = binary_search::find_predicate_begin(
states, [&](const auto &item) { return item->frame >= frame; });
if (i == states.size()) {
return -1;
}
return i;
}
static int64_t find_state_at_frame_exact(
const Span<std::unique_ptr<ModifierSimulationStateAtFrame>> states, const SubFrame &frame)
{
const int64_t i = find_state_at_frame(states, frame);
if (i == -1) {
return -1;
}
if (states[i]->frame != frame) {
return -1;
}
return i;
}
bool ModifierSimulationCache::has_state_at_frame(const SubFrame &frame) const bool ModifierSimulationCache::has_state_at_frame(const SubFrame &frame) const
{ {
std::lock_guard lock(states_at_frames_mutex_); std::lock_guard lock(states_at_frames_mutex_);
for (const auto &item : states_at_frames_) { return find_state_at_frame_exact(states_at_frames_, frame) != -1;
if (item->frame == frame) {
return true;
}
}
return false;
} }
bool ModifierSimulationCache::has_states() const bool ModifierSimulationCache::has_states() const
@ -115,23 +135,26 @@ const ModifierSimulationState *ModifierSimulationCache::get_state_at_exact_frame
const SubFrame &frame) const const SubFrame &frame) const
{ {
std::lock_guard lock(states_at_frames_mutex_); std::lock_guard lock(states_at_frames_mutex_);
for (const auto &item : states_at_frames_) { const int64_t i = find_state_at_frame_exact(states_at_frames_, frame);
if (item->frame == frame) { if (i == -1) {
return &item->state;
}
}
return nullptr; return nullptr;
} }
return &states_at_frames_[i]->state;
}
ModifierSimulationState &ModifierSimulationCache::get_state_at_frame_for_write( ModifierSimulationState &ModifierSimulationCache::get_state_at_frame_for_write(
const SubFrame &frame) const SubFrame &frame)
{ {
std::lock_guard lock(states_at_frames_mutex_); std::lock_guard lock(states_at_frames_mutex_);
for (const auto &item : states_at_frames_) { const int64_t i = find_state_at_frame_exact(states_at_frames_, frame);
if (item->frame == frame) { if (i != -1) {
return item->state; return states_at_frames_[i]->state;
} }
if (!states_at_frames_.is_empty()) {
BLI_assert(frame > states_at_frames_.last()->frame);
} }
states_at_frames_.append(std::make_unique<ModifierSimulationStateAtFrame>()); states_at_frames_.append(std::make_unique<ModifierSimulationStateAtFrame>());
states_at_frames_.last()->frame = frame; states_at_frames_.last()->frame = frame;
states_at_frames_.last()->state.owner_ = this; states_at_frames_.last()->state.owner_ = this;
@ -141,23 +164,22 @@ ModifierSimulationState &ModifierSimulationCache::get_state_at_frame_for_write(
StatesAroundFrame ModifierSimulationCache::get_states_around_frame(const SubFrame &frame) const StatesAroundFrame ModifierSimulationCache::get_states_around_frame(const SubFrame &frame) const
{ {
std::lock_guard lock(states_at_frames_mutex_); std::lock_guard lock(states_at_frames_mutex_);
StatesAroundFrame states_around_frame; const int64_t i = find_state_at_frame(states_at_frames_, frame);
for (const auto &item : states_at_frames_) { StatesAroundFrame states_around_frame{};
if (item->frame < frame) { if (i == -1) {
if (states_around_frame.prev == nullptr || item->frame > states_around_frame.prev->frame) { if (!states_at_frames_.is_empty() && states_at_frames_.last()->frame < frame) {
states_around_frame.prev = item.get(); states_around_frame.prev = states_at_frames_.last().get();
} }
return states_around_frame;
} }
if (item->frame == frame) { if (states_at_frames_[i]->frame == frame) {
if (states_around_frame.current == nullptr) { states_around_frame.current = states_at_frames_[i].get();
states_around_frame.current = item.get();
}
}
if (item->frame > frame) {
if (states_around_frame.next == nullptr || item->frame < states_around_frame.next->frame) {
states_around_frame.next = item.get();
} }
if (i > 0) {
states_around_frame.prev = states_at_frames_[i - 1].get();
} }
if (i < states_at_frames_.size() - 2) {
states_around_frame.next = states_at_frames_[i + 1].get();
} }
return states_around_frame; return states_around_frame;
} }

View File

@ -83,7 +83,10 @@ static int append_avi(void *context_v,
int recty, int recty,
const char *suffix, const char *suffix,
ReportList *reports); ReportList *reports);
static void filepath_avi(char *string, const RenderData *rd, bool preview, const char *suffix); static void filepath_avi(char filepath[FILE_MAX],
const RenderData *rd,
bool preview,
const char *suffix);
static void *context_create_avi(void); static void *context_create_avi(void);
static void context_free_avi(void *context_v); static void context_free_avi(void *context_v);
#endif /* WITH_AVI */ #endif /* WITH_AVI */
@ -141,7 +144,10 @@ bMovieHandle *BKE_movie_handle_get(const char imtype)
#ifdef WITH_AVI #ifdef WITH_AVI
static void filepath_avi(char *filepath, const RenderData *rd, bool preview, const char *suffix) static void filepath_avi(char filepath[FILE_MAX],
const RenderData *rd,
bool preview,
const char *suffix)
{ {
int sfra, efra; int sfra, efra;
@ -158,7 +164,7 @@ static void filepath_avi(char *filepath, const RenderData *rd, bool preview, con
efra = rd->efra; efra = rd->efra;
} }
strcpy(filepath, rd->pic); BLI_strncpy(filepath, rd->pic, FILE_MAX);
BLI_path_abs(filepath, BKE_main_blendfile_path_from_global()); BLI_path_abs(filepath, BKE_main_blendfile_path_from_global());
BLI_file_ensure_parent_dir_exists(filepath); BLI_file_ensure_parent_dir_exists(filepath);
@ -188,13 +194,13 @@ static int start_avi(void *context_v,
const char *suffix) const char *suffix)
{ {
int x, y; int x, y;
char name[256]; char filepath[FILE_MAX];
AviFormat format; AviFormat format;
int quality; int quality;
double framerate; double framerate;
AviMovie *avi = context_v; AviMovie *avi = context_v;
filepath_avi(name, rd, preview, suffix); filepath_avi(filepath, rd, preview, suffix);
x = rectx; x = rectx;
y = recty; y = recty;
@ -209,7 +215,7 @@ static int start_avi(void *context_v,
format = AVI_FORMAT_MJPEG; format = AVI_FORMAT_MJPEG;
} }
if (AVI_open_compress(name, avi, 1, format) != AVI_ERROR_NONE) { if (AVI_open_compress(filepath, avi, 1, format) != AVI_ERROR_NONE) {
BKE_report(reports, RPT_ERROR, "Cannot open or start AVI movie file"); BKE_report(reports, RPT_ERROR, "Cannot open or start AVI movie file");
return 0; return 0;
} }
@ -222,7 +228,7 @@ static int start_avi(void *context_v,
avi->interlace = 0; avi->interlace = 0;
avi->odd_fields = 0; avi->odd_fields = 0;
printf("Created avi: %s\n", name); printf("Created avi: %s\n", filepath);
return 1; return 1;
} }
@ -298,7 +304,10 @@ static void context_free_avi(void *context_v)
#endif /* WITH_AVI */ #endif /* WITH_AVI */
void BKE_movie_filepath_get(char *filepath, const RenderData *rd, bool preview, const char *suffix) void BKE_movie_filepath_get(char filepath[/*FILE_MAX*/ 1024],
const RenderData *rd,
bool preview,
const char *suffix)
{ {
bMovieHandle *mh = BKE_movie_handle_get(rd->im_format.imtype); bMovieHandle *mh = BKE_movie_handle_get(rd->im_format.imtype);
if (mh && mh->get_movie_path) { if (mh && mh->get_movie_path) {

View File

@ -1428,7 +1428,7 @@ static void ffmpeg_filepath_get(FFMpegContext *context,
BLI_path_suffix(filepath, FILE_MAX, suffix, ""); BLI_path_suffix(filepath, FILE_MAX, suffix, "");
} }
void BKE_ffmpeg_filepath_get(char *filepath, void BKE_ffmpeg_filepath_get(char filepath[/*FILE_MAX*/ 1024],
const RenderData *rd, const RenderData *rd,
bool preview, bool preview,
const char *suffix) const char *suffix)

View File

@ -21,7 +21,7 @@ namespace blender::bounds {
/** /**
* Find the smallest and largest values element-wise in the span. * Find the smallest and largest values element-wise in the span.
*/ */
template<typename T> inline std::optional<Bounds<T>> min_max(Span<T> values) template<typename T> [[nodiscard]] inline std::optional<Bounds<T>> min_max(Span<T> values)
{ {
if (values.is_empty()) { if (values.is_empty()) {
return std::nullopt; return std::nullopt;
@ -48,7 +48,8 @@ template<typename T> inline std::optional<Bounds<T>> min_max(Span<T> values)
* first. The template type T is expected to have an addition operator implemented with RadiusT. * first. The template type T is expected to have an addition operator implemented with RadiusT.
*/ */
template<typename T, typename RadiusT> template<typename T, typename RadiusT>
inline std::optional<Bounds<T>> min_max_with_radii(Span<T> values, Span<RadiusT> radii) [[nodiscard]] inline std::optional<Bounds<T>> min_max_with_radii(Span<T> values,
Span<RadiusT> radii)
{ {
BLI_assert(values.size() == radii.size()); BLI_assert(values.size() == radii.size());
if (values.is_empty()) { if (values.is_empty()) {
@ -72,4 +73,25 @@ inline std::optional<Bounds<T>> min_max_with_radii(Span<T> values, Span<RadiusT>
}); });
} }
template<typename T> [[nodiscard]] inline Bounds<T> merge(const Bounds<T> &a, const Bounds<T> &b)
{
return {math::min(a.min, b.min), math::max(a.max, b.max)};
}
template<typename T>
[[nodiscard]] inline std::optional<Bounds<T>> merge(const std::optional<Bounds<T>> &a,
const std::optional<Bounds<T>> &b)
{
if (a.has_value() && b.has_value()) {
return merge(*a, *b);
}
if (a.has_value()) {
return a;
}
if (b.has_value()) {
return b;
}
return std::nullopt;
}
} // namespace blender::bounds } // namespace blender::bounds

View File

@ -117,7 +117,7 @@ int BLI_path_sequence_decode(const char *path,
if (head) { if (head) {
/* Name_end points to last character of head, /* Name_end points to last character of head,
* make it +1 so null-terminator is nicely placed. */ * make it +1 so null-terminator is nicely placed. */
BLI_strncpy(head, path, name_end + 1); BLI_strncpy(head, path, MIN2(head_maxncpy, name_end + 1));
} }
if (r_digits_len) { if (r_digits_len) {
*r_digits_len = 0; *r_digits_len = 0;

View File

@ -32,6 +32,9 @@
int getname_anim_fcurve(char *name, ID *id, FCurve *fcu) int getname_anim_fcurve(char *name, ID *id, FCurve *fcu)
{ {
/* Could make an argument, it's a documented limit at the moment. */
const size_t name_maxncpy = 256;
int icon = 0; int icon = 0;
/* sanity checks */ /* sanity checks */
@ -41,13 +44,13 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu)
if (ELEM(NULL, id, fcu, fcu->rna_path)) { if (ELEM(NULL, id, fcu, fcu->rna_path)) {
if (fcu == NULL) { if (fcu == NULL) {
strcpy(name, TIP_("<invalid>")); BLI_strncpy(name, TIP_("<invalid>"), name_maxncpy);
} }
else if (fcu->rna_path == NULL) { else if (fcu->rna_path == NULL) {
strcpy(name, TIP_("<no path>")); BLI_strncpy(name, TIP_("<no path>"), name_maxncpy);
} }
else { /* id == NULL */ else { /* id == NULL */
BLI_snprintf(name, 256, "%s[%d]", fcu->rna_path, fcu->array_index); BLI_snprintf(name, name_maxncpy, "%s[%d]", fcu->rna_path, fcu->array_index);
} }
} }
else { else {
@ -171,10 +174,10 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu)
/* XXX we need to check for invalid names... /* XXX we need to check for invalid names...
* XXX the name length limit needs to be passed in or as some define */ * XXX the name length limit needs to be passed in or as some define */
if (structname) { if (structname) {
BLI_snprintf(name, 256, "%s%s (%s)", arrayname, propname, structname); BLI_snprintf(name, name_maxncpy, "%s%s (%s)", arrayname, propname, structname);
} }
else { else {
BLI_snprintf(name, 256, "%s%s", arrayname, propname); BLI_snprintf(name, name_maxncpy, "%s%s", arrayname, propname);
} }
/* free temp name if nameprop is set */ /* free temp name if nameprop is set */
@ -193,7 +196,7 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu)
} }
else { else {
/* invalid path */ /* invalid path */
BLI_snprintf(name, 256, "\"%s[%d]\"", fcu->rna_path, fcu->array_index); BLI_snprintf(name, name_maxncpy, "\"%s[%d]\"", fcu->rna_path, fcu->array_index);
/* icon for this should be the icon for the base ID */ /* icon for this should be the icon for the base ID */
/* TODO: or should we just use the error icon? */ /* TODO: or should we just use the error icon? */

View File

@ -497,10 +497,10 @@ static int poselib_blend_modal(bContext *C, wmOperator *op, const wmEvent *event
ED_slider_status_string_get(pbd->slider, slider_string, sizeof(slider_string)); ED_slider_status_string_get(pbd->slider, slider_string, sizeof(slider_string));
if (pbd->state == POSE_BLEND_BLENDING) { if (pbd->state == POSE_BLEND_BLENDING) {
strcpy(tab_string, TIP_("[Tab] - Show original pose")); STRNCPY(tab_string, TIP_("[Tab] - Show original pose"));
} }
else { else {
strcpy(tab_string, TIP_("[Tab] - Show blended pose")); STRNCPY(tab_string, TIP_("[Tab] - Show blended pose"));
} }
SNPRINTF(status_string, "%s | %s | [Ctrl] - Flip Pose", tab_string, slider_string); SNPRINTF(status_string, "%s | %s | [Ctrl] - Flip Pose", tab_string, slider_string);

View File

@ -941,21 +941,21 @@ static void pose_slide_draw_status(bContext *C, tPoseSlideOp *pso)
switch (pso->mode) { switch (pso->mode) {
case POSESLIDE_PUSH: case POSESLIDE_PUSH:
strcpy(mode_str, TIP_("Push Pose")); STRNCPY(mode_str, TIP_("Push Pose"));
break; break;
case POSESLIDE_RELAX: case POSESLIDE_RELAX:
strcpy(mode_str, TIP_("Relax Pose")); STRNCPY(mode_str, TIP_("Relax Pose"));
break; break;
case POSESLIDE_BREAKDOWN: case POSESLIDE_BREAKDOWN:
strcpy(mode_str, TIP_("Breakdown")); STRNCPY(mode_str, TIP_("Breakdown"));
break; break;
case POSESLIDE_BLEND: case POSESLIDE_BLEND:
strcpy(mode_str, TIP_("Blend to Neighbor")); STRNCPY(mode_str, TIP_("Blend to Neighbor"));
break; break;
default: default:
/* Unknown. */ /* Unknown. */
strcpy(mode_str, TIP_("Sliding-Tool")); STRNCPY(mode_str, TIP_("Sliding-Tool"));
break; break;
} }

View File

@ -1273,7 +1273,6 @@ void ED_curve_editnurb_make(Object *obedit)
actkey = BKE_keyblock_from_object(obedit); actkey = BKE_keyblock_from_object(obedit);
if (actkey) { if (actkey) {
// XXX strcpy(G.editModeTitleExtra, "(Key) ");
/* TODO(@ideasman42): undo_system: investigate why this was needed. */ /* TODO(@ideasman42): undo_system: investigate why this was needed. */
#if 0 #if 0
undo_editmode_clear(); undo_editmode_clear();

View File

@ -231,7 +231,7 @@ static int gpencil_layer_add_exec(bContext *C, wmOperator *op)
RNA_property_string_get(op->ptr, prop, name); RNA_property_string_get(op->ptr, prop, name);
} }
else { else {
strcpy(name, "GP_Layer"); STRNCPY(name, "GP_Layer");
} }
bGPDlayer *gpl = BKE_gpencil_layer_addnew(gpd, name, true, false); bGPDlayer *gpl = BKE_gpencil_layer_addnew(gpd, name, true, false);

View File

@ -1853,7 +1853,7 @@ static int gpencil_move_to_layer_exec(bContext *C, wmOperator *op)
RNA_property_string_get(op->ptr, prop, name); RNA_property_string_get(op->ptr, prop, name);
} }
else { else {
strcpy(name, "GP_Layer"); STRNCPY(name, "GP_Layer");
} }
target_layer = BKE_gpencil_layer_addnew(gpd, name, true, false); target_layer = BKE_gpencil_layer_addnew(gpd, name, true, false);
} }

View File

@ -735,24 +735,25 @@ typedef struct GPMatArray {
static uint get_material_type(MaterialGPencilStyle *gp_style, static uint get_material_type(MaterialGPencilStyle *gp_style,
bool use_stroke, bool use_stroke,
bool use_fill, bool use_fill,
char *name) char *name,
size_t name_maxncpy)
{ {
uint r_i = 0; uint r_i = 0;
if ((use_stroke) && (use_fill)) { if ((use_stroke) && (use_fill)) {
switch (gp_style->mode) { switch (gp_style->mode) {
case GP_MATERIAL_MODE_LINE: { case GP_MATERIAL_MODE_LINE: {
r_i = 1; r_i = 1;
strcpy(name, "Line Stroke-Fill"); BLI_strncpy(name, "Line Stroke-Fill", name_maxncpy);
break; break;
} }
case GP_MATERIAL_MODE_DOT: { case GP_MATERIAL_MODE_DOT: {
r_i = 2; r_i = 2;
strcpy(name, "Dots Stroke-Fill"); BLI_strncpy(name, "Dots Stroke-Fill", name_maxncpy);
break; break;
} }
case GP_MATERIAL_MODE_SQUARE: { case GP_MATERIAL_MODE_SQUARE: {
r_i = 3; r_i = 3;
strcpy(name, "Squares Stroke-Fill"); BLI_strncpy(name, "Squares Stroke-Fill", name_maxncpy);
break; break;
} }
default: default:
@ -763,17 +764,17 @@ static uint get_material_type(MaterialGPencilStyle *gp_style,
switch (gp_style->mode) { switch (gp_style->mode) {
case GP_MATERIAL_MODE_LINE: { case GP_MATERIAL_MODE_LINE: {
r_i = 4; r_i = 4;
strcpy(name, "Line Stroke"); BLI_strncpy(name, "Line Stroke", name_maxncpy);
break; break;
} }
case GP_MATERIAL_MODE_DOT: { case GP_MATERIAL_MODE_DOT: {
r_i = 5; r_i = 5;
strcpy(name, "Dots Stroke"); BLI_strncpy(name, "Dots Stroke", name_maxncpy);
break; break;
} }
case GP_MATERIAL_MODE_SQUARE: { case GP_MATERIAL_MODE_SQUARE: {
r_i = 6; r_i = 6;
strcpy(name, "Squares Stroke"); BLI_strncpy(name, "Squares Stroke", name_maxncpy);
break; break;
} }
default: default:
@ -782,7 +783,7 @@ static uint get_material_type(MaterialGPencilStyle *gp_style,
} }
else { else {
r_i = 7; r_i = 7;
strcpy(name, "Solid Fill"); BLI_strncpy(name, "Solid Fill", name_maxncpy);
} }
/* Create key TSSSSFFFF (T: Type S: Stroke Alpha F: Fill Alpha) */ /* Create key TSSSSFFFF (T: Type S: Stroke Alpha F: Fill Alpha) */
@ -878,7 +879,7 @@ static int gpencil_material_to_vertex_exec(bContext *C, wmOperator *op)
/* Only for no Stencil materials. */ /* Only for no Stencil materials. */
if (!is_stencil) { if (!is_stencil) {
/* Create material type unique key by type and alpha. */ /* Create material type unique key by type and alpha. */
uint key = get_material_type(gp_style, use_stroke, use_fill, name); uint key = get_material_type(gp_style, use_stroke, use_fill, name, sizeof(name));
/* Check if material exist. */ /* Check if material exist. */
bool found = false; bool found = false;

View File

@ -51,6 +51,9 @@ void ED_node_cursor_location_get(const struct SpaceNode *snode, float value[2]);
void ED_node_cursor_location_set(struct SpaceNode *snode, const float value[2]); void ED_node_cursor_location_set(struct SpaceNode *snode, const float value[2]);
int ED_node_tree_path_length(struct SpaceNode *snode); int ED_node_tree_path_length(struct SpaceNode *snode);
/**
* \param value: The path output at least the size of `ED_node_tree_path_length(snode) + 1`.
*/
void ED_node_tree_path_get(struct SpaceNode *snode, char *value); void ED_node_tree_path_get(struct SpaceNode *snode, char *value);
void ED_node_tree_start(struct SpaceNode *snode, void ED_node_tree_start(struct SpaceNode *snode,

View File

@ -2175,7 +2175,7 @@ void uiLayoutSetPropSep(uiLayout *layout, bool is_sep);
void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep); void uiLayoutSetPropDecorate(uiLayout *layout, bool is_sep);
int uiLayoutGetLocalDir(const uiLayout *layout); int uiLayoutGetLocalDir(const uiLayout *layout);
int uiLayoutGetOperatorContext(uiLayout *layout); wmOperatorCallContext uiLayoutGetOperatorContext(uiLayout *layout);
bool uiLayoutGetActive(uiLayout *layout); bool uiLayoutGetActive(uiLayout *layout);
bool uiLayoutGetActiveDefault(uiLayout *layout); bool uiLayoutGetActiveDefault(uiLayout *layout);
bool uiLayoutGetActivateInit(uiLayout *layout); bool uiLayoutGetActivateInit(uiLayout *layout);
@ -2523,7 +2523,7 @@ enum uiTemplateListFlags {
UI_TEMPLATE_LIST_FLAGS_LAST UI_TEMPLATE_LIST_FLAGS_LAST
}; };
ENUM_OPERATORS(enum uiTemplateListFlags, UI_TEMPLATE_LIST_FLAGS_LAST); ENUM_OPERATORS(uiTemplateListFlags, UI_TEMPLATE_LIST_FLAGS_LAST);
void uiTemplateList(uiLayout *layout, void uiTemplateList(uiLayout *layout,
const struct bContext *C, const struct bContext *C,

View File

@ -2166,7 +2166,7 @@ static bool ui_but_drag_init(bContext *C,
else if (but->type == UI_BTYPE_VIEW_ITEM) { else if (but->type == UI_BTYPE_VIEW_ITEM) {
const uiButViewItem *view_item_but = (uiButViewItem *)but; const uiButViewItem *view_item_but = (uiButViewItem *)but;
if (view_item_but->view_item) { if (view_item_but->view_item) {
UI_view_item_drag_start(C, view_item_but->view_item); return UI_view_item_drag_start(C, view_item_but->view_item);
} }
} }
else { else {
@ -11347,6 +11347,10 @@ static int ui_handle_menus_recursive(bContext *C,
} }
} }
if (!menu->retvalue) {
ui_handle_viewlist_items_hover(event, menu->region);
}
if (do_towards_reinit) { if (do_towards_reinit) {
ui_mouse_motion_towards_reinit(menu, event->xy); ui_mouse_motion_towards_reinit(menu, event->xy);
} }

View File

@ -5636,7 +5636,7 @@ uiBlock *uiLayoutGetBlock(uiLayout *layout)
return layout->root->block; return layout->root->block;
} }
int uiLayoutGetOperatorContext(uiLayout *layout) wmOperatorCallContext uiLayoutGetOperatorContext(uiLayout *layout)
{ {
return layout->root->opcontext; return layout->root->opcontext;
} }

View File

@ -1026,8 +1026,8 @@ static void override_idtemplate_menu()
MenuType *mt; MenuType *mt;
mt = MEM_cnew<MenuType>(__func__); mt = MEM_cnew<MenuType>(__func__);
strcpy(mt->idname, "UI_MT_idtemplate_liboverride"); STRNCPY(mt->idname, "UI_MT_idtemplate_liboverride");
strcpy(mt->label, N_("Library Override")); STRNCPY(mt->label, N_("Library Override"));
mt->poll = override_idtemplate_menu_poll; mt->poll = override_idtemplate_menu_poll;
mt->draw = override_idtemplate_menu_draw; mt->draw = override_idtemplate_menu_draw;
WM_menutype_add(mt); WM_menutype_add(mt);

View File

@ -214,9 +214,8 @@ static void ui_update_color_picker_buts_rgb(uiBut *from_but,
} }
rgb_float_to_uchar(rgb_hex_uchar, rgb_hex); rgb_float_to_uchar(rgb_hex_uchar, rgb_hex);
SNPRINTF(col, "%02X%02X%02X", UNPACK3_EX((uint), rgb_hex_uchar, )); const int col_len = SNPRINTF_RLEN(col, "%02X%02X%02X", UNPACK3_EX((uint), rgb_hex_uchar, ));
memcpy(bt->poin, col, col_len + 1);
strcpy(bt->poin, col);
} }
else if (bt->str[1] == ' ') { else if (bt->str[1] == ' ') {
if (bt->str[0] == 'R') { if (bt->str[0] == 'R') {

View File

@ -123,9 +123,9 @@ static void hud_panel_operator_redo_draw(const bContext *C, Panel *panel)
static void hud_panels_register(ARegionType *art, int space_type, int region_type) static void hud_panels_register(ARegionType *art, int space_type, int region_type)
{ {
PanelType *pt = MEM_cnew<PanelType>(__func__); PanelType *pt = MEM_cnew<PanelType>(__func__);
strcpy(pt->idname, "OPERATOR_PT_redo"); STRNCPY(pt->idname, "OPERATOR_PT_redo");
strcpy(pt->label, N_("Redo")); STRNCPY(pt->label, N_("Redo"));
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw_header = hud_panel_operator_redo_draw_header; pt->draw_header = hud_panel_operator_redo_draw_header;
pt->draw = hud_panel_operator_redo_draw; pt->draw = hud_panel_operator_redo_draw;
pt->poll = hud_panel_operator_redo_poll; pt->poll = hud_panel_operator_redo_poll;

View File

@ -647,7 +647,7 @@ static uiTooltipData *ui_tooltip_data_from_tool(bContext *C, uiBut *but, bool is
if (has_valid_context == false) { if (has_valid_context == false) {
/* pass */ /* pass */
} }
else if (BPY_run_string_as_string_and_size( else if (BPY_run_string_as_string_and_len(
C, expr_imports, expr, nullptr, &expr_result, &expr_result_len)) C, expr_imports, expr, nullptr, &expr_result, &expr_result_len))
{ {
/* pass. */ /* pass. */

View File

@ -490,8 +490,9 @@ static bool add_collection_search_item(CollItemSearch *cis,
* removed). */ * removed). */
BKE_id_full_name_ui_prefix_get( BKE_id_full_name_ui_prefix_get(
name_buf, static_cast<const ID *>(cis->data), false, UI_SEP_CHAR, &name_prefix_offset); name_buf, static_cast<const ID *>(cis->data), false, UI_SEP_CHAR, &name_prefix_offset);
BLI_assert(strlen(name_buf) <= MEM_allocN_len(cis->name)); const int name_buf_len = strlen(name_buf);
strcpy(cis->name, name_buf); BLI_assert(name_buf_len <= strlen(cis->name));
memcpy(cis->name, name_buf, name_buf_len + 1);
} }
return UI_search_item_add(items, return UI_search_item_add(items,

View File

@ -1571,7 +1571,7 @@ float UI_text_clip_middle_ex(const uiFontStyle *fstyle,
const float parts_strwidth = (okwidth - sep_strwidth) / 2.0f; const float parts_strwidth = (okwidth - sep_strwidth) / 2.0f;
if (rpart) { if (rpart) {
strcpy(rpart_buf, rpart); STRNCPY(rpart_buf, rpart);
*rpart = '\0'; *rpart = '\0';
rpart = rpart_buf; rpart = rpart_buf;
} }

View File

@ -68,6 +68,20 @@ void AbstractGridView::change_state_delayed()
BLI_assert_msg( BLI_assert_msg(
is_reconstructed(), is_reconstructed(),
"These state changes are supposed to be delayed until reconstruction is completed"); "These state changes are supposed to be delayed until reconstruction is completed");
/* Debug-only sanity check: Ensure only one item requests to be active. */
#ifndef NDEBUG
bool has_active = false;
foreach_item([&has_active](AbstractGridViewItem &item) {
if (item.should_be_active().value_or(false)) {
BLI_assert_msg(
!has_active,
"Only one view item should ever return true for its `should_be_active()` method");
has_active = true;
}
});
#endif
foreach_item([](AbstractGridViewItem &item) { item.change_state_delayed(); }); foreach_item([](AbstractGridViewItem &item) { item.change_state_delayed(); });
} }

View File

@ -108,7 +108,7 @@ AbstractTreeViewItem *AbstractTreeView::find_matching_child(
const AbstractTreeViewItem &lookup_item, const TreeViewOrItem &items) const AbstractTreeViewItem &lookup_item, const TreeViewOrItem &items)
{ {
for (const auto &iter_item : items.children_) { for (const auto &iter_item : items.children_) {
if (lookup_item.matches_single(*iter_item)) { if (lookup_item.matches(*iter_item)) {
/* We have a matching item! */ /* We have a matching item! */
return iter_item.get(); return iter_item.get();
} }
@ -122,6 +122,20 @@ void AbstractTreeView::change_state_delayed()
BLI_assert_msg( BLI_assert_msg(
is_reconstructed(), is_reconstructed(),
"These state changes are supposed to be delayed until reconstruction is completed"); "These state changes are supposed to be delayed until reconstruction is completed");
/* Debug-only sanity check: Ensure only one item requests to be active. */
#ifndef NDEBUG
bool has_active = false;
foreach_item([&has_active](AbstractTreeViewItem &item) {
if (item.should_be_active().value_or(false)) {
BLI_assert_msg(
!has_active,
"Only one view item should ever return true for its `should_be_active()` method");
has_active = true;
}
});
#endif
foreach_item([](AbstractTreeViewItem &item) { item.change_state_delayed(); }); foreach_item([](AbstractTreeViewItem &item) { item.change_state_delayed(); });
} }
@ -176,7 +190,7 @@ void AbstractTreeViewItem::collapse_chevron_click_fn(bContext *C,
* lookup the hovered item via context here. */ * lookup the hovered item via context here. */
const wmWindow *win = CTX_wm_window(C); const wmWindow *win = CTX_wm_window(C);
const ARegion *region = CTX_wm_region(C); const ARegion *region = CTX_wm_menu(C) ? CTX_wm_menu(C) : CTX_wm_region(C);
uiViewItemHandle *hovered_item_handle = UI_region_views_find_item_at(region, uiViewItemHandle *hovered_item_handle = UI_region_views_find_item_at(region,
win->eventstate->xy); win->eventstate->xy);
@ -474,14 +488,16 @@ void TreeViewLayoutBuilder::build_row(AbstractTreeViewItem &item) const
uiLayoutSetActive(overlap, false); uiLayoutSetActive(overlap, false);
} }
uiLayoutRow(overlap, false); uiLayout *row = uiLayoutRow(overlap, false);
/* Enable emboss for mouse hover highlight. */
uiLayoutSetEmboss(row, UI_EMBOSS);
/* Every item gets one! Other buttons can be overlapped on top. */ /* Every item gets one! Other buttons can be overlapped on top. */
item.add_treerow_button(block_); item.add_treerow_button(block_);
/* After adding tree-row button (would disable hover highlighting). */ /* After adding tree-row button (would disable hover highlighting). */
UI_block_emboss_set(&block_, UI_EMBOSS_NONE); UI_block_emboss_set(&block_, UI_EMBOSS_NONE);
uiLayout *row = uiLayoutRow(overlap, true); row = uiLayoutRow(overlap, true);
item.add_indent(*row); item.add_indent(*row);
item.add_collapse_chevron(block_); item.add_collapse_chevron(block_);

View File

@ -737,7 +737,7 @@ static void *undomesh_from_editmesh(UndoMesh *um, BMEditMesh *em, Key *key, Undo
/* Copy the ID name characters to the mesh so code that depends on accessing the ID type can work /* Copy the ID name characters to the mesh so code that depends on accessing the ID type can work
* on it. Necessary to use the attribute API. */ * on it. Necessary to use the attribute API. */
strcpy(um->me.id.name, "MEundomesh_from_editmesh"); STRNCPY(um->me.id.name, "MEundomesh_from_editmesh");
/* Runtime data is necessary for some asserts in other code, and the overhead of creating it for /* Runtime data is necessary for some asserts in other code, and the overhead of creating it for
* undo meshes should be low. */ * undo meshes should be low. */

View File

@ -1449,7 +1449,7 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op)
md->source_type = LRT_SOURCE_SCENE; md->source_type = LRT_SOURCE_SCENE;
} }
/* Only created one layer and one material. */ /* Only created one layer and one material. */
strcpy(md->target_layer, ((bGPDlayer *)gpd->layers.first)->info); STRNCPY(md->target_layer, ((bGPDlayer *)gpd->layers.first)->info);
md->target_material = BKE_gpencil_material(ob, 1); md->target_material = BKE_gpencil_material(ob, 1);
if (md->target_material) { if (md->target_material) {
id_us_plus(&md->target_material->id); id_us_plus(&md->target_material->id);

View File

@ -51,6 +51,10 @@
#include "object_intern.h" #include "object_intern.h"
#include "WM_api.h"
#include "UI_interface.h"
namespace blender::ed::object::bake_simulation { namespace blender::ed::object::bake_simulation {
static bool calculate_to_frame_poll(bContext *C) static bool calculate_to_frame_poll(bContext *C)
@ -252,10 +256,6 @@ static void bake_simulation_job_startjob(void *customdata,
if (md->type == eModifierType_Nodes) { if (md->type == eModifierType_Nodes) {
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md); NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
nmd->simulation_cache->ptr->reset(); nmd->simulation_cache->ptr->reset();
if (StringRef(nmd->simulation_bake_directory).is_empty()) {
nmd->simulation_bake_directory = BLI_strdup(
bke::sim::get_default_modifier_bake_directory(*job.bmain, *object, *md).c_str());
}
char absolute_bake_dir[FILE_MAX]; char absolute_bake_dir[FILE_MAX];
STRNCPY(absolute_bake_dir, nmd->simulation_bake_directory); STRNCPY(absolute_bake_dir, nmd->simulation_bake_directory);
BLI_path_abs(absolute_bake_dir, base_path); BLI_path_abs(absolute_bake_dir, base_path);
@ -362,7 +362,7 @@ static void bake_simulation_job_endjob(void *customdata)
WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, nullptr); WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, nullptr);
} }
static int bake_simulation_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/) static int bake_simulation_execute(bContext *C, wmOperator *op)
{ {
wmWindowManager *wm = CTX_wm_manager(C); wmWindowManager *wm = CTX_wm_manager(C);
Scene *scene = CTX_data_scene(C); Scene *scene = CTX_data_scene(C);
@ -405,6 +405,160 @@ static int bake_simulation_invoke(bContext *C, wmOperator *op, const wmEvent * /
return OPERATOR_RUNNING_MODAL; return OPERATOR_RUNNING_MODAL;
} }
struct PathStringHash {
uint64_t operator()(const StringRef s) const
{
/* Normalize the paths so we can compare them. */
DynamicStackBuffer<256> norm_buf(s.size() + 1, 8);
memcpy(norm_buf.buffer(), s.data(), s.size() + 1);
char *norm = static_cast<char *>(norm_buf.buffer());
BLI_path_slash_native(norm);
/* Strip ending slash. */
BLI_path_slash_rstrip(norm);
BLI_path_normalize(norm);
return get_default_hash(norm);
}
};
struct PathStringEquality {
bool operator()(const StringRef a, const StringRef b) const
{
return BLI_path_cmp_normalized(a.data(), b.data()) == 0;
}
};
static bool bake_directory_has_data(const StringRefNull absolute_bake_dir)
{
char meta_dir[FILE_MAX];
BLI_path_join(meta_dir, sizeof(meta_dir), absolute_bake_dir.c_str(), "meta");
char bdata_dir[FILE_MAX];
BLI_path_join(bdata_dir, sizeof(bdata_dir), absolute_bake_dir.c_str(), "bdata");
if (!BLI_is_dir(meta_dir) || !BLI_is_dir(bdata_dir)) {
return false;
}
return true;
}
static void bake_simulation_validate_paths(bContext *C,
wmOperator *op,
const Span<Object *> objects)
{
Main *bmain = CTX_data_main(C);
for (Object *object : objects) {
if (!BKE_id_is_editable(bmain, &object->id)) {
continue;
}
LISTBASE_FOREACH (ModifierData *, md, &object->modifiers) {
if (md->type != eModifierType_Nodes) {
continue;
}
NodesModifierData *nmd = reinterpret_cast<NodesModifierData *>(md);
if (StringRef(nmd->simulation_bake_directory).is_empty()) {
BKE_reportf(op->reports,
RPT_INFO,
"Bake directory of object %s, modifier %s is empty, setting default path",
object->id.name + 2,
md->name);
nmd->simulation_bake_directory = BLI_strdup(
bke::sim::get_default_modifier_bake_directory(*bmain, *object, *md).c_str());
}
}
}
}
/* Map for counting path references. */
using PathUsersMap = Map<std::string,
int,
default_inline_buffer_capacity(sizeof(std::string)),
DefaultProbingStrategy,
PathStringHash,
PathStringEquality>;
static PathUsersMap bake_simulation_get_path_users(bContext *C, const Span<Object *> objects)
{
Main *bmain = CTX_data_main(C);
PathUsersMap path_users;
for (const Object *object : objects) {
const char *base_path = ID_BLEND_PATH(bmain, &object->id);
LISTBASE_FOREACH (const ModifierData *, md, &object->modifiers) {
if (md->type != eModifierType_Nodes) {
continue;
}
const NodesModifierData *nmd = reinterpret_cast<const NodesModifierData *>(md);
if (StringRef(nmd->simulation_bake_directory).is_empty()) {
continue;
}
char absolute_bake_dir[FILE_MAX];
STRNCPY(absolute_bake_dir, nmd->simulation_bake_directory);
BLI_path_abs(absolute_bake_dir, base_path);
path_users.add_or_modify(
absolute_bake_dir, [](int *value) { *value = 1; }, [](int *value) { ++(*value); });
}
}
return path_users;
}
static int bake_simulation_invoke(bContext *C, wmOperator *op, const wmEvent * /*event*/)
{
Vector<Object *> objects;
if (RNA_boolean_get(op->ptr, "selected")) {
CTX_DATA_BEGIN (C, Object *, object, selected_objects) {
objects.append(object);
}
CTX_DATA_END;
}
else {
if (Object *object = CTX_data_active_object(C)) {
objects.append(object);
}
}
/* Set empty paths to default. */
bake_simulation_validate_paths(C, op, objects);
PathUsersMap path_users = bake_simulation_get_path_users(C, objects);
bool has_path_conflict = false;
bool has_existing_bake_data = false;
for (const auto &item : path_users.items()) {
/* Check if multiple caches are writing to the same bake directory. */
if (item.value > 1) {
BKE_reportf(op->reports,
RPT_ERROR,
"Path conflict: %d caches set to path %s",
item.value,
item.key.data());
has_path_conflict = true;
}
/* Check if path exists and contains bake data already. */
if (bake_directory_has_data(item.key.data())) {
has_existing_bake_data = true;
}
}
if (has_path_conflict) {
UI_popup_menu_reports(C, op->reports);
return OPERATOR_CANCELLED;
}
if (has_existing_bake_data) {
return WM_operator_confirm_message(C, op, "Overwrite existing bake data");
}
return bake_simulation_execute(C, op);
}
static int bake_simulation_modal(bContext *C, wmOperator * /*op*/, const wmEvent * /*event*/) static int bake_simulation_modal(bContext *C, wmOperator * /*op*/, const wmEvent * /*event*/)
{ {
if (!WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_BAKE_SIMULATION_NODES)) { if (!WM_jobs_test(CTX_wm_manager(C), CTX_data_scene(C), WM_JOB_TYPE_BAKE_SIMULATION_NODES)) {
@ -493,6 +647,7 @@ void OBJECT_OT_simulation_nodes_cache_bake(wmOperatorType *ot)
ot->description = "Bake simulations in geometry nodes modifiers"; ot->description = "Bake simulations in geometry nodes modifiers";
ot->idname = __func__; ot->idname = __func__;
ot->exec = bake_simulation_execute;
ot->invoke = bake_simulation_invoke; ot->invoke = bake_simulation_invoke;
ot->modal = bake_simulation_modal; ot->modal = bake_simulation_modal;
ot->poll = bake_simulation_poll; ot->poll = bake_simulation_poll;

View File

@ -1452,7 +1452,7 @@ static int constraint_delete_exec(bContext *C, wmOperator *op)
/* Store name temporarily for report. */ /* Store name temporarily for report. */
char name[MAX_NAME]; char name[MAX_NAME];
strcpy(name, con->name); STRNCPY(name, con->name);
/* free the constraint */ /* free the constraint */
if (BKE_constraint_remove_ex(lb, ob, con, true)) { if (BKE_constraint_remove_ex(lb, ob, con, true)) {
@ -1525,7 +1525,7 @@ static int constraint_apply_exec(bContext *C, wmOperator *op)
/* Store name temporarily for report. */ /* Store name temporarily for report. */
char name[MAX_NAME]; char name[MAX_NAME];
strcpy(name, con->name); STRNCPY(name, con->name);
const bool is_first_constraint = con != constraints->first; const bool is_first_constraint = con != constraints->first;
/* Copy the constraint. */ /* Copy the constraint. */
@ -1622,7 +1622,7 @@ static int constraint_copy_exec(bContext *C, wmOperator *op)
/* Store name temporarily for report. */ /* Store name temporarily for report. */
char name[MAX_NAME]; char name[MAX_NAME];
strcpy(name, con->name); STRNCPY(name, con->name);
/* Copy the constraint. */ /* Copy the constraint. */
bConstraint *copy_con; bConstraint *copy_con;

View File

@ -20,6 +20,7 @@
#include "DNA_scene_types.h" #include "DNA_scene_types.h"
#include "BLI_listbase.h" #include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_string_utf8.h" #include "BLI_string_utf8.h"
#include "BLI_string_utils.h" #include "BLI_string_utils.h"
#include "BLI_utildefines.h" #include "BLI_utildefines.h"
@ -552,7 +553,7 @@ static int gpencil_modifier_remove_exec(bContext *C, wmOperator *op)
/* Store name temporarily for report. */ /* Store name temporarily for report. */
char name[MAX_NAME]; char name[MAX_NAME];
strcpy(name, md->name); STRNCPY(name, md->name);
if (!ED_object_gpencil_modifier_remove(op->reports, bmain, ob, md)) { if (!ED_object_gpencil_modifier_remove(op->reports, bmain, ob, md)) {
return OPERATOR_CANCELLED; return OPERATOR_CANCELLED;
@ -735,7 +736,7 @@ static int gpencil_modifier_apply_exec(bContext *C, wmOperator *op)
char name[MAX_NAME]; char name[MAX_NAME];
if (do_report) { if (do_report) {
reports_len = BLI_listbase_count(&op->reports->list); reports_len = BLI_listbase_count(&op->reports->list);
strcpy(name, md->name); /* Store name temporarily since the modifier is removed. */ STRNCPY(name, md->name); /* Store name temporarily since the modifier is removed. */
} }
if (!ED_object_gpencil_modifier_apply(bmain, op->reports, depsgraph, ob, md, apply_as)) { if (!ED_object_gpencil_modifier_apply(bmain, op->reports, depsgraph, ob, md, apply_as)) {

View File

@ -1517,7 +1517,7 @@ static int modifier_remove_exec(bContext *C, wmOperator *op)
/* Store name temporarily for report. */ /* Store name temporarily for report. */
char name[MAX_NAME]; char name[MAX_NAME];
strcpy(name, md->name); STRNCPY(name, md->name);
if (!ED_object_modifier_remove(op->reports, bmain, scene, ob, md)) { if (!ED_object_modifier_remove(op->reports, bmain, scene, ob, md)) {
return OPERATOR_CANCELLED; return OPERATOR_CANCELLED;
@ -1769,7 +1769,7 @@ static int modifier_apply_exec_ex(bContext *C, wmOperator *op, int apply_as, boo
char name[MAX_NAME]; char name[MAX_NAME];
if (do_report) { if (do_report) {
reports_len = BLI_listbase_count(&op->reports->list); reports_len = BLI_listbase_count(&op->reports->list);
strcpy(name, md->name); /* Store name temporarily since the modifier is removed. */ STRNCPY(name, md->name); /* Store name temporarily since the modifier is removed. */
} }
if (!ED_object_modifier_apply( if (!ED_object_modifier_apply(

View File

@ -488,7 +488,7 @@ static int shaderfx_remove_exec(bContext *C, wmOperator *op)
/* Store name temporarily for report. */ /* Store name temporarily for report. */
char name[MAX_NAME]; char name[MAX_NAME];
strcpy(name, fx->name); STRNCPY(name, fx->name);
if (!ED_object_shaderfx_remove(op->reports, bmain, ob, fx)) { if (!ED_object_shaderfx_remove(op->reports, bmain, ob, fx)) {
return OPERATOR_CANCELLED; return OPERATOR_CANCELLED;

View File

@ -1444,7 +1444,9 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
BKE_mesh_center_of_volume(me, cent); BKE_mesh_center_of_volume(me, cent);
} }
else if (around == V3D_AROUND_CENTER_BOUNDS) { else if (around == V3D_AROUND_CENTER_BOUNDS) {
BKE_mesh_center_bounds(me, cent); if (const std::optional<Bounds<float3>> bounds = me->bounds_min_max()) {
cent = math::midpoint(bounds->min, bounds->max);
}
} }
else { /* #V3D_AROUND_CENTER_MEDIAN. */ else { /* #V3D_AROUND_CENTER_MEDIAN. */
BKE_mesh_center_median(me, cent); BKE_mesh_center_median(me, cent);
@ -1696,11 +1698,8 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
/* done */ /* done */
} }
else if (around == V3D_AROUND_CENTER_BOUNDS) { else if (around == V3D_AROUND_CENTER_BOUNDS) {
float3 min(std::numeric_limits<float>::max()); const Bounds<float3> bounds = *curves.bounds_min_max();
float3 max(-std::numeric_limits<float>::max()); cent = math::midpoint(bounds.min, bounds.max);
if (curves.bounds_min_max(min, max)) {
cent = math::midpoint(min, max);
}
} }
else if (around == V3D_AROUND_CENTER_MEDIAN) { else if (around == V3D_AROUND_CENTER_MEDIAN) {
cent = calculate_mean(curves.positions()); cent = calculate_mean(curves.positions());
@ -1729,10 +1728,8 @@ static int object_origin_set_exec(bContext *C, wmOperator *op)
/* Done. */ /* Done. */
} }
else if (around == V3D_AROUND_CENTER_BOUNDS) { else if (around == V3D_AROUND_CENTER_BOUNDS) {
float3 min(std::numeric_limits<float>::max()); if (const std::optional<Bounds<float3>> bounds = pointcloud.bounds_min_max()) {
float3 max(-std::numeric_limits<float>::max()); cent = math::midpoint(bounds->min, bounds->max);
if (pointcloud.bounds_min_max(min, max)) {
cent = math::midpoint(min, max);
} }
} }
else if (around == V3D_AROUND_CENTER_MEDIAN) { else if (around == V3D_AROUND_CENTER_MEDIAN) {

View File

@ -620,7 +620,8 @@ static Scene *preview_prepare_scene(
/* new UI convention: draw is in pixel space already. */ /* new UI convention: draw is in pixel space already. */
/* uses UI_BTYPE_ROUNDBOX button in block to get the rect */ /* uses UI_BTYPE_ROUNDBOX button in block to get the rect */
static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect, rcti *newrect) static bool ed_preview_draw_rect(
Scene *scene, ScrArea *area, int split, int first, rcti *rect, rcti *newrect)
{ {
Render *re; Render *re;
RenderView *rv; RenderView *rv;
@ -668,35 +669,21 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect
} }
if (rv && rv->combined_buffer.data) { if (rv && rv->combined_buffer.data) {
if (abs(rres.rectx - newx) < 2 && abs(rres.recty - newy) < 2) { if (abs(rres.rectx - newx) < 2 && abs(rres.recty - newy) < 2) {
newrect->xmax = max_ii(newrect->xmax, rect->xmin + rres.rectx + offx); newrect->xmax = max_ii(newrect->xmax, rect->xmin + rres.rectx + offx);
newrect->ymax = max_ii(newrect->ymax, rect->ymin + rres.recty); newrect->ymax = max_ii(newrect->ymax, rect->ymin + rres.recty);
if (rres.rectx && rres.recty) { if (rres.rectx && rres.recty) {
uchar *rect_byte = static_cast<uchar *>(
MEM_mallocN(rres.rectx * rres.recty * sizeof(int), "ed_preview_draw_rect"));
float fx = rect->xmin + offx; float fx = rect->xmin + offx;
float fy = rect->ymin; float fy = rect->ymin;
/* material preview only needs monoscopy (view 0) */ ImBuf *ibuf = IMB_allocImBuf(rres.rectx, rres.recty, 0, 0);
RE_AcquiredResultGet32(re, &rres, (uint *)rect_byte, 0); IMB_assign_float_buffer(ibuf, rv->combined_buffer.data, IB_DO_NOT_TAKE_OWNERSHIP);
IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_3D_IMAGE_COLOR); ED_draw_imbuf(
immDrawPixelsTexTiled(&state, ibuf, fx, fy, false, &scene->view_settings, &scene->display_settings, 1.0f, 1.0f);
fx,
fy,
rres.rectx,
rres.recty,
GPU_RGBA8,
false,
rect_byte,
1.0f,
1.0f,
nullptr);
MEM_freeN(rect_byte); IMB_freeImBuf(ibuf);
ok = true; ok = true;
} }
@ -711,6 +698,7 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect
void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, rcti *rect) void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, rcti *rect)
{ {
if (idp) { if (idp) {
Scene *scene = CTX_data_scene(C);
wmWindowManager *wm = CTX_wm_manager(C); wmWindowManager *wm = CTX_wm_manager(C);
ScrArea *area = CTX_wm_area(C); ScrArea *area = CTX_wm_area(C);
ID *id = (ID *)idp; ID *id = (ID *)idp;
@ -730,11 +718,11 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r
newrect.ymax = rect->ymin; newrect.ymax = rect->ymin;
if (parent) { if (parent) {
ok = ed_preview_draw_rect(area, 1, 1, rect, &newrect); ok = ed_preview_draw_rect(scene, area, 1, 1, rect, &newrect);
ok &= ed_preview_draw_rect(area, 1, 0, rect, &newrect); ok &= ed_preview_draw_rect(scene, area, 1, 0, rect, &newrect);
} }
else { else {
ok = ed_preview_draw_rect(area, 0, 0, rect, &newrect); ok = ed_preview_draw_rect(scene, area, 0, 0, rect, &newrect);
} }
if (ok) { if (ok) {

View File

@ -328,9 +328,9 @@ static void screen_user_menu_draw(const bContext *C, Menu *menu)
void ED_screen_user_menu_register(void) void ED_screen_user_menu_register(void)
{ {
MenuType *mt = MEM_callocN(sizeof(MenuType), __func__); MenuType *mt = MEM_callocN(sizeof(MenuType), __func__);
strcpy(mt->idname, "SCREEN_MT_user_menu"); STRNCPY(mt->idname, "SCREEN_MT_user_menu");
strcpy(mt->label, N_("Quick Favorites")); STRNCPY(mt->label, N_("Quick Favorites"));
strcpy(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
mt->draw = screen_user_menu_draw; mt->draw = screen_user_menu_draw;
WM_menutype_add(mt); WM_menutype_add(mt);
} }

View File

@ -15,6 +15,7 @@
#include "MEM_guardedalloc.h" #include "MEM_guardedalloc.h"
#include "BLI_math.h" #include "BLI_math.h"
#include "BLI_math_vector.hh"
#include "BLI_utildefines.h" #include "BLI_utildefines.h"
#include "BLT_translation.h" #include "BLT_translation.h"
@ -792,21 +793,20 @@ void PAINT_OT_sample_color(wmOperatorType *ot)
/** \name Texture Paint Toggle Operator /** \name Texture Paint Toggle Operator
* \{ */ * \{ */
static void paint_init_pivot_mesh(Object *ob, float location[3]) static blender::float3 paint_init_pivot_mesh(Object *ob)
{ {
using namespace blender;
const Mesh *me_eval = BKE_object_get_evaluated_mesh(ob); const Mesh *me_eval = BKE_object_get_evaluated_mesh(ob);
if (!me_eval) { if (!me_eval) {
me_eval = (const Mesh *)ob->data; me_eval = (const Mesh *)ob->data;
} }
float min[3] = {FLT_MAX, FLT_MAX, FLT_MAX}, max[3] = {-FLT_MAX, -FLT_MAX, -FLT_MAX}; const std::optional<Bounds<float3>> bounds = me_eval->bounds_min_max();
if (!bounds) {
if (!BKE_mesh_minmax(me_eval, min, max)) { return float3(0.0f);
zero_v3(location);
zero_v3(max);
} }
interp_v3_v3v3(location, min, max, 0.5f); return math::midpoint(bounds->min, bounds->max);
} }
static void paint_init_pivot_curves(Object *ob, float location[3]) static void paint_init_pivot_curves(Object *ob, float location[3])
@ -824,11 +824,11 @@ static void paint_init_pivot_grease_pencil(Object *ob, float location[3])
void paint_init_pivot(Object *ob, Scene *scene) void paint_init_pivot(Object *ob, Scene *scene)
{ {
UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings; UnifiedPaintSettings *ups = &scene->toolsettings->unified_paint_settings;
float location[3];
blender::float3 location;
switch (ob->type) { switch (ob->type) {
case OB_MESH: case OB_MESH:
paint_init_pivot_mesh(ob, location); location = paint_init_pivot_mesh(ob);
break; break;
case OB_CURVES: case OB_CURVES:
paint_init_pivot_curves(ob, location); paint_init_pivot_curves(ob, location);

View File

@ -30,25 +30,25 @@ void action_buttons_register(ARegionType * /*art*/)
/* TODO: AnimData / Actions List */ /* TODO: AnimData / Actions List */
pt = MEM_cnew<PanelType>("spacetype action panel properties"); pt = MEM_cnew<PanelType>("spacetype action panel properties");
strcpy(pt->idname, "ACTION_PT_properties"); STRNCPY(pt->idname, "ACTION_PT_properties");
strcpy(pt->label, N_("Active F-Curve")); STRNCPY(pt->label, N_("Active F-Curve"));
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = action_anim_panel_properties; pt->draw = action_anim_panel_properties;
pt->poll = action_anim_panel_poll; pt->poll = action_anim_panel_poll;
BLI_addtail(&art->paneltypes, pt); BLI_addtail(&art->paneltypes, pt);
pt = MEM_cnew<PanelType>("spacetype action panel properties"); pt = MEM_cnew<PanelType>("spacetype action panel properties");
strcpy(pt->idname, "ACTION_PT_key_properties"); STRNCPY(pt->idname, "ACTION_PT_key_properties");
strcpy(pt->label, N_("Active Keyframe")); STRNCPY(pt->label, N_("Active Keyframe"));
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = action_anim_panel_key_properties; pt->draw = action_anim_panel_key_properties;
pt->poll = action_anim_panel_poll; pt->poll = action_anim_panel_poll;
BLI_addtail(&art->paneltypes, pt); BLI_addtail(&art->paneltypes, pt);
pt = MEM_callocN(sizeof(PanelType), "spacetype action panel modifiers"); pt = MEM_callocN(sizeof(PanelType), "spacetype action panel modifiers");
strcpy(pt->idname, "ACTION_PT_modifiers"); STRNCPY(pt->idname, "ACTION_PT_modifiers");
strcpy(pt->label, N_("Modifiers")); STRNCPY(pt->label, N_("Modifiers"));
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = action_anim_panel_modifiers; pt->draw = action_anim_panel_modifiers;
pt->poll = action_anim_panel_poll; pt->poll = action_anim_panel_poll;
BLI_addtail(&art->paneltypes, pt); BLI_addtail(&art->paneltypes, pt);

View File

@ -12,6 +12,7 @@
#include "MEM_guardedalloc.h" #include "MEM_guardedalloc.h"
#include "BLI_listbase.h" #include "BLI_listbase.h"
#include "BLI_string.h"
#include "BLI_utildefines.h" #include "BLI_utildefines.h"
#include "BLT_translation.h" #include "BLT_translation.h"
@ -1254,9 +1255,9 @@ static void buttons_panel_context_draw(const bContext *C, Panel *panel)
void buttons_context_register(ARegionType *art) void buttons_context_register(ARegionType *art)
{ {
PanelType *pt = MEM_callocN(sizeof(PanelType), "spacetype buttons panel context"); PanelType *pt = MEM_callocN(sizeof(PanelType), "spacetype buttons panel context");
strcpy(pt->idname, "PROPERTIES_PT_context"); STRNCPY(pt->idname, "PROPERTIES_PT_context");
strcpy(pt->label, N_("Context")); /* XXX C panels unavailable through RNA bpy.types! */ STRNCPY(pt->label, N_("Context")); /* XXX C panels unavailable through RNA bpy.types! */
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->poll = buttons_panel_context_poll; pt->poll = buttons_panel_context_poll;
pt->draw = buttons_panel_context_draw; pt->draw = buttons_panel_context_draw;
pt->flag = PANEL_TYPE_NO_HEADER | PANEL_TYPE_NO_SEARCH; pt->flag = PANEL_TYPE_NO_HEADER | PANEL_TYPE_NO_SEARCH;

View File

@ -73,10 +73,10 @@ void ED_clip_buttons_register(ARegionType *art)
PanelType *pt; PanelType *pt;
pt = MEM_cnew<PanelType>("spacetype clip panel metadata"); pt = MEM_cnew<PanelType>("spacetype clip panel metadata");
strcpy(pt->idname, "CLIP_PT_metadata"); STRNCPY(pt->idname, "CLIP_PT_metadata");
strcpy(pt->label, N_("Metadata")); STRNCPY(pt->label, N_("Metadata"));
strcpy(pt->category, "Footage"); STRNCPY(pt->category, "Footage");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->poll = metadata_panel_context_poll; pt->poll = metadata_panel_context_poll;
pt->draw = metadata_panel_context_draw; pt->draw = metadata_panel_context_draw;
pt->flag |= PANEL_TYPE_DEFAULT_CLOSED; pt->flag |= PANEL_TYPE_DEFAULT_CLOSED;

View File

@ -273,7 +273,7 @@ static void draw_movieclip_notes(SpaceClip *sc, ARegion *region)
} }
else { else {
if (sc->flag & SC_LOCK_SELECTION) { if (sc->flag & SC_LOCK_SELECTION) {
strcpy(str, "Locked"); STRNCPY(str, "Locked");
} }
} }
@ -1082,16 +1082,16 @@ static void draw_marker_texts(SpaceClip *sc,
pos[1] = pos[1] * zoomy - fontsize; pos[1] = pos[1] * zoomy - fontsize;
if (marker->flag & MARKER_DISABLED) { if (marker->flag & MARKER_DISABLED) {
strcpy(state, "disabled"); STRNCPY(state, "disabled");
} }
else if (marker->framenr != ED_space_clip_get_clip_frame_number(sc)) { else if (marker->framenr != ED_space_clip_get_clip_frame_number(sc)) {
strcpy(state, "estimated"); STRNCPY(state, "estimated");
} }
else if (marker->flag & MARKER_TRACKED) { else if (marker->flag & MARKER_TRACKED) {
strcpy(state, "tracked"); STRNCPY(state, "tracked");
} }
else { else {
strcpy(state, "keyframed"); STRNCPY(state, "keyframed");
} }
if (state[0]) { if (state[0]) {

View File

@ -2023,9 +2023,9 @@ void file_external_operations_menu_register(void)
MenuType *mt; MenuType *mt;
mt = MEM_callocN(sizeof(MenuType), "spacetype file menu file operations"); mt = MEM_callocN(sizeof(MenuType), "spacetype file menu file operations");
strcpy(mt->idname, "FILEBROWSER_MT_operations_menu"); STRNCPY(mt->idname, "FILEBROWSER_MT_operations_menu");
strcpy(mt->label, N_("External")); STRNCPY(mt->label, N_("External"));
strcpy(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
mt->draw = file_os_operations_menu_draw; mt->draw = file_os_operations_menu_draw;
mt->poll = file_os_operations_menu_poll; mt->poll = file_os_operations_menu_poll;
WM_menutype_add(mt); WM_menutype_add(mt);

View File

@ -94,9 +94,9 @@ void file_tool_props_region_panels_register(ARegionType *art)
PanelType *pt; PanelType *pt;
pt = MEM_callocN(sizeof(PanelType), "spacetype file operator properties"); pt = MEM_callocN(sizeof(PanelType), "spacetype file operator properties");
strcpy(pt->idname, "FILE_PT_operator"); STRNCPY(pt->idname, "FILE_PT_operator");
strcpy(pt->label, N_("Operator")); STRNCPY(pt->label, N_("Operator"));
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->flag = PANEL_TYPE_NO_HEADER; pt->flag = PANEL_TYPE_NO_HEADER;
pt->poll = file_panel_operator_poll; pt->poll = file_panel_operator_poll;
pt->draw_header = file_panel_operator_header; pt->draw_header = file_panel_operator_header;
@ -208,9 +208,9 @@ void file_execute_region_panels_register(ARegionType *art)
PanelType *pt; PanelType *pt;
pt = MEM_callocN(sizeof(PanelType), "spacetype file execution buttons"); pt = MEM_callocN(sizeof(PanelType), "spacetype file execution buttons");
strcpy(pt->idname, "FILE_PT_execution_buttons"); STRNCPY(pt->idname, "FILE_PT_execution_buttons");
strcpy(pt->label, N_("Execute Buttons")); STRNCPY(pt->label, N_("Execute Buttons"));
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->flag = PANEL_TYPE_NO_HEADER; pt->flag = PANEL_TYPE_NO_HEADER;
pt->poll = file_panel_operator_poll; pt->poll = file_panel_operator_poll;
pt->draw = file_panel_execution_buttons_draw; pt->draw = file_panel_execution_buttons_draw;
@ -260,9 +260,9 @@ void file_tools_region_panels_register(ARegionType *art)
PanelType *pt; PanelType *pt;
pt = MEM_callocN(sizeof(PanelType), "spacetype file asset catalog buttons"); pt = MEM_callocN(sizeof(PanelType), "spacetype file asset catalog buttons");
strcpy(pt->idname, "FILE_PT_asset_catalog_buttons"); STRNCPY(pt->idname, "FILE_PT_asset_catalog_buttons");
strcpy(pt->label, N_("Asset Catalogs")); STRNCPY(pt->label, N_("Asset Catalogs"));
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->flag = PANEL_TYPE_NO_HEADER; pt->flag = PANEL_TYPE_NO_HEADER;
pt->poll = file_panel_asset_browsing_poll; pt->poll = file_panel_asset_browsing_poll;
pt->draw = file_panel_asset_catalog_buttons_draw; pt->draw = file_panel_asset_catalog_buttons_draw;

View File

@ -1345,7 +1345,7 @@ static void parent_dir_until_exists_or_default_root(char *dir)
#ifdef WIN32 #ifdef WIN32
BLI_windows_get_default_root_dir(dir); BLI_windows_get_default_root_dir(dir);
#else #else
strcpy(dir, "/"); ARRAY_SET_ITEMS(dir, '/', '\0');
#endif #endif
} }
} }

View File

@ -205,7 +205,7 @@ static void graph_panel_properties(const bContext *C, Panel *panel)
acf->name(ale, name); acf->name(ale, name);
} }
else { else {
strcpy(name, IFACE_("<invalid>")); STRNCPY(name, IFACE_("<invalid>"));
icon = ICON_ERROR; icon = ICON_ERROR;
} }
@ -1469,47 +1469,47 @@ void graph_buttons_register(ARegionType *art)
PanelType *pt; PanelType *pt;
pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel properties"); pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel properties");
strcpy(pt->idname, "GRAPH_PT_properties"); STRNCPY(pt->idname, "GRAPH_PT_properties");
strcpy(pt->label, N_("Active F-Curve")); STRNCPY(pt->label, N_("Active F-Curve"));
strcpy(pt->category, "F-Curve"); STRNCPY(pt->category, "F-Curve");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = graph_panel_properties; pt->draw = graph_panel_properties;
pt->poll = graph_panel_poll; pt->poll = graph_panel_poll;
BLI_addtail(&art->paneltypes, pt); BLI_addtail(&art->paneltypes, pt);
pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel properties"); pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel properties");
strcpy(pt->idname, "GRAPH_PT_key_properties"); STRNCPY(pt->idname, "GRAPH_PT_key_properties");
strcpy(pt->label, N_("Active Keyframe")); STRNCPY(pt->label, N_("Active Keyframe"));
strcpy(pt->category, "F-Curve"); STRNCPY(pt->category, "F-Curve");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = graph_panel_key_properties; pt->draw = graph_panel_key_properties;
pt->poll = graph_panel_poll; pt->poll = graph_panel_poll;
BLI_addtail(&art->paneltypes, pt); BLI_addtail(&art->paneltypes, pt);
pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel drivers driven"); pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel drivers driven");
strcpy(pt->idname, "GRAPH_PT_driven_property"); STRNCPY(pt->idname, "GRAPH_PT_driven_property");
strcpy(pt->label, N_("Driven Property")); STRNCPY(pt->label, N_("Driven Property"));
strcpy(pt->category, "Drivers"); STRNCPY(pt->category, "Drivers");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = graph_panel_driven_property; pt->draw = graph_panel_driven_property;
pt->poll = graph_panel_drivers_poll; pt->poll = graph_panel_drivers_poll;
BLI_addtail(&art->paneltypes, pt); BLI_addtail(&art->paneltypes, pt);
pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel drivers"); pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel drivers");
strcpy(pt->idname, "GRAPH_PT_drivers"); STRNCPY(pt->idname, "GRAPH_PT_drivers");
strcpy(pt->label, N_("Driver")); STRNCPY(pt->label, N_("Driver"));
strcpy(pt->category, "Drivers"); STRNCPY(pt->category, "Drivers");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = graph_panel_drivers; pt->draw = graph_panel_drivers;
pt->draw_header = graph_panel_drivers_header; pt->draw_header = graph_panel_drivers_header;
pt->poll = graph_panel_drivers_poll; pt->poll = graph_panel_drivers_poll;
BLI_addtail(&art->paneltypes, pt); BLI_addtail(&art->paneltypes, pt);
pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel drivers popover"); pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel drivers popover");
strcpy(pt->idname, "GRAPH_PT_drivers_popover"); STRNCPY(pt->idname, "GRAPH_PT_drivers_popover");
strcpy(pt->label, N_("Add/Edit Driver")); STRNCPY(pt->label, N_("Add/Edit Driver"));
strcpy(pt->category, "Drivers"); STRNCPY(pt->category, "Drivers");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = graph_panel_drivers_popover; pt->draw = graph_panel_drivers_popover;
pt->poll = graph_panel_drivers_popover_poll; pt->poll = graph_panel_drivers_popover_poll;
BLI_addtail(&art->paneltypes, pt); BLI_addtail(&art->paneltypes, pt);
@ -1518,10 +1518,10 @@ void graph_buttons_register(ARegionType *art)
WM_paneltype_add(pt); WM_paneltype_add(pt);
pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel modifiers"); pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel modifiers");
strcpy(pt->idname, "GRAPH_PT_modifiers"); STRNCPY(pt->idname, "GRAPH_PT_modifiers");
strcpy(pt->label, N_("Modifiers")); STRNCPY(pt->label, N_("Modifiers"));
strcpy(pt->category, "Modifiers"); STRNCPY(pt->category, "Modifiers");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->flag = PANEL_TYPE_NO_HEADER; pt->flag = PANEL_TYPE_NO_HEADER;
pt->draw = graph_panel_modifiers; pt->draw = graph_panel_modifiers;
pt->poll = graph_panel_poll; pt->poll = graph_panel_poll;
@ -1531,10 +1531,10 @@ void graph_buttons_register(ARegionType *art)
ANIM_modifier_panels_register_graph_only(art, GRAPH_FMODIFIER_PANEL_PREFIX, graph_panel_poll); ANIM_modifier_panels_register_graph_only(art, GRAPH_FMODIFIER_PANEL_PREFIX, graph_panel_poll);
pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel view"); pt = MEM_callocN(sizeof(PanelType), "spacetype graph panel view");
strcpy(pt->idname, "GRAPH_PT_view"); STRNCPY(pt->idname, "GRAPH_PT_view");
strcpy(pt->label, N_("Show Cursor")); STRNCPY(pt->label, N_("Show Cursor"));
strcpy(pt->category, "View"); STRNCPY(pt->category, "View");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = graph_panel_cursor; pt->draw = graph_panel_cursor;
pt->draw_header = graph_panel_cursor_header; pt->draw_header = graph_panel_cursor_header;
BLI_addtail(&art->paneltypes, pt); BLI_addtail(&art->paneltypes, pt);

View File

@ -125,7 +125,7 @@ static void common_draw_status_header(bContext *C, tGraphSliderOp *gso, const ch
ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR); ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR);
strcpy(mode_str, TIP_(operator_name)); STRNCPY(mode_str, TIP_(operator_name));
if (hasNumInput(&gso->num)) { if (hasNumInput(&gso->num)) {
char str_ofs[NUM_STR_REP_LEN]; char str_ofs[NUM_STR_REP_LEN];
@ -424,7 +424,7 @@ static void decimate_draw_status(bContext *C, tGraphSliderOp *gso)
ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR); ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR);
strcpy(mode_str, TIP_("Decimate Keyframes")); STRNCPY(mode_str, TIP_("Decimate Keyframes"));
if (hasNumInput(&gso->num)) { if (hasNumInput(&gso->num)) {
char str_ofs[NUM_STR_REP_LEN]; char str_ofs[NUM_STR_REP_LEN];

View File

@ -1296,10 +1296,10 @@ void image_buttons_register(ARegionType *art)
PanelType *pt; PanelType *pt;
pt = MEM_callocN(sizeof(PanelType), "spacetype image panel metadata"); pt = MEM_callocN(sizeof(PanelType), "spacetype image panel metadata");
strcpy(pt->idname, "IMAGE_PT_metadata"); STRNCPY(pt->idname, "IMAGE_PT_metadata");
strcpy(pt->label, N_("Metadata")); STRNCPY(pt->label, N_("Metadata"));
strcpy(pt->category, "Image"); STRNCPY(pt->category, "Image");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->order = 10; pt->order = 10;
pt->poll = metadata_panel_context_poll; pt->poll = metadata_panel_context_poll;
pt->draw = metadata_panel_context_draw; pt->draw = metadata_panel_context_draw;

View File

@ -610,50 +610,50 @@ void nla_buttons_register(ARegionType *art)
PanelType *pt; PanelType *pt;
pt = MEM_cnew<PanelType>("spacetype nla panel animdata"); pt = MEM_cnew<PanelType>("spacetype nla panel animdata");
strcpy(pt->idname, "NLA_PT_animdata"); STRNCPY(pt->idname, "NLA_PT_animdata");
strcpy(pt->label, N_("Animation Data")); STRNCPY(pt->label, N_("Animation Data"));
strcpy(pt->category, "Edited Action"); STRNCPY(pt->category, "Edited Action");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->flag = PANEL_TYPE_NO_HEADER; pt->flag = PANEL_TYPE_NO_HEADER;
pt->draw = nla_panel_animdata; pt->draw = nla_panel_animdata;
pt->poll = nla_animdata_panel_poll; pt->poll = nla_animdata_panel_poll;
BLI_addtail(&art->paneltypes, pt); BLI_addtail(&art->paneltypes, pt);
pt = MEM_cnew<PanelType>("spacetype nla panel properties"); pt = MEM_cnew<PanelType>("spacetype nla panel properties");
strcpy(pt->idname, "NLA_PT_stripname"); STRNCPY(pt->idname, "NLA_PT_stripname");
strcpy(pt->label, N_("Active Strip Name")); STRNCPY(pt->label, N_("Active Strip Name"));
strcpy(pt->category, "Strip"); STRNCPY(pt->category, "Strip");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->flag = PANEL_TYPE_NO_HEADER; pt->flag = PANEL_TYPE_NO_HEADER;
pt->draw = nla_panel_stripname; pt->draw = nla_panel_stripname;
pt->poll = nla_strip_panel_poll; pt->poll = nla_strip_panel_poll;
BLI_addtail(&art->paneltypes, pt); BLI_addtail(&art->paneltypes, pt);
PanelType *pt_properties = pt = MEM_cnew<PanelType>("spacetype nla panel properties"); PanelType *pt_properties = pt = MEM_cnew<PanelType>("spacetype nla panel properties");
strcpy(pt->idname, "NLA_PT_properties"); STRNCPY(pt->idname, "NLA_PT_properties");
strcpy(pt->label, N_("Active Strip")); STRNCPY(pt->label, N_("Active Strip"));
strcpy(pt->category, "Strip"); STRNCPY(pt->category, "Strip");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_properties; pt->draw = nla_panel_properties;
pt->poll = nla_strip_panel_poll; pt->poll = nla_strip_panel_poll;
BLI_addtail(&art->paneltypes, pt); BLI_addtail(&art->paneltypes, pt);
pt = MEM_cnew<PanelType>("spacetype nla panel properties"); pt = MEM_cnew<PanelType>("spacetype nla panel properties");
strcpy(pt->idname, "NLA_PT_actionclip"); STRNCPY(pt->idname, "NLA_PT_actionclip");
strcpy(pt->label, N_("Action Clip")); STRNCPY(pt->label, N_("Action Clip"));
strcpy(pt->category, "Strip"); STRNCPY(pt->category, "Strip");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_actclip; pt->draw = nla_panel_actclip;
pt->flag = PANEL_TYPE_DEFAULT_CLOSED; pt->flag = PANEL_TYPE_DEFAULT_CLOSED;
pt->poll = nla_strip_actclip_panel_poll; pt->poll = nla_strip_actclip_panel_poll;
BLI_addtail(&art->paneltypes, pt); BLI_addtail(&art->paneltypes, pt);
pt = MEM_cnew<PanelType>("spacetype nla panel evaluation"); pt = MEM_cnew<PanelType>("spacetype nla panel evaluation");
strcpy(pt->idname, "NLA_PT_evaluation"); STRNCPY(pt->idname, "NLA_PT_evaluation");
strcpy(pt->parent_id, "NLA_PT_properties"); STRNCPY(pt->parent_id, "NLA_PT_properties");
strcpy(pt->label, N_("Animated Influence")); STRNCPY(pt->label, N_("Animated Influence"));
strcpy(pt->category, "Strip"); STRNCPY(pt->category, "Strip");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_evaluation; pt->draw = nla_panel_evaluation;
pt->draw_header = nla_panel_animated_influence_header; pt->draw_header = nla_panel_animated_influence_header;
pt->parent = pt_properties; pt->parent = pt_properties;
@ -663,11 +663,11 @@ void nla_buttons_register(ARegionType *art)
BLI_addtail(&art->paneltypes, pt); BLI_addtail(&art->paneltypes, pt);
pt = MEM_cnew<PanelType>("spacetype nla panel animated strip time"); pt = MEM_cnew<PanelType>("spacetype nla panel animated strip time");
strcpy(pt->idname, "NLA_PT_animated_strip_time"); STRNCPY(pt->idname, "NLA_PT_animated_strip_time");
strcpy(pt->parent_id, "NLA_PT_properties"); STRNCPY(pt->parent_id, "NLA_PT_properties");
strcpy(pt->label, N_("Animated Strip Time")); STRNCPY(pt->label, N_("Animated Strip Time"));
strcpy(pt->category, "Strip"); STRNCPY(pt->category, "Strip");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_animated_strip_time; pt->draw = nla_panel_animated_strip_time;
pt->draw_header = nla_panel_animated_strip_time_header; pt->draw_header = nla_panel_animated_strip_time_header;
pt->parent = pt_properties; pt->parent = pt_properties;
@ -677,10 +677,10 @@ void nla_buttons_register(ARegionType *art)
BLI_addtail(&art->paneltypes, pt); BLI_addtail(&art->paneltypes, pt);
pt = MEM_cnew<PanelType>("spacetype nla panel modifiers"); pt = MEM_cnew<PanelType>("spacetype nla panel modifiers");
strcpy(pt->idname, "NLA_PT_modifiers"); STRNCPY(pt->idname, "NLA_PT_modifiers");
strcpy(pt->label, N_("Modifiers")); STRNCPY(pt->label, N_("Modifiers"));
strcpy(pt->category, "Modifiers"); STRNCPY(pt->category, "Modifiers");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = nla_panel_modifiers; pt->draw = nla_panel_modifiers;
pt->poll = nla_strip_eval_panel_poll; pt->poll = nla_strip_eval_panel_poll;
pt->flag = PANEL_TYPE_NO_HEADER; pt->flag = PANEL_TYPE_NO_HEADER;

View File

@ -412,7 +412,7 @@ static void nla_main_region_message_subscribe(const wmRegionMessageSubscribePara
PointerRNA ptr; PointerRNA ptr;
RNA_pointer_create(&screen->id, &RNA_SpaceNLA, area->spacedata.first, &ptr); RNA_pointer_create(&screen->id, &RNA_SpaceNLA, area->spacedata.first, &ptr);
wmMsgSubscribeValue msg_sub_value_region_tag_redraw; wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {};
msg_sub_value_region_tag_redraw.owner = region; msg_sub_value_region_tag_redraw.owner = region;
msg_sub_value_region_tag_redraw.user_data = region; msg_sub_value_region_tag_redraw.user_data = region;
msg_sub_value_region_tag_redraw.notify = ED_region_do_msg_notify_tag_redraw; msg_sub_value_region_tag_redraw.notify = ED_region_do_msg_notify_tag_redraw;
@ -488,7 +488,7 @@ static void nla_channel_region_message_subscribe(const wmRegionMessageSubscribeP
PointerRNA ptr; PointerRNA ptr;
RNA_pointer_create(&screen->id, &RNA_SpaceNLA, area->spacedata.first, &ptr); RNA_pointer_create(&screen->id, &RNA_SpaceNLA, area->spacedata.first, &ptr);
wmMsgSubscribeValue msg_sub_value_region_tag_redraw; wmMsgSubscribeValue msg_sub_value_region_tag_redraw = {};
msg_sub_value_region_tag_redraw.owner = region; msg_sub_value_region_tag_redraw.owner = region;
msg_sub_value_region_tag_redraw.user_data = region; msg_sub_value_region_tag_redraw.user_data = region;
msg_sub_value_region_tag_redraw.notify = ED_region_do_msg_notify_tag_redraw; msg_sub_value_region_tag_redraw.notify = ED_region_do_msg_notify_tag_redraw;

View File

@ -186,33 +186,6 @@ void NODE_OT_clipboard_copy(wmOperatorType *ot)
/** \name Paste /** \name Paste
* \{ */ * \{ */
static void remap_pairing(bNodeTree &dst_tree, const Map<const bNode *, bNode *> &node_map)
{
/* We don't have the old tree for looking up output nodes by ID,
* so we have to build a map first to find copied output nodes in the new tree. */
Map<int32_t, bNode *> dst_output_node_map;
for (const auto &item : node_map.items()) {
if (item.key->type == GEO_NODE_SIMULATION_OUTPUT) {
dst_output_node_map.add_new(item.key->identifier, item.value);
}
}
for (bNode *dst_node : node_map.values()) {
if (dst_node->type == GEO_NODE_SIMULATION_INPUT) {
NodeGeometrySimulationInput &data = *static_cast<NodeGeometrySimulationInput *>(
dst_node->storage);
if (const bNode *output_node = dst_output_node_map.lookup_default(data.output_node_id,
nullptr)) {
data.output_node_id = output_node->identifier;
}
else {
data.output_node_id = 0;
blender::nodes::update_node_declaration_and_sockets(dst_tree, *dst_node);
}
}
}
}
static int node_clipboard_paste_exec(bContext *C, wmOperator *op) static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
{ {
SpaceNode &snode = *CTX_wm_space_node(C); SpaceNode &snode = *CTX_wm_space_node(C);
@ -278,6 +251,8 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
for (bNode *new_node : node_map.values()) { for (bNode *new_node : node_map.values()) {
nodeSetSelected(new_node, true); nodeSetSelected(new_node, true);
new_node->flag &= ~NODE_ACTIVE;
/* The parent pointer must be redirected to new node. */ /* The parent pointer must be redirected to new node. */
if (new_node->parent) { if (new_node->parent) {
if (node_map.contains(new_node->parent)) { if (node_map.contains(new_node->parent)) {
@ -327,7 +302,7 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op)
bke::nodeDeclarationEnsure(&tree, new_node); bke::nodeDeclarationEnsure(&tree, new_node);
} }
remap_pairing(tree, node_map); remap_node_pairing(tree, node_map);
tree.ensure_topology_cache(); tree.ensure_topology_cache();
for (bNode *new_node : node_map.values()) { for (bNode *new_node : node_map.values()) {

View File

@ -3100,7 +3100,7 @@ static void find_bounds_by_zone_recursive(const SpaceNode &snode,
if (link.fromnode == nullptr) { if (link.fromnode == nullptr) {
continue; continue;
} }
if (zone.contains_node_recursively(*link.fromnode) || zone.input_node == link.fromnode) { if (zone.contains_node_recursively(*link.fromnode) && zone.output_node != link.fromnode) {
const float2 pos = node_link_bezier_points_dragged(snode, link)[3]; const float2 pos = node_link_bezier_points_dragged(snode, link)[3];
rctf rect; rctf rect;
BLI_rctf_init_pt_radius(&rect, pos, node_padding); BLI_rctf_init_pt_radius(&rect, pos, node_padding);
@ -3246,14 +3246,14 @@ static void node_draw_nodetree(const bContext &C,
GPU_blend(GPU_BLEND_ALPHA); GPU_blend(GPU_BLEND_ALPHA);
nodelink_batch_start(snode); nodelink_batch_start(snode);
LISTBASE_FOREACH (const bNodeLink *, link, &ntree.links) { for (const bNodeLink *link : ntree.all_links()) {
if (!nodeLinkIsHidden(link) && !bke::nodeLinkIsSelected(link)) { if (!nodeLinkIsHidden(link) && !bke::nodeLinkIsSelected(link)) {
node_draw_link(C, region.v2d, snode, *link, false); node_draw_link(C, region.v2d, snode, *link, false);
} }
} }
/* Draw selected node links after the unselected ones, so they are shown on top. */ /* Draw selected node links after the unselected ones, so they are shown on top. */
LISTBASE_FOREACH (const bNodeLink *, link, &ntree.links) { for (const bNodeLink *link : ntree.all_links()) {
if (!nodeLinkIsHidden(link) && bke::nodeLinkIsSelected(link)) { if (!nodeLinkIsHidden(link) && bke::nodeLinkIsSelected(link)) {
node_draw_link(C, region.v2d, snode, *link, true); node_draw_link(C, region.v2d, snode, *link, true);
} }

View File

@ -1261,11 +1261,11 @@ static void node_duplicate_reparent_recursive(bNodeTree *ntree,
} }
} }
static void remap_pairing(bNodeTree &dst_tree, const Map<bNode *, bNode *> &node_map) void remap_node_pairing(bNodeTree &dst_tree, const Map<const bNode *, bNode *> &node_map)
{ {
/* We don't have the old tree for looking up output nodes by ID, /* We don't have the old tree for looking up output nodes by ID,
* so we have to build a map first to find copied output nodes in the new tree. */ * so we have to build a map first to find copied output nodes in the new tree. */
Map<uint32_t, bNode *> dst_output_node_map; Map<int32_t, bNode *> dst_output_node_map;
for (const auto &item : node_map.items()) { for (const auto &item : node_map.items()) {
if (item.key->type == GEO_NODE_SIMULATION_OUTPUT) { if (item.key->type == GEO_NODE_SIMULATION_OUTPUT) {
dst_output_node_map.add_new(item.key->identifier, item.value); dst_output_node_map.add_new(item.key->identifier, item.value);
@ -1376,7 +1376,14 @@ static int node_duplicate_exec(bContext *C, wmOperator *op)
} }
} }
remap_pairing(*ntree, node_map); {
/* Use temporary map that has const key, because that's what the function below expects. */
Map<const bNode *, bNode *> const_node_map;
for (const auto item : node_map.items()) {
const_node_map.add(item.key, item.value);
}
remap_node_pairing(*ntree, const_node_map);
}
/* Deselect old nodes, select the copies instead. */ /* Deselect old nodes, select the copies instead. */
for (const auto item : node_map.items()) { for (const auto item : node_map.items()) {

View File

@ -914,10 +914,14 @@ static void node_group_make_insert_selected(const bContext &C,
links_to_remove.add(link); links_to_remove.add(link);
continue; continue;
} }
if (link->fromnode == gnode) {
links_to_remove.add(link);
continue;
}
if (nodes_to_move.contains(link->fromnode)) { if (nodes_to_move.contains(link->fromnode)) {
internal_links_to_move.add(link); internal_links_to_move.add(link);
continue;
} }
else {
InputSocketInfo &info = input_links.lookup_or_add_default(link->fromsock); InputSocketInfo &info = input_links.lookup_or_add_default(link->fromsock);
info.from_node = link->fromnode; info.from_node = link->fromnode;
info.links.append(link); info.links.append(link);
@ -926,22 +930,24 @@ static void node_group_make_insert_selected(const bContext &C,
} }
} }
} }
}
for (bNodeSocket *output_socket : node->output_sockets()) { for (bNodeSocket *output_socket : node->output_sockets()) {
for (bNodeLink *link : output_socket->directly_linked_links()) { for (bNodeLink *link : output_socket->directly_linked_links()) {
if (nodeLinkIsHidden(link)) { if (nodeLinkIsHidden(link)) {
links_to_remove.add(link); links_to_remove.add(link);
continue; continue;
} }
if (link->tonode == gnode) {
links_to_remove.add(link);
continue;
}
if (nodes_to_move.contains(link->tonode)) { if (nodes_to_move.contains(link->tonode)) {
internal_links_to_move.add(link); internal_links_to_move.add(link);
continue;
} }
else {
output_links.append({link, add_interface_from_socket(ntree, group, *link->fromsock)}); output_links.append({link, add_interface_from_socket(ntree, group, *link->fromsock)});
} }
} }
} }
}
struct NewInternalLinkInfo { struct NewInternalLinkInfo {
bNode *node; bNode *node;

View File

@ -336,6 +336,8 @@ bNodeSocket *node_find_indicated_socket(SpaceNode &snode,
float node_link_dim_factor(const View2D &v2d, const bNodeLink &link); float node_link_dim_factor(const View2D &v2d, const bNodeLink &link);
bool node_link_is_hidden_or_dimmed(const View2D &v2d, const bNodeLink &link); bool node_link_is_hidden_or_dimmed(const View2D &v2d, const bNodeLink &link);
void remap_node_pairing(bNodeTree &dst_tree, const Map<const bNode *, bNode *> &node_map);
void NODE_OT_duplicate(wmOperatorType *ot); void NODE_OT_duplicate(wmOperatorType *ot);
void NODE_OT_delete(wmOperatorType *ot); void NODE_OT_delete(wmOperatorType *ot);
void NODE_OT_delete_reconnect(wmOperatorType *ot); void NODE_OT_delete_reconnect(wmOperatorType *ot);

View File

@ -178,18 +178,20 @@ int ED_node_tree_path_length(SpaceNode *snode)
void ED_node_tree_path_get(SpaceNode *snode, char *value) void ED_node_tree_path_get(SpaceNode *snode, char *value)
{ {
int i = 0; int i = 0;
#ifndef NDEBUG
value[0] = '\0'; const char *value_orig = value;
#endif
/* Note that the caller ensures there is enough space available. */
LISTBASE_FOREACH_INDEX (bNodeTreePath *, path, &snode->treepath, i) { LISTBASE_FOREACH_INDEX (bNodeTreePath *, path, &snode->treepath, i) {
if (i == 0) { const int len = strlen(path->display_name);
strcpy(value, path->display_name); if (i != 0) {
value += strlen(path->display_name); *value++ = '/';
}
else {
BLI_sprintf(value, "/%s", path->display_name);
value += strlen(path->display_name) + 1;
} }
memcpy(value, path->display_name, len);
value += len;
} }
*value = '\0';
BLI_assert(ptrdiff_t(ED_node_tree_path_length(snode)) == ptrdiff_t(value - value_orig));
} }
void ED_node_set_active_viewer_key(SpaceNode *snode) void ED_node_set_active_viewer_key(SpaceNode *snode)
@ -247,7 +249,7 @@ static SpaceLink *node_create(const ScrArea * /*area*/, const Scene * /*scene*/)
/* select the first tree type for valid type */ /* select the first tree type for valid type */
NODE_TREE_TYPES_BEGIN (treetype) { NODE_TREE_TYPES_BEGIN (treetype) {
strcpy(snode->tree_idname, treetype->idname); STRNCPY(snode->tree_idname, treetype->idname);
break; break;
} }
NODE_TREE_TYPES_END; NODE_TREE_TYPES_END;

View File

@ -85,9 +85,9 @@ void sequencer_buttons_register(ARegionType *art)
#if 0 #if 0
pt = MEM_callocN(sizeof(PanelType), "spacetype sequencer panel gpencil"); pt = MEM_callocN(sizeof(PanelType), "spacetype sequencer panel gpencil");
strcpy(pt->idname, "SEQUENCER_PT_gpencil"); STRNCPY(pt->idname, "SEQUENCER_PT_gpencil");
strcpy(pt->label, N_("Grease Pencil")); STRNCPY(pt->label, N_("Grease Pencil"));
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw_header = ED_gpencil_panel_standard_header; pt->draw_header = ED_gpencil_panel_standard_header;
pt->draw = ED_gpencil_panel_standard; pt->draw = ED_gpencil_panel_standard;
pt->poll = sequencer_grease_pencil_panel_poll; pt->poll = sequencer_grease_pencil_panel_poll;
@ -95,10 +95,10 @@ void sequencer_buttons_register(ARegionType *art)
#endif #endif
pt = MEM_cnew<PanelType>("spacetype sequencer panel metadata"); pt = MEM_cnew<PanelType>("spacetype sequencer panel metadata");
strcpy(pt->idname, "SEQUENCER_PT_metadata"); STRNCPY(pt->idname, "SEQUENCER_PT_metadata");
strcpy(pt->label, N_("Metadata")); STRNCPY(pt->label, N_("Metadata"));
strcpy(pt->category, "Metadata"); STRNCPY(pt->category, "Metadata");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->poll = metadata_panel_context_poll; pt->poll = metadata_panel_context_poll;
pt->draw = metadata_panel_context_draw; pt->draw = metadata_panel_context_draw;
pt->order = 10; pt->order = 10;

View File

@ -14,6 +14,7 @@
#include "BLI_blenlib.h" #include "BLI_blenlib.h"
#include "BLI_math.h" #include "BLI_math.h"
#include "BLI_string.h"
#include "BLI_timecode.h" #include "BLI_timecode.h"
#include "BLI_utildefines.h" #include "BLI_utildefines.h"
@ -2016,7 +2017,7 @@ static int sequencer_meta_make_exec(bContext *C, wmOperator *op)
} }
seqm->machine = active_seq ? active_seq->machine : channel_max; seqm->machine = active_seq ? active_seq->machine : channel_max;
strcpy(seqm->name + 2, "MetaStrip"); BLI_strncpy(seqm->name + 2, "MetaStrip", sizeof(seqm->name) - 2);
SEQ_sequence_base_unique_name_recursive(scene, &ed->seqbase, seqm); SEQ_sequence_base_unique_name_recursive(scene, &ed->seqbase, seqm);
seqm->start = meta_start_frame; seqm->start = meta_start_frame;
seqm->len = meta_end_frame - meta_start_frame; seqm->len = meta_end_frame - meta_start_frame;

View File

@ -14,9 +14,9 @@ namespace blender::ed::spreadsheet {
void spreadsheet_data_set_region_panels_register(ARegionType &region_type) void spreadsheet_data_set_region_panels_register(ARegionType &region_type)
{ {
PanelType *panel_type = MEM_cnew<PanelType>(__func__); PanelType *panel_type = MEM_cnew<PanelType>(__func__);
strcpy(panel_type->idname, "SPREADSHEET_PT_data_set"); STRNCPY(panel_type->idname, "SPREADSHEET_PT_data_set");
strcpy(panel_type->label, N_("Data Set")); STRNCPY(panel_type->label, N_("Data Set"));
strcpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
panel_type->flag = PANEL_TYPE_NO_HEADER; panel_type->flag = PANEL_TYPE_NO_HEADER;
panel_type->draw = spreadsheet_data_set_panel_draw; panel_type->draw = spreadsheet_data_set_panel_draw;
BLI_addtail(&region_type.paneltypes, panel_type); BLI_addtail(&region_type.paneltypes, panel_type);

View File

@ -341,10 +341,10 @@ void register_row_filter_panels(ARegionType &region_type)
{ {
{ {
PanelType *panel_type = MEM_cnew<PanelType>(__func__); PanelType *panel_type = MEM_cnew<PanelType>(__func__);
strcpy(panel_type->idname, "SPREADSHEET_PT_row_filters"); STRNCPY(panel_type->idname, "SPREADSHEET_PT_row_filters");
strcpy(panel_type->label, N_("Filters")); STRNCPY(panel_type->label, N_("Filters"));
strcpy(panel_type->category, "Filters"); STRNCPY(panel_type->category, "Filters");
strcpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
panel_type->flag = PANEL_TYPE_NO_HEADER; panel_type->flag = PANEL_TYPE_NO_HEADER;
panel_type->draw = spreadsheet_row_filters_layout; panel_type->draw = spreadsheet_row_filters_layout;
BLI_addtail(&region_type.paneltypes, panel_type); BLI_addtail(&region_type.paneltypes, panel_type);
@ -352,10 +352,10 @@ void register_row_filter_panels(ARegionType &region_type)
{ {
PanelType *panel_type = MEM_cnew<PanelType>(__func__); PanelType *panel_type = MEM_cnew<PanelType>(__func__);
strcpy(panel_type->idname, "SPREADSHEET_PT_filter"); STRNCPY(panel_type->idname, "SPREADSHEET_PT_filter");
strcpy(panel_type->label, ""); STRNCPY(panel_type->label, "");
strcpy(panel_type->category, "Filters"); STRNCPY(panel_type->category, "Filters");
strcpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
panel_type->flag = PANEL_TYPE_INSTANCED | PANEL_TYPE_HEADER_EXPAND; panel_type->flag = PANEL_TYPE_INSTANCED | PANEL_TYPE_HEADER_EXPAND;
panel_type->draw_header = spreadsheet_filter_panel_draw_header; panel_type->draw_header = spreadsheet_filter_panel_draw_header;
panel_type->draw = spreadsheet_filter_panel_draw; panel_type->draw = spreadsheet_filter_panel_draw;

View File

@ -212,9 +212,9 @@ static void recent_files_menu_register(void)
MenuType *mt; MenuType *mt;
mt = MEM_callocN(sizeof(MenuType), "spacetype info menu recent files"); mt = MEM_callocN(sizeof(MenuType), "spacetype info menu recent files");
strcpy(mt->idname, "TOPBAR_MT_file_open_recent"); STRNCPY(mt->idname, "TOPBAR_MT_file_open_recent");
strcpy(mt->label, N_("Open Recent")); STRNCPY(mt->label, N_("Open Recent"));
strcpy(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
mt->draw = recent_files_menu_draw; mt->draw = recent_files_menu_draw;
WM_menutype_add(mt); WM_menutype_add(mt);
} }
@ -270,9 +270,9 @@ static void undo_history_menu_register(void)
MenuType *mt; MenuType *mt;
mt = MEM_callocN(sizeof(MenuType), __func__); mt = MEM_callocN(sizeof(MenuType), __func__);
strcpy(mt->idname, "TOPBAR_MT_undo_history"); STRNCPY(mt->idname, "TOPBAR_MT_undo_history");
strcpy(mt->label, N_("Undo History")); STRNCPY(mt->label, N_("Undo History"));
strcpy(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
mt->draw = undo_history_draw_menu; mt->draw = undo_history_draw_menu;
WM_menutype_add(mt); WM_menutype_add(mt);
} }

View File

@ -1799,19 +1799,19 @@ void view3d_buttons_register(ARegionType *art)
PanelType *pt; PanelType *pt;
pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel object"); pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel object");
strcpy(pt->idname, "VIEW3D_PT_transform"); STRNCPY(pt->idname, "VIEW3D_PT_transform");
strcpy(pt->label, N_("Transform")); /* XXX C panels unavailable through RNA bpy.types! */ STRNCPY(pt->label, N_("Transform")); /* XXX C panels unavailable through RNA bpy.types! */
strcpy(pt->category, "Item"); STRNCPY(pt->category, "Item");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = view3d_panel_transform; pt->draw = view3d_panel_transform;
pt->poll = view3d_panel_transform_poll; pt->poll = view3d_panel_transform_poll;
BLI_addtail(&art->paneltypes, pt); BLI_addtail(&art->paneltypes, pt);
pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel vgroup"); pt = MEM_callocN(sizeof(PanelType), "spacetype view3d panel vgroup");
strcpy(pt->idname, "VIEW3D_PT_vgroup"); STRNCPY(pt->idname, "VIEW3D_PT_vgroup");
strcpy(pt->label, N_("Vertex Weights")); /* XXX C panels unavailable through RNA bpy.types! */ STRNCPY(pt->label, N_("Vertex Weights")); /* XXX C panels unavailable through RNA bpy.types! */
strcpy(pt->category, "Item"); STRNCPY(pt->category, "Item");
strcpy(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(pt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
pt->draw = view3d_panel_vgroup; pt->draw = view3d_panel_vgroup;
pt->poll = view3d_panel_vgroup_poll; pt->poll = view3d_panel_vgroup_poll;
BLI_addtail(&art->paneltypes, pt); BLI_addtail(&art->paneltypes, pt);
@ -1819,9 +1819,9 @@ void view3d_buttons_register(ARegionType *art)
MenuType *mt; MenuType *mt;
mt = MEM_callocN(sizeof(MenuType), "spacetype view3d menu collections"); mt = MEM_callocN(sizeof(MenuType), "spacetype view3d menu collections");
strcpy(mt->idname, "VIEW3D_MT_collection"); STRNCPY(mt->idname, "VIEW3D_MT_collection");
strcpy(mt->label, N_("Collection")); STRNCPY(mt->label, N_("Collection"));
strcpy(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); STRNCPY(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA);
mt->draw = hide_collections_menu_draw; mt->draw = hide_collections_menu_draw;
WM_menutype_add(mt); WM_menutype_add(mt);
} }

View File

@ -263,10 +263,10 @@ void ED_uvedit_buttons_register(ARegionType *art)
{ {
PanelType *pt = MEM_cnew<PanelType>(__func__); PanelType *pt = MEM_cnew<PanelType>(__func__);
strcpy(pt->idname, "IMAGE_PT_uv"); STRNCPY(pt->idname, "IMAGE_PT_uv");
strcpy(pt->label, N_("UV Vertex")); /* XXX C panels unavailable through RNA bpy.types! */ STRNCPY(pt->label, N_("UV Vertex")); /* XXX C panels unavailable through RNA bpy.types! */
/* Could be 'Item' matching 3D view, avoid new tab for two buttons. */ /* Could be 'Item' matching 3D view, avoid new tab for two buttons. */
strcpy(pt->category, "Image"); STRNCPY(pt->category, "Image");
pt->draw = image_panel_uv; pt->draw = image_panel_uv;
pt->poll = image_panel_uv_poll; pt->poll = image_panel_uv_poll;
BLI_addtail(&art->paneltypes, pt); BLI_addtail(&art->paneltypes, pt);

View File

@ -93,6 +93,9 @@ class GraphExecutor : public LazyFunction {
void *init_storage(LinearAllocator<> &allocator) const override; void *init_storage(LinearAllocator<> &allocator) const override;
void destruct_storage(void *storage) const override; void destruct_storage(void *storage) const override;
std::string input_name(int index) const override;
std::string output_name(int index) const override;
private: private:
void execute_impl(Params &params, const Context &context) const override; void execute_impl(Params &params, const Context &context) const override;
}; };

View File

@ -1451,6 +1451,22 @@ void GraphExecutor::destruct_storage(void *storage) const
std::destroy_at(static_cast<Executor *>(storage)); std::destroy_at(static_cast<Executor *>(storage));
} }
std::string GraphExecutor::input_name(const int index) const
{
const lf::OutputSocket &socket = *graph_inputs_[index];
std::stringstream ss;
ss << socket.node().name() << " - " << socket.name();
return ss.str();
}
std::string GraphExecutor::output_name(const int index) const
{
const lf::InputSocket &socket = *graph_outputs_[index];
std::stringstream ss;
ss << socket.node().name() << " - " << socket.name();
return ss.str();
}
void GraphExecutorLogger::log_socket_value(const Socket &socket, void GraphExecutorLogger::log_socket_value(const Socket &socket,
const GPointer value, const GPointer value,
const Context &context) const const Context &context) const

View File

@ -2413,14 +2413,13 @@ static bool lineart_geometry_check_visible(double model_view_proj[4][4],
double shift_y, double shift_y,
Mesh *use_mesh) Mesh *use_mesh)
{ {
using namespace blender;
if (!use_mesh) { if (!use_mesh) {
return false; return false;
} }
float mesh_min[3], mesh_max[3]; const Bounds<float3> bounds = *use_mesh->bounds_min_max();
INIT_MINMAX(mesh_min, mesh_max);
BKE_mesh_minmax(use_mesh, mesh_min, mesh_max);
BoundBox bb; BoundBox bb;
BKE_boundbox_init_from_minmax(&bb, mesh_min, mesh_max); BKE_boundbox_init_from_minmax(&bb, bounds.min, bounds.max);
double co[8][4]; double co[8][4];
double tmp[3]; double tmp[3];

View File

@ -198,9 +198,8 @@ void ShaderCreateInfo::validate_merge(const ShaderCreateInfo &other_info)
} }
}; };
auto print_error_msg = [&](const Resource &res) { auto print_error_msg = [&](const Resource &res, Vector<Resource> &resources) {
std::cout << name_ << ": Validation failed : Overlapping "; auto print_resource_name = [&](const Resource &res) {
switch (res.bind_type) { switch (res.bind_type) {
case Resource::BindType::UNIFORM_BUFFER: case Resource::BindType::UNIFORM_BUFFER:
std::cout << "Uniform Buffer " << res.uniformbuf.name; std::cout << "Uniform Buffer " << res.uniformbuf.name;
@ -218,18 +217,30 @@ void ShaderCreateInfo::validate_merge(const ShaderCreateInfo &other_info)
std::cout << "Unknown Type"; std::cout << "Unknown Type";
break; break;
} }
std::cout << " (" << res.slot << ") while merging " << other_info.name_ << std::endl; };
for (const Resource &_res : resources) {
if (&res != &_res && res.bind_type == _res.bind_type && res.slot == _res.slot) {
std::cout << name_ << ": Validation failed : Overlapping ";
print_resource_name(res);
std::cout << " and ";
print_resource_name(_res);
std::cout << " at (" << res.slot << ") while merging " << other_info.name_ << std::endl;
}
}
}; };
for (auto &res : batch_resources_) { for (auto &res : batch_resources_) {
if (register_resource(res) == false) { if (register_resource(res) == false) {
print_error_msg(res); print_error_msg(res, batch_resources_);
print_error_msg(res, pass_resources_);
} }
} }
for (auto &res : pass_resources_) { for (auto &res : pass_resources_) {
if (register_resource(res) == false) { if (register_resource(res) == false) {
print_error_msg(res); print_error_msg(res, batch_resources_);
print_error_msg(res, pass_resources_);
} }
} }
} }

View File

@ -67,7 +67,7 @@ void IMB_exrtile_begin_write(
* *
* \param passname: Here is the raw channel name without the layer. * \param passname: Here is the raw channel name without the layer.
*/ */
void IMB_exr_set_channel(void *handle, bool IMB_exr_set_channel(void *handle,
const char *layname, const char *layname,
const char *passname, const char *passname,
int xstride, int xstride,

View File

@ -95,26 +95,30 @@ static void free_anim_movie(anim * /*anim*/)
/* pass */ /* pass */
} }
static int an_stringdec(const char *filepath, char *head, char *tail, ushort *numlen) static int an_stringdec(const char *filepath,
char *head,
size_t head_maxncpy,
char *tail,
size_t tail_maxncpy,
ushort *r_numlen)
{ {
ushort len, nume, nums = 0; const ushort len = strlen(filepath);
short i;
bool found = false; bool found = false;
len = strlen(filepath); ushort num_beg = 0;
nume = len; ushort num_end = len;
for (i = len - 1; i >= 0; i--) { for (short i = (short)len - 1; i >= 0; i--) {
if (filepath[i] == SEP) { if (filepath[i] == SEP) {
break; break;
} }
if (isdigit(filepath[i])) { if (isdigit(filepath[i])) {
if (found) { if (found) {
nums = i; num_beg = i;
} }
else { else {
nume = i; num_end = i;
nums = i; num_beg = i;
found = true; found = true;
} }
} }
@ -125,15 +129,14 @@ static int an_stringdec(const char *filepath, char *head, char *tail, ushort *nu
} }
} }
if (found) { if (found) {
strcpy(tail, &filepath[nume + 1]); BLI_strncpy(tail, &filepath[num_end + 1], MIN2(num_beg + 1, tail_maxncpy));
strcpy(head, filepath); BLI_strncpy(head, filepath, head_maxncpy);
head[nums] = '\0'; *r_numlen = num_end - num_beg + 1;
*numlen = nume - nums + 1; return int(atoi(&(filepath)[num_beg]));
return int(atoi(&(filepath)[nums]));
} }
tail[0] = '\0'; tail[0] = '\0';
strcpy(head, filepath); BLI_strncpy(head, filepath, head_maxncpy);
*numlen = 0; *r_numlen = 0;
return true; return true;
} }
@ -1593,9 +1596,6 @@ ImBuf *IMB_anim_absolute(anim *anim,
IMB_Proxy_Size preview_size) IMB_Proxy_Size preview_size)
{ {
ImBuf *ibuf = nullptr; ImBuf *ibuf = nullptr;
char head[256], tail[256];
ushort digits;
int pic;
int filter_y; int filter_y;
if (anim == nullptr) { if (anim == nullptr) {
return nullptr; return nullptr;
@ -1628,15 +1628,19 @@ ImBuf *IMB_anim_absolute(anim *anim,
} }
switch (anim->curtype) { switch (anim->curtype) {
case ANIM_SEQUENCE: case ANIM_SEQUENCE: {
pic = an_stringdec(anim->filepath_first, head, tail, &digits); char head[ARRAY_SIZE(anim->filepath_first)], tail[ARRAY_SIZE(anim->filepath_first)];
pic += position; ushort digits;
const int pic = an_stringdec(
anim->filepath_first, head, sizeof(head), tail, sizeof(tail), &digits) +
position;
an_stringenc(anim->filepath, sizeof(anim->filepath), head, tail, digits, pic); an_stringenc(anim->filepath, sizeof(anim->filepath), head, tail, digits, pic);
ibuf = IMB_loadiffname(anim->filepath, IB_rect, anim->colorspace); ibuf = IMB_loadiffname(anim->filepath, IB_rect, anim->colorspace);
if (ibuf) { if (ibuf) {
anim->cur_position = position; anim->cur_position = position;
} }
break; break;
}
case ANIM_MOVIE: case ANIM_MOVIE:
ibuf = movie_fetchibuf(anim, position); ibuf = movie_fetchibuf(anim, position);
if (ibuf) { if (ibuf) {

View File

@ -1095,11 +1095,10 @@ bool IMB_exr_begin_read(
return true; return true;
} }
void IMB_exr_set_channel( bool IMB_exr_set_channel(
void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect) void *handle, const char *layname, const char *passname, int xstride, int ystride, float *rect)
{ {
ExrHandle *data = (ExrHandle *)handle; ExrHandle *data = (ExrHandle *)handle;
ExrChannel *echan;
char name[EXR_TOT_MAXNAME + 1]; char name[EXR_TOT_MAXNAME + 1];
if (layname && layname[0] != '\0') { if (layname && layname[0] != '\0') {
@ -1113,16 +1112,17 @@ void IMB_exr_set_channel(
BLI_strncpy(name, passname, EXR_TOT_MAXNAME - 1); BLI_strncpy(name, passname, EXR_TOT_MAXNAME - 1);
} }
echan = (ExrChannel *)BLI_findstring(&data->channels, name, offsetof(ExrChannel, name)); ExrChannel *echan = (ExrChannel *)BLI_findstring(
&data->channels, name, offsetof(ExrChannel, name));
if (echan == nullptr) {
return false;
}
if (echan) {
echan->xstride = xstride; echan->xstride = xstride;
echan->ystride = ystride; echan->ystride = ystride;
echan->rect = rect; echan->rect = rect;
} return true;
else {
printf("IMB_exr_set_channel error %s\n", name);
}
} }
float *IMB_exr_channel_rect(void *handle, float *IMB_exr_channel_rect(void *handle,
@ -1354,9 +1354,6 @@ void IMB_exr_read_channels(void *handle)
frameBuffer.insert(echan->m->internal_name, frameBuffer.insert(echan->m->internal_name,
Slice(Imf::FLOAT, (char *)rect, xstride, ystride)); Slice(Imf::FLOAT, (char *)rect, xstride, ystride));
} }
else {
printf("warning, channel with no rect set %s\n", echan->m->internal_name.c_str());
}
} }
/* Read pixels. */ /* Read pixels. */

View File

@ -56,13 +56,14 @@ void IMB_exrtile_begin_write(void * /*handle*/,
{ {
} }
void IMB_exr_set_channel(void * /*handle*/, bool IMB_exr_set_channel(void * /*handle*/,
const char * /*layname*/, const char * /*layname*/,
const char * /*passname*/, const char * /*passname*/,
int /*xstride*/, int /*xstride*/,
int /*ystride*/, int /*ystride*/,
float * /*rect*/) float * /*rect*/)
{ {
return false;
} }
float *IMB_exr_channel_rect(void * /*handle*/, float *IMB_exr_channel_rect(void * /*handle*/,
const char * /*layname*/, const char * /*layname*/,

View File

@ -323,14 +323,13 @@ void USDGenericMeshWriter::write_mesh(HierarchyContext &context, Mesh *mesh)
} }
/* Blender grows its bounds cache to cover animated meshes, so only author once. */ /* Blender grows its bounds cache to cover animated meshes, so only author once. */
float bound_min[3]; if (const std::optional<Bounds<float3>> bounds = mesh->bounds_min_max()) {
float bound_max[3]; pxr::VtArray<pxr::GfVec3f> extent{
INIT_MINMAX(bound_min, bound_max); pxr::GfVec3f{bounds->min[0], bounds->min[1], bounds->min[2]},
BKE_mesh_minmax(mesh, bound_min, bound_max); pxr::GfVec3f{bounds->max[0], bounds->max[1], bounds->max[2]}};
pxr::VtArray<pxr::GfVec3f> extent{pxr::GfVec3f{bound_min[0], bound_min[1], bound_min[2]},
pxr::GfVec3f{bound_max[0], bound_max[1], bound_max[2]}};
usd_mesh.CreateExtentAttr().Set(extent); usd_mesh.CreateExtentAttr().Set(extent);
} }
}
static void get_vertices(const Mesh *mesh, USDMeshData &usd_mesh_data) static void get_vertices(const Mesh *mesh, USDMeshData &usd_mesh_data)
{ {

View File

@ -13,6 +13,7 @@
#include "DNA_listBase.h" #include "DNA_listBase.h"
#ifdef __cplusplus #ifdef __cplusplus
# include "BLI_bounds_types.hh"
# include "BLI_function_ref.hh" # include "BLI_function_ref.hh"
# include "BLI_map.hh" # include "BLI_map.hh"
# include "BLI_math_vector_types.hh" # include "BLI_math_vector_types.hh"
@ -457,7 +458,7 @@ typedef struct GreasePencil {
void foreach_editable_drawing(int frame, void foreach_editable_drawing(int frame,
blender::FunctionRef<void(int, GreasePencilDrawing &)> function); blender::FunctionRef<void(int, GreasePencilDrawing &)> function);
bool bounds_min_max(blender::float3 &min, blender::float3 &max) const; std::optional<blender::Bounds<blender::float3>> bounds_min_max() const;
/* For debugging purposes. */ /* For debugging purposes. */
void print_layer_tree(); void print_layer_tree();

View File

@ -17,6 +17,8 @@
/** Workaround to forward-declare C++ type in C header. */ /** Workaround to forward-declare C++ type in C header. */
#ifdef __cplusplus #ifdef __cplusplus
# include <optional>
# include "BLI_bounds_types.hh" # include "BLI_bounds_types.hh"
# include "BLI_math_vector_types.hh" # include "BLI_math_vector_types.hh"
# include "BLI_offset_indices.hh" # include "BLI_offset_indices.hh"
@ -302,6 +304,12 @@ typedef struct Mesh {
*/ */
blender::Span<int> looptri_polys() const; blender::Span<int> looptri_polys() const;
/**
* Calculate the largest and smallest position values of vertices.
* \note Does not take non-mesh data (edit mesh) into account, see #BKE_mesh_wrapper_minmax,
*/
std::optional<blender::Bounds<blender::float3>> bounds_min_max() const;
/** Set cached mesh bounds to a known-correct value to avoid their lazy calculation later on. */ /** Set cached mesh bounds to a known-correct value to avoid their lazy calculation later on. */
void bounds_set_eager(const blender::Bounds<blender::float3> &bounds); void bounds_set_eager(const blender::Bounds<blender::float3> &bounds);

View File

@ -536,9 +536,8 @@ typedef struct bNodeLink {
/** Panel in node tree for grouping sockets. */ /** Panel in node tree for grouping sockets. */
typedef struct bNodePanel { typedef struct bNodePanel {
/* UI name of the panel (not unique) */
char *name; char *name;
int flag;
int _pad;
} bNodePanel; } bNodePanel;
/* the basis for a Node tree, all links and nodes reside internal here */ /* the basis for a Node tree, all links and nodes reside internal here */
@ -608,8 +607,6 @@ typedef struct bNodeTree {
struct bNodePanel **panels_array; struct bNodePanel **panels_array;
int panels_num; int panels_num;
int active_panel; int active_panel;
int next_panel_identifier;
char _pad2[4];
bNodeTreeRuntimeHandle *runtime; bNodeTreeRuntimeHandle *runtime;
@ -649,6 +646,9 @@ typedef struct bNodeTree {
blender::Span<const bNode *> nodes_by_type(blender::StringRefNull type_idname) const; blender::Span<const bNode *> nodes_by_type(blender::StringRefNull type_idname) const;
/** Frame nodes without any parents. */ /** Frame nodes without any parents. */
blender::Span<bNode *> root_frames() const; blender::Span<bNode *> root_frames() const;
/** A span containing all links in the node tree. */
blender::Span<bNodeLink *> all_links();
blender::Span<const bNodeLink *> all_links() const;
/** /**
* Cached toposort of all nodes. If there are cycles, the returned array is not actually a * Cached toposort of all nodes. If there are cycles, the returned array is not actually a
* toposort. However, if a connected component does not contain a cycle, this component is sorted * toposort. However, if a connected component does not contain a cycle, this component is sorted

Some files were not shown because too many files have changed in this diff Show More