diff options
author | Hans Goudey <h.goudey@me.com> | 2022-09-21 19:53:26 +0300 |
---|---|---|
committer | Hans Goudey <h.goudey@me.com> | 2022-09-21 19:59:33 +0300 |
commit | bcc37dd9604266434369ee0d0985e2b33910355d (patch) | |
tree | 016522f82ba2760a57fba38b7aa6eae378956ab1 | |
parent | fd0333afab93878630c55888029c3ea9d27323e6 (diff) | |
parent | c1f622e63e387c70bd2577e87260b8df9a496d1d (diff) |
Merge branch 'master' into refactor-mesh-selection-generic
29 files changed, 781 insertions, 631 deletions
diff --git a/intern/cycles/blender/addon/engine.py b/intern/cycles/blender/addon/engine.py index e211f53cf31..1a99674d239 100644 --- a/intern/cycles/blender/addon/engine.py +++ b/intern/cycles/blender/addon/engine.py @@ -13,7 +13,7 @@ def _configure_argument_parser(): action='store_true') parser.add_argument("--cycles-device", help="Set the device to use for Cycles, overriding user preferences and the scene setting." - "Valid options are 'CPU', 'CUDA', 'OPTIX', 'HIP' or 'METAL'." + "Valid options are 'CPU', 'CUDA', 'OPTIX', 'HIP', 'ONEAPI', or 'METAL'." "Additionally, you can append '+CPU' to any GPU type for hybrid rendering.", default=None) return parser diff --git a/source/blender/blenlib/BLI_fileops.h b/source/blender/blenlib/BLI_fileops.h index 063e60ecf03..0ff75ca16e5 100644 --- a/source/blender/blenlib/BLI_fileops.h +++ b/source/blender/blenlib/BLI_fileops.h @@ -101,6 +101,7 @@ typedef enum eFileAttributes { FILE_ATTR_MOUNT_POINT = 1 << 14, /* Volume mounted as a folder. */ FILE_ATTR_HARDLINK = 1 << 15, /* Duplicated directory entry. */ } eFileAttributes; +ENUM_OPERATORS(eFileAttributes, FILE_ATTR_HARDLINK); #define FILE_ATTR_ANY_LINK \ (FILE_ATTR_ALIAS | FILE_ATTR_REPARSE_POINT | FILE_ATTR_SYMLINK | FILE_ATTR_JUNCTION_POINT | \ diff --git a/source/blender/blenlib/BLI_vector_adaptor.hh b/source/blender/blenlib/BLI_vector_adaptor.hh deleted file mode 100644 index 82d731aacd8..00000000000 --- a/source/blender/blenlib/BLI_vector_adaptor.hh +++ /dev/null @@ -1,88 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -#pragma once - -/** \file - * \ingroup bli - * - * A `blender::VectorAdaptor` is a container with a fixed maximum size and does not own the - * underlying memory. When an adaptor is constructed, you have to provide it with an uninitialized - * array that will be filled when elements are added to the vector. The vector adaptor is not able - * to grow. Therefore, it is undefined behavior to add more elements than fit into the provided - * buffer. - */ - -#include "BLI_span.hh" - -namespace blender { - -template<typename T> class VectorAdaptor { - private: - T *begin_; - T *end_; - T *capacity_end_; - - public: - VectorAdaptor() : begin_(nullptr), end_(nullptr), capacity_end_(nullptr) - { - } - - VectorAdaptor(T *data, int64_t capacity, int64_t size = 0) - : begin_(data), end_(data + size), capacity_end_(data + capacity) - { - } - - VectorAdaptor(MutableSpan<T> span) : VectorAdaptor(span.data(), span.size(), 0) - { - } - - void append(const T &value) - { - BLI_assert(end_ < capacity_end_); - new (end_) T(value); - end_++; - } - - void append(T &&value) - { - BLI_assert(end_ < capacity_end_); - new (end_) T(std::move(value)); - end_++; - } - - void append_n_times(const T &value, int64_t n) - { - BLI_assert(end_ + n <= capacity_end_); - uninitialized_fill_n(end_, n, value); - end_ += n; - } - - void extend(Span<T> values) - { - BLI_assert(end_ + values.size() <= capacity_end_); - uninitialized_copy_n(values.data(), values.size(), end_); - end_ += values.size(); - } - - int64_t capacity() const - { - return capacity_end_ - begin_; - } - - int64_t size() const - { - return end_ - begin_; - } - - bool is_empty() const - { - return begin_ == end_; - } - - bool is_full() const - { - return end_ == capacity_end_; - } -}; - -} // namespace blender diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index 36acbd41ad7..e0d05f8c36a 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -333,7 +333,6 @@ set(SRC BLI_uuid.h BLI_uvproject.h BLI_vector.hh - BLI_vector_adaptor.hh BLI_vector_set.hh BLI_vector_set_slots.hh BLI_virtual_array.hh diff --git a/source/blender/bmesh/intern/bmesh_mesh_convert.cc b/source/blender/bmesh/intern/bmesh_mesh_convert.cc index 7164b837451..088b04b8351 100644 --- a/source/blender/bmesh/intern/bmesh_mesh_convert.cc +++ b/source/blender/bmesh/intern/bmesh_mesh_convert.cc @@ -899,6 +899,20 @@ static void write_fn_to_attribute(blender::bke::MutableAttributeAccessor attribu attribute.finish(); } +static void assert_bmesh_has_no_mesh_only_attributes(BMesh &bm) +{ + (void)bm; /* Unused in the release builds. */ + + /* The "hide" attributes are stored as flags on #BMesh. */ + BLI_assert(CustomData_get_layer_named(&bm.vdata, CD_PROP_BOOL, ".hide_vert") == nullptr); + BLI_assert(CustomData_get_layer_named(&bm.edata, CD_PROP_BOOL, ".hide_edge") == nullptr); + BLI_assert(CustomData_get_layer_named(&bm.pdata, CD_PROP_BOOL, ".hide_poly") == nullptr); + /* The "selection" attributes are stored as flags on #BMesh. */ + BLI_assert(CustomData_get_layer_named(&bm.vdata, CD_PROP_BOOL, ".selection_vert") == nullptr); + BLI_assert(CustomData_get_layer_named(&bm.edata, CD_PROP_BOOL, ".selection_edge") == nullptr); + BLI_assert(CustomData_get_layer_named(&bm.pdata, CD_PROP_BOOL, ".selection_poly") == nullptr); +} + static void convert_bmesh_hide_flags_to_mesh_attributes(BMesh &bm, const bool need_hide_vert, const bool need_hide_edge, @@ -907,9 +921,7 @@ static void convert_bmesh_hide_flags_to_mesh_attributes(BMesh &bm, { using namespace blender; /* The "hide" attributes are stored as flags on #BMesh. */ - BLI_assert(CustomData_get_layer_named(&bm.vdata, CD_PROP_BOOL, ".hide_vert") == nullptr); - BLI_assert(CustomData_get_layer_named(&bm.edata, CD_PROP_BOOL, ".hide_edge") == nullptr); - BLI_assert(CustomData_get_layer_named(&bm.pdata, CD_PROP_BOOL, ".hide_poly") == nullptr); + assert_bmesh_has_no_mesh_only_attributes(bm); if (!(need_hide_vert || need_hide_edge || need_hide_poly)) { return; @@ -936,11 +948,6 @@ static void convert_bmesh_selection_flags_to_mesh_attributes(BMesh &bm, Mesh &mesh) { using namespace blender; - /* The "selection" attributes are stored as flags on #BMesh. */ - BLI_assert(CustomData_get_layer_named(&bm.vdata, CD_PROP_BOOL, ".selection_vert") == nullptr); - BLI_assert(CustomData_get_layer_named(&bm.edata, CD_PROP_BOOL, ".selection_edge") == nullptr); - BLI_assert(CustomData_get_layer_named(&bm.pdata, CD_PROP_BOOL, ".selection_poly") == nullptr); - if (!(need_selection_vert || need_selection_edge || need_selection_poly)) { return; } @@ -1244,8 +1251,12 @@ void BM_mesh_bm_to_me(Main *bmain, BMesh *bm, Mesh *me, const struct BMeshToMesh BKE_mesh_runtime_clear_geometry(me); } +/* NOTE: The function is called from multiple threads with the same input BMesh and different + * mesh objects. */ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks *cd_mask_extra) { + using namespace blender; + /* Must be an empty mesh. */ BLI_assert(me->totvert == 0); BLI_assert(cd_mask_extra == nullptr || (cd_mask_extra->vmask & CD_MASK_SHAPEKEY) == 0); @@ -1286,20 +1297,16 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE); - bool need_selection_vert = false; - bool need_selection_edge = false; - bool need_selection_poly = false; - bool need_hide_vert = false; - bool need_hide_edge = false; - bool need_hide_poly = false; - bool need_material_index = false; - /* Clear normals on the mesh completely, since the original vertex and polygon count might be * different than the BMesh's. */ BKE_mesh_clear_derived_normals(me); me->runtime.deformed_only = true; + bke::MutableAttributeAccessor mesh_attributes = me->attributes_for_write(); + + bke::SpanAttributeWriter<bool> hide_vert_attribute; + bke::SpanAttributeWriter<bool> selection_vert_attribute; BM_ITER_MESH_INDEX (eve, &iter, bm, BM_VERTS_OF_MESH, i) { MVert *mv = &mvert[i]; @@ -1308,16 +1315,26 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * BM_elem_index_set(eve, i); /* set_inline */ if (BM_elem_flag_test(eve, BM_ELEM_HIDDEN)) { - need_hide_vert = true; + if (!hide_vert_attribute) { + hide_vert_attribute = mesh_attributes.lookup_or_add_for_write_only_span<bool>( + ".hide_vert", ATTR_DOMAIN_POINT); + } + hide_vert_attribute.span[i] = true; } if (BM_elem_flag_test(eve, BM_ELEM_SELECT)) { - need_selection_vert = true; + if (!selection_vert_attribute) { + selection_vert_attribute = mesh_attributes.lookup_or_add_for_write_only_span<bool>( + ".selection_vert", ATTR_DOMAIN_POINT); + } + selection_vert_attribute.span[i] = true; } CustomData_from_bmesh_block(&bm->vdata, &me->vdata, eve->head.data, i); } bm->elem_index_dirty &= ~BM_VERT; + bke::SpanAttributeWriter<bool> hide_edge_attribute; + bke::SpanAttributeWriter<bool> selection_edge_attribute; BM_ITER_MESH_INDEX (eed, &iter, bm, BM_EDGES_OF_MESH, i) { MEdge *med = &medge[i]; @@ -1328,10 +1345,18 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * med->flag = BM_edge_flag_to_mflag(eed); if (BM_elem_flag_test(eed, BM_ELEM_HIDDEN)) { - need_hide_edge = true; + if (!hide_edge_attribute) { + hide_edge_attribute = mesh_attributes.lookup_or_add_for_write_only_span<bool>( + ".hide_edge", ATTR_DOMAIN_EDGE); + } + hide_edge_attribute.span[i] = true; } if (BM_elem_flag_test(eed, BM_ELEM_SELECT)) { - need_selection_edge = true; + if (!selection_edge_attribute) { + selection_edge_attribute = mesh_attributes.lookup_or_add_for_write_only_span<bool>( + ".selection_edge", ATTR_DOMAIN_EDGE); + } + selection_edge_attribute.span[i] = true; } /* Handle this differently to editmode switching, @@ -1351,6 +1376,9 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * bm->elem_index_dirty &= ~BM_EDGE; j = 0; + bke::SpanAttributeWriter<int> material_index_attribute; + bke::SpanAttributeWriter<bool> hide_poly_attribute; + bke::SpanAttributeWriter<bool> selection_poly_attribute; BM_ITER_MESH_INDEX (efa, &iter, bm, BM_FACES_OF_MESH, i) { BMLoop *l_iter; BMLoop *l_first; @@ -1361,15 +1389,27 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * mp->totloop = efa->len; mp->flag = BM_face_flag_to_mflag(efa); if (BM_elem_flag_test(efa, BM_ELEM_HIDDEN)) { - need_hide_poly = true; + if (!hide_poly_attribute) { + hide_poly_attribute = mesh_attributes.lookup_or_add_for_write_only_span<bool>( + ".hide_poly", ATTR_DOMAIN_FACE); + } + hide_poly_attribute.span[i] = true; } if (BM_elem_flag_test(efa, BM_ELEM_SELECT)) { - need_selection_poly = true; + if (!selection_poly_attribute) { + selection_poly_attribute = mesh_attributes.lookup_or_add_for_write_only_span<bool>( + ".selection_poly", ATTR_DOMAIN_FACE); + } + selection_poly_attribute.span[i] = true; } mp->loopstart = j; if (efa->mat_nr != 0) { - need_material_index = true; + if (!material_index_attribute) { + material_index_attribute = mesh_attributes.lookup_or_add_for_write_only_span<int>( + "material_index", ATTR_DOMAIN_FACE); + } + material_index_attribute.span[i] = efa->mat_nr; } l_iter = l_first = BM_FACE_FIRST_LOOP(efa); @@ -1388,18 +1428,30 @@ void BM_mesh_bm_to_me_for_eval(BMesh *bm, Mesh *me, const CustomData_MeshMasks * } bm->elem_index_dirty &= ~(BM_FACE | BM_LOOP); - if (need_material_index) { - BM_mesh_elem_table_ensure(bm, BM_FACE); - write_fn_to_attribute<int>( - me->attributes_for_write(), "material_index", ATTR_DOMAIN_FACE, [&](const int i) { - return static_cast<int>(BM_face_at_index(bm, i)->mat_nr); - }); + if (material_index_attribute) { + material_index_attribute.finish(); } - convert_bmesh_hide_flags_to_mesh_attributes( - *bm, need_hide_vert, need_hide_edge, need_hide_poly, *me); - convert_bmesh_selection_flags_to_mesh_attributes( - *bm, need_selection_vert, need_selection_edge, need_selection_poly, *me); + assert_bmesh_has_no_mesh_only_attributes(*bm); + + if (hide_vert_attribute) { + hide_vert_attribute.finish(); + } + if (hide_edge_attribute) { + hide_edge_attribute.finish(); + } + if (hide_poly_attribute) { + hide_poly_attribute.finish(); + } + if (selection_vert_attribute) { + selection_vert_attribute.finish(); + } + if (selection_edge_attribute) { + selection_edge_attribute.finish(); + } + if (selection_poly_attribute) { + selection_poly_attribute.finish(); + } me->cd_flag = BM_mesh_cd_flag_from_bmesh(bm); } diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt index e799c5ce32a..a394ea4a54a 100644 --- a/source/blender/depsgraph/CMakeLists.txt +++ b/source/blender/depsgraph/CMakeLists.txt @@ -26,6 +26,8 @@ set(SRC intern/builder/deg_builder.cc intern/builder/deg_builder_cache.cc intern/builder/deg_builder_cycle.cc + intern/builder/deg_builder_key.cc + intern/builder/deg_builder_key.h intern/builder/deg_builder_map.cc intern/builder/deg_builder_nodes.cc intern/builder/deg_builder_nodes_rig.cc @@ -34,7 +36,6 @@ set(SRC intern/builder/deg_builder_pchanmap.cc intern/builder/deg_builder_relations.cc intern/builder/deg_builder_relations_drivers.cc - intern/builder/deg_builder_relations_keys.cc intern/builder/deg_builder_relations_rig.cc intern/builder/deg_builder_relations_scene.cc intern/builder/deg_builder_relations_view_layer.cc diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc b/source/blender/depsgraph/intern/builder/deg_builder_key.cc index 8506a97c408..741c415b5cd 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations_keys.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_key.cc @@ -7,20 +7,26 @@ * Methods for constructing depsgraph */ -#include "intern/builder/deg_builder_relations.h" +#include "intern/builder/deg_builder_key.h" + +#include "RNA_path.h" namespace blender::deg { -//////////////////////////////////////////////////////////////////////////////// -/* Time source. */ +/* -------------------------------------------------------------------- */ +/** \name Time source + * \{ */ string TimeSourceKey::identifier() const { return string("TimeSourceKey"); } -//////////////////////////////////////////////////////////////////////////////// -// Component. +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Component + * \{ */ string ComponentKey::identifier() const { @@ -35,8 +41,11 @@ string ComponentKey::identifier() const return result; } -//////////////////////////////////////////////////////////////////////////////// -// Operation. +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Operation + * \{ */ string OperationKey::identifier() const { @@ -51,8 +60,11 @@ string OperationKey::identifier() const return result; } -//////////////////////////////////////////////////////////////////////////////// -// RNA path. +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name RNA path + * \{ */ RNAPathKey::RNAPathKey(ID *id, const char *path, RNAPointerSource source) : id(id), source(source) { @@ -79,4 +91,6 @@ string RNAPathKey::identifier() const return string("RnaPathKey(") + "id: " + id_name + ", prop: '" + prop_name + "')"; } +/** \} */ + } // namespace blender::deg diff --git a/source/blender/depsgraph/intern/builder/deg_builder_key.h b/source/blender/depsgraph/intern/builder/deg_builder_key.h new file mode 100644 index 00000000000..4f8b2dc9f8f --- /dev/null +++ b/source/blender/depsgraph/intern/builder/deg_builder_key.h @@ -0,0 +1,201 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2013 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup depsgraph + */ + +#pragma once + +#include "intern/builder/deg_builder_rna.h" +#include "intern/depsgraph_type.h" +#include "intern/node/deg_node_component.h" +#include "intern/node/deg_node_id.h" +#include "intern/node/deg_node_operation.h" + +#include "DNA_ID.h" + +#include "RNA_access.h" +#include "RNA_types.h" + +struct ID; +struct PropertyRNA; + +namespace blender::deg { + +struct TimeSourceKey { + TimeSourceKey() = default; + + string identifier() const; +}; + +struct ComponentKey { + ComponentKey() = default; + + inline ComponentKey(const ID *id, NodeType type, const char *name = "") + : id(id), type(type), name(name) + { + } + + string identifier() const; + + const ID *id = nullptr; + NodeType type = NodeType::UNDEFINED; + const char *name = ""; +}; + +struct OperationKey { + OperationKey() = default; + + inline OperationKey(const ID *id, NodeType component_type, const char *name, int name_tag = -1) + : id(id), + component_type(component_type), + component_name(""), + opcode(OperationCode::OPERATION), + name(name), + name_tag(name_tag) + { + } + + OperationKey(const ID *id, + NodeType component_type, + const char *component_name, + const char *name, + int name_tag) + : id(id), + component_type(component_type), + component_name(component_name), + opcode(OperationCode::OPERATION), + name(name), + name_tag(name_tag) + { + } + + OperationKey(const ID *id, NodeType component_type, OperationCode opcode) + : id(id), + component_type(component_type), + component_name(""), + opcode(opcode), + name(""), + name_tag(-1) + { + } + + OperationKey(const ID *id, + NodeType component_type, + const char *component_name, + OperationCode opcode) + : id(id), + component_type(component_type), + component_name(component_name), + opcode(opcode), + name(""), + name_tag(-1) + { + } + + OperationKey(const ID *id, + NodeType component_type, + OperationCode opcode, + const char *name, + int name_tag = -1) + : id(id), + component_type(component_type), + component_name(""), + opcode(opcode), + name(name), + name_tag(name_tag) + { + } + + OperationKey(const ID *id, + NodeType component_type, + const char *component_name, + OperationCode opcode, + const char *name, + int name_tag = -1) + : id(id), + component_type(component_type), + component_name(component_name), + opcode(opcode), + name(name), + name_tag(name_tag) + { + } + + OperationKey(OperationKey &&other) noexcept = default; + OperationKey &operator=(OperationKey &&other) = default; + + OperationKey(const OperationKey &other) = default; + OperationKey &operator=(const OperationKey &other) = default; + + string identifier() const; + + const ID *id = nullptr; + NodeType component_type = NodeType::UNDEFINED; + const char *component_name = ""; + OperationCode opcode = OperationCode::OPERATION; + const char *name = ""; + int name_tag = -1; +}; + +/* Similar to the the OperationKey but does not contain external references, which makes it + * suitable to identify operations even after the original database or graph was destroyed. + * The downside of this key over the OperationKey is that it performs string allocation upon + * the key construction. */ +struct PersistentOperationKey : public OperationKey { + /* Create the key which identifies the given operation node. */ + PersistentOperationKey(const OperationNode *operation_node) + { + const ComponentNode *component_node = operation_node->owner; + const IDNode *id_node = component_node->owner; + + /* Copy names over to our object, so that the key stays valid even after the `operation_node` + * is destroyed.*/ + component_name_storage_ = component_node->name; + name_storage_ = operation_node->name; + + /* Assign fields used by the OperationKey API. */ + id = id_node->id_orig; + component_type = component_node->type; + component_name = component_name_storage_.c_str(); + opcode = operation_node->opcode; + name = name_storage_.c_str(); + name_tag = operation_node->name_tag; + } + + PersistentOperationKey(PersistentOperationKey &&other) noexcept : OperationKey(other) + { + component_name_storage_ = std::move(other.component_name_storage_); + name_storage_ = std::move(other.name_storage_); + + /* Re-assign pointers to the strings. + * This is needed because string content can actually change address if the string uses the + * small string optimization. */ + component_name = component_name_storage_.c_str(); + name = name_storage_.c_str(); + } + + PersistentOperationKey &operator=(PersistentOperationKey &&other) = delete; + + PersistentOperationKey(const PersistentOperationKey &other) = delete; + PersistentOperationKey &operator=(const PersistentOperationKey &other) = delete; + + private: + string component_name_storage_; + string name_storage_; +}; + +struct RNAPathKey { + RNAPathKey(ID *id, const char *path, RNAPointerSource source); + RNAPathKey(ID *id, const PointerRNA &ptr, PropertyRNA *prop, RNAPointerSource source); + + string identifier() const; + + ID *id; + PointerRNA ptr; + PropertyRNA *prop; + RNAPointerSource source; +}; + +} // namespace blender::deg diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 80be781da48..f95c0700a47 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -104,6 +104,7 @@ #include "SEQ_sequencer.h" #include "intern/builder/deg_builder.h" +#include "intern/builder/deg_builder_key.h" #include "intern/builder/deg_builder_rna.h" #include "intern/depsgraph.h" #include "intern/depsgraph_tag.h" @@ -208,7 +209,7 @@ IDNode *DepsgraphNodeBuilder::add_id_node(ID *id) return id_node; } -IDNode *DepsgraphNodeBuilder::find_id_node(ID *id) +IDNode *DepsgraphNodeBuilder::find_id_node(const ID *id) { return graph_->find_id_node(id); } @@ -228,6 +229,17 @@ ComponentNode *DepsgraphNodeBuilder::add_component_node(ID *id, return comp_node; } +ComponentNode *DepsgraphNodeBuilder::find_component_node(const ID *id, + const NodeType comp_type, + const char *comp_name) +{ + IDNode *id_node = find_id_node(id); + if (id_node == nullptr) { + return nullptr; + } + return id_node->find_component(comp_type, comp_name); +} + OperationNode *DepsgraphNodeBuilder::add_operation_node(ComponentNode *comp_node, OperationCode opcode, const DepsEvalOperationCb &op, @@ -311,23 +323,32 @@ bool DepsgraphNodeBuilder::has_operation_node(ID *id, return find_operation_node(id, comp_type, comp_name, opcode, name, name_tag) != nullptr; } -OperationNode *DepsgraphNodeBuilder::find_operation_node(ID *id, +OperationNode *DepsgraphNodeBuilder::find_operation_node(const ID *id, NodeType comp_type, const char *comp_name, OperationCode opcode, const char *name, int name_tag) { - ComponentNode *comp_node = add_component_node(id, comp_type, comp_name); + ComponentNode *comp_node = find_component_node(id, comp_type, comp_name); + if (comp_node == nullptr) { + return nullptr; + } return comp_node->find_operation(opcode, name, name_tag); } OperationNode *DepsgraphNodeBuilder::find_operation_node( - ID *id, NodeType comp_type, OperationCode opcode, const char *name, int name_tag) + const ID *id, NodeType comp_type, OperationCode opcode, const char *name, int name_tag) { return find_operation_node(id, comp_type, "", opcode, name, name_tag); } +OperationNode *DepsgraphNodeBuilder::find_operation_node(const OperationKey &key) +{ + return find_operation_node( + key.id, key.component_type, key.component_name, key.opcode, key.name, key.name_tag); +} + ID *DepsgraphNodeBuilder::get_cow_id(const ID *id_orig) const { return graph_->get_cow_id(id_orig); @@ -371,17 +392,8 @@ void DepsgraphNodeBuilder::begin_build() id_node->id_cow = nullptr; } - for (OperationNode *op_node : graph_->entry_tags) { - ComponentNode *comp_node = op_node->owner; - IDNode *id_node = comp_node->owner; - - SavedEntryTag entry_tag; - entry_tag.id_orig = id_node->id_orig; - entry_tag.component_type = comp_node->type; - entry_tag.opcode = op_node->opcode; - entry_tag.name = op_node->name; - entry_tag.name_tag = op_node->name_tag; - saved_entry_tags_.append(entry_tag); + for (const OperationNode *op_node : graph_->entry_tags) { + saved_entry_tags_.append_as(op_node); } /* Make sure graph has no nodes left from previous state. */ @@ -499,23 +511,15 @@ void DepsgraphNodeBuilder::update_invalid_cow_pointers() void DepsgraphNodeBuilder::tag_previously_tagged_nodes() { - for (const SavedEntryTag &entry_tag : saved_entry_tags_) { - IDNode *id_node = find_id_node(entry_tag.id_orig); - if (id_node == nullptr) { - continue; - } - ComponentNode *comp_node = id_node->find_component(entry_tag.component_type); - if (comp_node == nullptr) { - continue; - } - OperationNode *op_node = comp_node->find_operation( - entry_tag.opcode, entry_tag.name.c_str(), entry_tag.name_tag); - if (op_node == nullptr) { + for (const OperationKey &operation_key : saved_entry_tags_) { + OperationNode *operation_node = find_operation_node(operation_key); + if (operation_node == nullptr) { continue; } + /* Since the tag is coming from a saved copy of entry tags, this means * that originally node was explicitly tagged for user update. */ - op_node->tag_update(graph_, DEG_UPDATE_SOURCE_USER_EDIT); + operation_node->tag_update(graph_, DEG_UPDATE_SOURCE_USER_EDIT); } } diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h index d5ac601ebff..a8efe8fca9f 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.h @@ -8,6 +8,7 @@ #pragma once #include "intern/builder/deg_builder.h" +#include "intern/builder/deg_builder_key.h" #include "intern/builder/deg_builder_map.h" #include "intern/depsgraph_type.h" #include "intern/node/deg_node_id.h" @@ -56,6 +57,7 @@ struct ComponentNode; struct Depsgraph; class DepsgraphBuilderCache; struct IDNode; +struct OperationKey; struct OperationNode; struct TimeSourceNode; @@ -92,10 +94,11 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder { int foreach_id_cow_detect_need_for_update_callback(ID *id_cow_self, ID *id_pointer); IDNode *add_id_node(ID *id); - IDNode *find_id_node(ID *id); + IDNode *find_id_node(const ID *id); TimeSourceNode *add_time_source(); ComponentNode *add_component_node(ID *id, NodeType comp_type, const char *comp_name = ""); + ComponentNode *find_component_node(const ID *id, NodeType comp_type, const char *comp_name = ""); OperationNode *add_operation_node(ComponentNode *comp_node, OperationCode opcode, @@ -137,15 +140,20 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder { const char *name = "", int name_tag = -1); - OperationNode *find_operation_node(ID *id, + OperationNode *find_operation_node(const ID *id, NodeType comp_type, const char *comp_name, OperationCode opcode, const char *name = "", int name_tag = -1); - OperationNode *find_operation_node( - ID *id, NodeType comp_type, OperationCode opcode, const char *name = "", int name_tag = -1); + OperationNode *find_operation_node(const ID *id, + NodeType comp_type, + OperationCode opcode, + const char *name = "", + int name_tag = -1); + + OperationNode *find_operation_node(const OperationKey &key); virtual void build_id(ID *id); @@ -255,17 +263,9 @@ class DepsgraphNodeBuilder : public DepsgraphBuilder { }; protected: - /* Allows to identify an operation which was tagged for update at the time - * relations are being updated. We can not reuse operation node pointer - * since it will change during dependency graph construction. */ - struct SavedEntryTag { - ID *id_orig; - NodeType component_type; - OperationCode opcode; - string name; - int name_tag; - }; - Vector<SavedEntryTag> saved_entry_tags_; + /* Entry tags from the previous state of the dependency graph. + * Stored before the graph is re-created so that they can be transferred over. */ + Vector<PersistentOperationKey> saved_entry_tags_; struct BuilderWalkUserData { DepsgraphNodeBuilder *builder; diff --git a/source/blender/depsgraph/intern/builder/deg_builder_relations.h b/source/blender/depsgraph/intern/builder/deg_builder_relations.h index 7d3a0fd9217..901e4a1acbb 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_relations.h +++ b/source/blender/depsgraph/intern/builder/deg_builder_relations.h @@ -14,14 +14,13 @@ #include "DNA_ID.h" -#include "RNA_access.h" #include "RNA_path.h" -#include "RNA_types.h" #include "BLI_string.h" #include "BLI_utildefines.h" #include "intern/builder/deg_builder.h" +#include "intern/builder/deg_builder_key.h" #include "intern/builder/deg_builder_map.h" #include "intern/builder/deg_builder_rna.h" #include "intern/builder/deg_builder_stack.h" @@ -69,8 +68,6 @@ struct bNodeTree; struct bPoseChannel; struct bSound; -struct PropertyRNA; - namespace blender::deg { struct ComponentNode; @@ -84,128 +81,6 @@ struct Relation; struct RootPChanMap; struct TimeSourceNode; -struct TimeSourceKey { - TimeSourceKey() = default; - - string identifier() const; -}; - -struct ComponentKey { - ComponentKey() = default; - - inline ComponentKey(const ID *id, NodeType type, const char *name = "") - : id(id), type(type), name(name) - { - } - - string identifier() const; - - const ID *id = nullptr; - NodeType type = NodeType::UNDEFINED; - const char *name = ""; -}; - -struct OperationKey { - OperationKey() = default; - - inline OperationKey(const ID *id, NodeType component_type, const char *name, int name_tag = -1) - : id(id), - component_type(component_type), - component_name(""), - opcode(OperationCode::OPERATION), - name(name), - name_tag(name_tag) - { - } - - OperationKey(const ID *id, - NodeType component_type, - const char *component_name, - const char *name, - int name_tag) - : id(id), - component_type(component_type), - component_name(component_name), - opcode(OperationCode::OPERATION), - name(name), - name_tag(name_tag) - { - } - - OperationKey(const ID *id, NodeType component_type, OperationCode opcode) - : id(id), - component_type(component_type), - component_name(""), - opcode(opcode), - name(""), - name_tag(-1) - { - } - - OperationKey(const ID *id, - NodeType component_type, - const char *component_name, - OperationCode opcode) - : id(id), - component_type(component_type), - component_name(component_name), - opcode(opcode), - name(""), - name_tag(-1) - { - } - - OperationKey(const ID *id, - NodeType component_type, - OperationCode opcode, - const char *name, - int name_tag = -1) - : id(id), - component_type(component_type), - component_name(""), - opcode(opcode), - name(name), - name_tag(name_tag) - { - } - - OperationKey(const ID *id, - NodeType component_type, - const char *component_name, - OperationCode opcode, - const char *name, - int name_tag = -1) - : id(id), - component_type(component_type), - component_name(component_name), - opcode(opcode), - name(name), - name_tag(name_tag) - { - } - - string identifier() const; - - const ID *id = nullptr; - NodeType component_type = NodeType::UNDEFINED; - const char *component_name = ""; - OperationCode opcode = OperationCode::OPERATION; - const char *name = ""; - int name_tag = -1; -}; - -struct RNAPathKey { - RNAPathKey(ID *id, const char *path, RNAPointerSource source); - RNAPathKey(ID *id, const PointerRNA &ptr, PropertyRNA *prop, RNAPointerSource source); - - string identifier() const; - - ID *id; - PointerRNA ptr; - PropertyRNA *prop; - RNAPointerSource source; -}; - class DepsgraphRelationBuilder : public DepsgraphBuilder { public: DepsgraphRelationBuilder(Main *bmain, Depsgraph *graph, DepsgraphBuilderCache *cache); diff --git a/source/blender/depsgraph/intern/node/deg_node_component.cc b/source/blender/depsgraph/intern/node/deg_node_component.cc index 40b4b36a29c..ebb4450579f 100644 --- a/source/blender/depsgraph/intern/node/deg_node_component.cc +++ b/source/blender/depsgraph/intern/node/deg_node_component.cc @@ -90,10 +90,11 @@ ComponentNode::~ComponentNode() string ComponentNode::identifier() const { - const string idname = this->owner->name; - const string typebuf = "" + to_string(static_cast<int>(type)) + ")"; - return typebuf + name + " : " + idname + - "( affects_visible_id: " + (affects_visible_id ? "true" : "false") + ")"; + const string type_name = type_get_factory(type)->type_name(); + const string name_part = name[0] ? (string(" '") + name + "'") : ""; + + return "[" + type_name + "]" + name_part + " : " + + "(affects_visible_id: " + (affects_visible_id ? "true" : "false") + ")"; } OperationNode *ComponentNode::find_operation(OperationIDKey key) const diff --git a/source/blender/depsgraph/intern/node/deg_node_factory_impl.h b/source/blender/depsgraph/intern/node/deg_node_factory_impl.h index d9d0a1c1e3e..5059368120e 100644 --- a/source/blender/depsgraph/intern/node/deg_node_factory_impl.h +++ b/source/blender/depsgraph/intern/node/deg_node_factory_impl.h @@ -34,15 +34,8 @@ Node *DepsNodeFactoryImpl<ModeObjectType>::create_node(const ID *id, const char *name) const { Node *node = new ModeObjectType(); - /* Populate base node settings. */ node->type = type(); - /* Set name if provided, or use default type name. */ - if (name[0] != '\0') { - node->name = name; - } - else { - node->name = type_name(); - } + node->name = name; node->init(id, subdata); return node; } diff --git a/source/blender/editors/space_buttons/buttons_ops.c b/source/blender/editors/space_buttons/buttons_ops.c index 10fb008049d..a9ce9a3d723 100644 --- a/source/blender/editors/space_buttons/buttons_ops.c +++ b/source/blender/editors/space_buttons/buttons_ops.c @@ -337,6 +337,12 @@ static int file_browse_invoke(bContext *C, wmOperator *op, const wmEvent *event) RNA_string_set(op->ptr, path_prop, str); MEM_freeN(str); + PropertyRNA *prop_check_existing = RNA_struct_find_property(op->ptr, "check_existing"); + if (!RNA_property_is_set(op->ptr, prop_check_existing)) { + const bool is_output_path = (RNA_property_flag(prop) & PROP_PATH_OUTPUT) != 0; + RNA_property_boolean_set(op->ptr, prop_check_existing, is_output_path); + } + WM_event_add_fileselect(C, op); return OPERATOR_RUNNING_MODAL; diff --git a/source/blender/editors/space_file/CMakeLists.txt b/source/blender/editors/space_file/CMakeLists.txt index 792b9120e7b..fb9d5ab9b13 100644 --- a/source/blender/editors/space_file/CMakeLists.txt +++ b/source/blender/editors/space_file/CMakeLists.txt @@ -27,8 +27,9 @@ set(SRC file_ops.c file_panels.c file_utils.c - filelist.c + filelist.cc filesel.c + folder_history.cc fsmenu.c space_file.c diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index 788bafe8089..676fdff268e 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -185,6 +185,19 @@ void file_on_reload_callback_register(struct SpaceFile *sfile, onReloadFn callback, onReloadFnData custom_data); +/* folder_history.cc */ + +/* not listbase itself */ +void folderlist_free(struct ListBase *folderlist); +void folderlist_popdir(struct ListBase *folderlist, char *dir); +void folderlist_pushdir(struct ListBase *folderlist, const char *dir); +const char *folderlist_peeklastdir(struct ListBase *folderlist); +int folderlist_clear_next(struct SpaceFile *sfile); + +void folder_history_list_ensure_for_active_browse_mode(struct SpaceFile *sfile); +void folder_history_list_free(struct SpaceFile *sfile); +struct ListBase folder_history_list_duplicate(struct ListBase *listbase); + /* file_panels.c */ void file_tool_props_region_panels_register(struct ARegionType *art); diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.cc index 24e1faaf4c9..2b9b23620ee 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.cc @@ -7,11 +7,11 @@ /* global includes */ -#include <math.h> -#include <stdlib.h> -#include <string.h> +#include <cmath> +#include <cstdlib> +#include <cstring> +#include <ctime> #include <sys/stat.h> -#include <time.h> #ifndef WIN32 # include <unistd.h> @@ -79,183 +79,14 @@ #define FILEDIR_NBR_ENTRIES_UNSET -1 -/* ----------------- FOLDERLIST (previous/next) -------------- */ - -typedef struct FolderList { - struct FolderList *next, *prev; - char *foldername; -} FolderList; - -void folderlist_popdir(struct ListBase *folderlist, char *dir) -{ - const char *prev_dir; - struct FolderList *folder; - folder = folderlist->last; - - if (folder) { - /* remove the current directory */ - MEM_freeN(folder->foldername); - BLI_freelinkN(folderlist, folder); - - folder = folderlist->last; - if (folder) { - prev_dir = folder->foldername; - BLI_strncpy(dir, prev_dir, FILE_MAXDIR); - } - } - /* delete the folder next or use setdir directly before PREVIOUS OP */ -} - -void folderlist_pushdir(ListBase *folderlist, const char *dir) -{ - if (!dir[0]) { - return; - } - - struct FolderList *folder, *previous_folder; - previous_folder = folderlist->last; - - /* check if already exists */ - if (previous_folder && previous_folder->foldername) { - if (BLI_path_cmp(previous_folder->foldername, dir) == 0) { - return; - } - } - - /* create next folder element */ - folder = MEM_mallocN(sizeof(*folder), __func__); - folder->foldername = BLI_strdup(dir); - - /* add it to the end of the list */ - BLI_addtail(folderlist, folder); -} - -const char *folderlist_peeklastdir(ListBase *folderlist) -{ - struct FolderList *folder; - - if (!folderlist->last) { - return NULL; - } - - folder = folderlist->last; - return folder->foldername; -} - -int folderlist_clear_next(struct SpaceFile *sfile) -{ - const FileSelectParams *params = ED_fileselect_get_active_params(sfile); - struct FolderList *folder; - - /* if there is no folder_next there is nothing we can clear */ - if (BLI_listbase_is_empty(sfile->folders_next)) { - return 0; - } - - /* if previous_folder, next_folder or refresh_folder operators are executed - * it doesn't clear folder_next */ - folder = sfile->folders_prev->last; - if ((!folder) || (BLI_path_cmp(folder->foldername, params->dir) == 0)) { - return 0; - } - - /* eventually clear flist->folders_next */ - return 1; -} - -void folderlist_free(ListBase *folderlist) -{ - if (folderlist) { - FolderList *folder; - for (folder = folderlist->first; folder; folder = folder->next) { - MEM_freeN(folder->foldername); - } - BLI_freelistN(folderlist); - } -} - -static ListBase folderlist_duplicate(ListBase *folderlist) -{ - ListBase folderlistn = {NULL}; - - BLI_duplicatelist(&folderlistn, folderlist); - - for (FolderList *folder = folderlistn.first; folder; folder = folder->next) { - folder->foldername = MEM_dupallocN(folder->foldername); - } - return folderlistn; -} - -/* ----------------- Folder-History (wraps/owns file list above) -------------- */ - -static FileFolderHistory *folder_history_find(const SpaceFile *sfile, eFileBrowse_Mode browse_mode) -{ - LISTBASE_FOREACH (FileFolderHistory *, history, &sfile->folder_histories) { - if (history->browse_mode == browse_mode) { - return history; - } - } - - return NULL; -} - -void folder_history_list_ensure_for_active_browse_mode(SpaceFile *sfile) -{ - FileFolderHistory *history = folder_history_find(sfile, sfile->browse_mode); - - if (!history) { - history = MEM_callocN(sizeof(*history), __func__); - history->browse_mode = sfile->browse_mode; - BLI_addtail(&sfile->folder_histories, history); - } - - sfile->folders_next = &history->folders_next; - sfile->folders_prev = &history->folders_prev; -} - -static void folder_history_entry_free(SpaceFile *sfile, FileFolderHistory *history) -{ - if (sfile->folders_prev == &history->folders_prev) { - sfile->folders_prev = NULL; - } - if (sfile->folders_next == &history->folders_next) { - sfile->folders_next = NULL; - } - folderlist_free(&history->folders_prev); - folderlist_free(&history->folders_next); - BLI_freelinkN(&sfile->folder_histories, history); -} - -void folder_history_list_free(SpaceFile *sfile) -{ - LISTBASE_FOREACH_MUTABLE (FileFolderHistory *, history, &sfile->folder_histories) { - folder_history_entry_free(sfile, history); - } -} - -ListBase folder_history_list_duplicate(ListBase *listbase) -{ - ListBase histories = {NULL}; - - LISTBASE_FOREACH (FileFolderHistory *, history, listbase) { - FileFolderHistory *history_new = MEM_dupallocN(history); - history_new->folders_prev = folderlist_duplicate(&history->folders_prev); - history_new->folders_next = folderlist_duplicate(&history->folders_next); - BLI_addtail(&histories, history_new); - } - - return histories; -} - /* ------------------FILELIST------------------------ */ -typedef struct FileListInternEntry { - struct FileListInternEntry *next, *prev; +struct FileListInternEntry { + FileListInternEntry *next, *prev; FileUID uid; - /** eFileSel_File_Types */ - int typeflag; + eFileSel_File_Types typeflag; /** ID type, in case typeflag has FILE_TYPE_BLENDERLIB set. */ int blentype; @@ -287,18 +118,18 @@ typedef struct FileListInternEntry { /** Defined in BLI_fileops.h */ eFileAttributes attributes; BLI_stat_t st; -} FileListInternEntry; +}; -typedef struct FileListIntern { +struct FileListIntern { /** FileListInternEntry items. */ ListBase entries; FileListInternEntry **filtered; FileUID curr_uid; /* Used to generate UID during internal listing. */ -} FileListIntern; +}; #define FILELIST_ENTRYCACHESIZE_DEFAULT 1024 /* Keep it a power of two! */ -typedef struct FileListEntryCache { +struct FileListEntryCache { size_t size; /* The size of the cache... */ int flags; @@ -327,7 +158,7 @@ typedef struct FileListEntryCache { * previews either in `previews_pool` or `previews_done`. #filelist_cache_previews_update() makes * previews in `preview_done` ready for display, so the counter is decremented there. */ int previews_todo_count; -} FileListEntryCache; +}; /** #FileListCache.flags */ enum { @@ -335,21 +166,21 @@ enum { FLC_PREVIEWS_ACTIVE = 1 << 1, }; -typedef struct FileListEntryPreview { +struct FileListEntryPreview { char filepath[FILE_MAX]; uint flags; int index; int attributes; /* from FileDirEntry. */ int icon_id; -} FileListEntryPreview; +}; /* Dummy wrapper around FileListEntryPreview to ensure we do not access freed memory when freeing * tasks' data (see T74609). */ -typedef struct FileListEntryPreviewTaskData { +struct FileListEntryPreviewTaskData { FileListEntryPreview *preview; -} FileListEntryPreviewTaskData; +}; -typedef struct FileListFilter { +struct FileListFilter { uint64_t filter; uint64_t filter_id; char filter_glob[FILE_MAXFILE]; @@ -357,7 +188,7 @@ typedef struct FileListFilter { short flags; FileAssetCatalogFilterSettingsHandle *asset_catalog_filter; -} FileListFilter; +}; /** #FileListFilter.flags */ enum { @@ -369,13 +200,13 @@ enum { }; struct FileListReadJob; -typedef struct FileList { +struct FileList { FileDirEntryArr filelist; eFileSelectType type; /* The library this list was created for. Stored here so we know when to re-read. */ AssetLibraryReference *asset_library_ref; - struct AssetLibrary *asset_library; /* Non-owning pointer. */ + AssetLibrary *asset_library; /* Non-owning pointer. */ short flags; @@ -386,11 +217,11 @@ typedef struct FileList { /** * File indexer to use. Attribute is always set. */ - const struct FileIndexerType *indexer; + const FileIndexerType *indexer; - struct FileListIntern filelist_intern; + FileListIntern filelist_intern; - struct FileListEntryCache filelist_cache; + FileListEntryCache filelist_cache; /* We need to keep those info outside of actual filelist items, * because those are no more persistent @@ -403,7 +234,7 @@ typedef struct FileList { short max_recursion; short recursion_level; - struct BlendHandle *libfiledata; + BlendHandle *libfiledata; /* Set given path as root directory, * if last bool is true may change given string in place to a valid value. @@ -419,7 +250,7 @@ typedef struct FileList { void (*prepare_filter_fn)(const struct FileList *, FileListFilter *); short tags; /* FileListTags */ -} FileList; +}; /** #FileList.flags */ enum { @@ -459,23 +290,23 @@ enum { static ImBuf *gSpecialFileImages[SPECIAL_IMG_MAX]; -static void filelist_readjob_main(struct FileListReadJob *job_params, +static void filelist_readjob_main(FileListReadJob *job_params, short *stop, short *do_update, float *progress); -static void filelist_readjob_lib(struct FileListReadJob *job_params, +static void filelist_readjob_lib(FileListReadJob *job_params, short *stop, short *do_update, float *progress); -static void filelist_readjob_dir(struct FileListReadJob *job_params, +static void filelist_readjob_dir(FileListReadJob *job_params, short *stop, short *do_update, float *progress); -static void filelist_readjob_asset_library(struct FileListReadJob *job_params, +static void filelist_readjob_asset_library(FileListReadJob *job_params, short *stop, short *do_update, float *progress); -static void filelist_readjob_main_assets(struct FileListReadJob *job_params, +static void filelist_readjob_main_assets(FileListReadJob *job_params, short *stop, short *do_update, float *progress); @@ -493,7 +324,7 @@ struct FileSortData { bool inverted; }; -static int compare_apply_inverted(int val, const struct FileSortData *sort_data) +static int compare_apply_inverted(int val, const FileSortData *sort_data) { return sort_data->inverted ? -val : val; } @@ -602,9 +433,9 @@ static int compare_direntry_generic(const FileListInternEntry *entry1, static int compare_name(void *user_data, const void *a1, const void *a2) { - const FileListInternEntry *entry1 = a1; - const FileListInternEntry *entry2 = a2; - const struct FileSortData *sort_data = user_data; + const FileListInternEntry *entry1 = static_cast<const FileListInternEntry *>(a1); + const FileListInternEntry *entry2 = static_cast<const FileListInternEntry *>(a2); + const FileSortData *sort_data = static_cast<const FileSortData *>(user_data); int ret; if ((ret = compare_direntry_generic(entry1, entry2))) { @@ -616,9 +447,9 @@ static int compare_name(void *user_data, const void *a1, const void *a2) static int compare_date(void *user_data, const void *a1, const void *a2) { - const FileListInternEntry *entry1 = a1; - const FileListInternEntry *entry2 = a2; - const struct FileSortData *sort_data = user_data; + const FileListInternEntry *entry1 = static_cast<const FileListInternEntry *>(a1); + const FileListInternEntry *entry2 = static_cast<const FileListInternEntry *>(a2); + const FileSortData *sort_data = static_cast<const FileSortData *>(user_data); int64_t time1, time2; int ret; @@ -640,9 +471,9 @@ static int compare_date(void *user_data, const void *a1, const void *a2) static int compare_size(void *user_data, const void *a1, const void *a2) { - const FileListInternEntry *entry1 = a1; - const FileListInternEntry *entry2 = a2; - const struct FileSortData *sort_data = user_data; + const FileListInternEntry *entry1 = static_cast<const FileListInternEntry *>(a1); + const FileListInternEntry *entry2 = static_cast<const FileListInternEntry *>(a2); + const FileSortData *sort_data = static_cast<const FileSortData *>(user_data); uint64_t size1, size2; int ret; @@ -664,9 +495,9 @@ static int compare_size(void *user_data, const void *a1, const void *a2) static int compare_extension(void *user_data, const void *a1, const void *a2) { - const FileListInternEntry *entry1 = a1; - const FileListInternEntry *entry2 = a2; - const struct FileSortData *sort_data = user_data; + const FileListInternEntry *entry1 = static_cast<const FileListInternEntry *>(a1); + const FileListInternEntry *entry2 = static_cast<const FileListInternEntry *>(a2); + const FileSortData *sort_data = static_cast<const FileSortData *>(user_data); int ret; if ((ret = compare_direntry_generic(entry1, entry2))) { @@ -720,7 +551,7 @@ static int compare_extension(void *user_data, const void *a1, const void *a2) void filelist_sort(struct FileList *filelist) { if (filelist->flags & FL_NEED_SORTING) { - void *sort_cb = NULL; + int (*sort_cb)(void *, const void *, const void *) = nullptr; switch (filelist->sort) { case FILE_SORT_ALPHA: @@ -740,10 +571,10 @@ void filelist_sort(struct FileList *filelist) BLI_assert(0); break; } - BLI_listbase_sort_r( - &filelist->filelist_intern.entries, - sort_cb, - &(struct FileSortData){.inverted = (filelist->flags & FL_SORT_INVERT) != 0}); + + FileSortData sort_data{0}; + sort_data.inverted = (filelist->flags & FL_SORT_INVERT) != 0; + BLI_listbase_sort_r(&filelist->filelist_intern.entries, sort_cb, &sort_data); filelist_tag_needs_filtering(filelist); filelist->flags &= ~FL_NEED_SORTING; @@ -1062,7 +893,7 @@ void filelist_filter(FileList *filelist) { int num_filtered = 0; const int num_files = filelist->filelist.entries_num; - FileListInternEntry **filtered_tmp, *file; + FileListInternEntry **filtered_tmp; if (ELEM(filelist->filelist.entries_num, FILEDIR_NBR_ENTRIES_UNSET, 0)) { return; @@ -1087,10 +918,11 @@ void filelist_filter(FileList *filelist) filelist->prepare_filter_fn(filelist, &filelist->filter_data); } - filtered_tmp = MEM_mallocN(sizeof(*filtered_tmp) * (size_t)num_files, __func__); + filtered_tmp = static_cast<FileListInternEntry **>( + MEM_mallocN(sizeof(*filtered_tmp) * (size_t)num_files, __func__)); /* Filter remap & count how many files are left after filter in a single loop. */ - for (file = filelist->filelist_intern.entries.first; file; file = file->next) { + LISTBASE_FOREACH (FileListInternEntry *, file, &filelist->filelist_intern.entries) { if (filelist->filter_fn(file, filelist->filelist.root, &filelist->filter_data)) { filtered_tmp[num_filtered++] = file; } @@ -1099,8 +931,8 @@ void filelist_filter(FileList *filelist) if (filelist->filelist_intern.filtered) { MEM_freeN(filelist->filelist_intern.filtered); } - filelist->filelist_intern.filtered = MEM_mallocN( - sizeof(*filelist->filelist_intern.filtered) * (size_t)num_filtered, __func__); + filelist->filelist_intern.filtered = static_cast<FileListInternEntry **>( + MEM_mallocN(sizeof(*filelist->filelist_intern.filtered) * (size_t)num_filtered, __func__)); memcpy(filelist->filelist_intern.filtered, filtered_tmp, sizeof(*filelist->filelist_intern.filtered) * (size_t)num_filtered); @@ -1228,8 +1060,7 @@ void filelist_setlibrary(FileList *filelist, const AssetLibraryReference *asset_ } if (!filelist->asset_library_ref) { - filelist->asset_library_ref = MEM_mallocN(sizeof(*filelist->asset_library_ref), - "filelist asset library"); + filelist->asset_library_ref = MEM_new<AssetLibraryReference>("filelist asset library"); *filelist->asset_library_ref = *asset_library_ref; filelist->flags |= FL_FORCE_RESET; @@ -1335,7 +1166,7 @@ static int filelist_geticon_ex(const FileDirEntry *file, const bool is_main, const bool ignore_libdir) { - const eFileSel_File_Types typeflag = file->typeflag; + const eFileSel_File_Types typeflag = (eFileSel_File_Types)file->typeflag; if ((typeflag & FILE_TYPE_DIR) && !(ignore_libdir && (typeflag & (FILE_TYPE_BLENDERLIB | FILE_TYPE_BLENDER)))) { @@ -1581,10 +1412,7 @@ static void filelist_intern_entry_free(FileListInternEntry *entry) static void filelist_intern_free(FileListIntern *filelist_intern) { - FileListInternEntry *entry, *entry_next; - - for (entry = filelist_intern->entries.first; entry; entry = entry_next) { - entry_next = entry->next; + LISTBASE_FOREACH_MUTABLE (FileListInternEntry *, entry, &filelist_intern->entries) { filelist_intern_entry_free(entry); } BLI_listbase_clear(&filelist_intern->entries); @@ -1614,11 +1442,14 @@ static int filelist_intern_free_main_files(FileListIntern *filelist_intern) static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdata) { - FileListEntryCache *cache = BLI_task_pool_user_data(pool); - FileListEntryPreviewTaskData *preview_taskdata = taskdata; + FileListEntryCache *cache = static_cast<FileListEntryCache *>(BLI_task_pool_user_data(pool)); + FileListEntryPreviewTaskData *preview_taskdata = static_cast<FileListEntryPreviewTaskData *>( + taskdata); FileListEntryPreview *preview = preview_taskdata->preview; - ThumbSource source = 0; + /* XXX #THB_SOURCE_IMAGE for "historic" reasons. The case of an undefined source should be + * handled better. */ + ThumbSource source = THB_SOURCE_IMAGE; // printf("%s: Start (%d)...\n", __func__, threadid); @@ -1662,7 +1493,8 @@ static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdat static void filelist_cache_preview_freef(TaskPool *__restrict UNUSED(pool), void *taskdata) { - FileListEntryPreviewTaskData *preview_taskdata = taskdata; + FileListEntryPreviewTaskData *preview_taskdata = static_cast<FileListEntryPreviewTaskData *>( + taskdata); /* In case the preview wasn't moved to the "done" queue yet. */ if (preview_taskdata->preview) { @@ -1689,7 +1521,8 @@ static void filelist_cache_previews_clear(FileListEntryCache *cache) BLI_task_pool_cancel(cache->previews_pool); FileListEntryPreview *preview; - while ((preview = BLI_thread_queue_pop_timeout(cache->previews_done, 0))) { + while ((preview = static_cast<FileListEntryPreview *>( + BLI_thread_queue_pop_timeout(cache->previews_done, 0)))) { // printf("%s: DONE %d - %s - %p\n", __func__, preview->index, preview->path, // preview->img); if (preview->icon_id) { @@ -1749,7 +1582,7 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry filelist_cache_preview_ensure_running(cache); entry->flags |= FILE_ENTRY_PREVIEW_LOADING; - FileListEntryPreview *preview = MEM_mallocN(sizeof(*preview), __func__); + FileListEntryPreview *preview = MEM_new<FileListEntryPreview>(__func__); preview->index = index; preview->flags = entry->typeflag; preview->attributes = entry->attributes; @@ -1775,8 +1608,8 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry } // printf("%s: %d - %s\n", __func__, preview->index, preview->filepath); - FileListEntryPreviewTaskData *preview_taskdata = MEM_mallocN(sizeof(*preview_taskdata), - __func__); + FileListEntryPreviewTaskData *preview_taskdata = MEM_new<FileListEntryPreviewTaskData>( + __func__); preview_taskdata->preview = preview; BLI_task_pool_push(cache->previews_pool, filelist_cache_preview_runf, @@ -1793,11 +1626,12 @@ static void filelist_cache_init(FileListEntryCache *cache, size_t cache_size) cache->block_cursor = cache->block_start_index = cache->block_center_index = cache->block_end_index = 0; - cache->block_entries = MEM_mallocN(sizeof(*cache->block_entries) * cache_size, __func__); + cache->block_entries = static_cast<FileDirEntry **>( + MEM_mallocN(sizeof(*cache->block_entries) * cache_size, __func__)); cache->misc_entries = BLI_ghash_ptr_new_ex(__func__, cache_size); - cache->misc_entries_indices = MEM_mallocN(sizeof(*cache->misc_entries_indices) * cache_size, - __func__); + cache->misc_entries_indices = static_cast<int *>( + MEM_mallocN(sizeof(*cache->misc_entries_indices) * cache_size, __func__)); copy_vn_i(cache->misc_entries_indices, cache_size, -1); cache->misc_cursor = 0; @@ -1815,8 +1649,6 @@ static void filelist_cache_init(FileListEntryCache *cache, size_t cache_size) static void filelist_cache_free(FileListEntryCache *cache) { - FileDirEntry *entry, *entry_next; - if (!(cache->flags & FLC_IS_INIT)) { return; } @@ -1830,8 +1662,7 @@ static void filelist_cache_free(FileListEntryCache *cache) BLI_ghash_free(cache->uids, NULL, NULL); - for (entry = cache->cached_entries.first; entry; entry = entry_next) { - entry_next = entry->next; + LISTBASE_FOREACH_MUTABLE (FileDirEntry *, entry, &cache->cached_entries) { filelist_entry_free(entry); } BLI_listbase_clear(&cache->cached_entries); @@ -1839,8 +1670,6 @@ static void filelist_cache_free(FileListEntryCache *cache) static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size) { - FileDirEntry *entry, *entry_next; - if (!(cache->flags & FLC_IS_INIT)) { return; } @@ -1850,14 +1679,14 @@ static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size) cache->block_cursor = cache->block_start_index = cache->block_center_index = cache->block_end_index = 0; if (new_size != cache->size) { - cache->block_entries = MEM_reallocN(cache->block_entries, - sizeof(*cache->block_entries) * new_size); + cache->block_entries = static_cast<FileDirEntry **>( + MEM_reallocN(cache->block_entries, sizeof(*cache->block_entries) * new_size)); } BLI_ghash_clear_ex(cache->misc_entries, NULL, NULL, new_size); if (new_size != cache->size) { - cache->misc_entries_indices = MEM_reallocN(cache->misc_entries_indices, - sizeof(*cache->misc_entries_indices) * new_size); + cache->misc_entries_indices = static_cast<int *>(MEM_reallocN( + cache->misc_entries_indices, sizeof(*cache->misc_entries_indices) * new_size)); } copy_vn_i(cache->misc_entries_indices, new_size, -1); @@ -1865,8 +1694,7 @@ static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size) cache->size = new_size; - for (entry = cache->cached_entries.first; entry; entry = entry_next) { - entry_next = entry->next; + LISTBASE_FOREACH_MUTABLE (FileDirEntry *, entry, &cache->cached_entries) { filelist_entry_free(entry); } BLI_listbase_clear(&cache->cached_entries); @@ -1874,7 +1702,7 @@ static void filelist_cache_clear(FileListEntryCache *cache, size_t new_size) FileList *filelist_new(short type) { - FileList *p = MEM_callocN(sizeof(*p), __func__); + FileList *p = MEM_cnew<FileList>(__func__); filelist_cache_init(&p->filelist_cache, FILELIST_ENTRYCACHESIZE_DEFAULT); @@ -1891,7 +1719,7 @@ void filelist_settype(FileList *filelist, short type) return; } - filelist->type = type; + filelist->type = (eFileSelectType)type; filelist->tags = 0; filelist->indexer = &file_indexer_noop; switch (filelist->type) { @@ -2181,7 +2009,7 @@ static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int in FileListEntryCache *cache = &filelist->filelist_cache; FileDirEntry *ret; - ret = MEM_callocN(sizeof(*ret), __func__); + ret = MEM_cnew<FileDirEntry>(__func__); ret->size = (uint64_t)entry->st.st_size; ret->time = (int64_t)entry->st.st_mtime; @@ -2240,7 +2068,8 @@ FileDirEntry *filelist_file_ex(struct FileList *filelist, const int index, const return cache->block_entries[idx]; } - if ((ret = BLI_ghash_lookup(cache->misc_entries, POINTER_FROM_INT(index)))) { + if ((ret = static_cast<FileDirEntry *>( + BLI_ghash_lookup(cache->misc_entries, POINTER_FROM_INT(index))))) { return ret; } @@ -2253,7 +2082,8 @@ FileDirEntry *filelist_file_ex(struct FileList *filelist, const int index, const /* Else, we have to add new entry to 'misc' cache - and possibly make room for it first! */ ret = filelist_file_create_entry(filelist, index); old_index = cache->misc_entries_indices[cache->misc_cursor]; - if ((old = BLI_ghash_popkey(cache->misc_entries, POINTER_FROM_INT(old_index), NULL))) { + if ((old = static_cast<FileDirEntry *>( + BLI_ghash_popkey(cache->misc_entries, POINTER_FROM_INT(old_index), NULL)))) { BLI_ghash_remove(cache->uids, POINTER_FROM_UINT(old->uid), NULL, NULL); filelist_file_release_entry(filelist, old); } @@ -2371,7 +2201,8 @@ static bool filelist_file_cache_block_create(FileList *filelist, FileDirEntry *entry; /* That entry might have already been requested and stored in misc cache... */ - if ((entry = BLI_ghash_popkey(cache->misc_entries, POINTER_FROM_INT(idx), NULL)) == NULL) { + if ((entry = static_cast<FileDirEntry *>( + BLI_ghash_popkey(cache->misc_entries, POINTER_FROM_INT(idx), NULL))) == NULL) { entry = filelist_file_create_entry(filelist, idx); BLI_ghash_insert(cache->uids, POINTER_FROM_UINT(entry->uid), entry); } @@ -2660,7 +2491,8 @@ bool filelist_cache_previews_update(FileList *filelist) // printf("%s: Update Previews...\n", __func__); while (!BLI_thread_queue_is_empty(cache->previews_done)) { - FileListEntryPreview *preview = BLI_thread_queue_pop(cache->previews_done); + FileListEntryPreview *preview = static_cast<FileListEntryPreview *>( + BLI_thread_queue_pop(cache->previews_done)); FileDirEntry *entry; /* Paranoid (should never happen currently @@ -3050,8 +2882,8 @@ static int filelist_readjob_list_dir(const char *root, continue; } - entry = MEM_callocN(sizeof(*entry), __func__); - entry->relpath = MEM_dupallocN(files[i].relname); + entry = MEM_cnew<FileListInternEntry>(__func__); + entry->relpath = static_cast<char *>(MEM_dupallocN(files[i].relname)); entry->st = files[i].s; BLI_join_dirfile(full_path, FILE_MAX, root, entry->relpath); @@ -3069,14 +2901,14 @@ static int filelist_readjob_list_dir(const char *root, /* Is this a file that points to another file? */ if (entry->attributes & FILE_ATTR_ALIAS) { - entry->redirection_path = MEM_callocN(FILE_MAXDIR, __func__); + entry->redirection_path = MEM_cnew_array<char>(FILE_MAXDIR, __func__); if (BLI_file_alias_target(full_path, entry->redirection_path)) { if (BLI_is_dir(entry->redirection_path)) { entry->typeflag = FILE_TYPE_DIR; BLI_path_slash_ensure(entry->redirection_path); } else { - entry->typeflag = ED_path_extension_type(entry->redirection_path); + entry->typeflag = (eFileSel_File_Types)ED_path_extension_type(entry->redirection_path); } target = entry->redirection_path; #ifdef WIN32 @@ -3101,7 +2933,7 @@ static int filelist_readjob_list_dir(const char *root, } } else { - entry->typeflag = ED_path_extension_type(target); + entry->typeflag = (eFileSel_File_Types)ED_path_extension_type(target); if (filter_glob[0] && BLI_path_extension_check_glob(target, filter_glob)) { entry->typeflag |= FILE_TYPE_OPERATOR; } @@ -3124,6 +2956,8 @@ static int filelist_readjob_list_dir(const char *root, } typedef enum ListLibOptions { + LIST_LIB_OPTION_NONE = 0, + /* Will read both the groups + actual ids from the library. Reduces the amount of times that * a library needs to be opened. */ LIST_LIB_RECURSIVE = (1 << 0), @@ -3134,11 +2968,12 @@ typedef enum ListLibOptions { /* Add given root as result. */ LIST_LIB_ADD_PARENT = (1 << 2), } ListLibOptions; +ENUM_OPERATORS(ListLibOptions, LIST_LIB_ADD_PARENT); static FileListInternEntry *filelist_readjob_list_lib_group_create(const int idcode, const char *group_name) { - FileListInternEntry *entry = MEM_callocN(sizeof(*entry), __func__); + FileListInternEntry *entry = MEM_cnew<FileListInternEntry>(__func__); entry->relpath = BLI_strdup(group_name); entry->typeflag |= FILE_TYPE_BLENDERLIB | FILE_TYPE_DIR; entry->blentype = idcode; @@ -3151,7 +2986,7 @@ static void filelist_readjob_list_lib_add_datablock(ListBase *entries, const int idcode, const char *group_name) { - FileListInternEntry *entry = MEM_callocN(sizeof(*entry), __func__); + FileListInternEntry *entry = MEM_cnew<FileListInternEntry>(__func__); if (prefix_relpath_with_group_name) { entry->relpath = BLI_sprintfN("%s/%s", group_name, datablock_info->name); } @@ -3175,7 +3010,7 @@ static void filelist_readjob_list_lib_add_datablocks(ListBase *entries, const char *group_name) { for (LinkNode *ln = datablock_infos; ln; ln = ln->next) { - struct BLODataBlockInfo *datablock_info = ln->link; + struct BLODataBlockInfo *datablock_info = static_cast<BLODataBlockInfo *>(ln->link); filelist_readjob_list_lib_add_datablock( entries, datablock_info, prefix_relpath_with_group_name, idcode, group_name); } @@ -3199,7 +3034,7 @@ static void filelist_readjob_list_lib_add_from_indexer_entries( static FileListInternEntry *filelist_readjob_list_lib_navigate_to_parent_entry_create(void) { - FileListInternEntry *entry = MEM_callocN(sizeof(*entry), __func__); + FileListInternEntry *entry = MEM_cnew<FileListInternEntry>(__func__); entry->relpath = BLI_strdup(FILENAME_PARENT); entry->typeflag |= (FILE_TYPE_BLENDERLIB | FILE_TYPE_DIR); return entry; @@ -3279,7 +3114,7 @@ static int filelist_readjob_list_lib(const char *root, } /* Open the library file. */ - BlendFileReadReport bf_reports = {.reports = NULL}; + BlendFileReadReport bf_reports{}; libfiledata = BLO_blendhandle_from_file(dir, &bf_reports); if (libfiledata == NULL) { return 0; @@ -3310,7 +3145,7 @@ static int filelist_readjob_list_lib(const char *root, group_len = BLI_linklist_count(groups); for (LinkNode *ln = groups; ln; ln = ln->next) { - const char *group_name = ln->link; + const char *group_name = static_cast<char *>(ln->link); const int idcode = groupname_to_code(group_name); FileListInternEntry *group_entry = filelist_readjob_list_lib_group_create(idcode, group_name); @@ -3615,7 +3450,7 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib, int dirs_done_count = 0, dirs_todo_count = 1; todo_dirs = BLI_stack_new(sizeof(*td_dir), __func__); - td_dir = BLI_stack_push_r(todo_dirs); + td_dir = static_cast<TodoDir *>(BLI_stack_push_r(todo_dirs)); td_dir->level = 1; BLI_strncpy(dir, filelist->filelist.root, sizeof(dir)); @@ -3625,13 +3460,13 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib, td_dir->dir = BLI_strdup(dir); /* Init the file indexer. */ - FileIndexer indexer_runtime = {.callbacks = filelist->indexer}; + FileIndexer indexer_runtime{}; + indexer_runtime.callbacks = filelist->indexer; if (indexer_runtime.callbacks->init_user_data) { indexer_runtime.user_data = indexer_runtime.callbacks->init_user_data(dir, sizeof(dir)); } while (!BLI_stack_is_empty(todo_dirs) && !(*stop)) { - FileListInternEntry *entry; int entries_num = 0; char *subdir; @@ -3639,7 +3474,7 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib, int recursion_level; bool skip_currpar; - td_dir = BLI_stack_peek(todo_dirs); + td_dir = static_cast<TodoDir *>(BLI_stack_peek(todo_dirs)); subdir = td_dir->dir; recursion_level = td_dir->level; skip_currpar = (recursion_level > 1); @@ -3657,7 +3492,7 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib, bool is_lib = false; if (do_lib) { - ListLibOptions list_lib_options = 0; + ListLibOptions list_lib_options = LIST_LIB_OPTION_NONE; if (!skip_currpar) { list_lib_options |= LIST_LIB_ADD_PARENT; } @@ -3684,7 +3519,7 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib, subdir, &entries, filter_glob, do_lib, job_params->main_name, skip_currpar); } - for (entry = entries.first; entry; entry = entry->next) { + LISTBASE_FOREACH (FileListInternEntry *, entry, &entries) { entry->uid = filelist_uid_generate(filelist); /* When loading entries recursive, the rel_path should be relative from the root dir. @@ -3701,7 +3536,7 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib, /* We have a directory we want to list, add it to todo list! */ BLI_join_dirfile(dir, sizeof(dir), root, entry->relpath); BLI_path_normalize_dir(job_params->main_name, dir); - td_dir = BLI_stack_push_r(todo_dirs); + td_dir = static_cast<TodoDir *>(BLI_stack_push_r(todo_dirs)); td_dir->level = recursion_level + 1; td_dir->dir = BLI_strdup(dir); dirs_todo_count++; @@ -3727,7 +3562,7 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib, /* If we were interrupted by stop, stack may not be empty and we need to free * pending dir paths. */ while (!BLI_stack_is_empty(todo_dirs)) { - td_dir = BLI_stack_peek(todo_dirs); + td_dir = static_cast<TodoDir *>(BLI_stack_peek(todo_dirs)); MEM_freeN(td_dir->dir); BLI_stack_discard(todo_dirs); } @@ -3831,7 +3666,7 @@ static void filelist_readjob_main_assets_add_items(FileListReadJob *job_params, const char *id_code_name = BKE_idtype_idcode_to_name(GS(id_iter->name)); - entry = MEM_callocN(sizeof(*entry), __func__); + entry = MEM_cnew<FileListInternEntry>(__func__); entry->relpath = BLI_strdup(id_code_name); entry->name = id_iter->name + 2; entry->free_name = false; @@ -3935,7 +3770,7 @@ static bool filelist_readjob_is_partial_read(const FileListReadJob *read_job) */ static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update, float *progress) { - FileListReadJob *flrj = flrjv; + FileListReadJob *flrj = static_cast<FileListReadJob *>(flrjv); // printf("START filelist reading (%d files, main thread: %d)\n", // flrj->filelist->filelist.entries_num, BLI_thread_is_main()); @@ -3944,7 +3779,7 @@ static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update BLI_assert((flrj->tmp_filelist == NULL) && flrj->filelist); - flrj->tmp_filelist = MEM_dupallocN(flrj->filelist); + flrj->tmp_filelist = static_cast<FileList *>(MEM_dupallocN(flrj->filelist)); BLI_listbase_clear(&flrj->tmp_filelist->filelist.entries); flrj->tmp_filelist->filelist.entries_num = FILEDIR_NBR_ENTRIES_UNSET; @@ -3976,7 +3811,7 @@ static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update */ static void filelist_readjob_update(void *flrjv) { - FileListReadJob *flrj = flrjv; + FileListReadJob *flrj = static_cast<FileListReadJob *>(flrjv); FileListIntern *fl_intern = &flrj->filelist->filelist_intern; ListBase new_entries = {NULL}; int entries_num, new_entries_num = 0; @@ -4019,7 +3854,7 @@ static void filelist_readjob_update(void *flrjv) static void filelist_readjob_endjob(void *flrjv) { - FileListReadJob *flrj = flrjv; + FileListReadJob *flrj = static_cast<FileListReadJob *>(flrjv); /* In case there would be some dangling update... */ filelist_readjob_update(flrjv); @@ -4030,7 +3865,7 @@ static void filelist_readjob_endjob(void *flrjv) static void filelist_readjob_free(void *flrjv) { - FileListReadJob *flrj = flrjv; + FileListReadJob *flrj = static_cast<FileListReadJob *>(flrjv); // printf("END filelist reading (%d files)\n", flrj->filelist->filelist.entries_num); @@ -4060,7 +3895,7 @@ void filelist_readjob_start(FileList *filelist, const int space_notifier, const } /* prepare job data */ - flrj = MEM_callocN(sizeof(*flrj), __func__); + flrj = MEM_cnew<FileListReadJob>(__func__); flrj->filelist = filelist; flrj->current_main = bmain; BLI_strncpy(flrj->main_name, BKE_main_blendfile_path(bmain), sizeof(flrj->main_name)); diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h index 4c1ae79eb22..89831483fdf 100644 --- a/source/blender/editors/space_file/filelist.h +++ b/source/blender/editors/space_file/filelist.h @@ -35,17 +35,6 @@ typedef enum FileCheckType { CHECK_ALL = 3, } FileCheckType; -/* not listbase itself */ -void folderlist_free(struct ListBase *folderlist); -void folderlist_popdir(struct ListBase *folderlist, char *dir); -void folderlist_pushdir(struct ListBase *folderlist, const char *dir); -const char *folderlist_peeklastdir(struct ListBase *folderlist); -int folderlist_clear_next(struct SpaceFile *sfile); - -void folder_history_list_ensure_for_active_browse_mode(struct SpaceFile *sfile); -void folder_history_list_free(struct SpaceFile *sfile); -struct ListBase folder_history_list_duplicate(struct ListBase *listbase); - void filelist_setsorting(struct FileList *filelist, short sort, bool invert_sort); void filelist_sort(struct FileList *filelist); diff --git a/source/blender/editors/space_file/folder_history.cc b/source/blender/editors/space_file/folder_history.cc new file mode 100644 index 00000000000..9aa1d181584 --- /dev/null +++ b/source/blender/editors/space_file/folder_history.cc @@ -0,0 +1,191 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2007 Blender Foundation. All rights reserved. */ + +/** \file + * \ingroup spfile + * + * Storage for a list of folders for history backward and forward navigation. + */ + +#include <cstring> + +#include "BLI_listbase.h" +#include "BLI_path_util.h" +#include "BLI_string.h" + +#include "BKE_context.h" + +#include "DNA_space_types.h" + +#include "ED_fileselect.h" + +#include "MEM_guardedalloc.h" + +#include "file_intern.h" + +/* ----------------- FOLDERLIST (previous/next) -------------- */ + +typedef struct FolderList { + struct FolderList *next, *prev; + char *foldername; +} FolderList; + +void folderlist_popdir(struct ListBase *folderlist, char *dir) +{ + const char *prev_dir; + struct FolderList *folder; + folder = static_cast<FolderList *>(folderlist->last); + + if (folder) { + /* remove the current directory */ + MEM_freeN(folder->foldername); + BLI_freelinkN(folderlist, folder); + + folder = static_cast<FolderList *>(folderlist->last); + if (folder) { + prev_dir = folder->foldername; + BLI_strncpy(dir, prev_dir, FILE_MAXDIR); + } + } + /* delete the folder next or use setdir directly before PREVIOUS OP */ +} + +void folderlist_pushdir(ListBase *folderlist, const char *dir) +{ + if (!dir[0]) { + return; + } + + struct FolderList *folder, *previous_folder; + previous_folder = static_cast<FolderList *>(folderlist->last); + + /* check if already exists */ + if (previous_folder && previous_folder->foldername) { + if (BLI_path_cmp(previous_folder->foldername, dir) == 0) { + return; + } + } + + /* create next folder element */ + folder = MEM_new<FolderList>(__func__); + folder->foldername = BLI_strdup(dir); + + /* add it to the end of the list */ + BLI_addtail(folderlist, folder); +} + +const char *folderlist_peeklastdir(ListBase *folderlist) +{ + struct FolderList *folder; + + if (!folderlist->last) { + return NULL; + } + + folder = static_cast<FolderList *>(folderlist->last); + return folder->foldername; +} + +int folderlist_clear_next(struct SpaceFile *sfile) +{ + const FileSelectParams *params = ED_fileselect_get_active_params(sfile); + struct FolderList *folder; + + /* if there is no folder_next there is nothing we can clear */ + if (BLI_listbase_is_empty(sfile->folders_next)) { + return 0; + } + + /* if previous_folder, next_folder or refresh_folder operators are executed + * it doesn't clear folder_next */ + folder = static_cast<FolderList *>(sfile->folders_prev->last); + if ((!folder) || (BLI_path_cmp(folder->foldername, params->dir) == 0)) { + return 0; + } + + /* eventually clear flist->folders_next */ + return 1; +} + +void folderlist_free(ListBase *folderlist) +{ + if (folderlist) { + LISTBASE_FOREACH (FolderList *, folder, folderlist) { + MEM_freeN(folder->foldername); + } + BLI_freelistN(folderlist); + } +} + +static ListBase folderlist_duplicate(ListBase *folderlist) +{ + ListBase folderlistn = {NULL}; + + BLI_duplicatelist(&folderlistn, folderlist); + + LISTBASE_FOREACH (FolderList *, folder, &folderlistn) { + folder->foldername = (char *)MEM_dupallocN(folder->foldername); + } + return folderlistn; +} + +/* ----------------- Folder-History (wraps/owns file list above) -------------- */ + +static FileFolderHistory *folder_history_find(const SpaceFile *sfile, eFileBrowse_Mode browse_mode) +{ + LISTBASE_FOREACH (FileFolderHistory *, history, &sfile->folder_histories) { + if (history->browse_mode == browse_mode) { + return history; + } + } + + return NULL; +} + +void folder_history_list_ensure_for_active_browse_mode(SpaceFile *sfile) +{ + FileFolderHistory *history = folder_history_find(sfile, (eFileBrowse_Mode)sfile->browse_mode); + + if (!history) { + history = MEM_cnew<FileFolderHistory>(__func__); + history->browse_mode = sfile->browse_mode; + BLI_addtail(&sfile->folder_histories, history); + } + + sfile->folders_next = &history->folders_next; + sfile->folders_prev = &history->folders_prev; +} + +static void folder_history_entry_free(SpaceFile *sfile, FileFolderHistory *history) +{ + if (sfile->folders_prev == &history->folders_prev) { + sfile->folders_prev = NULL; + } + if (sfile->folders_next == &history->folders_next) { + sfile->folders_next = NULL; + } + folderlist_free(&history->folders_prev); + folderlist_free(&history->folders_next); + BLI_freelinkN(&sfile->folder_histories, history); +} + +void folder_history_list_free(SpaceFile *sfile) +{ + LISTBASE_FOREACH_MUTABLE (FileFolderHistory *, history, &sfile->folder_histories) { + folder_history_entry_free(sfile, history); + } +} + +ListBase folder_history_list_duplicate(ListBase *listbase) +{ + ListBase histories = {NULL}; + + LISTBASE_FOREACH (FileFolderHistory *, history, listbase) { + FileFolderHistory *history_new = static_cast<FileFolderHistory *>(MEM_dupallocN(history)); + history_new->folders_prev = folderlist_duplicate(&history->folders_prev); + history_new->folders_next = folderlist_duplicate(&history->folders_next); + BLI_addtail(&histories, history_new); + } + + return histories; +} diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 44d4cef53a6..6bb8dc6aa18 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -1086,6 +1086,7 @@ typedef enum eFileSel_File_Types { FILE_TYPE_DIR = (1 << 30), FILE_TYPE_BLENDERLIB = (1u << 31), } eFileSel_File_Types; +ENUM_OPERATORS(eFileSel_File_Types, FILE_TYPE_BLENDERLIB); /** Selection Flags in filesel: struct direntry, unsigned char selflag. */ typedef enum eDirEntry_SelectFlag { diff --git a/source/blender/makesdna/DNA_windowmanager_types.h b/source/blender/makesdna/DNA_windowmanager_types.h index 1c71129a3c7..d57cca0b055 100644 --- a/source/blender/makesdna/DNA_windowmanager_types.h +++ b/source/blender/makesdna/DNA_windowmanager_types.h @@ -307,7 +307,22 @@ typedef struct wmWindow { */ short pie_event_type_last; - /** Storage for event system. */ + /** + * Storage for event system. + * + * For the most part this is storage for `wmEvent.xy` & `wmEvent.modifiers`. + * newly added key/button events copy the cursor location and modifier state stored here. + * + * It's also convenient at times to be able to pass this as if it's a regular event. + * + * - This is not simply the current event being handled. + * The type and value is always set to the last press/release events + * otherwise cursor motion would always clear these values. + * + * - The value of `eventstate->modifiers` is set from the last pressed/released modifier key. + * This has the down side that the modifier value will be incorrect if users hold both + * left/right modifiers then release one. See note in #wm_event_add_ghostevent for details. + */ struct wmEvent *eventstate; /** Keep the last handled event in `event_queue` here (owned and must be freed). */ struct wmEvent *event_last_handled; diff --git a/source/blender/makesrna/RNA_types.h b/source/blender/makesrna/RNA_types.h index 353b2903fb1..b9556a411cf 100644 --- a/source/blender/makesrna/RNA_types.h +++ b/source/blender/makesrna/RNA_types.h @@ -179,7 +179,7 @@ typedef enum PropertySubType { /* Make sure enums are updated with these */ /* HIGHEST FLAG IN USE: 1 << 31 - * FREE FLAGS: 2, 9, 11, 13, 14, 15. */ + * FREE FLAGS: 9, 11, 13, 14, 15. */ typedef enum PropertyFlag { /** * Editable means the property is editable in the user @@ -299,6 +299,12 @@ typedef enum PropertyFlag { * properties which denotes whether modifier panel is collapsed or not. */ PROP_NO_DEG_UPDATE = (1 << 30), + + /** + * Filepaths that refer to output get a special treatment such + * as having the +/- operators available in the file browser. + **/ + PROP_PATH_OUTPUT = (1 << 2), } PropertyFlag; /** diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 971043158e1..892d523bdcf 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -7060,6 +7060,7 @@ static void def_cmp_output_file(BlenderRNA *brna, StructRNA *srna) prop = RNA_def_property(srna, "base_path", PROP_STRING, PROP_FILEPATH); RNA_def_property_string_sdna(prop, NULL, "base_path"); RNA_def_property_ui_text(prop, "Base Path", "Base output path for the image"); + RNA_def_property_flag(prop, PROP_PATH_OUTPUT); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); prop = RNA_def_property(srna, "active_input_index", PROP_INT, PROP_NONE); diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index 57f75fe892c..8d5e82cbfa8 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -160,6 +160,7 @@ const EnumPropertyItem rna_enum_property_flag_items[] = { 0, "Update on every keystroke in textedit 'mode'", ""}, + {PROP_PATH_OUTPUT, "OUTPUT_PATH", 0, "Output Path", ""}, {0, NULL, 0, NULL, NULL}, }; @@ -729,6 +730,12 @@ static bool rna_Property_is_library_editable_flag_get(PointerRNA *ptr) return (prop->flag & PROP_LIB_EXCEPTION) != 0; } +static bool rna_Property_is_path_output_flag_get(PointerRNA *ptr) +{ + PropertyRNA *prop = (PropertyRNA *)ptr->data; + return (prop->flag & PROP_PATH_OUTPUT) != 0; +} + static int rna_Property_tags_get(PointerRNA *ptr) { return RNA_property_tags(ptr->data); @@ -3023,6 +3030,12 @@ static void rna_def_property(BlenderRNA *brna) RNA_def_property_ui_text( prop, "Library Editable", "Property is editable from linked instances (changes not saved)"); + prop = RNA_def_property(srna, "is_path_output", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + RNA_def_property_boolean_funcs(prop, "rna_Property_is_path_output_flag_get", NULL); + RNA_def_property_ui_text( + prop, "Path Output", "Property is a filename, filepath or directory output"); + prop = RNA_def_property(srna, "tags", PROP_ENUM, PROP_NONE); RNA_def_property_clear_flag(prop, PROP_EDITABLE); RNA_def_property_enum_items(prop, dummy_prop_tags); diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 27cfe766eef..a1612159806 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -6553,6 +6553,7 @@ static void rna_def_scene_render_data(BlenderRNA *brna) "Output Path", "Directory/name to save animations, # characters defines the position " "and length of frame numbers"); + RNA_def_property_flag(prop, PROP_PATH_OUTPUT); RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); /* Render result EXR cache. */ diff --git a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc index b3fc24ded68..a0bd28218cc 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_distribute_points_in_volume.cc @@ -181,9 +181,9 @@ static void point_scatter_density_grid(const openvdb::FloatGrid &grid, static void geo_node_distribute_points_in_volume_exec(GeoNodeExecParams params) { - GeometrySet geometry_set_in = params.extract_input<GeometrySet>("Volume"); - #ifdef WITH_OPENVDB + GeometrySet geometry_set = params.extract_input<GeometrySet>("Volume"); + const NodeGeometryDistributePointsInVolume &storage = node_storage(params.node()); const GeometryNodeDistributePointsInVolumeMode mode = static_cast<GeometryNodeDistributePointsInVolumeMode>(storage.mode); @@ -192,7 +192,6 @@ static void geo_node_distribute_points_in_volume_exec(GeoNodeExecParams params) int seed; float3 spacing{0, 0, 0}; float threshold; - if (mode == GEO_NODE_DISTRIBUTE_POINTS_IN_VOLUME_DENSITY_RANDOM) { density = params.extract_input<float>("Density"); seed = params.extract_input<int>("Seed"); @@ -202,7 +201,7 @@ static void geo_node_distribute_points_in_volume_exec(GeoNodeExecParams params) threshold = params.extract_input<float>("Threshold"); } - geometry_set_in.modify_geometry_sets([&](GeometrySet &geometry_set) { + geometry_set.modify_geometry_sets([&](GeometrySet &geometry_set) { if (!geometry_set.has_volume()) { geometry_set.keep_only({GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_INSTANCES}); return; @@ -252,10 +251,10 @@ static void geo_node_distribute_points_in_volume_exec(GeoNodeExecParams params) point_radii.finish(); geometry_set.replace_pointcloud(pointcloud); - geometry_set.keep_only({GEO_COMPONENT_TYPE_POINT_CLOUD, GEO_COMPONENT_TYPE_INSTANCES}); + geometry_set.keep_only_during_modify({GEO_COMPONENT_TYPE_POINT_CLOUD}); }); - params.set_output("Points", std::move(geometry_set_in)); + params.set_output("Points", std::move(geometry_set)); #else params.set_default_remaining_outputs(); diff --git a/source/blender/python/mathutils/mathutils_Color.c b/source/blender/python/mathutils/mathutils_Color.c index 955fa4b6f92..a66178baefc 100644 --- a/source/blender/python/mathutils/mathutils_Color.c +++ b/source/blender/python/mathutils/mathutils_Color.c @@ -14,7 +14,9 @@ #include "../generic/py_capi_utils.h" #include "../generic/python_utildefines.h" -#include "IMB_colormanagement.h" +#ifndef MATH_STANDALONE +# include "IMB_colormanagement.h" +#endif #ifndef MATH_STANDALONE # include "BLI_dynstr.h" @@ -92,6 +94,8 @@ static PyObject *Color_new(PyTypeObject *type, PyObject *args, PyObject *kwds) /** \name Color Methods: Color Space Conversion * \{ */ +#ifndef MATH_STANDALONE + PyDoc_STRVAR(Color_from_scene_linear_to_srgb_doc, ".. function:: from_scene_linear_to_srgb()\n" "\n" @@ -204,6 +208,8 @@ static PyObject *Color_from_rec709_linear_to_scene_linear(ColorObject *self) return Color_CreatePyObject(col, Py_TYPE(self)); } +#endif /* MATH_STANDALONE */ + /** \} */ /* -------------------------------------------------------------------- */ @@ -1050,7 +1056,8 @@ static struct PyMethodDef Color_methods[] = { /* base-math methods */ {"freeze", (PyCFunction)BaseMathObject_freeze, METH_NOARGS, BaseMathObject_freeze_doc}, - /* Color-space methods. */ +/* Color-space methods. */ +#ifndef MATH_STANDALONE {"from_scene_linear_to_srgb", (PyCFunction)Color_from_scene_linear_to_srgb, METH_NOARGS, @@ -1083,6 +1090,8 @@ static struct PyMethodDef Color_methods[] = { (PyCFunction)Color_from_rec709_linear_to_scene_linear, METH_NOARGS, Color_from_rec709_linear_to_scene_linear_doc}, +#endif /* MATH_STANDALONE */ + {NULL, NULL, 0, NULL}, }; diff --git a/source/blender/windowmanager/intern/wm_event_system.cc b/source/blender/windowmanager/intern/wm_event_system.cc index 841df253dab..c26696704dd 100644 --- a/source/blender/windowmanager/intern/wm_event_system.cc +++ b/source/blender/windowmanager/intern/wm_event_system.cc @@ -5481,6 +5481,25 @@ void wm_event_add_ghostevent(wmWindowManager *wm, wmWindow *win, int type, void } } + /* NOTE(@campbellbarton): Setting the modifier state based on press/release + * is technically incorrect. + * + * - The user might hold both left/right modifier keys, then only release one. + * + * This could be solved by storing a separate flag for the left/right modifiers, + * and combine them into `event.modifiers`. + * + * - The user might have multiple keyboards (or keyboard + NDOF device) + * where it's possible to press the same modifier key multiple times. + * + * This could be solved by tracking the number of held modifier keys, + * (this is in fact what LIBXKB does), however doing this relies on all GHOST + * back-ends properly reporting every press/release as any mismatch could result + * in modifier keys being stuck (which is very bad!). + * + * To my knowledge users never reported a bug relating to these limitations so + * it seems reasonable to keep the current logic. */ + switch (event.type) { case EVT_LEFTSHIFTKEY: case EVT_RIGHTSHIFTKEY: { diff --git a/source/blender/windowmanager/intern/wm_operator_props.c b/source/blender/windowmanager/intern/wm_operator_props.c index 71c948dfbb9..bd3322a8023 100644 --- a/source/blender/windowmanager/intern/wm_operator_props.c +++ b/source/blender/windowmanager/intern/wm_operator_props.c @@ -120,16 +120,14 @@ void WM_operator_properties_filesel(wmOperatorType *ot, RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); } - if (action == FILE_SAVE) { - /* NOTE: this is only used to check if we should highlight the filename area red when the - * filepath is an existing file. */ - prop = RNA_def_boolean(ot->srna, - "check_existing", - true, - "Check Existing", - "Check and warn on overwriting existing files"); - RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); - } + /* NOTE: this is only used to check if we should highlight the filename area red when the + * filepath is an existing file. */ + prop = RNA_def_boolean(ot->srna, + "check_existing", + action == FILE_SAVE, + "Check Existing", + "Check and warn on overwriting existing files"); + RNA_def_property_flag(prop, PROP_HIDDEN | PROP_SKIP_SAVE); prop = RNA_def_boolean( ot->srna, "filter_blender", (filter & FILE_TYPE_BLENDER) != 0, "Filter .blend files", ""); |