diff options
Diffstat (limited to 'source/blender')
485 files changed, 8459 insertions, 6434 deletions
diff --git a/source/blender/blenkernel/BKE_armature.h b/source/blender/blenkernel/BKE_armature.h index db44a771095..f5face2120e 100644 --- a/source/blender/blenkernel/BKE_armature.h +++ b/source/blender/blenkernel/BKE_armature.h @@ -27,6 +27,8 @@ extern "C" { #endif +struct AnimationEvalContext; +struct bAction; struct BMEditMesh; struct Bone; struct Depsgraph; @@ -193,6 +195,12 @@ void BKE_pose_where_is_bone(struct Depsgraph *depsgraph, bool do_extra); void BKE_pose_where_is_bone_tail(struct bPoseChannel *pchan); +/* Evaluate the action and apply it to the pose. If any pose bones are selected, only FCurves that + * relate to those bones are evaluated. */ +void BKE_pose_apply_action(struct Object *ob, + struct bAction *action, + struct AnimationEvalContext *anim_eval_context); + /* get_objectspace_bone_matrix has to be removed still */ void get_objectspace_bone_matrix(struct Bone *bone, float M_accumulatedMatrix[4][4], diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 66bfe620df7..133f1c5100a 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -39,7 +39,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 10 +#define BLENDER_FILE_SUBVERSION 11 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and show a warning if the file diff --git a/source/blender/blenkernel/BKE_context.h b/source/blender/blenkernel/BKE_context.h index 94392dd78da..3d30188e517 100644 --- a/source/blender/blenkernel/BKE_context.h +++ b/source/blender/blenkernel/BKE_context.h @@ -197,6 +197,7 @@ struct SpaceInfo *CTX_wm_space_info(const bContext *C); struct SpaceUserPref *CTX_wm_space_userpref(const bContext *C); struct SpaceClip *CTX_wm_space_clip(const bContext *C); struct SpaceTopBar *CTX_wm_space_topbar(const bContext *C); +struct SpaceSpreadsheet *CTX_wm_space_spreadsheet(const bContext *C); void CTX_wm_manager_set(bContext *C, struct wmWindowManager *wm); void CTX_wm_window_set(bContext *C, struct wmWindow *win); diff --git a/source/blender/blenkernel/BKE_cryptomatte.hh b/source/blender/blenkernel/BKE_cryptomatte.hh index f10b4c1f7c4..98fdfc965bc 100644 --- a/source/blender/blenkernel/BKE_cryptomatte.hh +++ b/source/blender/blenkernel/BKE_cryptomatte.hh @@ -29,6 +29,8 @@ #include "BLI_map.hh" #include "BLI_string_ref.hh" +#include "BKE_cryptomatte.h" + struct ID; namespace blender::bke::cryptomatte { @@ -103,4 +105,13 @@ struct CryptomatteStampDataCallbackData { static void extract_layer_manifest(void *_data, const char *propname, char *propvalue, int len); }; +struct CryptomatteSessionDeleter { + void operator()(CryptomatteSession *session) + { + BKE_cryptomatte_free(session); + } +}; + +using CryptomatteSessionPtr = std::unique_ptr<CryptomatteSession, CryptomatteSessionDeleter>; + } // namespace blender::bke::cryptomatte diff --git a/source/blender/blenkernel/BKE_mesh_boolean_convert.h b/source/blender/blenkernel/BKE_mesh_boolean_convert.h index be5cbb305fa..a87f2609e46 100644 --- a/source/blender/blenkernel/BKE_mesh_boolean_convert.h +++ b/source/blender/blenkernel/BKE_mesh_boolean_convert.h @@ -31,6 +31,7 @@ Mesh *BKE_mesh_boolean(const Mesh **meshes, const float (*obmats[])[4][4], const int meshes_len, const bool use_self, + const bool hole_tolerant, const int boolean_mode); #ifdef __cplusplus diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index d675df6d868..f5f65e71f7f 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -301,11 +301,11 @@ typedef struct bNodeType { void (*free_self)(struct bNodeType *ntype); /* **** execution callbacks **** */ - NodeInitExecFunction initexecfunc; - NodeFreeExecFunction freeexecfunc; - NodeExecFunction execfunc; + NodeInitExecFunction init_exec_fn; + NodeFreeExecFunction free_exec_fn; + NodeExecFunction exec_fn; /* gpu */ - NodeGPUExecFunction gpufunc; + NodeGPUExecFunction gpu_fn; /* Expands the bNode into nodes in a multi-function network, which will be evaluated later on. */ NodeExpandInMFNetworkFunction expand_in_mf_network; @@ -829,10 +829,10 @@ void node_type_group_update(struct bNodeType *ntype, struct bNode *node)); void node_type_exec(struct bNodeType *ntype, - NodeInitExecFunction initexecfunc, - NodeFreeExecFunction freeexecfunc, - NodeExecFunction execfunc); -void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpufunc); + NodeInitExecFunction init_exec_fn, + NodeFreeExecFunction free_exec_fn, + NodeExecFunction exec_fn); +void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpu_fn); void node_type_internal_links(struct bNodeType *ntype, void (*update_internal_links)(struct bNodeTree *, struct bNode *)); @@ -1348,7 +1348,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree, #define GEO_NODE_BOOLEAN 1003 #define GEO_NODE_POINT_DISTRIBUTE 1004 #define GEO_NODE_POINT_INSTANCE 1005 -#define GEO_NODE_SUBDIVISION_SURFACE 1006 +#define GEO_NODE_SUBDIVIDE_SMOOTH 1006 #define GEO_NODE_OBJECT_INFO 1007 #define GEO_NODE_ATTRIBUTE_RANDOMIZE 1008 #define GEO_NODE_ATTRIBUTE_MATH 1009 @@ -1371,7 +1371,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree, #define GEO_NODE_VOLUME_TO_MESH 1026 #define GEO_NODE_ATTRIBUTE_COMBINE_XYZ 1027 #define GEO_NODE_ATTRIBUTE_SEPARATE_XYZ 1028 -#define GEO_NODE_SUBDIVISION_SURFACE_SIMPLE 1029 +#define GEO_NODE_SUBDIVIDE 1029 /** \} */ diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 4f0218e2f8f..2aca43c6df7 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -77,6 +77,7 @@ set(SRC intern/appdir.c intern/armature.c intern/armature_deform.c + intern/armature_pose.cc intern/armature_update.c intern/asset.cc intern/attribute.c @@ -130,6 +131,10 @@ set(SRC intern/fmodifier.c intern/font.c intern/freestyle.c + intern/geometry_component_instances.cc + intern/geometry_component_mesh.cc + intern/geometry_component_pointcloud.cc + intern/geometry_component_volume.cc intern/geometry_set.cc intern/geometry_set_instances.cc intern/gpencil.c @@ -429,6 +434,7 @@ set(SRC nla_private.h particle_private.h tracking_private.h + intern/attribute_access_intern.hh intern/CCGSubSurf.h intern/CCGSubSurf_inline.h intern/CCGSubSurf_intern.h diff --git a/source/blender/blenkernel/intern/armature_pose.cc b/source/blender/blenkernel/intern/armature_pose.cc new file mode 100644 index 00000000000..bb371b16c42 --- /dev/null +++ b/source/blender/blenkernel/intern/armature_pose.cc @@ -0,0 +1,133 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2015 Blender Foundation. + * All rights reserved. + * + * Defines and code for core node types + */ + +/** \file + * \ingroup bke + */ + +#include "BKE_animsys.h" +#include "BKE_armature.h" + +#include "BLI_set.hh" + +#include "DNA_action_types.h" +#include "DNA_anim_types.h" +#include "DNA_armature_types.h" +#include "DNA_object_types.h" + +#include "RNA_access.h" + +namespace { +using BoneNameSet = blender::Set<std::string>; + +// Forward declarations. +BoneNameSet pose_apply_find_selected_bones(const bPose *pose); +void pose_apply_disable_fcurves_for_unselected_bones(bAction *action, + const BoneNameSet &selected_bone_names); +void pose_apply_restore_fcurves(bAction *action); +} // namespace + +void BKE_pose_apply_action(struct Object *ob, + struct bAction *action, + struct AnimationEvalContext *anim_eval_context) +{ + bPose *pose = ob->pose; + if (pose == nullptr) { + return; + } + + const BoneNameSet selected_bone_names = pose_apply_find_selected_bones(pose); + const bool limit_to_selected_bones = !selected_bone_names.is_empty(); + + if (limit_to_selected_bones) { + /* Mute all FCurves that are not associated with selected bones. This separates the concept of + * bone selection from the FCurve evaluation code. */ + pose_apply_disable_fcurves_for_unselected_bones(action, selected_bone_names); + } + + /* Apply the Action. */ + PointerRNA pose_owner_ptr; + RNA_id_pointer_create(&ob->id, &pose_owner_ptr); + animsys_evaluate_action(&pose_owner_ptr, action, anim_eval_context, false); + + if (limit_to_selected_bones) { + pose_apply_restore_fcurves(action); + } +} + +namespace { +BoneNameSet pose_apply_find_selected_bones(const bPose *pose) +{ + BoneNameSet selected_bone_names; + bool all_bones_selected = true; + bool no_bones_selected = true; + + LISTBASE_FOREACH (bPoseChannel *, pchan, &pose->chanbase) { + const bool is_selected = (pchan->bone->flag & BONE_SELECTED) != 0 && + (pchan->bone->flag & BONE_HIDDEN_P) == 0; + all_bones_selected &= is_selected; + no_bones_selected &= !is_selected; + + if (is_selected) { + /* Bone names are unique, so no need to check for duplicates. */ + selected_bone_names.add_new(pchan->name); + } + } + + /* If no bones are selected, act as if all are. */ + if (all_bones_selected || no_bones_selected) { + return BoneNameSet(); /* An empty set means "ignore bone selection". */ + } + return selected_bone_names; +} + +void pose_apply_restore_fcurves(bAction *action) +{ + /* TODO(Sybren): Restore the FCurve flags, instead of just erasing the 'disabled' flag. */ + LISTBASE_FOREACH (FCurve *, fcu, &action->curves) { + fcu->flag &= ~FCURVE_DISABLED; + } +} + +void pose_apply_disable_fcurves_for_unselected_bones(bAction *action, + const BoneNameSet &selected_bone_names) +{ + LISTBASE_FOREACH (FCurve *, fcu, &action->curves) { + if (!fcu->rna_path || !strstr(fcu->rna_path, "pose.bones[")) { + continue; + } + + /* Get bone name, and check if this bone is selected. */ + char *bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["); + if (!bone_name) { + continue; + } + const bool is_selected = selected_bone_names.contains(bone_name); + MEM_freeN(bone_name); + if (is_selected) { + continue; + } + + fcu->flag |= FCURVE_DISABLED; + } +} + +} // namespace diff --git a/source/blender/blenkernel/intern/attribute_access.cc b/source/blender/blenkernel/intern/attribute_access.cc index aeb7fba47e8..01a1333c3ce 100644 --- a/source/blender/blenkernel/intern/attribute_access.cc +++ b/source/blender/blenkernel/intern/attribute_access.cc @@ -31,11 +31,14 @@ #include "BLI_color.hh" #include "BLI_float2.hh" #include "BLI_span.hh" +#include "BLI_threads.h" #include "CLG_log.h" #include "NOD_node_tree_multi_function.hh" +#include "attribute_access_intern.hh" + static CLG_LogRef LOG = {"bke.attribute_access"}; using blender::float3; @@ -46,9 +49,6 @@ using blender::bke::ReadAttributePtr; using blender::bke::WriteAttributePtr; using blender::fn::GMutableSpan; -/* Can't include BKE_object_deform.h right now, due to an enum forward declaration. */ -extern "C" MDeformVert *BKE_object_defgroup_data_create(ID *id); - namespace blender::bke { /* -------------------------------------------------------------------- */ @@ -158,101 +158,6 @@ void WriteAttribute::apply_span_if_necessary() } } -class VertexWeightWriteAttribute final : public WriteAttribute { - private: - MDeformVert *dverts_; - const int dvert_index_; - - public: - VertexWeightWriteAttribute(MDeformVert *dverts, const int totvert, const int dvert_index) - : WriteAttribute(ATTR_DOMAIN_POINT, CPPType::get<float>(), totvert), - dverts_(dverts), - dvert_index_(dvert_index) - { - } - - void get_internal(const int64_t index, void *r_value) const override - { - get_internal(dverts_, dvert_index_, index, r_value); - } - - void set_internal(const int64_t index, const void *value) override - { - MDeformWeight *weight = BKE_defvert_ensure_index(&dverts_[index], dvert_index_); - weight->weight = *reinterpret_cast<const float *>(value); - } - - static void get_internal(const MDeformVert *dverts, - const int dvert_index, - const int64_t index, - void *r_value) - { - if (dverts == nullptr) { - *(float *)r_value = 0.0f; - return; - } - const MDeformVert &dvert = dverts[index]; - for (const MDeformWeight &weight : Span(dvert.dw, dvert.totweight)) { - if (weight.def_nr == dvert_index) { - *(float *)r_value = weight.weight; - return; - } - } - *(float *)r_value = 0.0f; - } -}; - -class VertexWeightReadAttribute final : public ReadAttribute { - private: - const MDeformVert *dverts_; - const int dvert_index_; - - public: - VertexWeightReadAttribute(const MDeformVert *dverts, const int totvert, const int dvert_index) - : ReadAttribute(ATTR_DOMAIN_POINT, CPPType::get<float>(), totvert), - dverts_(dverts), - dvert_index_(dvert_index) - { - } - - void get_internal(const int64_t index, void *r_value) const override - { - VertexWeightWriteAttribute::get_internal(dverts_, dvert_index_, index, r_value); - } -}; - -template<typename T> class ArrayWriteAttribute final : public WriteAttribute { - private: - MutableSpan<T> data_; - - public: - ArrayWriteAttribute(AttributeDomain domain, MutableSpan<T> data) - : WriteAttribute(domain, CPPType::get<T>(), data.size()), data_(data) - { - } - - void get_internal(const int64_t index, void *r_value) const override - { - new (r_value) T(data_[index]); - } - - void set_internal(const int64_t index, const void *value) override - { - data_[index] = *reinterpret_cast<const T *>(value); - } - - void initialize_span(const bool UNUSED(write_only)) override - { - array_buffer_ = data_.data(); - array_is_temporary_ = false; - } - - void apply_span_if_necessary() override - { - /* Do nothing, because the span contains the attribute itself already. */ - } -}; - /* This is used by the #OutputAttributePtr class. */ class TemporaryWriteAttribute final : public WriteAttribute { public: @@ -301,135 +206,6 @@ class TemporaryWriteAttribute final : public WriteAttribute { } }; -template<typename T> class ArrayReadAttribute final : public ReadAttribute { - private: - Span<T> data_; - - public: - ArrayReadAttribute(AttributeDomain domain, Span<T> data) - : ReadAttribute(domain, CPPType::get<T>(), data.size()), data_(data) - { - } - - void get_internal(const int64_t index, void *r_value) const override - { - new (r_value) T(data_[index]); - } - - void initialize_span() const override - { - /* The data will not be modified, so this const_cast is fine. */ - array_buffer_ = const_cast<T *>(data_.data()); - array_is_temporary_ = false; - } -}; - -template<typename T> class OwnedArrayReadAttribute final : public ReadAttribute { - private: - Array<T> data_; - - public: - OwnedArrayReadAttribute(AttributeDomain domain, Array<T> data) - : ReadAttribute(domain, CPPType::get<T>(), data.size()), data_(std::move(data)) - { - } - - void get_internal(const int64_t index, void *r_value) const override - { - new (r_value) T(data_[index]); - } - - void initialize_span() const override - { - /* The data will not be modified, so this const_cast is fine. */ - array_buffer_ = const_cast<T *>(data_.data()); - array_is_temporary_ = false; - } -}; - -template<typename StructT, - typename ElemT, - ElemT (*GetFunc)(const StructT &), - void (*SetFunc)(StructT &, const ElemT &)> -class DerivedArrayWriteAttribute final : public WriteAttribute { - private: - MutableSpan<StructT> data_; - - public: - DerivedArrayWriteAttribute(AttributeDomain domain, MutableSpan<StructT> data) - : WriteAttribute(domain, CPPType::get<ElemT>(), data.size()), data_(data) - { - } - - void get_internal(const int64_t index, void *r_value) const override - { - const StructT &struct_value = data_[index]; - const ElemT value = GetFunc(struct_value); - new (r_value) ElemT(value); - } - - void set_internal(const int64_t index, const void *value) override - { - StructT &struct_value = data_[index]; - const ElemT &typed_value = *reinterpret_cast<const ElemT *>(value); - SetFunc(struct_value, typed_value); - } -}; - -template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)> -class DerivedArrayReadAttribute final : public ReadAttribute { - private: - Span<StructT> data_; - - public: - DerivedArrayReadAttribute(AttributeDomain domain, Span<StructT> data) - : ReadAttribute(domain, CPPType::get<ElemT>(), data.size()), data_(data) - { - } - - void get_internal(const int64_t index, void *r_value) const override - { - const StructT &struct_value = data_[index]; - const ElemT value = GetFunc(struct_value); - new (r_value) ElemT(value); - } -}; - -class ConstantReadAttribute final : public ReadAttribute { - private: - void *value_; - - public: - ConstantReadAttribute(AttributeDomain domain, - const int64_t size, - const CPPType &type, - const void *value) - : ReadAttribute(domain, type, size) - { - value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__); - type.copy_to_uninitialized(value, value_); - } - - ~ConstantReadAttribute() override - { - this->cpp_type_.destruct(value_); - MEM_freeN(value_); - } - - void get_internal(const int64_t UNUSED(index), void *r_value) const override - { - this->cpp_type_.copy_to_uninitialized(value_, r_value); - } - - void initialize_span() const override - { - const int element_size = cpp_type_.size(); - array_buffer_ = MEM_mallocN_aligned(size_ * element_size, cpp_type_.alignment(), __func__); - array_is_temporary_ = true; - cpp_type_.fill_uninitialized(value_, array_buffer_, size_); - } -}; - class ConvertedReadAttribute final : public ReadAttribute { private: const CPPType &from_type_; @@ -437,9 +213,6 @@ class ConvertedReadAttribute final : public ReadAttribute { ReadAttributePtr base_attribute_; const nodes::DataTypeConversions &conversions_; - static constexpr int MaxValueSize = 64; - static constexpr int MaxValueAlignment = 64; - public: ConvertedReadAttribute(ReadAttributePtr base_attribute, const CPPType &to_type) : ReadAttribute(base_attribute->domain(), to_type, base_attribute->size()), @@ -448,17 +221,13 @@ class ConvertedReadAttribute final : public ReadAttribute { base_attribute_(std::move(base_attribute)), conversions_(nodes::get_implicit_type_conversions()) { - if (from_type_.size() > MaxValueSize || from_type_.alignment() > MaxValueAlignment) { - throw std::runtime_error( - "type is larger than expected, the buffer size has to be increased"); - } } void get_internal(const int64_t index, void *r_value) const override { - AlignedBuffer<MaxValueSize, MaxValueAlignment> buffer; - base_attribute_->get(index, buffer.ptr()); - conversions_.convert(from_type_, to_type_, buffer.ptr(), r_value); + BUFFER_FOR_CPP_TYPE_VALUE(from_type_, buffer); + base_attribute_->get(index, buffer); + conversions_.convert(from_type_, to_type_, buffer, r_value); } }; @@ -598,964 +367,321 @@ AttributeDomain attribute_domain_highest_priority(Span<AttributeDomain> domains) return highest_priority_domain; } -/** - * A #BuiltinAttributeProvider is responsible for exactly one attribute on a geometry component. - * The attribute is identified by its name and has a fixed domain and type. Builtin attributes do - * not follow the same loose rules as other attributes, because they are mapped to internal - * "legacy" data structures. For example, some builtin attributes cannot be deleted. */ -class BuiltinAttributeProvider { - public: - /* Some utility enums to avoid hard to read booleans in function calls. */ - enum CreatableEnum { - Creatable, - NonCreatable, - }; - enum WritableEnum { - Writable, - Readonly, - }; - enum DeletableEnum { - Deletable, - NonDeletable, - }; - - protected: - const std::string name_; - const AttributeDomain domain_; - const CustomDataType data_type_; - const CreatableEnum createable_; - const WritableEnum writable_; - const DeletableEnum deletable_; - - public: - BuiltinAttributeProvider(std::string name, - const AttributeDomain domain, - const CustomDataType data_type, - const CreatableEnum createable, - const WritableEnum writable, - const DeletableEnum deletable) - : name_(std::move(name)), - domain_(domain), - data_type_(data_type), - createable_(createable), - writable_(writable), - deletable_(deletable) - { - } - - virtual ReadAttributePtr try_get_for_read(const GeometryComponent &component) const = 0; - virtual WriteAttributePtr try_get_for_write(GeometryComponent &component) const = 0; - virtual bool try_delete(GeometryComponent &component) const = 0; - virtual bool try_create(GeometryComponent &UNUSED(component)) const = 0; - virtual bool exists(const GeometryComponent &component) const = 0; - - StringRefNull name() const - { - return name_; - } - - AttributeDomain domain() const - { - return domain_; +ReadAttributePtr BuiltinCustomDataLayerProvider::try_get_for_read( + const GeometryComponent &component) const +{ + const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); + if (custom_data == nullptr) { + return {}; } - CustomDataType data_type() const - { - return data_type_; + if (update_on_read_ != nullptr) { + update_on_read_(component); } -}; - -/** - * A #DynamicAttributesProvider manages a set of named attributes on a geometry component. Each - * attribute has a name, domain and type. - */ -class DynamicAttributesProvider { - public: - virtual ReadAttributePtr try_get_for_read(const GeometryComponent &component, - const StringRef attribute_name) const = 0; - virtual WriteAttributePtr try_get_for_write(GeometryComponent &component, - const StringRef attribute_name) const = 0; - virtual bool try_delete(GeometryComponent &component, const StringRef attribute_name) const = 0; - virtual bool try_create(GeometryComponent &UNUSED(component), - const StringRef UNUSED(attribute_name), - const AttributeDomain UNUSED(domain), - const CustomDataType UNUSED(data_type)) const - { - /* Some providers should not create new attributes. */ - return false; - }; - - virtual bool foreach_attribute(const GeometryComponent &component, - const AttributeForeachCallback callback) const = 0; - virtual void supported_domains(Vector<AttributeDomain> &r_domains) const = 0; -}; - -/** - * Utility to group together multiple functions that are used to access custom data on geometry - * components in a generic way. - */ -struct CustomDataAccessInfo { - using CustomDataGetter = CustomData *(*)(GeometryComponent &component); - using ConstCustomDataGetter = const CustomData *(*)(const GeometryComponent &component); - using UpdateCustomDataPointers = void (*)(GeometryComponent &component); - - CustomDataGetter get_custom_data; - ConstCustomDataGetter get_const_custom_data; - UpdateCustomDataPointers update_custom_data_pointers; -}; -/** - * This provider is used to provide access to builtin attributes. It supports making internal types - * available as different types. For example, the vertex position attribute is stored as part of - * the #MVert struct, but is exposed as float3 attribute. - */ -class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider { - using AsReadAttribute = ReadAttributePtr (*)(const void *data, const int domain_size); - using AsWriteAttribute = WriteAttributePtr (*)(void *data, const int domain_size); - using UpdateOnWrite = void (*)(GeometryComponent &component); - const CustomDataType stored_type_; - const CustomDataAccessInfo custom_data_access_; - const AsReadAttribute as_read_attribute_; - const AsWriteAttribute as_write_attribute_; - const UpdateOnWrite update_on_write_; - - public: - BuiltinCustomDataLayerProvider(std::string attribute_name, - const AttributeDomain domain, - const CustomDataType attribute_type, - const CustomDataType stored_type, - const CreatableEnum creatable, - const WritableEnum writable, - const DeletableEnum deletable, - const CustomDataAccessInfo custom_data_access, - const AsReadAttribute as_read_attribute, - const AsWriteAttribute as_write_attribute, - const UpdateOnWrite update_on_write) - : BuiltinAttributeProvider( - std::move(attribute_name), domain, attribute_type, creatable, writable, deletable), - stored_type_(stored_type), - custom_data_access_(custom_data_access), - as_read_attribute_(as_read_attribute), - as_write_attribute_(as_write_attribute), - update_on_write_(update_on_write) - { + const int domain_size = component.attribute_domain_size(domain_); + const void *data = CustomData_get_layer(custom_data, stored_type_); + if (data == nullptr) { + return {}; } + return as_read_attribute_(data, domain_size); +} - ReadAttributePtr try_get_for_read(const GeometryComponent &component) const final - { - const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); - if (custom_data == nullptr) { - return {}; - } - const int domain_size = component.attribute_domain_size(domain_); - const void *data = CustomData_get_layer(custom_data, stored_type_); - if (data == nullptr) { - return {}; - } - return as_read_attribute_(data, domain_size); +WriteAttributePtr BuiltinCustomDataLayerProvider::try_get_for_write( + GeometryComponent &component) const +{ + if (writable_ != Writable) { + return {}; } - - WriteAttributePtr try_get_for_write(GeometryComponent &component) const final - { - if (writable_ != Writable) { - return {}; - } - CustomData *custom_data = custom_data_access_.get_custom_data(component); - if (custom_data == nullptr) { - return {}; - } - const int domain_size = component.attribute_domain_size(domain_); - void *data = CustomData_get_layer(custom_data, stored_type_); - if (data == nullptr) { - return {}; - } - void *new_data = CustomData_duplicate_referenced_layer(custom_data, stored_type_, domain_size); - if (data != new_data) { - custom_data_access_.update_custom_data_pointers(component); - data = new_data; - } - if (update_on_write_ != nullptr) { - update_on_write_(component); - } - return as_write_attribute_(data, domain_size); + CustomData *custom_data = custom_data_access_.get_custom_data(component); + if (custom_data == nullptr) { + return {}; } - - bool try_delete(GeometryComponent &component) const final - { - if (deletable_ != Deletable) { - return false; - } - CustomData *custom_data = custom_data_access_.get_custom_data(component); - if (custom_data == nullptr) { - return {}; - } - - const int domain_size = component.attribute_domain_size(domain_); - const int layer_index = CustomData_get_layer_index(custom_data, stored_type_); - const bool delete_success = CustomData_free_layer( - custom_data, stored_type_, domain_size, layer_index); - if (delete_success) { - custom_data_access_.update_custom_data_pointers(component); - } - return delete_success; + const int domain_size = component.attribute_domain_size(domain_); + void *data = CustomData_get_layer(custom_data, stored_type_); + if (data == nullptr) { + return {}; } - - bool try_create(GeometryComponent &component) const final - { - if (createable_ != Creatable) { - return false; - } - CustomData *custom_data = custom_data_access_.get_custom_data(component); - if (custom_data == nullptr) { - return false; - } - if (CustomData_get_layer(custom_data, stored_type_) != nullptr) { - /* Exists already. */ - return false; - } - const int domain_size = component.attribute_domain_size(domain_); - const void *data = CustomData_add_layer( - custom_data, stored_type_, CD_DEFAULT, nullptr, domain_size); - const bool success = data != nullptr; - if (success) { - custom_data_access_.update_custom_data_pointers(component); - } - return success; + void *new_data = CustomData_duplicate_referenced_layer(custom_data, stored_type_, domain_size); + if (data != new_data) { + custom_data_access_.update_custom_data_pointers(component); + data = new_data; } - - bool exists(const GeometryComponent &component) const final - { - const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); - if (custom_data == nullptr) { - return false; - } - const void *data = CustomData_get_layer(custom_data, stored_type_); - return data != nullptr; + if (update_on_write_ != nullptr) { + update_on_write_(component); } -}; - -/** - * This is the attribute provider for most user generated attributes. - */ -class CustomDataAttributeProvider final : public DynamicAttributesProvider { - private: - static constexpr uint64_t supported_types_mask = CD_MASK_PROP_FLOAT | CD_MASK_PROP_FLOAT2 | - CD_MASK_PROP_FLOAT3 | CD_MASK_PROP_INT32 | - CD_MASK_PROP_COLOR | CD_MASK_PROP_BOOL; - const AttributeDomain domain_; - const CustomDataAccessInfo custom_data_access_; + return as_write_attribute_(data, domain_size); +} - public: - CustomDataAttributeProvider(const AttributeDomain domain, - const CustomDataAccessInfo custom_data_access) - : domain_(domain), custom_data_access_(custom_data_access) - { +bool BuiltinCustomDataLayerProvider::try_delete(GeometryComponent &component) const +{ + if (deletable_ != Deletable) { + return false; } - - ReadAttributePtr try_get_for_read(const GeometryComponent &component, - const StringRef attribute_name) const final - { - const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); - if (custom_data == nullptr) { - return {}; - } - const int domain_size = component.attribute_domain_size(domain_); - for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { - if (layer.name != attribute_name) { - continue; - } - const CustomDataType data_type = (CustomDataType)layer.type; - switch (data_type) { - case CD_PROP_FLOAT: - return this->layer_to_read_attribute<float>(layer, domain_size); - case CD_PROP_FLOAT2: - return this->layer_to_read_attribute<float2>(layer, domain_size); - case CD_PROP_FLOAT3: - return this->layer_to_read_attribute<float3>(layer, domain_size); - case CD_PROP_INT32: - return this->layer_to_read_attribute<int>(layer, domain_size); - case CD_PROP_COLOR: - return this->layer_to_read_attribute<Color4f>(layer, domain_size); - case CD_PROP_BOOL: - return this->layer_to_read_attribute<bool>(layer, domain_size); - default: - break; - } - } + CustomData *custom_data = custom_data_access_.get_custom_data(component); + if (custom_data == nullptr) { return {}; } - WriteAttributePtr try_get_for_write(GeometryComponent &component, - const StringRef attribute_name) const final - { - CustomData *custom_data = custom_data_access_.get_custom_data(component); - if (custom_data == nullptr) { - return {}; - } - const int domain_size = component.attribute_domain_size(domain_); - for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) { - if (layer.name != attribute_name) { - continue; - } - CustomData_duplicate_referenced_layer_named( - custom_data, layer.type, layer.name, domain_size); - const CustomDataType data_type = (CustomDataType)layer.type; - switch (data_type) { - case CD_PROP_FLOAT: - return this->layer_to_write_attribute<float>(layer, domain_size); - case CD_PROP_FLOAT2: - return this->layer_to_write_attribute<float2>(layer, domain_size); - case CD_PROP_FLOAT3: - return this->layer_to_write_attribute<float3>(layer, domain_size); - case CD_PROP_INT32: - return this->layer_to_write_attribute<int>(layer, domain_size); - case CD_PROP_COLOR: - return this->layer_to_write_attribute<Color4f>(layer, domain_size); - case CD_PROP_BOOL: - return this->layer_to_write_attribute<bool>(layer, domain_size); - default: - break; - } - } - return {}; + const int domain_size = component.attribute_domain_size(domain_); + const int layer_index = CustomData_get_layer_index(custom_data, stored_type_); + const bool delete_success = CustomData_free_layer( + custom_data, stored_type_, domain_size, layer_index); + if (delete_success) { + custom_data_access_.update_custom_data_pointers(component); } + return delete_success; +} - bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final - { - CustomData *custom_data = custom_data_access_.get_custom_data(component); - if (custom_data == nullptr) { - return false; - } - const int domain_size = component.attribute_domain_size(domain_); - for (const int i : IndexRange(custom_data->totlayer)) { - const CustomDataLayer &layer = custom_data->layers[i]; - if (this->type_is_supported((CustomDataType)layer.type) && layer.name == attribute_name) { - CustomData_free_layer(custom_data, layer.type, domain_size, i); - return true; - } - } +bool BuiltinCustomDataLayerProvider::try_create(GeometryComponent &component) const +{ + if (createable_ != Creatable) { return false; } - - bool try_create(GeometryComponent &component, - const StringRef attribute_name, - const AttributeDomain domain, - const CustomDataType data_type) const final - { - if (domain_ != domain) { - return false; - } - if (!this->type_is_supported(data_type)) { - return false; - } - CustomData *custom_data = custom_data_access_.get_custom_data(component); - if (custom_data == nullptr) { - return false; - } - for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { - if (layer.name == attribute_name) { - return false; - } - } - const int domain_size = component.attribute_domain_size(domain_); - char attribute_name_c[MAX_NAME]; - attribute_name.copy(attribute_name_c); - CustomData_add_layer_named( - custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c); - return true; + CustomData *custom_data = custom_data_access_.get_custom_data(component); + if (custom_data == nullptr) { + return false; } - - bool foreach_attribute(const GeometryComponent &component, - const AttributeForeachCallback callback) const final - { - const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); - if (custom_data == nullptr) { - return true; - } - for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { - const CustomDataType data_type = (CustomDataType)layer.type; - if (this->type_is_supported(data_type)) { - AttributeMetaData meta_data{domain_, data_type}; - if (!callback(layer.name, meta_data)) { - return false; - } - } - } - return true; + if (CustomData_get_layer(custom_data, stored_type_) != nullptr) { + /* Exists already. */ + return false; } - - void supported_domains(Vector<AttributeDomain> &r_domains) const final - { - r_domains.append_non_duplicates(domain_); + const int domain_size = component.attribute_domain_size(domain_); + const void *data = CustomData_add_layer( + custom_data, stored_type_, CD_DEFAULT, nullptr, domain_size); + const bool success = data != nullptr; + if (success) { + custom_data_access_.update_custom_data_pointers(component); } + return success; +} - private: - template<typename T> - ReadAttributePtr layer_to_read_attribute(const CustomDataLayer &layer, - const int domain_size) const - { - return std::make_unique<ArrayReadAttribute<T>>( - domain_, Span(static_cast<const T *>(layer.data), domain_size)); +bool BuiltinCustomDataLayerProvider::exists(const GeometryComponent &component) const +{ + const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); + if (custom_data == nullptr) { + return false; } + const void *data = CustomData_get_layer(custom_data, stored_type_); + return data != nullptr; +} - template<typename T> - WriteAttributePtr layer_to_write_attribute(CustomDataLayer &layer, const int domain_size) const - { - return std::make_unique<ArrayWriteAttribute<T>>( - domain_, MutableSpan(static_cast<T *>(layer.data), domain_size)); +ReadAttributePtr CustomDataAttributeProvider::try_get_for_read( + const GeometryComponent &component, const StringRef attribute_name) const +{ + const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); + if (custom_data == nullptr) { + return {}; } - - bool type_is_supported(CustomDataType data_type) const - { - return ((1ULL << data_type) & supported_types_mask) != 0; + const int domain_size = component.attribute_domain_size(domain_); + for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { + if (layer.name != attribute_name) { + continue; + } + const CustomDataType data_type = (CustomDataType)layer.type; + switch (data_type) { + case CD_PROP_FLOAT: + return this->layer_to_read_attribute<float>(layer, domain_size); + case CD_PROP_FLOAT2: + return this->layer_to_read_attribute<float2>(layer, domain_size); + case CD_PROP_FLOAT3: + return this->layer_to_read_attribute<float3>(layer, domain_size); + case CD_PROP_INT32: + return this->layer_to_read_attribute<int>(layer, domain_size); + case CD_PROP_COLOR: + return this->layer_to_read_attribute<Color4f>(layer, domain_size); + case CD_PROP_BOOL: + return this->layer_to_read_attribute<bool>(layer, domain_size); + default: + break; + } } -}; - -static Mesh *get_mesh_from_component_for_write(GeometryComponent &component) -{ - BLI_assert(component.type() == GeometryComponentType::Mesh); - MeshComponent &mesh_component = static_cast<MeshComponent &>(component); - return mesh_component.get_for_write(); + return {}; } -static const Mesh *get_mesh_from_component_for_read(const GeometryComponent &component) +WriteAttributePtr CustomDataAttributeProvider::try_get_for_write( + GeometryComponent &component, const StringRef attribute_name) const { - BLI_assert(component.type() == GeometryComponentType::Mesh); - const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); - return mesh_component.get_for_read(); -} - -/** - * This attribute provider is used for uv maps and vertex colors. - */ -class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider { - private: - using AsReadAttribute = ReadAttributePtr (*)(const void *data, const int domain_size); - using AsWriteAttribute = WriteAttributePtr (*)(void *data, const int domain_size); - const AttributeDomain domain_; - const CustomDataType attribute_type_; - const CustomDataType stored_type_; - const CustomDataAccessInfo custom_data_access_; - const AsReadAttribute as_read_attribute_; - const AsWriteAttribute as_write_attribute_; - - public: - NamedLegacyCustomDataProvider(const AttributeDomain domain, - const CustomDataType attribute_type, - const CustomDataType stored_type, - const CustomDataAccessInfo custom_data_access, - const AsReadAttribute as_read_attribute, - const AsWriteAttribute as_write_attribute) - : domain_(domain), - attribute_type_(attribute_type), - stored_type_(stored_type), - custom_data_access_(custom_data_access), - as_read_attribute_(as_read_attribute), - as_write_attribute_(as_write_attribute) - { - } - - ReadAttributePtr try_get_for_read(const GeometryComponent &component, - const StringRef attribute_name) const final - { - const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); - if (custom_data == nullptr) { - return {}; - } - for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { - if (layer.type == stored_type_) { - if (layer.name == attribute_name) { - const int domain_size = component.attribute_domain_size(domain_); - return as_read_attribute_(layer.data, domain_size); - } - } - } + CustomData *custom_data = custom_data_access_.get_custom_data(component); + if (custom_data == nullptr) { return {}; } - - WriteAttributePtr try_get_for_write(GeometryComponent &component, - const StringRef attribute_name) const final - { - CustomData *custom_data = custom_data_access_.get_custom_data(component); - if (custom_data == nullptr) { - return {}; - } - for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) { - if (layer.type == stored_type_) { - if (layer.name == attribute_name) { - const int domain_size = component.attribute_domain_size(domain_); - void *data_old = layer.data; - void *data_new = CustomData_duplicate_referenced_layer_named( - custom_data, stored_type_, layer.name, domain_size); - if (data_old != data_new) { - custom_data_access_.update_custom_data_pointers(component); - } - return as_write_attribute_(layer.data, domain_size); - } - } + const int domain_size = component.attribute_domain_size(domain_); + for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) { + if (layer.name != attribute_name) { + continue; + } + CustomData_duplicate_referenced_layer_named(custom_data, layer.type, layer.name, domain_size); + const CustomDataType data_type = (CustomDataType)layer.type; + switch (data_type) { + case CD_PROP_FLOAT: + return this->layer_to_write_attribute<float>(layer, domain_size); + case CD_PROP_FLOAT2: + return this->layer_to_write_attribute<float2>(layer, domain_size); + case CD_PROP_FLOAT3: + return this->layer_to_write_attribute<float3>(layer, domain_size); + case CD_PROP_INT32: + return this->layer_to_write_attribute<int>(layer, domain_size); + case CD_PROP_COLOR: + return this->layer_to_write_attribute<Color4f>(layer, domain_size); + case CD_PROP_BOOL: + return this->layer_to_write_attribute<bool>(layer, domain_size); + default: + break; } - return {}; } + return {}; +} - bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final - { - CustomData *custom_data = custom_data_access_.get_custom_data(component); - if (custom_data == nullptr) { - return false; - } - for (const int i : IndexRange(custom_data->totlayer)) { - const CustomDataLayer &layer = custom_data->layers[i]; - if (layer.type == stored_type_) { - if (layer.name == attribute_name) { - const int domain_size = component.attribute_domain_size(domain_); - CustomData_free_layer(custom_data, stored_type_, domain_size, i); - custom_data_access_.update_custom_data_pointers(component); - return true; - } - } - } +bool CustomDataAttributeProvider::try_delete(GeometryComponent &component, + const StringRef attribute_name) const +{ + CustomData *custom_data = custom_data_access_.get_custom_data(component); + if (custom_data == nullptr) { return false; } - - bool foreach_attribute(const GeometryComponent &component, - const AttributeForeachCallback callback) const final - { - const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); - if (custom_data == nullptr) { + const int domain_size = component.attribute_domain_size(domain_); + for (const int i : IndexRange(custom_data->totlayer)) { + const CustomDataLayer &layer = custom_data->layers[i]; + if (this->type_is_supported((CustomDataType)layer.type) && layer.name == attribute_name) { + CustomData_free_layer(custom_data, layer.type, domain_size, i); return true; } - for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { - if (layer.type == stored_type_) { - AttributeMetaData meta_data{domain_, attribute_type_}; - if (!callback(layer.name, meta_data)) { - return false; - } - } - } - return true; } + return false; +} - void supported_domains(Vector<AttributeDomain> &r_domains) const final - { - r_domains.append_non_duplicates(domain_); +bool CustomDataAttributeProvider::try_create(GeometryComponent &component, + const StringRef attribute_name, + const AttributeDomain domain, + const CustomDataType data_type) const +{ + if (domain_ != domain) { + return false; } -}; - -/** - * This provider makes vertex groups available as float attributes. - */ -class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { - public: - ReadAttributePtr try_get_for_read(const GeometryComponent &component, - const StringRef attribute_name) const final - { - BLI_assert(component.type() == GeometryComponentType::Mesh); - const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); - const Mesh *mesh = mesh_component.get_for_read(); - const int vertex_group_index = mesh_component.vertex_group_names().lookup_default_as( - attribute_name, -1); - if (vertex_group_index < 0) { - return {}; - } - if (mesh == nullptr || mesh->dvert == nullptr) { - static const float default_value = 0.0f; - return std::make_unique<ConstantReadAttribute>( - ATTR_DOMAIN_POINT, mesh->totvert, CPPType::get<float>(), &default_value); - } - return std::make_unique<VertexWeightReadAttribute>( - mesh->dvert, mesh->totvert, vertex_group_index); + if (!this->type_is_supported(data_type)) { + return false; } - - WriteAttributePtr try_get_for_write(GeometryComponent &component, - const StringRef attribute_name) const final - { - BLI_assert(component.type() == GeometryComponentType::Mesh); - MeshComponent &mesh_component = static_cast<MeshComponent &>(component); - Mesh *mesh = mesh_component.get_for_write(); - if (mesh == nullptr) { - return {}; - } - const int vertex_group_index = mesh_component.vertex_group_names().lookup_default_as( - attribute_name, -1); - if (vertex_group_index < 0) { - return {}; - } - if (mesh->dvert == nullptr) { - BKE_object_defgroup_data_create(&mesh->id); - } - else { - /* Copy the data layer if it is shared with some other mesh. */ - mesh->dvert = (MDeformVert *)CustomData_duplicate_referenced_layer( - &mesh->vdata, CD_MDEFORMVERT, mesh->totvert); - } - return std::make_unique<blender::bke::VertexWeightWriteAttribute>( - mesh->dvert, mesh->totvert, vertex_group_index); + CustomData *custom_data = custom_data_access_.get_custom_data(component); + if (custom_data == nullptr) { + return false; } - - bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final - { - BLI_assert(component.type() == GeometryComponentType::Mesh); - MeshComponent &mesh_component = static_cast<MeshComponent &>(component); - - const int vertex_group_index = mesh_component.vertex_group_names().pop_default_as( - attribute_name, -1); - if (vertex_group_index < 0) { + for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { + if (layer.name == attribute_name) { return false; } - Mesh *mesh = mesh_component.get_for_write(); - if (mesh == nullptr) { - return true; - } - if (mesh->dvert == nullptr) { - return true; - } - for (MDeformVert &dvert : MutableSpan(mesh->dvert, mesh->totvert)) { - MDeformWeight *weight = BKE_defvert_find_index(&dvert, vertex_group_index); - BKE_defvert_remove_group(&dvert, weight); - } - return true; } + const int domain_size = component.attribute_domain_size(domain_); + char attribute_name_c[MAX_NAME]; + attribute_name.copy(attribute_name_c); + CustomData_add_layer_named( + custom_data, data_type, CD_DEFAULT, nullptr, domain_size, attribute_name_c); + return true; +} - bool foreach_attribute(const GeometryComponent &component, - const AttributeForeachCallback callback) const final - { - BLI_assert(component.type() == GeometryComponentType::Mesh); - const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); - for (const auto item : mesh_component.vertex_group_names().items()) { - const StringRefNull name = item.key; - const int vertex_group_index = item.value; - if (vertex_group_index >= 0) { - AttributeMetaData meta_data{ATTR_DOMAIN_POINT, CD_PROP_FLOAT}; - if (!callback(name, meta_data)) { - return false; - } - } - } +bool CustomDataAttributeProvider::foreach_attribute(const GeometryComponent &component, + const AttributeForeachCallback callback) const +{ + const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); + if (custom_data == nullptr) { return true; } - - void supported_domains(Vector<AttributeDomain> &r_domains) const final - { - r_domains.append_non_duplicates(ATTR_DOMAIN_POINT); - } -}; - -/** - * This is a container for multiple attribute providers that are used by one geometry component - * type (e.g. there is a set of attribute providers for mesh components). - */ -class ComponentAttributeProviders { - private: - /** - * Builtin attribute providers are identified by their name. Attribute names that are in this - * map will only be accessed using builtin attribute providers. Therefore, these providers have - * higher priority when an attribute name is looked up. Usually, that means that builtin - * providers are checked before dynamic ones. - */ - Map<std::string, const BuiltinAttributeProvider *> builtin_attribute_providers_; - /** - * An ordered list of dynamic attribute providers. The order is important because that is order - * in which they are checked when an attribute is looked up. - */ - Vector<const DynamicAttributesProvider *> dynamic_attribute_providers_; - /** - * All the domains that are supported by at least one of the providers above. - */ - Vector<AttributeDomain> supported_domains_; - - public: - ComponentAttributeProviders(Span<const BuiltinAttributeProvider *> builtin_attribute_providers, - Span<const DynamicAttributesProvider *> dynamic_attribute_providers) - : dynamic_attribute_providers_(dynamic_attribute_providers) - { - Set<AttributeDomain> domains; - for (const BuiltinAttributeProvider *provider : builtin_attribute_providers) { - /* Use #add_new to make sure that no two builtin attributes have the same name. */ - builtin_attribute_providers_.add_new(provider->name(), provider); - supported_domains_.append_non_duplicates(provider->domain()); - } - for (const DynamicAttributesProvider *provider : dynamic_attribute_providers) { - provider->supported_domains(supported_domains_); + for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { + const CustomDataType data_type = (CustomDataType)layer.type; + if (this->type_is_supported(data_type)) { + AttributeMetaData meta_data{domain_, data_type}; + if (!callback(layer.name, meta_data)) { + return false; + } } } - - const Map<std::string, const BuiltinAttributeProvider *> &builtin_attribute_providers() const - { - return builtin_attribute_providers_; - } - - Span<const DynamicAttributesProvider *> dynamic_attribute_providers() const - { - return dynamic_attribute_providers_; - } - - Span<AttributeDomain> supported_domains() const - { - return supported_domains_; - } -}; - -static float3 get_vertex_position(const MVert &vert) -{ - return float3(vert.co); -} - -static void set_vertex_position(MVert &vert, const float3 &position) -{ - copy_v3_v3(vert.co, position); -} - -static ReadAttributePtr make_vertex_position_read_attribute(const void *data, - const int domain_size) -{ - return std::make_unique<DerivedArrayReadAttribute<MVert, float3, get_vertex_position>>( - ATTR_DOMAIN_POINT, Span<MVert>((const MVert *)data, domain_size)); + return true; } -static WriteAttributePtr make_vertex_position_write_attribute(void *data, const int domain_size) +ReadAttributePtr NamedLegacyCustomDataProvider::try_get_for_read( + const GeometryComponent &component, const StringRef attribute_name) const { - return std::make_unique< - DerivedArrayWriteAttribute<MVert, float3, get_vertex_position, set_vertex_position>>( - ATTR_DOMAIN_POINT, MutableSpan<MVert>((MVert *)data, domain_size)); -} - -static void tag_normals_dirty_when_writing_position(GeometryComponent &component) -{ - Mesh *mesh = get_mesh_from_component_for_write(component); - if (mesh != nullptr) { - mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); + if (custom_data == nullptr) { + return {}; } + for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { + if (layer.type == stored_type_) { + if (layer.name == attribute_name) { + const int domain_size = component.attribute_domain_size(domain_); + return as_read_attribute_(layer.data, domain_size); + } + } + } + return {}; } -static int get_material_index(const MPoly &mpoly) -{ - return static_cast<int>(mpoly.mat_nr); -} - -static void set_material_index(MPoly &mpoly, const int &index) -{ - mpoly.mat_nr = static_cast<short>(std::clamp(index, 0, SHRT_MAX)); -} - -static ReadAttributePtr make_material_index_read_attribute(const void *data, const int domain_size) -{ - return std::make_unique<DerivedArrayReadAttribute<MPoly, int, get_material_index>>( - ATTR_DOMAIN_POLYGON, Span<MPoly>((const MPoly *)data, domain_size)); -} - -static WriteAttributePtr make_material_index_write_attribute(void *data, const int domain_size) -{ - return std::make_unique< - DerivedArrayWriteAttribute<MPoly, int, get_material_index, set_material_index>>( - ATTR_DOMAIN_POLYGON, MutableSpan<MPoly>((MPoly *)data, domain_size)); -} - -static float2 get_loop_uv(const MLoopUV &uv) -{ - return float2(uv.uv); -} - -static void set_loop_uv(MLoopUV &uv, const float2 &co) -{ - copy_v2_v2(uv.uv, co); -} - -static ReadAttributePtr make_uvs_read_attribute(const void *data, const int domain_size) -{ - return std::make_unique<DerivedArrayReadAttribute<MLoopUV, float2, get_loop_uv>>( - ATTR_DOMAIN_CORNER, Span((const MLoopUV *)data, domain_size)); -} - -static WriteAttributePtr make_uvs_write_attribute(void *data, const int domain_size) -{ - return std::make_unique<DerivedArrayWriteAttribute<MLoopUV, float2, get_loop_uv, set_loop_uv>>( - ATTR_DOMAIN_CORNER, MutableSpan((MLoopUV *)data, domain_size)); -} - -static Color4f get_loop_color(const MLoopCol &col) -{ - Color4f value; - rgba_uchar_to_float(value, &col.r); - return value; -} - -static void set_loop_color(MLoopCol &col, const Color4f &value) -{ - rgba_float_to_uchar(&col.r, value); -} - -static ReadAttributePtr make_vertex_color_read_attribute(const void *data, const int domain_size) -{ - return std::make_unique<DerivedArrayReadAttribute<MLoopCol, Color4f, get_loop_color>>( - ATTR_DOMAIN_CORNER, Span((const MLoopCol *)data, domain_size)); -} - -static WriteAttributePtr make_vertex_color_write_attribute(void *data, const int domain_size) -{ - return std::make_unique< - DerivedArrayWriteAttribute<MLoopCol, Color4f, get_loop_color, set_loop_color>>( - ATTR_DOMAIN_CORNER, MutableSpan((MLoopCol *)data, domain_size)); -} - -template<typename T, AttributeDomain Domain> -static ReadAttributePtr make_array_read_attribute(const void *data, const int domain_size) +WriteAttributePtr NamedLegacyCustomDataProvider::try_get_for_write( + GeometryComponent &component, const StringRef attribute_name) const { - return std::make_unique<ArrayReadAttribute<T>>(Domain, Span<T>((const T *)data, domain_size)); + CustomData *custom_data = custom_data_access_.get_custom_data(component); + if (custom_data == nullptr) { + return {}; + } + for (CustomDataLayer &layer : MutableSpan(custom_data->layers, custom_data->totlayer)) { + if (layer.type == stored_type_) { + if (layer.name == attribute_name) { + const int domain_size = component.attribute_domain_size(domain_); + void *data_old = layer.data; + void *data_new = CustomData_duplicate_referenced_layer_named( + custom_data, stored_type_, layer.name, domain_size); + if (data_old != data_new) { + custom_data_access_.update_custom_data_pointers(component); + } + return as_write_attribute_(layer.data, domain_size); + } + } + } + return {}; } -template<typename T, AttributeDomain Domain> -static WriteAttributePtr make_array_write_attribute(void *data, const int domain_size) +bool NamedLegacyCustomDataProvider::try_delete(GeometryComponent &component, + const StringRef attribute_name) const { - return std::make_unique<ArrayWriteAttribute<T>>(Domain, MutableSpan<T>((T *)data, domain_size)); + CustomData *custom_data = custom_data_access_.get_custom_data(component); + if (custom_data == nullptr) { + return false; + } + for (const int i : IndexRange(custom_data->totlayer)) { + const CustomDataLayer &layer = custom_data->layers[i]; + if (layer.type == stored_type_) { + if (layer.name == attribute_name) { + const int domain_size = component.attribute_domain_size(domain_); + CustomData_free_layer(custom_data, stored_type_, domain_size, i); + custom_data_access_.update_custom_data_pointers(component); + return true; + } + } + } + return false; } -/** - * In this function all the attribute providers for a mesh component are created. Most data in this - * function is statically allocated, because it does not change over time. - */ -static ComponentAttributeProviders create_attribute_providers_for_mesh() +bool NamedLegacyCustomDataProvider::foreach_attribute( + const GeometryComponent &component, const AttributeForeachCallback callback) const { - static auto update_custom_data_pointers = [](GeometryComponent &component) { - Mesh *mesh = get_mesh_from_component_for_write(component); - if (mesh != nullptr) { - BKE_mesh_update_customdata_pointers(mesh, false); + const CustomData *custom_data = custom_data_access_.get_const_custom_data(component); + if (custom_data == nullptr) { + return true; + } + for (const CustomDataLayer &layer : Span(custom_data->layers, custom_data->totlayer)) { + if (layer.type == stored_type_) { + AttributeMetaData meta_data{domain_, attribute_type_}; + if (!callback(layer.name, meta_data)) { + return false; + } } - }; - -#define MAKE_MUTABLE_CUSTOM_DATA_GETTER(NAME) \ - [](GeometryComponent &component) -> CustomData * { \ - Mesh *mesh = get_mesh_from_component_for_write(component); \ - return mesh ? &mesh->NAME : nullptr; \ - } -#define MAKE_CONST_CUSTOM_DATA_GETTER(NAME) \ - [](const GeometryComponent &component) -> const CustomData * { \ - const Mesh *mesh = get_mesh_from_component_for_read(component); \ - return mesh ? &mesh->NAME : nullptr; \ - } - - static CustomDataAccessInfo corner_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(ldata), - MAKE_CONST_CUSTOM_DATA_GETTER(ldata), - update_custom_data_pointers}; - static CustomDataAccessInfo point_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(vdata), - MAKE_CONST_CUSTOM_DATA_GETTER(vdata), - update_custom_data_pointers}; - static CustomDataAccessInfo edge_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(edata), - MAKE_CONST_CUSTOM_DATA_GETTER(edata), - update_custom_data_pointers}; - static CustomDataAccessInfo polygon_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(pdata), - MAKE_CONST_CUSTOM_DATA_GETTER(pdata), - update_custom_data_pointers}; - -#undef MAKE_CONST_CUSTOM_DATA_GETTER -#undef MAKE_MUTABLE_CUSTOM_DATA_GETTER - - static BuiltinCustomDataLayerProvider position("position", - ATTR_DOMAIN_POINT, - CD_PROP_FLOAT3, - CD_MVERT, - BuiltinAttributeProvider::NonCreatable, - BuiltinAttributeProvider::Writable, - BuiltinAttributeProvider::NonDeletable, - point_access, - make_vertex_position_read_attribute, - make_vertex_position_write_attribute, - tag_normals_dirty_when_writing_position); - - static BuiltinCustomDataLayerProvider material_index("material_index", - ATTR_DOMAIN_POLYGON, - CD_PROP_INT32, - CD_MPOLY, - BuiltinAttributeProvider::NonCreatable, - BuiltinAttributeProvider::Writable, - BuiltinAttributeProvider::NonDeletable, - polygon_access, - make_material_index_read_attribute, - make_material_index_write_attribute, - nullptr); - - static NamedLegacyCustomDataProvider uvs(ATTR_DOMAIN_CORNER, - CD_PROP_FLOAT2, - CD_MLOOPUV, - corner_access, - make_uvs_read_attribute, - make_uvs_write_attribute); - - static NamedLegacyCustomDataProvider vertex_colors(ATTR_DOMAIN_CORNER, - CD_PROP_COLOR, - CD_MLOOPCOL, - corner_access, - make_vertex_color_read_attribute, - make_vertex_color_write_attribute); - - static VertexGroupsAttributeProvider vertex_groups; - static CustomDataAttributeProvider corner_custom_data(ATTR_DOMAIN_CORNER, corner_access); - static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access); - static CustomDataAttributeProvider edge_custom_data(ATTR_DOMAIN_EDGE, edge_access); - static CustomDataAttributeProvider polygon_custom_data(ATTR_DOMAIN_POLYGON, polygon_access); - - return ComponentAttributeProviders({&position, &material_index}, - {&uvs, - &vertex_colors, - &corner_custom_data, - &vertex_groups, - &point_custom_data, - &edge_custom_data, - &polygon_custom_data}); + } + return true; } -/** - * In this function all the attribute providers for a point cloud component are created. Most data - * in this function is statically allocated, because it does not change over time. - */ -static ComponentAttributeProviders create_attribute_providers_for_point_cloud() +void NamedLegacyCustomDataProvider::supported_domains(Vector<AttributeDomain> &r_domains) const { - static auto update_custom_data_pointers = [](GeometryComponent &component) { - PointCloudComponent &pointcloud_component = static_cast<PointCloudComponent &>(component); - PointCloud *pointcloud = pointcloud_component.get_for_write(); - if (pointcloud != nullptr) { - BKE_pointcloud_update_customdata_pointers(pointcloud); - } - }; - static CustomDataAccessInfo point_access = { - [](GeometryComponent &component) -> CustomData * { - PointCloudComponent &pointcloud_component = static_cast<PointCloudComponent &>(component); - PointCloud *pointcloud = pointcloud_component.get_for_write(); - return pointcloud ? &pointcloud->pdata : nullptr; - }, - [](const GeometryComponent &component) -> const CustomData * { - const PointCloudComponent &pointcloud_component = static_cast<const PointCloudComponent &>( - component); - const PointCloud *pointcloud = pointcloud_component.get_for_read(); - return pointcloud ? &pointcloud->pdata : nullptr; - }, - update_custom_data_pointers}; - - static BuiltinCustomDataLayerProvider position( - "position", - ATTR_DOMAIN_POINT, - CD_PROP_FLOAT3, - CD_PROP_FLOAT3, - BuiltinAttributeProvider::NonCreatable, - BuiltinAttributeProvider::Writable, - BuiltinAttributeProvider::NonDeletable, - point_access, - make_array_read_attribute<float3, ATTR_DOMAIN_POINT>, - make_array_write_attribute<float3, ATTR_DOMAIN_POINT>, - nullptr); - static BuiltinCustomDataLayerProvider radius( - "radius", - ATTR_DOMAIN_POINT, - CD_PROP_FLOAT, - CD_PROP_FLOAT, - BuiltinAttributeProvider::Creatable, - BuiltinAttributeProvider::Writable, - BuiltinAttributeProvider::Deletable, - point_access, - make_array_read_attribute<float, ATTR_DOMAIN_POINT>, - make_array_write_attribute<float, ATTR_DOMAIN_POINT>, - nullptr); - static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access); - return ComponentAttributeProviders({&position, &radius}, {&point_custom_data}); + r_domains.append_non_duplicates(domain_); } } // namespace blender::bke @@ -1999,173 +1125,3 @@ void OutputAttributePtr::apply_span_and_save() } /** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Point Cloud Component - * \{ */ - -const blender::bke::ComponentAttributeProviders *PointCloudComponent::get_attribute_providers() - const -{ - static blender::bke::ComponentAttributeProviders providers = - blender::bke::create_attribute_providers_for_point_cloud(); - return &providers; -} - -int PointCloudComponent::attribute_domain_size(const AttributeDomain domain) const -{ - BLI_assert(domain == ATTR_DOMAIN_POINT); - UNUSED_VARS_NDEBUG(domain); - if (pointcloud_ == nullptr) { - return 0; - } - return pointcloud_->totpoint; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Mesh Component - * \{ */ - -const blender::bke::ComponentAttributeProviders *MeshComponent::get_attribute_providers() const -{ - static blender::bke::ComponentAttributeProviders providers = - blender::bke::create_attribute_providers_for_mesh(); - return &providers; -} - -int MeshComponent::attribute_domain_size(const AttributeDomain domain) const -{ - BLI_assert(this->attribute_domain_supported(domain)); - if (mesh_ == nullptr) { - return 0; - } - switch (domain) { - case ATTR_DOMAIN_CORNER: - return mesh_->totloop; - case ATTR_DOMAIN_POINT: - return mesh_->totvert; - case ATTR_DOMAIN_EDGE: - return mesh_->totedge; - case ATTR_DOMAIN_POLYGON: - return mesh_->totpoly; - default: - BLI_assert(false); - break; - } - return 0; -} - -namespace blender::bke { - -template<typename T> -static void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh, - const TypedReadAttribute<T> &attribute, - MutableSpan<T> r_values) -{ - BLI_assert(r_values.size() == mesh.totvert); - attribute_math::DefaultMixer<T> mixer(r_values); - - for (const int loop_index : IndexRange(mesh.totloop)) { - const T value = attribute[loop_index]; - const MLoop &loop = mesh.mloop[loop_index]; - const int point_index = loop.v; - mixer.mix_in(point_index, value); - } - mixer.finalize(); -} - -static ReadAttributePtr adapt_mesh_domain_corner_to_point(const Mesh &mesh, - ReadAttributePtr attribute) -{ - ReadAttributePtr new_attribute; - const CustomDataType data_type = attribute->custom_data_type(); - attribute_math::convert_to_static_type(data_type, [&](auto dummy) { - using T = decltype(dummy); - if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { - /* We compute all interpolated values at once, because for this interpolation, one has to - * iterate over all loops anyway. */ - Array<T> values(mesh.totvert); - adapt_mesh_domain_corner_to_point_impl<T>(mesh, *attribute, values); - new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, - std::move(values)); - } - }); - return new_attribute; -} - -template<typename T> -static void adapt_mesh_domain_point_to_corner_impl(const Mesh &mesh, - const TypedReadAttribute<T> &attribute, - MutableSpan<T> r_values) -{ - BLI_assert(r_values.size() == mesh.totloop); - - for (const int loop_index : IndexRange(mesh.totloop)) { - const int vertex_index = mesh.mloop[loop_index].v; - r_values[loop_index] = attribute[vertex_index]; - } -} - -static ReadAttributePtr adapt_mesh_domain_point_to_corner(const Mesh &mesh, - ReadAttributePtr attribute) -{ - ReadAttributePtr new_attribute; - const CustomDataType data_type = attribute->custom_data_type(); - attribute_math::convert_to_static_type(data_type, [&](auto dummy) { - using T = decltype(dummy); - /* It is not strictly necessary to compute the value for all corners here. Instead one could - * lazily lookup the mesh topology when a specific index accessed. This can be more efficient - * when an algorithm only accesses very few of the corner values. However, for the algorithms - * we currently have, precomputing the array is fine. Also, it is easier to implement. */ - Array<T> values(mesh.totloop); - adapt_mesh_domain_point_to_corner_impl<T>(mesh, *attribute, values); - new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_CORNER, - std::move(values)); - }); - return new_attribute; -} - -} // namespace blender::bke - -ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attribute, - const AttributeDomain new_domain) const -{ - if (!attribute) { - return {}; - } - if (attribute->size() == 0) { - return {}; - } - const AttributeDomain old_domain = attribute->domain(); - if (old_domain == new_domain) { - return attribute; - } - - switch (old_domain) { - case ATTR_DOMAIN_CORNER: { - switch (new_domain) { - case ATTR_DOMAIN_POINT: - return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(attribute)); - default: - break; - } - break; - } - case ATTR_DOMAIN_POINT: { - switch (new_domain) { - case ATTR_DOMAIN_CORNER: - return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(attribute)); - default: - break; - } - } - default: - break; - } - - return {}; -} - -/** \} */ diff --git a/source/blender/blenkernel/intern/attribute_access_intern.hh b/source/blender/blenkernel/intern/attribute_access_intern.hh new file mode 100644 index 00000000000..299da4c97fe --- /dev/null +++ b/source/blender/blenkernel/intern/attribute_access_intern.hh @@ -0,0 +1,499 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "BLI_map.hh" +#include "BLI_span.hh" +#include "BLI_string_ref.hh" +#include "BLI_vector.hh" + +namespace blender::bke { + +class ConstantReadAttribute final : public ReadAttribute { + private: + void *value_; + + public: + ConstantReadAttribute(AttributeDomain domain, + const int64_t size, + const CPPType &type, + const void *value) + : ReadAttribute(domain, type, size) + { + value_ = MEM_mallocN_aligned(type.size(), type.alignment(), __func__); + type.copy_to_uninitialized(value, value_); + } + + ~ConstantReadAttribute() override + { + this->cpp_type_.destruct(value_); + MEM_freeN(value_); + } + + void get_internal(const int64_t UNUSED(index), void *r_value) const override + { + this->cpp_type_.copy_to_uninitialized(value_, r_value); + } + + void initialize_span() const override + { + const int element_size = cpp_type_.size(); + array_buffer_ = MEM_mallocN_aligned(size_ * element_size, cpp_type_.alignment(), __func__); + array_is_temporary_ = true; + cpp_type_.fill_uninitialized(value_, array_buffer_, size_); + } +}; + +template<typename T> class ArrayReadAttribute final : public ReadAttribute { + private: + Span<T> data_; + + public: + ArrayReadAttribute(AttributeDomain domain, Span<T> data) + : ReadAttribute(domain, CPPType::get<T>(), data.size()), data_(data) + { + } + + void get_internal(const int64_t index, void *r_value) const override + { + new (r_value) T(data_[index]); + } + + void initialize_span() const override + { + /* The data will not be modified, so this const_cast is fine. */ + array_buffer_ = const_cast<T *>(data_.data()); + array_is_temporary_ = false; + } +}; + +template<typename T> class OwnedArrayReadAttribute final : public ReadAttribute { + private: + Array<T> data_; + + public: + OwnedArrayReadAttribute(AttributeDomain domain, Array<T> data) + : ReadAttribute(domain, CPPType::get<T>(), data.size()), data_(std::move(data)) + { + } + + void get_internal(const int64_t index, void *r_value) const override + { + new (r_value) T(data_[index]); + } + + void initialize_span() const override + { + /* The data will not be modified, so this const_cast is fine. */ + array_buffer_ = const_cast<T *>(data_.data()); + array_is_temporary_ = false; + } +}; + +template<typename StructT, typename ElemT, ElemT (*GetFunc)(const StructT &)> +class DerivedArrayReadAttribute final : public ReadAttribute { + private: + blender::Span<StructT> data_; + + public: + DerivedArrayReadAttribute(AttributeDomain domain, Span<StructT> data) + : ReadAttribute(domain, CPPType::get<ElemT>(), data.size()), data_(data) + { + } + + void get_internal(const int64_t index, void *r_value) const override + { + const StructT &struct_value = data_[index]; + const ElemT value = GetFunc(struct_value); + new (r_value) ElemT(value); + } +}; + +template<typename T> class ArrayWriteAttribute final : public WriteAttribute { + private: + MutableSpan<T> data_; + + public: + ArrayWriteAttribute(AttributeDomain domain, MutableSpan<T> data) + : WriteAttribute(domain, CPPType::get<T>(), data.size()), data_(data) + { + } + + void get_internal(const int64_t index, void *r_value) const override + { + new (r_value) T(data_[index]); + } + + void set_internal(const int64_t index, const void *value) override + { + data_[index] = *reinterpret_cast<const T *>(value); + } + + void initialize_span(const bool UNUSED(write_only)) override + { + array_buffer_ = data_.data(); + array_is_temporary_ = false; + } + + void apply_span_if_necessary() override + { + /* Do nothing, because the span contains the attribute itself already. */ + } +}; + +template<typename StructT, + typename ElemT, + ElemT (*GetFunc)(const StructT &), + void (*SetFunc)(StructT &, const ElemT &)> +class DerivedArrayWriteAttribute final : public WriteAttribute { + private: + blender::MutableSpan<StructT> data_; + + public: + DerivedArrayWriteAttribute(AttributeDomain domain, blender::MutableSpan<StructT> data) + : WriteAttribute(domain, CPPType::get<ElemT>(), data.size()), data_(data) + { + } + + void get_internal(const int64_t index, void *r_value) const override + { + const StructT &struct_value = data_[index]; + const ElemT value = GetFunc(struct_value); + new (r_value) ElemT(value); + } + + void set_internal(const int64_t index, const void *value) override + { + StructT &struct_value = data_[index]; + const ElemT &typed_value = *reinterpret_cast<const ElemT *>(value); + SetFunc(struct_value, typed_value); + } +}; + +/** + * Utility to group together multiple functions that are used to access custom data on geometry + * components in a generic way. + */ +struct CustomDataAccessInfo { + using CustomDataGetter = CustomData *(*)(GeometryComponent &component); + using ConstCustomDataGetter = const CustomData *(*)(const GeometryComponent &component); + using UpdateCustomDataPointers = void (*)(GeometryComponent &component); + + CustomDataGetter get_custom_data; + ConstCustomDataGetter get_const_custom_data; + UpdateCustomDataPointers update_custom_data_pointers; +}; + +/** + * A #BuiltinAttributeProvider is responsible for exactly one attribute on a geometry component. + * The attribute is identified by its name and has a fixed domain and type. Builtin attributes do + * not follow the same loose rules as other attributes, because they are mapped to internal + * "legacy" data structures. For example, some builtin attributes cannot be deleted. */ +class BuiltinAttributeProvider { + public: + /* Some utility enums to avoid hard to read booleans in function calls. */ + enum CreatableEnum { + Creatable, + NonCreatable, + }; + enum WritableEnum { + Writable, + Readonly, + }; + enum DeletableEnum { + Deletable, + NonDeletable, + }; + + protected: + const std::string name_; + const AttributeDomain domain_; + const CustomDataType data_type_; + const CreatableEnum createable_; + const WritableEnum writable_; + const DeletableEnum deletable_; + + public: + BuiltinAttributeProvider(std::string name, + const AttributeDomain domain, + const CustomDataType data_type, + const CreatableEnum createable, + const WritableEnum writable, + const DeletableEnum deletable) + : name_(std::move(name)), + domain_(domain), + data_type_(data_type), + createable_(createable), + writable_(writable), + deletable_(deletable) + { + } + + virtual ReadAttributePtr try_get_for_read(const GeometryComponent &component) const = 0; + virtual WriteAttributePtr try_get_for_write(GeometryComponent &component) const = 0; + virtual bool try_delete(GeometryComponent &component) const = 0; + virtual bool try_create(GeometryComponent &UNUSED(component)) const = 0; + virtual bool exists(const GeometryComponent &component) const = 0; + + blender::StringRefNull name() const + { + return name_; + } + + AttributeDomain domain() const + { + return domain_; + } + + CustomDataType data_type() const + { + return data_type_; + } +}; + +/** + * A #DynamicAttributesProvider manages a set of named attributes on a geometry component. Each + * attribute has a name, domain and type. + */ +class DynamicAttributesProvider { + public: + virtual ReadAttributePtr try_get_for_read(const GeometryComponent &component, + const blender::StringRef attribute_name) const = 0; + virtual WriteAttributePtr try_get_for_write(GeometryComponent &component, + const blender::StringRef attribute_name) const = 0; + virtual bool try_delete(GeometryComponent &component, + const blender::StringRef attribute_name) const = 0; + virtual bool try_create(GeometryComponent &UNUSED(component), + const blender::StringRef UNUSED(attribute_name), + const AttributeDomain UNUSED(domain), + const CustomDataType UNUSED(data_type)) const + { + /* Some providers should not create new attributes. */ + return false; + }; + + virtual bool foreach_attribute(const GeometryComponent &component, + const AttributeForeachCallback callback) const = 0; + virtual void supported_domains(blender::Vector<AttributeDomain> &r_domains) const = 0; +}; + +/** + * This is the attribute provider for most user generated attributes. + */ +class CustomDataAttributeProvider final : public DynamicAttributesProvider { + private: + static constexpr uint64_t supported_types_mask = CD_MASK_PROP_FLOAT | CD_MASK_PROP_FLOAT2 | + CD_MASK_PROP_FLOAT3 | CD_MASK_PROP_INT32 | + CD_MASK_PROP_COLOR | CD_MASK_PROP_BOOL; + const AttributeDomain domain_; + const CustomDataAccessInfo custom_data_access_; + + public: + CustomDataAttributeProvider(const AttributeDomain domain, + const CustomDataAccessInfo custom_data_access) + : domain_(domain), custom_data_access_(custom_data_access) + { + } + + ReadAttributePtr try_get_for_read(const GeometryComponent &component, + const blender::StringRef attribute_name) const final; + + WriteAttributePtr try_get_for_write(GeometryComponent &component, + const blender::StringRef attribute_name) const final; + + bool try_delete(GeometryComponent &component, + const blender::StringRef attribute_name) const final; + + bool try_create(GeometryComponent &component, + const blender::StringRef attribute_name, + const AttributeDomain domain, + const CustomDataType data_type) const final; + + bool foreach_attribute(const GeometryComponent &component, + const AttributeForeachCallback callback) const final; + + void supported_domains(blender::Vector<AttributeDomain> &r_domains) const final + { + r_domains.append_non_duplicates(domain_); + } + + private: + template<typename T> + ReadAttributePtr layer_to_read_attribute(const CustomDataLayer &layer, + const int domain_size) const + { + return std::make_unique<ArrayReadAttribute<T>>( + domain_, Span(static_cast<const T *>(layer.data), domain_size)); + } + + template<typename T> + WriteAttributePtr layer_to_write_attribute(CustomDataLayer &layer, const int domain_size) const + { + return std::make_unique<ArrayWriteAttribute<T>>( + domain_, MutableSpan(static_cast<T *>(layer.data), domain_size)); + } + + bool type_is_supported(CustomDataType data_type) const + { + return ((1ULL << data_type) & supported_types_mask) != 0; + } +}; + +/** + * This attribute provider is used for uv maps and vertex colors. + */ +class NamedLegacyCustomDataProvider final : public DynamicAttributesProvider { + private: + using AsReadAttribute = ReadAttributePtr (*)(const void *data, const int domain_size); + using AsWriteAttribute = WriteAttributePtr (*)(void *data, const int domain_size); + const AttributeDomain domain_; + const CustomDataType attribute_type_; + const CustomDataType stored_type_; + const CustomDataAccessInfo custom_data_access_; + const AsReadAttribute as_read_attribute_; + const AsWriteAttribute as_write_attribute_; + + public: + NamedLegacyCustomDataProvider(const AttributeDomain domain, + const CustomDataType attribute_type, + const CustomDataType stored_type, + const CustomDataAccessInfo custom_data_access, + const AsReadAttribute as_read_attribute, + const AsWriteAttribute as_write_attribute) + : domain_(domain), + attribute_type_(attribute_type), + stored_type_(stored_type), + custom_data_access_(custom_data_access), + as_read_attribute_(as_read_attribute), + as_write_attribute_(as_write_attribute) + { + } + + ReadAttributePtr try_get_for_read(const GeometryComponent &component, + const StringRef attribute_name) const final; + WriteAttributePtr try_get_for_write(GeometryComponent &component, + const StringRef attribute_name) const final; + bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final; + bool foreach_attribute(const GeometryComponent &component, + const AttributeForeachCallback callback) const final; + void supported_domains(Vector<AttributeDomain> &r_domains) const final; +}; + +/** + * This provider is used to provide access to builtin attributes. It supports making internal types + * available as different types. For example, the vertex position attribute is stored as part of + * the #MVert struct, but is exposed as float3 attribute. + */ +class BuiltinCustomDataLayerProvider final : public BuiltinAttributeProvider { + using AsReadAttribute = ReadAttributePtr (*)(const void *data, const int domain_size); + using AsWriteAttribute = WriteAttributePtr (*)(void *data, const int domain_size); + using UpdateOnRead = void (*)(const GeometryComponent &component); + using UpdateOnWrite = void (*)(GeometryComponent &component); + const CustomDataType stored_type_; + const CustomDataAccessInfo custom_data_access_; + const AsReadAttribute as_read_attribute_; + const AsWriteAttribute as_write_attribute_; + const UpdateOnRead update_on_read_; + const UpdateOnWrite update_on_write_; + + public: + BuiltinCustomDataLayerProvider(std::string attribute_name, + const AttributeDomain domain, + const CustomDataType attribute_type, + const CustomDataType stored_type, + const CreatableEnum creatable, + const WritableEnum writable, + const DeletableEnum deletable, + const CustomDataAccessInfo custom_data_access, + const AsReadAttribute as_read_attribute, + const AsWriteAttribute as_write_attribute, + const UpdateOnRead update_on_read, + const UpdateOnWrite update_on_write) + : BuiltinAttributeProvider( + std::move(attribute_name), domain, attribute_type, creatable, writable, deletable), + stored_type_(stored_type), + custom_data_access_(custom_data_access), + as_read_attribute_(as_read_attribute), + as_write_attribute_(as_write_attribute), + update_on_read_(update_on_read), + update_on_write_(update_on_write) + { + } + + ReadAttributePtr try_get_for_read(const GeometryComponent &component) const final; + WriteAttributePtr try_get_for_write(GeometryComponent &component) const final; + bool try_delete(GeometryComponent &component) const final; + bool try_create(GeometryComponent &component) const final; + bool exists(const GeometryComponent &component) const final; +}; + +/** + * This is a container for multiple attribute providers that are used by one geometry component + * type (e.g. there is a set of attribute providers for mesh components). + */ +class ComponentAttributeProviders { + private: + /** + * Builtin attribute providers are identified by their name. Attribute names that are in this + * map will only be accessed using builtin attribute providers. Therefore, these providers have + * higher priority when an attribute name is looked up. Usually, that means that builtin + * providers are checked before dynamic ones. + */ + blender::Map<std::string, const BuiltinAttributeProvider *> builtin_attribute_providers_; + /** + * An ordered list of dynamic attribute providers. The order is important because that is order + * in which they are checked when an attribute is looked up. + */ + blender::Vector<const DynamicAttributesProvider *> dynamic_attribute_providers_; + /** + * All the domains that are supported by at least one of the providers above. + */ + blender::Vector<AttributeDomain> supported_domains_; + + public: + ComponentAttributeProviders( + blender::Span<const BuiltinAttributeProvider *> builtin_attribute_providers, + blender::Span<const DynamicAttributesProvider *> dynamic_attribute_providers) + : dynamic_attribute_providers_(dynamic_attribute_providers) + { + blender::Set<AttributeDomain> domains; + for (const BuiltinAttributeProvider *provider : builtin_attribute_providers) { + /* Use #add_new to make sure that no two builtin attributes have the same name. */ + builtin_attribute_providers_.add_new(provider->name(), provider); + supported_domains_.append_non_duplicates(provider->domain()); + } + for (const DynamicAttributesProvider *provider : dynamic_attribute_providers) { + provider->supported_domains(supported_domains_); + } + } + + const blender::Map<std::string, const BuiltinAttributeProvider *> &builtin_attribute_providers() + const + { + return builtin_attribute_providers_; + } + + blender::Span<const DynamicAttributesProvider *> dynamic_attribute_providers() const + { + return dynamic_attribute_providers_; + } + + blender::Span<AttributeDomain> supported_domains() const + { + return supported_domains_; + } +}; + +} // namespace blender::bke
\ No newline at end of file diff --git a/source/blender/blenkernel/intern/blender_copybuffer.c b/source/blender/blenkernel/intern/blender_copybuffer.c index 9f5e038fb82..ec8962d5f6d 100644 --- a/source/blender/blenkernel/intern/blender_copybuffer.c +++ b/source/blender/blenkernel/intern/blender_copybuffer.c @@ -94,8 +94,9 @@ bool BKE_copybuffer_read(Main *bmain_dst, } /* Here appending/linking starts. */ const int flag = 0; + const int id_tag_extra = 0; struct LibraryLink_Params liblink_params; - BLO_library_link_params_init(&liblink_params, bmain_dst, flag); + BLO_library_link_params_init(&liblink_params, bmain_dst, flag, id_tag_extra); Main *mainl = BLO_library_link_begin(&bh, libname, &liblink_params); BLO_library_link_copypaste(mainl, bh, id_types_mask); BLO_library_link_end(mainl, &bh, &liblink_params); @@ -130,6 +131,7 @@ int BKE_copybuffer_paste(bContext *C, Main *mainl = NULL; Library *lib; BlendHandle *bh; + const int id_tag_extra = 0; bh = BLO_blendhandle_from_file(libname, reports); @@ -148,7 +150,8 @@ int BKE_copybuffer_paste(bContext *C, /* here appending/linking starts */ struct LibraryLink_Params liblink_params; - BLO_library_link_params_init_with_context(&liblink_params, bmain, flag, scene, view_layer, v3d); + BLO_library_link_params_init_with_context( + &liblink_params, bmain, flag, id_tag_extra, scene, view_layer, v3d); mainl = BLO_library_link_begin(&bh, libname, &liblink_params); const int num_pasted = BLO_library_link_copypaste(mainl, bh, id_types_mask); diff --git a/source/blender/blenkernel/intern/context.c b/source/blender/blenkernel/intern/context.c index 6bc385ecd31..cbf7a4483c0 100644 --- a/source/blender/blenkernel/intern/context.c +++ b/source/blender/blenkernel/intern/context.c @@ -914,6 +914,15 @@ struct SpaceTopBar *CTX_wm_space_topbar(const bContext *C) return NULL; } +struct SpaceSpreadsheet *CTX_wm_space_spreadsheet(const bContext *C) +{ + ScrArea *area = CTX_wm_area(C); + if (area && area->spacetype == SPACE_SPREADSHEET) { + return area->spacedata.first; + } + return NULL; +} + void CTX_wm_manager_set(bContext *C, wmWindowManager *wm) { C->wm.manager = wm; diff --git a/source/blender/blenkernel/intern/cryptomatte.cc b/source/blender/blenkernel/intern/cryptomatte.cc index 9d9cace3a35..55426f738ff 100644 --- a/source/blender/blenkernel/intern/cryptomatte.cc +++ b/source/blender/blenkernel/intern/cryptomatte.cc @@ -184,37 +184,39 @@ float BKE_cryptomatte_hash_to_float(uint32_t cryptomatte_hash) char *BKE_cryptomatte_entries_to_matte_id(NodeCryptomatte *node_storage) { - std::stringstream ss; - ss.precision(9); - + DynStr *matte_id = BLI_dynstr_new(); bool first = true; LISTBASE_FOREACH (CryptomatteEntry *, entry, &node_storage->entries) { if (!first) { - ss << ','; + BLI_dynstr_append(matte_id, ","); } - blender::StringRef entry_name(entry->name, BLI_strnlen(entry->name, sizeof(entry->name))); - if (!entry_name.is_empty()) { - ss << entry_name; + if (BLI_strnlen(entry->name, sizeof(entry->name)) != 0) { + BLI_dynstr_nappend(matte_id, entry->name, sizeof(entry->name)); } else { - ss << '<' << std::scientific << entry->encoded_hash << '>'; + BLI_dynstr_appendf(matte_id, "<%.9g>", entry->encoded_hash); } first = false; } - - /* Convert result to C string. */ - const std::string result_string = ss.str(); - const char *c_str = result_string.c_str(); - size_t result_len = result_string.size() + 1; - char *result = static_cast<char *>(MEM_mallocN(sizeof(char) * result_len, __func__)); - memcpy(result, c_str, result_len); + char *result = BLI_dynstr_get_cstring(matte_id); + BLI_dynstr_free(matte_id); return result; } void BKE_cryptomatte_matte_id_to_entries(NodeCryptomatte *node_storage, const char *matte_id) { BLI_freelistN(&node_storage->entries); - std::optional<CryptomatteSession> session = std::nullopt; + + if (matte_id == nullptr) { + MEM_SAFE_FREE(node_storage->matte_id); + return; + } + /* Update the matte_id so the files can be opened in versions that don't + * use `CryptomatteEntry`. */ + if (matte_id != node_storage->matte_id && STREQ(node_storage->matte_id, matte_id)) { + MEM_SAFE_FREE(node_storage->matte_id); + node_storage->matte_id = static_cast<char *>(MEM_dupallocN(matte_id)); + } std::istringstream ss(matte_id); while (ss.good()) { diff --git a/source/blender/blenkernel/intern/cryptomatte_test.cc b/source/blender/blenkernel/intern/cryptomatte_test.cc index 5481b97913c..faf1ad91cdc 100644 --- a/source/blender/blenkernel/intern/cryptomatte_test.cc +++ b/source/blender/blenkernel/intern/cryptomatte_test.cc @@ -21,8 +21,6 @@ #include "BKE_cryptomatte.hh" #include "BKE_image.h" -#include "DNA_node_types.h" - #include "RE_pipeline.h" #include "MEM_guardedalloc.h" @@ -77,17 +75,15 @@ static void test_cryptomatte_manifest(std::string expected, std::string manifest TEST(cryptomatte, layer_from_manifest) { test_cryptomatte_manifest("{}", "{}"); - test_cryptomatte_manifest("{\"Object\":\"12345678\"}", "{\"Object\": \"12345678\"}"); - test_cryptomatte_manifest("{\"Object\":\"12345678\",\"Object2\":\"87654321\"}", - "{\"Object\":\"12345678\",\"Object2\":\"87654321\"}"); - test_cryptomatte_manifest( - "{\"Object\":\"12345678\",\"Object2\":\"87654321\"}", - " { \"Object\" : \"12345678\" , \"Object2\" : \"87654321\" } "); - test_cryptomatte_manifest("{\"Object\\\"01\\\"\":\"12345678\"}", - "{\"Object\\\"01\\\"\": \"12345678\"}"); + test_cryptomatte_manifest(R"({"Object":"12345678"})", R"({"Object": "12345678"})"); + test_cryptomatte_manifest(R"({"Object":"12345678","Object2":"87654321")})", + R"({"Object":"12345678","Object2":"87654321"})"); + test_cryptomatte_manifest(R"({"Object":"12345678","Object2":"87654321"})", + R"( { "Object" : "12345678" , "Object2" : "87654321" } )"); + test_cryptomatte_manifest(R"({"Object\"01\"":"12345678"})", R"({"Object\"01\"": "12345678"})"); test_cryptomatte_manifest( - "{\"Object\\\"01\\\"\":\"12345678\",\"Object\":\"12345678\",\"Object2\":\"87654321\"}", - "{\"Object\\\"01\\\"\":\"12345678\",\"Object\":\"12345678\", \"Object2\":\"87654321\"}"); + R"({"Object\"01\"":"12345678","Object":"12345678","Object2":"87654321"})", + R"({"Object\"01\"":"12345678","Object":"12345678", "Object2":"87654321"})"); } TEST(cryptomatte, extract_layer_hash_from_metadata_key) @@ -127,7 +123,7 @@ static void validate_cryptomatte_session_from_stamp_data(void *UNUSED(data), EXPECT_STREQ("uint32_to_float32", propvalue); } else if (prop_name == "cryptomatte/87f095e/manifest") { - EXPECT_STREQ("{\"Object\":\"12345678\"}", propvalue); + EXPECT_STREQ(R"({"Object":"12345678"})", propvalue); } else if (prop_name == "cryptomatte/c42daa7/name") { @@ -140,7 +136,7 @@ static void validate_cryptomatte_session_from_stamp_data(void *UNUSED(data), EXPECT_STREQ("uint32_to_float32", propvalue); } else if (prop_name == "cryptomatte/c42daa7/manifest") { - EXPECT_STREQ("{\"Object2\":\"87654321\"}", propvalue); + EXPECT_STREQ(R"({"Object2":"87654321"})", propvalue); } else { @@ -155,12 +151,12 @@ TEST(cryptomatte, session_from_stamp_data) MEM_callocN(sizeof(RenderResult), __func__)); BKE_render_result_stamp_data(render_result, "cryptomatte/qwerty/name", "layer1"); BKE_render_result_stamp_data( - render_result, "cryptomatte/qwerty/manifest", "{\"Object\":\"12345678\"}"); + render_result, "cryptomatte/qwerty/manifest", R"({"Object":"12345678"})"); BKE_render_result_stamp_data(render_result, "cryptomatte/uiop/name", "layer2"); BKE_render_result_stamp_data( - render_result, "cryptomatte/uiop/manifest", "{\"Object2\":\"87654321\"}"); - CryptomatteSession *session = BKE_cryptomatte_init_from_render_result(render_result); - EXPECT_NE(session, nullptr); + render_result, "cryptomatte/uiop/manifest", R"({"Object2":"87654321"})"); + CryptomatteSessionPtr session(BKE_cryptomatte_init_from_render_result(render_result)); + EXPECT_NE(session.get(), nullptr); RE_FreeRenderResult(render_result); /* Create StampData from CryptomatteSession. */ @@ -168,25 +164,13 @@ TEST(cryptomatte, session_from_stamp_data) BLI_strncpy(view_layer.name, "viewlayername", sizeof(view_layer.name)); RenderResult *render_result2 = static_cast<RenderResult *>( MEM_callocN(sizeof(RenderResult), __func__)); - BKE_cryptomatte_store_metadata(session, render_result2, &view_layer); + BKE_cryptomatte_store_metadata(session.get(), render_result2, &view_layer); /* Validate StampData. */ BKE_stamp_info_callback( nullptr, render_result2->stamp_data, validate_cryptomatte_session_from_stamp_data, false); RE_FreeRenderResult(render_result2); - BKE_cryptomatte_free(session); -} - -TEST(cryptomatte, T86026) -{ - NodeCryptomatte storage = {{0.0f}}; - CryptomatteEntry entry = {nullptr}; - BLI_addtail(&storage.entries, &entry); - entry.encoded_hash = 4.76190593e-07; - char *matte_id = BKE_cryptomatte_entries_to_matte_id(&storage); - EXPECT_STREQ("<4.761905927e-07>", matte_id); - MEM_freeN(matte_id); } } // namespace blender::bke::cryptomatte::tests diff --git a/source/blender/blenkernel/intern/displist.c b/source/blender/blenkernel/intern/displist.c index c860e57520d..708b1971bd5 100644 --- a/source/blender/blenkernel/intern/displist.c +++ b/source/blender/blenkernel/intern/displist.c @@ -875,9 +875,9 @@ static float (*displist_vert_coords_alloc(ListBase *dispbase, int *r_vert_len))[ allverts = MEM_mallocN(sizeof(float[3]) * (*r_vert_len), "displist_vert_coords_alloc allverts"); fp = (float *)allverts; LISTBASE_FOREACH (DispList *, dl, dispbase) { - int offs = 3 * ((dl->type == DL_INDEX3) ? dl->nr : dl->parts * dl->nr); - memcpy(fp, dl->verts, sizeof(float) * offs); - fp += offs; + int ofs = 3 * ((dl->type == DL_INDEX3) ? dl->nr : dl->parts * dl->nr); + memcpy(fp, dl->verts, sizeof(float) * ofs); + fp += ofs; } return allverts; @@ -889,9 +889,9 @@ static void displist_vert_coords_apply(ListBase *dispbase, float (*allverts)[3]) fp = (float *)allverts; LISTBASE_FOREACH (DispList *, dl, dispbase) { - int offs = 3 * ((dl->type == DL_INDEX3) ? dl->nr : dl->parts * dl->nr); - memcpy(dl->verts, fp, sizeof(float) * offs); - fp += offs; + int ofs = 3 * ((dl->type == DL_INDEX3) ? dl->nr : dl->parts * dl->nr); + memcpy(dl->verts, fp, sizeof(float) * ofs); + fp += ofs; } } diff --git a/source/blender/blenkernel/intern/geometry_component_instances.cc b/source/blender/blenkernel/intern/geometry_component_instances.cc new file mode 100644 index 00000000000..a6ee7a1b918 --- /dev/null +++ b/source/blender/blenkernel/intern/geometry_component_instances.cc @@ -0,0 +1,173 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "BLI_float4x4.hh" +#include "BLI_map.hh" +#include "BLI_rand.hh" +#include "BLI_set.hh" +#include "BLI_span.hh" +#include "BLI_vector.hh" + +#include "DNA_collection_types.h" + +#include "BKE_geometry_set.hh" + +using blender::float4x4; +using blender::Map; +using blender::MutableSpan; +using blender::Set; +using blender::Span; + +/* -------------------------------------------------------------------- */ +/** \name Geometry Component Implementation + * \{ */ + +InstancesComponent::InstancesComponent() : GeometryComponent(GeometryComponentType::Instances) +{ +} + +GeometryComponent *InstancesComponent::copy() const +{ + InstancesComponent *new_component = new InstancesComponent(); + new_component->transforms_ = transforms_; + new_component->instanced_data_ = instanced_data_; + return new_component; +} + +void InstancesComponent::clear() +{ + instanced_data_.clear(); + transforms_.clear(); +} + +void InstancesComponent::add_instance(Object *object, float4x4 transform, const int id) +{ + InstancedData data; + data.type = INSTANCE_DATA_TYPE_OBJECT; + data.data.object = object; + this->add_instance(data, transform, id); +} + +void InstancesComponent::add_instance(Collection *collection, float4x4 transform, const int id) +{ + InstancedData data; + data.type = INSTANCE_DATA_TYPE_COLLECTION; + data.data.collection = collection; + this->add_instance(data, transform, id); +} + +void InstancesComponent::add_instance(InstancedData data, float4x4 transform, const int id) +{ + instanced_data_.append(data); + transforms_.append(transform); + ids_.append(id); +} + +Span<InstancedData> InstancesComponent::instanced_data() const +{ + return instanced_data_; +} + +Span<float4x4> InstancesComponent::transforms() const +{ + return transforms_; +} + +Span<int> InstancesComponent::ids() const +{ + return ids_; +} + +MutableSpan<float4x4> InstancesComponent::transforms() +{ + return transforms_; +} + +int InstancesComponent::instances_amount() const +{ + const int size = instanced_data_.size(); + BLI_assert(transforms_.size() == size); + return size; +} + +bool InstancesComponent::is_empty() const +{ + return transforms_.size() == 0; +} + +static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids) +{ + using namespace blender; + Array<int> unique_ids(original_ids.size()); + + Set<int> used_unique_ids; + used_unique_ids.reserve(original_ids.size()); + Vector<int> instances_with_id_collision; + for (const int instance_index : original_ids.index_range()) { + const int original_id = original_ids[instance_index]; + if (used_unique_ids.add(original_id)) { + /* The original id has not been used by another instance yet. */ + unique_ids[instance_index] = original_id; + } + else { + /* The original id of this instance collided with a previous instance, it needs to be looked + * at again in a second pass. Don't generate a new random id here, because this might collide + * with other existing ids. */ + instances_with_id_collision.append(instance_index); + } + } + + Map<int, RandomNumberGenerator> generator_by_original_id; + for (const int instance_index : instances_with_id_collision) { + const int original_id = original_ids[instance_index]; + RandomNumberGenerator &rng = generator_by_original_id.lookup_or_add_cb(original_id, [&]() { + RandomNumberGenerator rng; + rng.seed_random(original_id); + return rng; + }); + + const int max_iteration = 100; + for (int iteration = 0;; iteration++) { + /* Try generating random numbers until an unused one has been found. */ + const int random_id = rng.get_int32(); + if (used_unique_ids.add(random_id)) { + /* This random id is not used by another instance. */ + unique_ids[instance_index] = random_id; + break; + } + if (iteration == max_iteration) { + /* It seems to be very unlikely that we ever run into this case (assuming there are less + * than 2^30 instances). However, if that happens, it's better to use an id that is not + * unique than to be stuck in an infinite loop. */ + unique_ids[instance_index] = original_id; + break; + } + } + } + + return unique_ids; +} + +blender::Span<int> InstancesComponent::almost_unique_ids() const +{ + std::lock_guard lock(almost_unique_ids_mutex_); + if (almost_unique_ids_.size() != ids_.size()) { + almost_unique_ids_ = generate_unique_instance_ids(ids_); + } + return almost_unique_ids_; +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/geometry_component_mesh.cc b/source/blender/blenkernel/intern/geometry_component_mesh.cc new file mode 100644 index 00000000000..53defc89b7e --- /dev/null +++ b/source/blender/blenkernel/intern/geometry_component_mesh.cc @@ -0,0 +1,938 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "BLI_listbase.h" +#include "BLI_threads.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_object_types.h" + +#include "BKE_attribute_access.hh" +#include "BKE_attribute_math.hh" +#include "BKE_deform.h" +#include "BKE_geometry_set.hh" +#include "BKE_lib_id.h" +#include "BKE_mesh.h" + +#include "attribute_access_intern.hh" + +/* Can't include BKE_object_deform.h right now, due to an enum forward declaration. */ +extern "C" MDeformVert *BKE_object_defgroup_data_create(ID *id); + +using blender::bke::ReadAttributePtr; + +/* -------------------------------------------------------------------- */ +/** \name Geometry Component Implementation + * \{ */ + +MeshComponent::MeshComponent() : GeometryComponent(GeometryComponentType::Mesh) +{ +} + +MeshComponent::~MeshComponent() +{ + this->clear(); +} + +GeometryComponent *MeshComponent::copy() const +{ + MeshComponent *new_component = new MeshComponent(); + if (mesh_ != nullptr) { + new_component->mesh_ = BKE_mesh_copy_for_eval(mesh_, false); + new_component->ownership_ = GeometryOwnershipType::Owned; + new_component->vertex_group_names_ = blender::Map(vertex_group_names_); + } + return new_component; +} + +void MeshComponent::clear() +{ + BLI_assert(this->is_mutable()); + if (mesh_ != nullptr) { + if (ownership_ == GeometryOwnershipType::Owned) { + BKE_id_free(nullptr, mesh_); + } + mesh_ = nullptr; + } + vertex_group_names_.clear(); +} + +bool MeshComponent::has_mesh() const +{ + return mesh_ != nullptr; +} + +/* Clear the component and replace it with the new mesh. */ +void MeshComponent::replace(Mesh *mesh, GeometryOwnershipType ownership) +{ + BLI_assert(this->is_mutable()); + this->clear(); + mesh_ = mesh; + ownership_ = ownership; +} + +/* This function exists for the same reason as #vertex_group_names_. Non-nodes modifiers need to + * be able to replace the mesh data without losing the vertex group names, which may have come + * from another object. */ +void MeshComponent::replace_mesh_but_keep_vertex_group_names(Mesh *mesh, + GeometryOwnershipType ownership) +{ + BLI_assert(this->is_mutable()); + if (mesh_ != nullptr) { + if (ownership_ == GeometryOwnershipType::Owned) { + BKE_id_free(nullptr, mesh_); + } + mesh_ = nullptr; + } + mesh_ = mesh; + ownership_ = ownership; +} + +/* Return the mesh and clear the component. The caller takes over responsibility for freeing the + * mesh (if the component was responsible before). */ +Mesh *MeshComponent::release() +{ + BLI_assert(this->is_mutable()); + Mesh *mesh = mesh_; + mesh_ = nullptr; + return mesh; +} + +void MeshComponent::copy_vertex_group_names_from_object(const Object &object) +{ + BLI_assert(this->is_mutable()); + vertex_group_names_.clear(); + int index = 0; + LISTBASE_FOREACH (const bDeformGroup *, group, &object.defbase) { + vertex_group_names_.add(group->name, index); + index++; + } +} + +const blender::Map<std::string, int> &MeshComponent::vertex_group_names() const +{ + return vertex_group_names_; +} + +/* This is only exposed for the internal attribute API. */ +blender::Map<std::string, int> &MeshComponent::vertex_group_names() +{ + return vertex_group_names_; +} + +/* Get the mesh from this component. This method can be used by multiple threads at the same + * time. Therefore, the returned mesh should not be modified. No ownership is transferred. */ +const Mesh *MeshComponent::get_for_read() const +{ + return mesh_; +} + +/* Get the mesh from this component. This method can only be used when the component is mutable, + * i.e. it is not shared. The returned mesh can be modified. No ownership is transferred. */ +Mesh *MeshComponent::get_for_write() +{ + BLI_assert(this->is_mutable()); + if (ownership_ == GeometryOwnershipType::ReadOnly) { + mesh_ = BKE_mesh_copy_for_eval(mesh_, false); + ownership_ = GeometryOwnershipType::Owned; + } + return mesh_; +} + +bool MeshComponent::is_empty() const +{ + return mesh_ == nullptr; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Attribute Access + * \{ */ + +int MeshComponent::attribute_domain_size(const AttributeDomain domain) const +{ + BLI_assert(this->attribute_domain_supported(domain)); + if (mesh_ == nullptr) { + return 0; + } + switch (domain) { + case ATTR_DOMAIN_CORNER: + return mesh_->totloop; + case ATTR_DOMAIN_POINT: + return mesh_->totvert; + case ATTR_DOMAIN_EDGE: + return mesh_->totedge; + case ATTR_DOMAIN_POLYGON: + return mesh_->totpoly; + default: + BLI_assert(false); + break; + } + return 0; +} + +namespace blender::bke { + +template<typename T> +static void adapt_mesh_domain_corner_to_point_impl(const Mesh &mesh, + const TypedReadAttribute<T> &attribute, + MutableSpan<T> r_values) +{ + BLI_assert(r_values.size() == mesh.totvert); + attribute_math::DefaultMixer<T> mixer(r_values); + + for (const int loop_index : IndexRange(mesh.totloop)) { + const T value = attribute[loop_index]; + const MLoop &loop = mesh.mloop[loop_index]; + const int point_index = loop.v; + mixer.mix_in(point_index, value); + } + mixer.finalize(); +} + +static ReadAttributePtr adapt_mesh_domain_corner_to_point(const Mesh &mesh, + ReadAttributePtr attribute) +{ + ReadAttributePtr new_attribute; + const CustomDataType data_type = attribute->custom_data_type(); + attribute_math::convert_to_static_type(data_type, [&](auto dummy) { + using T = decltype(dummy); + if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { + /* We compute all interpolated values at once, because for this interpolation, one has to + * iterate over all loops anyway. */ + Array<T> values(mesh.totvert); + adapt_mesh_domain_corner_to_point_impl<T>(mesh, *attribute, values); + new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, + std::move(values)); + } + }); + return new_attribute; +} + +template<typename T> +static void adapt_mesh_domain_point_to_corner_impl(const Mesh &mesh, + const TypedReadAttribute<T> &attribute, + MutableSpan<T> r_values) +{ + BLI_assert(r_values.size() == mesh.totloop); + + for (const int loop_index : IndexRange(mesh.totloop)) { + const int vertex_index = mesh.mloop[loop_index].v; + r_values[loop_index] = attribute[vertex_index]; + } +} + +static ReadAttributePtr adapt_mesh_domain_point_to_corner(const Mesh &mesh, + ReadAttributePtr attribute) +{ + ReadAttributePtr new_attribute; + const CustomDataType data_type = attribute->custom_data_type(); + attribute_math::convert_to_static_type(data_type, [&](auto dummy) { + using T = decltype(dummy); + /* It is not strictly necessary to compute the value for all corners here. Instead one could + * lazily lookup the mesh topology when a specific index accessed. This can be more efficient + * when an algorithm only accesses very few of the corner values. However, for the algorithms + * we currently have, precomputing the array is fine. Also, it is easier to implement. */ + Array<T> values(mesh.totloop); + adapt_mesh_domain_point_to_corner_impl<T>(mesh, *attribute, values); + new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_CORNER, + std::move(values)); + }); + return new_attribute; +} + +/** + * \note Theoretically this interpolation does not need to compute all values at once. + * However, doing that makes the implementation simpler, and this can be optimized in the future if + * only some values are required. + */ +template<typename T> +static void adapt_mesh_domain_corner_to_polygon_impl(const Mesh &mesh, + Span<T> old_values, + MutableSpan<T> r_values) +{ + BLI_assert(r_values.size() == mesh.totpoly); + attribute_math::DefaultMixer<T> mixer(r_values); + + for (const int poly_index : IndexRange(mesh.totpoly)) { + const MPoly &poly = mesh.mpoly[poly_index]; + for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { + const T value = old_values[loop_index]; + mixer.mix_in(poly_index, value); + } + } + + mixer.finalize(); +} + +static ReadAttributePtr adapt_mesh_domain_corner_to_polygon(const Mesh &mesh, + ReadAttributePtr attribute) +{ + ReadAttributePtr new_attribute; + const CustomDataType data_type = attribute->custom_data_type(); + attribute_math::convert_to_static_type(data_type, [&](auto dummy) { + using T = decltype(dummy); + if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { + Array<T> values(mesh.totpoly); + adapt_mesh_domain_corner_to_polygon_impl<T>(mesh, attribute->get_span<T>(), values); + new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, + std::move(values)); + } + }); + return new_attribute; +} + +template<typename T> +void adapt_mesh_domain_polygon_to_point_impl(const Mesh &mesh, + Span<T> old_values, + MutableSpan<T> r_values) +{ + BLI_assert(r_values.size() == mesh.totvert); + attribute_math::DefaultMixer<T> mixer(r_values); + + for (const int poly_index : IndexRange(mesh.totpoly)) { + const MPoly &poly = mesh.mpoly[poly_index]; + const T value = old_values[poly_index]; + for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { + const MLoop &loop = mesh.mloop[loop_index]; + const int point_index = loop.v; + mixer.mix_in(point_index, value); + } + } + + mixer.finalize(); +} + +static ReadAttributePtr adapt_mesh_domain_polygon_to_point(const Mesh &mesh, + ReadAttributePtr attribute) +{ + ReadAttributePtr new_attribute; + const CustomDataType data_type = attribute->custom_data_type(); + attribute_math::convert_to_static_type(data_type, [&](auto dummy) { + using T = decltype(dummy); + if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { + Array<T> values(mesh.totvert); + adapt_mesh_domain_polygon_to_point_impl<T>(mesh, attribute->get_span<T>(), values); + new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, + std::move(values)); + } + }); + return new_attribute; +} + +template<typename T> +void adapt_mesh_domain_polygon_to_corner_impl(const Mesh &mesh, + const Span<T> old_values, + MutableSpan<T> r_values) +{ + BLI_assert(r_values.size() == mesh.totloop); + + for (const int poly_index : IndexRange(mesh.totpoly)) { + const MPoly &poly = mesh.mpoly[poly_index]; + MutableSpan<T> poly_corner_values = r_values.slice(poly.loopstart, poly.totloop); + poly_corner_values.fill(old_values[poly_index]); + } +} + +static ReadAttributePtr adapt_mesh_domain_polygon_to_corner(const Mesh &mesh, + ReadAttributePtr attribute) +{ + ReadAttributePtr new_attribute; + const CustomDataType data_type = attribute->custom_data_type(); + attribute_math::convert_to_static_type(data_type, [&](auto dummy) { + using T = decltype(dummy); + if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { + Array<T> values(mesh.totloop); + adapt_mesh_domain_polygon_to_corner_impl<T>(mesh, attribute->get_span<T>(), values); + new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, + std::move(values)); + } + }); + return new_attribute; +} + +/** + * \note Theoretically this interpolation does not need to compute all values at once. + * However, doing that makes the implementation simpler, and this can be optimized in the future if + * only some values are required. + */ +template<typename T> +static void adapt_mesh_domain_point_to_polygon_impl(const Mesh &mesh, + const Span<T> old_values, + MutableSpan<T> r_values) +{ + BLI_assert(r_values.size() == mesh.totpoly); + attribute_math::DefaultMixer<T> mixer(r_values); + + for (const int poly_index : IndexRange(mesh.totpoly)) { + const MPoly &poly = mesh.mpoly[poly_index]; + for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { + MLoop &loop = mesh.mloop[loop_index]; + const int point_index = loop.v; + mixer.mix_in(poly_index, old_values[point_index]); + } + } + mixer.finalize(); +} + +static ReadAttributePtr adapt_mesh_domain_point_to_polygon(const Mesh &mesh, + ReadAttributePtr attribute) +{ + ReadAttributePtr new_attribute; + const CustomDataType data_type = attribute->custom_data_type(); + attribute_math::convert_to_static_type(data_type, [&](auto dummy) { + using T = decltype(dummy); + if constexpr (!std::is_void_v<attribute_math::DefaultMixer<T>>) { + Array<T> values(mesh.totpoly); + adapt_mesh_domain_point_to_polygon_impl<T>(mesh, attribute->get_span<T>(), values); + new_attribute = std::make_unique<OwnedArrayReadAttribute<T>>(ATTR_DOMAIN_POINT, + std::move(values)); + } + }); + return new_attribute; +} + +} // namespace blender::bke + +ReadAttributePtr MeshComponent::attribute_try_adapt_domain(ReadAttributePtr attribute, + const AttributeDomain new_domain) const +{ + if (!attribute) { + return {}; + } + if (attribute->size() == 0) { + return {}; + } + const AttributeDomain old_domain = attribute->domain(); + if (old_domain == new_domain) { + return attribute; + } + + switch (old_domain) { + case ATTR_DOMAIN_CORNER: { + switch (new_domain) { + case ATTR_DOMAIN_POINT: + return blender::bke::adapt_mesh_domain_corner_to_point(*mesh_, std::move(attribute)); + case ATTR_DOMAIN_POLYGON: + return blender::bke::adapt_mesh_domain_corner_to_polygon(*mesh_, std::move(attribute)); + default: + break; + } + break; + } + case ATTR_DOMAIN_POINT: { + switch (new_domain) { + case ATTR_DOMAIN_CORNER: + return blender::bke::adapt_mesh_domain_point_to_corner(*mesh_, std::move(attribute)); + case ATTR_DOMAIN_POLYGON: + return blender::bke::adapt_mesh_domain_point_to_polygon(*mesh_, std::move(attribute)); + default: + break; + } + break; + } + case ATTR_DOMAIN_POLYGON: { + switch (new_domain) { + case ATTR_DOMAIN_POINT: + return blender::bke::adapt_mesh_domain_polygon_to_point(*mesh_, std::move(attribute)); + case ATTR_DOMAIN_CORNER: + return blender::bke::adapt_mesh_domain_polygon_to_corner(*mesh_, std::move(attribute)); + default: + break; + } + break; + } + default: + break; + } + + return {}; +} + +static Mesh *get_mesh_from_component_for_write(GeometryComponent &component) +{ + BLI_assert(component.type() == GeometryComponentType::Mesh); + MeshComponent &mesh_component = static_cast<MeshComponent &>(component); + return mesh_component.get_for_write(); +} + +static const Mesh *get_mesh_from_component_for_read(const GeometryComponent &component) +{ + BLI_assert(component.type() == GeometryComponentType::Mesh); + const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); + return mesh_component.get_for_read(); +} + +namespace blender::bke { + +static float3 get_vertex_position(const MVert &vert) +{ + return float3(vert.co); +} + +static void set_vertex_position(MVert &vert, const float3 &position) +{ + copy_v3_v3(vert.co, position); +} + +static ReadAttributePtr make_vertex_position_read_attribute(const void *data, + const int domain_size) +{ + return std::make_unique<DerivedArrayReadAttribute<MVert, float3, get_vertex_position>>( + ATTR_DOMAIN_POINT, Span<MVert>((const MVert *)data, domain_size)); +} + +static WriteAttributePtr make_vertex_position_write_attribute(void *data, const int domain_size) +{ + return std::make_unique< + DerivedArrayWriteAttribute<MVert, float3, get_vertex_position, set_vertex_position>>( + ATTR_DOMAIN_POINT, MutableSpan<MVert>((MVert *)data, domain_size)); +} + +static void tag_normals_dirty_when_writing_position(GeometryComponent &component) +{ + Mesh *mesh = get_mesh_from_component_for_write(component); + if (mesh != nullptr) { + mesh->runtime.cd_dirty_vert |= CD_MASK_NORMAL; + } +} + +static int get_material_index(const MPoly &mpoly) +{ + return static_cast<int>(mpoly.mat_nr); +} + +static void set_material_index(MPoly &mpoly, const int &index) +{ + mpoly.mat_nr = static_cast<short>(std::clamp(index, 0, SHRT_MAX)); +} + +static ReadAttributePtr make_material_index_read_attribute(const void *data, const int domain_size) +{ + return std::make_unique<DerivedArrayReadAttribute<MPoly, int, get_material_index>>( + ATTR_DOMAIN_POLYGON, Span<MPoly>((const MPoly *)data, domain_size)); +} + +static WriteAttributePtr make_material_index_write_attribute(void *data, const int domain_size) +{ + return std::make_unique< + DerivedArrayWriteAttribute<MPoly, int, get_material_index, set_material_index>>( + ATTR_DOMAIN_POLYGON, MutableSpan<MPoly>((MPoly *)data, domain_size)); +} + +static float3 get_vertex_normal(const MVert &vert) +{ + float3 result; + normal_short_to_float_v3(result, vert.no); + return result; +} + +static ReadAttributePtr make_vertex_normal_read_attribute(const void *data, const int domain_size) +{ + return std::make_unique<DerivedArrayReadAttribute<MVert, float3, get_vertex_normal>>( + ATTR_DOMAIN_POINT, Span<MVert>((const MVert *)data, domain_size)); +} + +static void update_vertex_normals_when_dirty(const GeometryComponent &component) +{ + const Mesh *mesh = get_mesh_from_component_for_read(component); + if (mesh == nullptr) { + return; + } + + /* Since normals are derived data, const write access to them is okay. However, ensure that + * two threads don't use write normals to a mesh at the same time. Note that this relies on + * the idempotence of the operation; calculating the normals just fills the MVert struct + * rather than allocating new memory. */ + if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) { + ThreadMutex *mesh_eval_mutex = (ThreadMutex *)mesh->runtime.eval_mutex; + BLI_mutex_lock(mesh_eval_mutex); + + /* Check again to avoid a second thread needlessly recalculating the same normals. */ + if (mesh->runtime.cd_dirty_vert & CD_MASK_NORMAL) { + BKE_mesh_calc_normals(const_cast<Mesh *>(mesh)); + } + + BLI_mutex_unlock(mesh_eval_mutex); + } +} + +static bool get_shade_smooth(const MPoly &mpoly) +{ + return mpoly.flag & ME_SMOOTH; +} + +static void set_shade_smooth(MPoly &mpoly, const bool &value) +{ + SET_FLAG_FROM_TEST(mpoly.flag, value, ME_SMOOTH); +} + +static ReadAttributePtr make_shade_smooth_read_attribute(const void *data, const int domain_size) +{ + return std::make_unique<DerivedArrayReadAttribute<MPoly, bool, get_shade_smooth>>( + ATTR_DOMAIN_POLYGON, Span<MPoly>((const MPoly *)data, domain_size)); +} + +static WriteAttributePtr make_shade_smooth_write_attribute(void *data, const int domain_size) +{ + return std::make_unique< + DerivedArrayWriteAttribute<MPoly, bool, get_shade_smooth, set_shade_smooth>>( + ATTR_DOMAIN_POLYGON, MutableSpan<MPoly>((MPoly *)data, domain_size)); +} + +static float2 get_loop_uv(const MLoopUV &uv) +{ + return float2(uv.uv); +} + +static void set_loop_uv(MLoopUV &uv, const float2 &co) +{ + copy_v2_v2(uv.uv, co); +} + +static ReadAttributePtr make_uvs_read_attribute(const void *data, const int domain_size) +{ + return std::make_unique<DerivedArrayReadAttribute<MLoopUV, float2, get_loop_uv>>( + ATTR_DOMAIN_CORNER, Span((const MLoopUV *)data, domain_size)); +} + +static WriteAttributePtr make_uvs_write_attribute(void *data, const int domain_size) +{ + return std::make_unique<DerivedArrayWriteAttribute<MLoopUV, float2, get_loop_uv, set_loop_uv>>( + ATTR_DOMAIN_CORNER, MutableSpan((MLoopUV *)data, domain_size)); +} + +static Color4f get_loop_color(const MLoopCol &col) +{ + Color4f value; + rgba_uchar_to_float(value, &col.r); + return value; +} + +static void set_loop_color(MLoopCol &col, const Color4f &value) +{ + rgba_float_to_uchar(&col.r, value); +} + +static ReadAttributePtr make_vertex_color_read_attribute(const void *data, const int domain_size) +{ + return std::make_unique<DerivedArrayReadAttribute<MLoopCol, Color4f, get_loop_color>>( + ATTR_DOMAIN_CORNER, Span((const MLoopCol *)data, domain_size)); +} + +static WriteAttributePtr make_vertex_color_write_attribute(void *data, const int domain_size) +{ + return std::make_unique< + DerivedArrayWriteAttribute<MLoopCol, Color4f, get_loop_color, set_loop_color>>( + ATTR_DOMAIN_CORNER, MutableSpan((MLoopCol *)data, domain_size)); +} + +class VertexWeightWriteAttribute final : public WriteAttribute { + private: + MDeformVert *dverts_; + const int dvert_index_; + + public: + VertexWeightWriteAttribute(MDeformVert *dverts, const int totvert, const int dvert_index) + : WriteAttribute(ATTR_DOMAIN_POINT, CPPType::get<float>(), totvert), + dverts_(dverts), + dvert_index_(dvert_index) + { + } + + void get_internal(const int64_t index, void *r_value) const override + { + get_internal(dverts_, dvert_index_, index, r_value); + } + + void set_internal(const int64_t index, const void *value) override + { + MDeformWeight *weight = BKE_defvert_ensure_index(&dverts_[index], dvert_index_); + weight->weight = *reinterpret_cast<const float *>(value); + } + + static void get_internal(const MDeformVert *dverts, + const int dvert_index, + const int64_t index, + void *r_value) + { + if (dverts == nullptr) { + *(float *)r_value = 0.0f; + return; + } + const MDeformVert &dvert = dverts[index]; + for (const MDeformWeight &weight : Span(dvert.dw, dvert.totweight)) { + if (weight.def_nr == dvert_index) { + *(float *)r_value = weight.weight; + return; + } + } + *(float *)r_value = 0.0f; + } +}; + +class VertexWeightReadAttribute final : public ReadAttribute { + private: + const MDeformVert *dverts_; + const int dvert_index_; + + public: + VertexWeightReadAttribute(const MDeformVert *dverts, const int totvert, const int dvert_index) + : ReadAttribute(ATTR_DOMAIN_POINT, CPPType::get<float>(), totvert), + dverts_(dverts), + dvert_index_(dvert_index) + { + } + + void get_internal(const int64_t index, void *r_value) const override + { + VertexWeightWriteAttribute::get_internal(dverts_, dvert_index_, index, r_value); + } +}; + +/** + * This provider makes vertex groups available as float attributes. + */ +class VertexGroupsAttributeProvider final : public DynamicAttributesProvider { + public: + ReadAttributePtr try_get_for_read(const GeometryComponent &component, + const StringRef attribute_name) const final + { + BLI_assert(component.type() == GeometryComponentType::Mesh); + const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); + const Mesh *mesh = mesh_component.get_for_read(); + const int vertex_group_index = mesh_component.vertex_group_names().lookup_default_as( + attribute_name, -1); + if (vertex_group_index < 0) { + return {}; + } + if (mesh == nullptr || mesh->dvert == nullptr) { + static const float default_value = 0.0f; + return std::make_unique<ConstantReadAttribute>( + ATTR_DOMAIN_POINT, mesh->totvert, CPPType::get<float>(), &default_value); + } + return std::make_unique<VertexWeightReadAttribute>( + mesh->dvert, mesh->totvert, vertex_group_index); + } + + WriteAttributePtr try_get_for_write(GeometryComponent &component, + const StringRef attribute_name) const final + { + BLI_assert(component.type() == GeometryComponentType::Mesh); + MeshComponent &mesh_component = static_cast<MeshComponent &>(component); + Mesh *mesh = mesh_component.get_for_write(); + if (mesh == nullptr) { + return {}; + } + const int vertex_group_index = mesh_component.vertex_group_names().lookup_default_as( + attribute_name, -1); + if (vertex_group_index < 0) { + return {}; + } + if (mesh->dvert == nullptr) { + BKE_object_defgroup_data_create(&mesh->id); + } + else { + /* Copy the data layer if it is shared with some other mesh. */ + mesh->dvert = (MDeformVert *)CustomData_duplicate_referenced_layer( + &mesh->vdata, CD_MDEFORMVERT, mesh->totvert); + } + return std::make_unique<blender::bke::VertexWeightWriteAttribute>( + mesh->dvert, mesh->totvert, vertex_group_index); + } + + bool try_delete(GeometryComponent &component, const StringRef attribute_name) const final + { + BLI_assert(component.type() == GeometryComponentType::Mesh); + MeshComponent &mesh_component = static_cast<MeshComponent &>(component); + + const int vertex_group_index = mesh_component.vertex_group_names().pop_default_as( + attribute_name, -1); + if (vertex_group_index < 0) { + return false; + } + Mesh *mesh = mesh_component.get_for_write(); + if (mesh == nullptr) { + return true; + } + if (mesh->dvert == nullptr) { + return true; + } + for (MDeformVert &dvert : MutableSpan(mesh->dvert, mesh->totvert)) { + MDeformWeight *weight = BKE_defvert_find_index(&dvert, vertex_group_index); + BKE_defvert_remove_group(&dvert, weight); + } + return true; + } + + bool foreach_attribute(const GeometryComponent &component, + const AttributeForeachCallback callback) const final + { + BLI_assert(component.type() == GeometryComponentType::Mesh); + const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component); + for (const auto item : mesh_component.vertex_group_names().items()) { + const StringRefNull name = item.key; + const int vertex_group_index = item.value; + if (vertex_group_index >= 0) { + AttributeMetaData meta_data{ATTR_DOMAIN_POINT, CD_PROP_FLOAT}; + if (!callback(name, meta_data)) { + return false; + } + } + } + return true; + } + + void supported_domains(Vector<AttributeDomain> &r_domains) const final + { + r_domains.append_non_duplicates(ATTR_DOMAIN_POINT); + } +}; + +/** + * In this function all the attribute providers for a mesh component are created. Most data in this + * function is statically allocated, because it does not change over time. + */ +static ComponentAttributeProviders create_attribute_providers_for_mesh() +{ + static auto update_custom_data_pointers = [](GeometryComponent &component) { + Mesh *mesh = get_mesh_from_component_for_write(component); + if (mesh != nullptr) { + BKE_mesh_update_customdata_pointers(mesh, false); + } + }; + +#define MAKE_MUTABLE_CUSTOM_DATA_GETTER(NAME) \ + [](GeometryComponent &component) -> CustomData * { \ + Mesh *mesh = get_mesh_from_component_for_write(component); \ + return mesh ? &mesh->NAME : nullptr; \ + } +#define MAKE_CONST_CUSTOM_DATA_GETTER(NAME) \ + [](const GeometryComponent &component) -> const CustomData * { \ + const Mesh *mesh = get_mesh_from_component_for_read(component); \ + return mesh ? &mesh->NAME : nullptr; \ + } + + static CustomDataAccessInfo corner_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(ldata), + MAKE_CONST_CUSTOM_DATA_GETTER(ldata), + update_custom_data_pointers}; + static CustomDataAccessInfo point_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(vdata), + MAKE_CONST_CUSTOM_DATA_GETTER(vdata), + update_custom_data_pointers}; + static CustomDataAccessInfo edge_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(edata), + MAKE_CONST_CUSTOM_DATA_GETTER(edata), + update_custom_data_pointers}; + static CustomDataAccessInfo polygon_access = {MAKE_MUTABLE_CUSTOM_DATA_GETTER(pdata), + MAKE_CONST_CUSTOM_DATA_GETTER(pdata), + update_custom_data_pointers}; + +#undef MAKE_CONST_CUSTOM_DATA_GETTER +#undef MAKE_MUTABLE_CUSTOM_DATA_GETTER + + static BuiltinCustomDataLayerProvider position("position", + ATTR_DOMAIN_POINT, + CD_PROP_FLOAT3, + CD_MVERT, + BuiltinAttributeProvider::NonCreatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::NonDeletable, + point_access, + make_vertex_position_read_attribute, + make_vertex_position_write_attribute, + nullptr, + tag_normals_dirty_when_writing_position); + + static BuiltinCustomDataLayerProvider material_index("material_index", + ATTR_DOMAIN_POLYGON, + CD_PROP_INT32, + CD_MPOLY, + BuiltinAttributeProvider::NonCreatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::NonDeletable, + polygon_access, + make_material_index_read_attribute, + make_material_index_write_attribute, + nullptr, + nullptr); + + static BuiltinCustomDataLayerProvider shade_smooth("shade_smooth", + ATTR_DOMAIN_POLYGON, + CD_PROP_BOOL, + CD_MPOLY, + BuiltinAttributeProvider::NonCreatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::NonDeletable, + polygon_access, + make_shade_smooth_read_attribute, + make_shade_smooth_write_attribute, + nullptr, + nullptr); + + static BuiltinCustomDataLayerProvider vertex_normal("vertex_normal", + ATTR_DOMAIN_POINT, + CD_PROP_FLOAT3, + CD_MVERT, + BuiltinAttributeProvider::NonCreatable, + BuiltinAttributeProvider::Readonly, + BuiltinAttributeProvider::NonDeletable, + point_access, + make_vertex_normal_read_attribute, + nullptr, + update_vertex_normals_when_dirty, + nullptr); + + static NamedLegacyCustomDataProvider uvs(ATTR_DOMAIN_CORNER, + CD_PROP_FLOAT2, + CD_MLOOPUV, + corner_access, + make_uvs_read_attribute, + make_uvs_write_attribute); + + static NamedLegacyCustomDataProvider vertex_colors(ATTR_DOMAIN_CORNER, + CD_PROP_COLOR, + CD_MLOOPCOL, + corner_access, + make_vertex_color_read_attribute, + make_vertex_color_write_attribute); + + static VertexGroupsAttributeProvider vertex_groups; + static CustomDataAttributeProvider corner_custom_data(ATTR_DOMAIN_CORNER, corner_access); + static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access); + static CustomDataAttributeProvider edge_custom_data(ATTR_DOMAIN_EDGE, edge_access); + static CustomDataAttributeProvider polygon_custom_data(ATTR_DOMAIN_POLYGON, polygon_access); + + return ComponentAttributeProviders({&position, &material_index, &vertex_normal, &shade_smooth}, + {&uvs, + &vertex_colors, + &corner_custom_data, + &vertex_groups, + &point_custom_data, + &edge_custom_data, + &polygon_custom_data}); +} + +} // namespace blender::bke + +const blender::bke::ComponentAttributeProviders *MeshComponent::get_attribute_providers() const +{ + static blender::bke::ComponentAttributeProviders providers = + blender::bke::create_attribute_providers_for_mesh(); + return &providers; +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/geometry_component_pointcloud.cc b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc new file mode 100644 index 00000000000..d7f0bf55bc9 --- /dev/null +++ b/source/blender/blenkernel/intern/geometry_component_pointcloud.cc @@ -0,0 +1,207 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "DNA_pointcloud_types.h" + +#include "BKE_attribute_access.hh" +#include "BKE_geometry_set.hh" +#include "BKE_lib_id.h" +#include "BKE_pointcloud.h" + +#include "attribute_access_intern.hh" + +/* -------------------------------------------------------------------- */ +/** \name Geometry Component Implementation + * \{ */ + +PointCloudComponent::PointCloudComponent() : GeometryComponent(GeometryComponentType::PointCloud) +{ +} + +PointCloudComponent::~PointCloudComponent() +{ + this->clear(); +} + +GeometryComponent *PointCloudComponent::copy() const +{ + PointCloudComponent *new_component = new PointCloudComponent(); + if (pointcloud_ != nullptr) { + new_component->pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false); + new_component->ownership_ = GeometryOwnershipType::Owned; + } + return new_component; +} + +void PointCloudComponent::clear() +{ + BLI_assert(this->is_mutable()); + if (pointcloud_ != nullptr) { + if (ownership_ == GeometryOwnershipType::Owned) { + BKE_id_free(nullptr, pointcloud_); + } + pointcloud_ = nullptr; + } +} + +bool PointCloudComponent::has_pointcloud() const +{ + return pointcloud_ != nullptr; +} + +/* Clear the component and replace it with the new point cloud. */ +void PointCloudComponent::replace(PointCloud *pointcloud, GeometryOwnershipType ownership) +{ + BLI_assert(this->is_mutable()); + this->clear(); + pointcloud_ = pointcloud; + ownership_ = ownership; +} + +/* Return the point cloud and clear the component. The caller takes over responsibility for freeing + * the point cloud (if the component was responsible before). */ +PointCloud *PointCloudComponent::release() +{ + BLI_assert(this->is_mutable()); + PointCloud *pointcloud = pointcloud_; + pointcloud_ = nullptr; + return pointcloud; +} + +/* Get the point cloud from this component. This method can be used by multiple threads at the same + * time. Therefore, the returned point cloud should not be modified. No ownership is transferred. + */ +const PointCloud *PointCloudComponent::get_for_read() const +{ + return pointcloud_; +} + +/* Get the point cloud from this component. This method can only be used when the component is + * mutable, i.e. it is not shared. The returned point cloud can be modified. No ownership is + * transferred. */ +PointCloud *PointCloudComponent::get_for_write() +{ + BLI_assert(this->is_mutable()); + if (ownership_ == GeometryOwnershipType::ReadOnly) { + pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false); + ownership_ = GeometryOwnershipType::Owned; + } + return pointcloud_; +} + +bool PointCloudComponent::is_empty() const +{ + return pointcloud_ == nullptr; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Attribute Access + * \{ */ + +int PointCloudComponent::attribute_domain_size(const AttributeDomain domain) const +{ + BLI_assert(domain == ATTR_DOMAIN_POINT); + UNUSED_VARS_NDEBUG(domain); + if (pointcloud_ == nullptr) { + return 0; + } + return pointcloud_->totpoint; +} + +namespace blender::bke { + +template<typename T, AttributeDomain Domain> +static ReadAttributePtr make_array_read_attribute(const void *data, const int domain_size) +{ + return std::make_unique<ArrayReadAttribute<T>>(Domain, Span<T>((const T *)data, domain_size)); +} + +template<typename T, AttributeDomain Domain> +static WriteAttributePtr make_array_write_attribute(void *data, const int domain_size) +{ + return std::make_unique<ArrayWriteAttribute<T>>(Domain, MutableSpan<T>((T *)data, domain_size)); +} + +/** + * In this function all the attribute providers for a point cloud component are created. Most data + * in this function is statically allocated, because it does not change over time. + */ +static ComponentAttributeProviders create_attribute_providers_for_point_cloud() +{ + static auto update_custom_data_pointers = [](GeometryComponent &component) { + PointCloudComponent &pointcloud_component = static_cast<PointCloudComponent &>(component); + PointCloud *pointcloud = pointcloud_component.get_for_write(); + if (pointcloud != nullptr) { + BKE_pointcloud_update_customdata_pointers(pointcloud); + } + }; + static CustomDataAccessInfo point_access = { + [](GeometryComponent &component) -> CustomData * { + PointCloudComponent &pointcloud_component = static_cast<PointCloudComponent &>(component); + PointCloud *pointcloud = pointcloud_component.get_for_write(); + return pointcloud ? &pointcloud->pdata : nullptr; + }, + [](const GeometryComponent &component) -> const CustomData * { + const PointCloudComponent &pointcloud_component = static_cast<const PointCloudComponent &>( + component); + const PointCloud *pointcloud = pointcloud_component.get_for_read(); + return pointcloud ? &pointcloud->pdata : nullptr; + }, + update_custom_data_pointers}; + + static BuiltinCustomDataLayerProvider position( + "position", + ATTR_DOMAIN_POINT, + CD_PROP_FLOAT3, + CD_PROP_FLOAT3, + BuiltinAttributeProvider::NonCreatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::NonDeletable, + point_access, + make_array_read_attribute<float3, ATTR_DOMAIN_POINT>, + make_array_write_attribute<float3, ATTR_DOMAIN_POINT>, + nullptr, + nullptr); + static BuiltinCustomDataLayerProvider radius( + "radius", + ATTR_DOMAIN_POINT, + CD_PROP_FLOAT, + CD_PROP_FLOAT, + BuiltinAttributeProvider::Creatable, + BuiltinAttributeProvider::Writable, + BuiltinAttributeProvider::Deletable, + point_access, + make_array_read_attribute<float, ATTR_DOMAIN_POINT>, + make_array_write_attribute<float, ATTR_DOMAIN_POINT>, + nullptr, + nullptr); + static CustomDataAttributeProvider point_custom_data(ATTR_DOMAIN_POINT, point_access); + return ComponentAttributeProviders({&position, &radius}, {&point_custom_data}); +} + +} // namespace blender::bke + +const blender::bke::ComponentAttributeProviders *PointCloudComponent::get_attribute_providers() + const +{ + static blender::bke::ComponentAttributeProviders providers = + blender::bke::create_attribute_providers_for_point_cloud(); + return &providers; +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/geometry_component_volume.cc b/source/blender/blenkernel/intern/geometry_component_volume.cc new file mode 100644 index 00000000000..5e35a10fe3d --- /dev/null +++ b/source/blender/blenkernel/intern/geometry_component_volume.cc @@ -0,0 +1,100 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "DNA_volume_types.h" + +#include "BKE_geometry_set.hh" +#include "BKE_lib_id.h" +#include "BKE_volume.h" + +/* -------------------------------------------------------------------- */ +/** \name Geometry Component Implementation + * \{ */ + +VolumeComponent::VolumeComponent() : GeometryComponent(GeometryComponentType::Volume) +{ +} + +VolumeComponent::~VolumeComponent() +{ + this->clear(); +} + +GeometryComponent *VolumeComponent::copy() const +{ + VolumeComponent *new_component = new VolumeComponent(); + if (volume_ != nullptr) { + new_component->volume_ = BKE_volume_copy_for_eval(volume_, false); + new_component->ownership_ = GeometryOwnershipType::Owned; + } + return new_component; +} + +void VolumeComponent::clear() +{ + BLI_assert(this->is_mutable()); + if (volume_ != nullptr) { + if (ownership_ == GeometryOwnershipType::Owned) { + BKE_id_free(nullptr, volume_); + } + volume_ = nullptr; + } +} + +bool VolumeComponent::has_volume() const +{ + return volume_ != nullptr; +} + +/* Clear the component and replace it with the new volume. */ +void VolumeComponent::replace(Volume *volume, GeometryOwnershipType ownership) +{ + BLI_assert(this->is_mutable()); + this->clear(); + volume_ = volume; + ownership_ = ownership; +} + +/* Return the volume and clear the component. The caller takes over responsibility for freeing the + * volume (if the component was responsible before). */ +Volume *VolumeComponent::release() +{ + BLI_assert(this->is_mutable()); + Volume *volume = volume_; + volume_ = nullptr; + return volume; +} + +/* Get the volume from this component. This method can be used by multiple threads at the same + * time. Therefore, the returned volume should not be modified. No ownership is transferred. */ +const Volume *VolumeComponent::get_for_read() const +{ + return volume_; +} + +/* Get the volume from this component. This method can only be used when the component is mutable, + * i.e. it is not shared. The returned volume can be modified. No ownership is transferred. */ +Volume *VolumeComponent::get_for_write() +{ + BLI_assert(this->is_mutable()); + if (ownership_ == GeometryOwnershipType::ReadOnly) { + volume_ = BKE_volume_copy_for_eval(volume_, false); + ownership_ = GeometryOwnershipType::Owned; + } + return volume_; +} + +/** \} */ diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc index 0274dfdbd1c..e7fb184023d 100644 --- a/source/blender/blenkernel/intern/geometry_set.cc +++ b/source/blender/blenkernel/intern/geometry_set.cc @@ -311,437 +311,6 @@ Volume *GeometrySet::get_volume_for_write() /** \} */ /* -------------------------------------------------------------------- */ -/** \name Mesh Component - * \{ */ - -MeshComponent::MeshComponent() : GeometryComponent(GeometryComponentType::Mesh) -{ -} - -MeshComponent::~MeshComponent() -{ - this->clear(); -} - -GeometryComponent *MeshComponent::copy() const -{ - MeshComponent *new_component = new MeshComponent(); - if (mesh_ != nullptr) { - new_component->mesh_ = BKE_mesh_copy_for_eval(mesh_, false); - new_component->ownership_ = GeometryOwnershipType::Owned; - new_component->vertex_group_names_ = blender::Map(vertex_group_names_); - } - return new_component; -} - -void MeshComponent::clear() -{ - BLI_assert(this->is_mutable()); - if (mesh_ != nullptr) { - if (ownership_ == GeometryOwnershipType::Owned) { - BKE_id_free(nullptr, mesh_); - } - mesh_ = nullptr; - } - vertex_group_names_.clear(); -} - -bool MeshComponent::has_mesh() const -{ - return mesh_ != nullptr; -} - -/* Clear the component and replace it with the new mesh. */ -void MeshComponent::replace(Mesh *mesh, GeometryOwnershipType ownership) -{ - BLI_assert(this->is_mutable()); - this->clear(); - mesh_ = mesh; - ownership_ = ownership; -} - -/* This function exists for the same reason as #vertex_group_names_. Non-nodes modifiers need to - * be able to replace the mesh data without losing the vertex group names, which may have come - * from another object. */ -void MeshComponent::replace_mesh_but_keep_vertex_group_names(Mesh *mesh, - GeometryOwnershipType ownership) -{ - BLI_assert(this->is_mutable()); - if (mesh_ != nullptr) { - if (ownership_ == GeometryOwnershipType::Owned) { - BKE_id_free(nullptr, mesh_); - } - mesh_ = nullptr; - } - mesh_ = mesh; - ownership_ = ownership; -} - -/* Return the mesh and clear the component. The caller takes over responsibility for freeing the - * mesh (if the component was responsible before). */ -Mesh *MeshComponent::release() -{ - BLI_assert(this->is_mutable()); - Mesh *mesh = mesh_; - mesh_ = nullptr; - return mesh; -} - -void MeshComponent::copy_vertex_group_names_from_object(const Object &object) -{ - BLI_assert(this->is_mutable()); - vertex_group_names_.clear(); - int index = 0; - LISTBASE_FOREACH (const bDeformGroup *, group, &object.defbase) { - vertex_group_names_.add(group->name, index); - index++; - } -} - -const blender::Map<std::string, int> &MeshComponent::vertex_group_names() const -{ - return vertex_group_names_; -} - -/* This is only exposed for the internal attribute API. */ -blender::Map<std::string, int> &MeshComponent::vertex_group_names() -{ - return vertex_group_names_; -} - -/* Get the mesh from this component. This method can be used by multiple threads at the same - * time. Therefore, the returned mesh should not be modified. No ownership is transferred. */ -const Mesh *MeshComponent::get_for_read() const -{ - return mesh_; -} - -/* Get the mesh from this component. This method can only be used when the component is mutable, - * i.e. it is not shared. The returned mesh can be modified. No ownership is transferred. */ -Mesh *MeshComponent::get_for_write() -{ - BLI_assert(this->is_mutable()); - if (ownership_ == GeometryOwnershipType::ReadOnly) { - mesh_ = BKE_mesh_copy_for_eval(mesh_, false); - ownership_ = GeometryOwnershipType::Owned; - } - return mesh_; -} - -bool MeshComponent::is_empty() const -{ - return mesh_ == nullptr; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Pointcloud Component - * \{ */ - -PointCloudComponent::PointCloudComponent() : GeometryComponent(GeometryComponentType::PointCloud) -{ -} - -PointCloudComponent::~PointCloudComponent() -{ - this->clear(); -} - -GeometryComponent *PointCloudComponent::copy() const -{ - PointCloudComponent *new_component = new PointCloudComponent(); - if (pointcloud_ != nullptr) { - new_component->pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false); - new_component->ownership_ = GeometryOwnershipType::Owned; - } - return new_component; -} - -void PointCloudComponent::clear() -{ - BLI_assert(this->is_mutable()); - if (pointcloud_ != nullptr) { - if (ownership_ == GeometryOwnershipType::Owned) { - BKE_id_free(nullptr, pointcloud_); - } - pointcloud_ = nullptr; - } -} - -bool PointCloudComponent::has_pointcloud() const -{ - return pointcloud_ != nullptr; -} - -/* Clear the component and replace it with the new point cloud. */ -void PointCloudComponent::replace(PointCloud *pointcloud, GeometryOwnershipType ownership) -{ - BLI_assert(this->is_mutable()); - this->clear(); - pointcloud_ = pointcloud; - ownership_ = ownership; -} - -/* Return the point cloud and clear the component. The caller takes over responsibility for freeing - * the point cloud (if the component was responsible before). */ -PointCloud *PointCloudComponent::release() -{ - BLI_assert(this->is_mutable()); - PointCloud *pointcloud = pointcloud_; - pointcloud_ = nullptr; - return pointcloud; -} - -/* Get the point cloud from this component. This method can be used by multiple threads at the same - * time. Therefore, the returned point cloud should not be modified. No ownership is transferred. - */ -const PointCloud *PointCloudComponent::get_for_read() const -{ - return pointcloud_; -} - -/* Get the point cloud from this component. This method can only be used when the component is - * mutable, i.e. it is not shared. The returned point cloud can be modified. No ownership is - * transferred. */ -PointCloud *PointCloudComponent::get_for_write() -{ - BLI_assert(this->is_mutable()); - if (ownership_ == GeometryOwnershipType::ReadOnly) { - pointcloud_ = BKE_pointcloud_copy_for_eval(pointcloud_, false); - ownership_ = GeometryOwnershipType::Owned; - } - return pointcloud_; -} - -bool PointCloudComponent::is_empty() const -{ - return pointcloud_ == nullptr; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Instances Component - * \{ */ - -InstancesComponent::InstancesComponent() : GeometryComponent(GeometryComponentType::Instances) -{ -} - -GeometryComponent *InstancesComponent::copy() const -{ - InstancesComponent *new_component = new InstancesComponent(); - new_component->transforms_ = transforms_; - new_component->instanced_data_ = instanced_data_; - return new_component; -} - -void InstancesComponent::clear() -{ - instanced_data_.clear(); - transforms_.clear(); -} - -void InstancesComponent::add_instance(Object *object, float4x4 transform, const int id) -{ - InstancedData data; - data.type = INSTANCE_DATA_TYPE_OBJECT; - data.data.object = object; - this->add_instance(data, transform, id); -} - -void InstancesComponent::add_instance(Collection *collection, float4x4 transform, const int id) -{ - InstancedData data; - data.type = INSTANCE_DATA_TYPE_COLLECTION; - data.data.collection = collection; - this->add_instance(data, transform, id); -} - -void InstancesComponent::add_instance(InstancedData data, float4x4 transform, const int id) -{ - instanced_data_.append(data); - transforms_.append(transform); - ids_.append(id); -} - -Span<InstancedData> InstancesComponent::instanced_data() const -{ - return instanced_data_; -} - -Span<float4x4> InstancesComponent::transforms() const -{ - return transforms_; -} - -Span<int> InstancesComponent::ids() const -{ - return ids_; -} - -MutableSpan<float4x4> InstancesComponent::transforms() -{ - return transforms_; -} - -int InstancesComponent::instances_amount() const -{ - const int size = instanced_data_.size(); - BLI_assert(transforms_.size() == size); - return size; -} - -bool InstancesComponent::is_empty() const -{ - return transforms_.size() == 0; -} - -static blender::Array<int> generate_unique_instance_ids(Span<int> original_ids) -{ - using namespace blender; - Array<int> unique_ids(original_ids.size()); - - Set<int> used_unique_ids; - used_unique_ids.reserve(original_ids.size()); - Vector<int> instances_with_id_collision; - for (const int instance_index : original_ids.index_range()) { - const int original_id = original_ids[instance_index]; - if (used_unique_ids.add(original_id)) { - /* The original id has not been used by another instance yet. */ - unique_ids[instance_index] = original_id; - } - else { - /* The original id of this instance collided with a previous instance, it needs to be looked - * at again in a second pass. Don't generate a new random id here, because this might collide - * with other existing ids. */ - instances_with_id_collision.append(instance_index); - } - } - - Map<int, RandomNumberGenerator> generator_by_original_id; - for (const int instance_index : instances_with_id_collision) { - const int original_id = original_ids[instance_index]; - RandomNumberGenerator &rng = generator_by_original_id.lookup_or_add_cb(original_id, [&]() { - RandomNumberGenerator rng; - rng.seed_random(original_id); - return rng; - }); - - const int max_iteration = 100; - for (int iteration = 0;; iteration++) { - /* Try generating random numbers until an unused one has been found. */ - const int random_id = rng.get_int32(); - if (used_unique_ids.add(random_id)) { - /* This random id is not used by another instance. */ - unique_ids[instance_index] = random_id; - break; - } - if (iteration == max_iteration) { - /* It seems to be very unlikely that we ever run into this case (assuming there are less - * than 2^30 instances). However, if that happens, it's better to use an id that is not - * unique than to be stuck in an infinite loop. */ - unique_ids[instance_index] = original_id; - break; - } - } - } - - return unique_ids; -} - -blender::Span<int> InstancesComponent::almost_unique_ids() const -{ - std::lock_guard lock(almost_unique_ids_mutex_); - if (almost_unique_ids_.size() != ids_.size()) { - almost_unique_ids_ = generate_unique_instance_ids(ids_); - } - return almost_unique_ids_; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Volume Component - * \{ */ - -VolumeComponent::VolumeComponent() : GeometryComponent(GeometryComponentType::Volume) -{ -} - -VolumeComponent::~VolumeComponent() -{ - this->clear(); -} - -GeometryComponent *VolumeComponent::copy() const -{ - VolumeComponent *new_component = new VolumeComponent(); - if (volume_ != nullptr) { - new_component->volume_ = BKE_volume_copy_for_eval(volume_, false); - new_component->ownership_ = GeometryOwnershipType::Owned; - } - return new_component; -} - -void VolumeComponent::clear() -{ - BLI_assert(this->is_mutable()); - if (volume_ != nullptr) { - if (ownership_ == GeometryOwnershipType::Owned) { - BKE_id_free(nullptr, volume_); - } - volume_ = nullptr; - } -} - -bool VolumeComponent::has_volume() const -{ - return volume_ != nullptr; -} - -/* Clear the component and replace it with the new volume. */ -void VolumeComponent::replace(Volume *volume, GeometryOwnershipType ownership) -{ - BLI_assert(this->is_mutable()); - this->clear(); - volume_ = volume; - ownership_ = ownership; -} - -/* Return the volume and clear the component. The caller takes over responsibility for freeing the - * volume (if the component was responsible before). */ -Volume *VolumeComponent::release() -{ - BLI_assert(this->is_mutable()); - Volume *volume = volume_; - volume_ = nullptr; - return volume; -} - -/* Get the volume from this component. This method can be used by multiple threads at the same - * time. Therefore, the returned volume should not be modified. No ownership is transferred. */ -const Volume *VolumeComponent::get_for_read() const -{ - return volume_; -} - -/* Get the volume from this component. This method can only be used when the component is mutable, - * i.e. it is not shared. The returned volume can be modified. No ownership is transferred. */ -Volume *VolumeComponent::get_for_write() -{ - BLI_assert(this->is_mutable()); - if (ownership_ == GeometryOwnershipType::ReadOnly) { - volume_ = BKE_volume_copy_for_eval(volume_, false); - ownership_ = GeometryOwnershipType::Owned; - } - return volume_; -} - -/** \} */ - -/* -------------------------------------------------------------------- */ /** \name C API * \{ */ diff --git a/source/blender/blenkernel/intern/geometry_set_instances.cc b/source/blender/blenkernel/intern/geometry_set_instances.cc index 1a260c5d48e..f3006385da3 100644 --- a/source/blender/blenkernel/intern/geometry_set_instances.cc +++ b/source/blender/blenkernel/intern/geometry_set_instances.cc @@ -378,7 +378,10 @@ static void join_instance_groups_mesh(Span<GeometryInstanceGroup> set_groups, /* Don't copy attributes that are stored directly in the mesh data structs. */ Map<std::string, AttributeKind> attributes; - gather_attribute_info(attributes, component_types, set_groups, {"position", "material_index"}); + gather_attribute_info(attributes, + component_types, + set_groups, + {"position", "material_index", "vertex_normal", "shade_smooth"}); join_attributes( set_groups, component_types, attributes, static_cast<GeometryComponent &>(dst_component)); } diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c index a511c1f9c4c..af921307bfb 100644 --- a/source/blender/blenkernel/intern/lib_id.c +++ b/source/blender/blenkernel/intern/lib_id.c @@ -171,7 +171,9 @@ static void lib_id_clear_library_data_ex(Main *bmain, ID *id) /* Conceptually, an ID made local is not the same as the linked one anymore. Reflect that by * regenerating its session UUID. */ - BKE_lib_libblock_session_uuid_renew(id); + if ((id->tag & LIB_TAG_TEMP_MAIN) == 0) { + BKE_lib_libblock_session_uuid_renew(id); + } /* We need to tag this IDs and all of its users, conceptually new local ID and original linked * ones are two completely different data-blocks that were virtually remapped, even though in @@ -1139,6 +1141,7 @@ static uint global_session_uuid = 0; void BKE_lib_libblock_session_uuid_ensure(ID *id) { if (id->session_uuid == MAIN_ID_SESSION_UUID_UNSET) { + BLI_assert((id->tag & LIB_TAG_TEMP_MAIN) == 0); /* Caller must ensure this. */ id->session_uuid = atomic_add_and_fetch_uint32(&global_session_uuid, 1); /* In case overflow happens, still assign a valid ID. This way opening files many times works * correctly. */ diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index 602c560cedd..702d718f2b9 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -24,6 +24,8 @@ #include <stdlib.h> #include <string.h> +#include "CLG_log.h" + #include "MEM_guardedalloc.h" #include "DNA_ID.h" @@ -66,6 +68,8 @@ # include "PIL_time_utildefines.h" #endif +static CLG_LogRef LOG = {"bke.liboverride"}; + static void lib_override_library_property_copy(IDOverrideLibraryProperty *op_dst, IDOverrideLibraryProperty *op_src); static void lib_override_library_property_operation_copy( @@ -1557,17 +1561,15 @@ bool BKE_lib_override_library_operations_create(Main *bmain, ID *local) created = true; } -#ifndef NDEBUG if (report_flags & RNA_OVERRIDE_MATCH_RESULT_RESTORED) { - printf("We did restore some properties of %s from its reference.\n", local->name); + CLOG_INFO(&LOG, 2, "We did restore some properties of %s from its reference", local->name); } if (report_flags & RNA_OVERRIDE_MATCH_RESULT_CREATED) { - printf("We did generate library override rules for %s\n", local->name); + CLOG_INFO(&LOG, 2, "We did generate library override rules for %s", local->name); } else { - printf("No new library override rules for %s\n", local->name); + CLOG_INFO(&LOG, 2, "No new library override rules for %s", local->name); } -#endif } return created; } diff --git a/source/blender/blenkernel/intern/mesh_boolean_convert.cc b/source/blender/blenkernel/intern/mesh_boolean_convert.cc index d9564f91a04..61c9f74531d 100644 --- a/source/blender/blenkernel/intern/mesh_boolean_convert.cc +++ b/source/blender/blenkernel/intern/mesh_boolean_convert.cc @@ -611,6 +611,9 @@ static void copy_or_interp_loop_attributes(Mesh *dest_mesh, * A non bmesh version could have the benefit of not copying data into src_blocks_ofs - * using the contiguous data instead. TODO: add to the custom data API. */ int target_layer_type_index = CustomData_get_named_layer(target_cd, ty, name); + if (!CustomData_layer_has_interp(source_cd, source_layer_i)) { + continue; + } int source_layer_type_index = source_layer_i - source_cd->typemap[ty]; BLI_assert(target_layer_type_index != -1 && source_layer_type_index >= 0); for (int j = 0; j < orig_mp->totloop; ++j) { @@ -759,6 +762,7 @@ static Mesh *imesh_to_mesh(IMesh *im, MeshesToIMeshInfo &mim) static Mesh *direct_mesh_boolean(Span<const Mesh *> meshes, Span<const float4x4 *> obmats, const bool use_self, + const bool hole_tolerant, const BoolOpType boolean_mode) { const int dbg_level = 0; @@ -781,7 +785,8 @@ static Mesh *direct_mesh_boolean(Span<const Mesh *> meshes, } return static_cast<int>(mim.mesh_poly_offset.size()) - 1; }; - IMesh m_out = boolean_mesh(m_in, boolean_mode, meshes_len, shape_fn, use_self, nullptr, &arena); + IMesh m_out = boolean_mesh( + m_in, boolean_mode, meshes_len, shape_fn, use_self, hole_tolerant, nullptr, &arena); if (dbg_level > 1) { std::cout << m_out; write_obj_mesh(m_out, "m_out"); @@ -805,6 +810,7 @@ Mesh *BKE_mesh_boolean(const Mesh **meshes, const float (*obmats[])[4][4], const int meshes_len, const bool use_self, + const bool hole_tolerant, const int boolean_mode) { const blender::float4x4 **transforms = (const blender::float4x4 **)obmats; @@ -812,6 +818,7 @@ Mesh *BKE_mesh_boolean(const Mesh **meshes, blender::Span(meshes, meshes_len), blender::Span(transforms, meshes_len), use_self, + hole_tolerant, static_cast<blender::meshintersect::BoolOpType>(boolean_mode)); } @@ -820,6 +827,7 @@ Mesh *BKE_mesh_boolean(const Mesh **UNUSED(meshes), const float (*obmats[])[4][4], const int UNUSED(meshes_len), const bool UNUSED(use_self), + const bool UNUSED(hole_tolerant), const int UNUSED(boolean_mode)) { UNUSED_VARS(obmats); diff --git a/source/blender/blenkernel/intern/node.cc b/source/blender/blenkernel/intern/node.cc index 55cb0d5cce4..9615fbc31e7 100644 --- a/source/blender/blenkernel/intern/node.cc +++ b/source/blender/blenkernel/intern/node.cc @@ -540,18 +540,11 @@ void ntreeBlendWrite(BlendWriter *writer, bNodeTree *ntree) } else if ((ntree->type == NTREE_COMPOSIT) && (node->type == CMP_NODE_CRYPTOMATTE)) { NodeCryptomatte *nc = (NodeCryptomatte *)node->storage; - /* Update the matte_id so the files can be opened in versions that don't - * use `CryptomatteEntry`. */ - MEM_SAFE_FREE(nc->matte_id); - nc->matte_id = BKE_cryptomatte_entries_to_matte_id(nc); - if (nc->matte_id) { - BLO_write_string(writer, nc->matte_id); - } + BLO_write_string(writer, nc->matte_id); LISTBASE_FOREACH (CryptomatteEntry *, entry, &nc->entries) { BLO_write_struct(writer, CryptomatteEntry, entry); } BLO_write_struct_by_name(writer, node->typeinfo->storagename, node->storage); - MEM_SAFE_FREE(nc->matte_id); } else if (node->type == FN_NODE_INPUT_STRING) { NodeInputString *storage = (NodeInputString *)node->storage; @@ -4482,18 +4475,18 @@ void node_type_group_update(struct bNodeType *ntype, } void node_type_exec(struct bNodeType *ntype, - NodeInitExecFunction initexecfunc, - NodeFreeExecFunction freeexecfunc, - NodeExecFunction execfunc) + NodeInitExecFunction init_exec_fn, + NodeFreeExecFunction free_exec_fn, + NodeExecFunction exec_fn) { - ntype->initexecfunc = initexecfunc; - ntype->freeexecfunc = freeexecfunc; - ntype->execfunc = execfunc; + ntype->init_exec_fn = init_exec_fn; + ntype->free_exec_fn = free_exec_fn; + ntype->exec_fn = exec_fn; } -void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpufunc) +void node_type_gpu(struct bNodeType *ntype, NodeGPUExecFunction gpu_fn) { - ntype->gpufunc = gpufunc; + ntype->gpu_fn = gpu_fn; } void node_type_internal_links(bNodeType *ntype, @@ -4816,8 +4809,8 @@ static void registerGeometryNodes() register_node_type_geo_point_translate(); register_node_type_geo_points_to_volume(); register_node_type_geo_sample_texture(); - register_node_type_geo_subdivision_surface(); - register_node_type_geo_subdivision_surface_simple(); + register_node_type_geo_subdivide_smooth(); + register_node_type_geo_subdivide(); register_node_type_geo_transform(); register_node_type_geo_triangulate(); register_node_type_geo_volume_to_mesh(); diff --git a/source/blender/blenkernel/intern/node_ui_storage.cc b/source/blender/blenkernel/intern/node_ui_storage.cc index 6e0253eca31..97f52dd3727 100644 --- a/source/blender/blenkernel/intern/node_ui_storage.cc +++ b/source/blender/blenkernel/intern/node_ui_storage.cc @@ -62,8 +62,12 @@ const NodeUIStorage *BKE_node_tree_ui_storage_get_from_context(const bContext *C } const Object *active_object = CTX_data_active_object(C); + if (active_object == nullptr) { + return nullptr; + } + const ModifierData *active_modifier = BKE_object_active_modifier(active_object); - if (active_object == nullptr || active_modifier == nullptr) { + if (active_modifier == nullptr) { return nullptr; } diff --git a/source/blender/blenkernel/intern/outliner_treehash.c b/source/blender/blenkernel/intern/outliner_treehash.c index 05873d20f7f..b9497d389e7 100644 --- a/source/blender/blenkernel/intern/outliner_treehash.c +++ b/source/blender/blenkernel/intern/outliner_treehash.c @@ -101,7 +101,7 @@ static unsigned int tse_hash(const void *ptr) unsigned int u_int; } hash; - BLI_assert(tse->type || !tse->nr); + BLI_assert((tse->type != TSE_SOME_ID) || !tse->nr); hash.h_pair[0] = tse->type; hash.h_pair[1] = tse->nr; @@ -193,7 +193,7 @@ static TseGroup *BKE_outliner_treehash_lookup_group(GHash *th, short type, short { TreeStoreElem tse_template; tse_template.type = type; - tse_template.nr = type ? nr : 0; /* we're picky! :) */ + tse_template.nr = (type == TSE_SOME_ID) ? 0 : nr; /* we're picky! :) */ tse_template.id = id; BLI_assert(th); diff --git a/source/blender/blenkernel/intern/paint.c b/source/blender/blenkernel/intern/paint.c index 08c5beedbf3..2e81b61ad8c 100644 --- a/source/blender/blenkernel/intern/paint.c +++ b/source/blender/blenkernel/intern/paint.c @@ -1760,7 +1760,7 @@ void BKE_sculpt_update_object_before_eval(Object *ob) SculptSession *ss = ob->sculpt; if (ss && ss->building_vp_handle == false) { - if (!ss->cache && !ss->filter_cache) { + if (!ss->cache && !ss->filter_cache && !ss->expand_cache) { /* We free pbvh on changes, except in the middle of drawing a stroke * since it can't deal with changing PVBH node organization, we hope * topology does not change in the meantime .. weak. */ diff --git a/source/blender/blenkernel/intern/particle.c b/source/blender/blenkernel/intern/particle.c index acda59ce96c..e50b321900a 100644 --- a/source/blender/blenkernel/intern/particle.c +++ b/source/blender/blenkernel/intern/particle.c @@ -3925,7 +3925,7 @@ static ModifierData *object_add_or_copy_particle_system( } if (name == NULL) { - name = (psys_orig != NULL) ? psys_orig->name : DATA_("ParticleSettings"); + name = (psys_orig != NULL) ? psys_orig->name : DATA_("ParticleSystem"); } psys = ob->particlesystem.first; @@ -3943,7 +3943,7 @@ static ModifierData *object_add_or_copy_particle_system( id_us_plus(&psys->part->id); } else { - psys->part = BKE_particlesettings_add(bmain, psys->name); + psys->part = BKE_particlesettings_add(bmain, DATA_("ParticleSettings")); } md = BKE_modifier_new(eModifierType_ParticleSystem); BLI_strncpy(md->name, psys->name, sizeof(md->name)); diff --git a/source/blender/blenkernel/intern/particle_distribute.c b/source/blender/blenkernel/intern/particle_distribute.c index c3cc9136057..ad617b4198b 100644 --- a/source/blender/blenkernel/intern/particle_distribute.c +++ b/source/blender/blenkernel/intern/particle_distribute.c @@ -338,18 +338,18 @@ static void hammersley_create(float *out, int n, int seed, float amount) { RNG *rng; - double offs[2], t; + double ofs[2], t; rng = BLI_rng_new(31415926 + n + seed); - offs[0] = BLI_rng_get_double(rng) + (double)amount; - offs[1] = BLI_rng_get_double(rng) + (double)amount; + ofs[0] = BLI_rng_get_double(rng) + (double)amount; + ofs[1] = BLI_rng_get_double(rng) + (double)amount; BLI_rng_free(rng); for (int k = 0; k < n; k++) { BLI_hammersley_1d(k, &t); - out[2 * k + 0] = fmod((double)k / (double)n + offs[0], 1.0); - out[2 * k + 1] = fmod(t + offs[1], 1.0); + out[2 * k + 0] = fmod((double)k / (double)n + ofs[0], 1.0); + out[2 * k + 1] = fmod(t + ofs[1], 1.0); } } diff --git a/source/blender/blenkernel/intern/screen.c b/source/blender/blenkernel/intern/screen.c index 8b911143668..f0220373678 100644 --- a/source/blender/blenkernel/intern/screen.c +++ b/source/blender/blenkernel/intern/screen.c @@ -1217,7 +1217,7 @@ static void write_panel_list(BlendWriter *writer, ListBase *lb) } } -static void write_area_regions(BlendWriter *writer, ScrArea *area) +static void write_area(BlendWriter *writer, ScrArea *area) { LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { write_region(writer, region, area->spacetype); @@ -1342,6 +1342,9 @@ static void write_area_regions(BlendWriter *writer, ScrArea *area) else if (sl->spacetype == SPACE_INFO) { BLO_write_struct(writer, SpaceInfo, sl); } + else if (sl->spacetype == SPACE_SPREADSHEET) { + BLO_write_struct(writer, SpaceSpreadsheet, sl); + } } } @@ -1356,7 +1359,7 @@ void BKE_screen_area_map_blend_write(BlendWriter *writer, ScrAreaMap *area_map) BLO_write_struct(writer, ScrGlobalAreaData, area->global); - write_area_regions(writer, area); + write_area(writer, area); area->butspacetype = SPACE_EMPTY; /* Unset again, was changed above. */ } @@ -1681,6 +1684,7 @@ static void direct_link_area(BlendDataReader *reader, ScrArea *area) sfile->op = NULL; sfile->previews_timer = NULL; sfile->tags = 0; + sfile->runtime = NULL; BLO_read_data_address(reader, &sfile->params); BLO_read_data_address(reader, &sfile->asset_params); } diff --git a/source/blender/blenkernel/intern/simulation.cc b/source/blender/blenkernel/intern/simulation.cc index 6b46804c251..216563b860d 100644 --- a/source/blender/blenkernel/intern/simulation.cc +++ b/source/blender/blenkernel/intern/simulation.cc @@ -54,7 +54,6 @@ #include "BLI_map.hh" #include "BLT_translation.h" -#include "FN_attributes_ref.hh" #include "FN_multi_function_network_evaluation.hh" #include "FN_multi_function_network_optimization.hh" diff --git a/source/blender/blenlib/BLI_array_utils.h b/source/blender/blenlib/BLI_array_utils.h index bd37d22023b..8f4630dd732 100644 --- a/source/blender/blenlib/BLI_array_utils.h +++ b/source/blender/blenlib/BLI_array_utils.h @@ -89,6 +89,14 @@ bool _bli_array_iter_span(const void *arr, bool _bli_array_is_zeroed(const void *arr, unsigned int arr_len, size_t arr_stride); #define BLI_array_is_zeroed(arr, arr_len) _bli_array_is_zeroed(arr, arr_len, sizeof(*(arr))) +bool _bli_array_iter_spiral_square(const void *arr_v, + const int arr_shape[2], + const size_t elem_size, + const int center[2], + const bool (*test_fn)(const void *arr_item, void *user_data), + void *user_data); +#define BLI_array_iter_spiral_square(arr, arr_shape, center, test_fn, user_data) \ + _bli_array_iter_spiral_square(arr, arr_shape, sizeof(*(arr)), center, test_fn, user_data) #ifdef __cplusplus } #endif diff --git a/source/blender/blenlib/BLI_linear_allocator.hh b/source/blender/blenlib/BLI_linear_allocator.hh index a616ec5cf28..47705b1d40b 100644 --- a/source/blender/blenlib/BLI_linear_allocator.hh +++ b/source/blender/blenlib/BLI_linear_allocator.hh @@ -38,18 +38,20 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya uintptr_t current_begin_; uintptr_t current_end_; - int64_t next_min_alloc_size_; #ifdef DEBUG int64_t debug_allocated_amount_ = 0; #endif + /* Buffers larger than that are not packed together with smaller allocations to avoid wasting + * memory. */ + constexpr static inline int64_t large_buffer_threshold = 4096; + public: LinearAllocator() { current_begin_ = 0; current_end_ = 0; - next_min_alloc_size_ = 64; } ~LinearAllocator() @@ -71,23 +73,23 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya BLI_assert(alignment >= 1); BLI_assert(is_power_of_2_i(alignment)); -#ifdef DEBUG - debug_allocated_amount_ += size; -#endif - const uintptr_t alignment_mask = alignment - 1; const uintptr_t potential_allocation_begin = (current_begin_ + alignment_mask) & ~alignment_mask; const uintptr_t potential_allocation_end = potential_allocation_begin + size; if (potential_allocation_end <= current_end_) { +#ifdef DEBUG + debug_allocated_amount_ += size; +#endif current_begin_ = potential_allocation_end; return reinterpret_cast<void *>(potential_allocation_begin); } - else { - this->allocate_new_buffer(size + alignment); + if (size <= large_buffer_threshold) { + this->allocate_new_buffer(size + alignment, alignment); return this->allocate(size, alignment); } + return this->allocator_large_buffer(size, alignment); }; /** @@ -116,14 +118,14 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya * * Arguments passed to this method will be forwarded to the constructor of T. * - * You must not call `delete` on the returned pointer. - * Instead, the destruct has to be called explicitly. + * You must not call `delete` on the returned value. + * Instead, only the destructor has to be called. */ - template<typename T, typename... Args> T *construct(Args &&... args) + template<typename T, typename... Args> destruct_ptr<T> construct(Args &&... args) { void *buffer = this->allocate(sizeof(T), alignof(T)); T *value = new (buffer) T(std::forward<Args>(args)...); - return value; + return destruct_ptr<T>(value); } /** @@ -195,7 +197,7 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya } private: - void allocate_new_buffer(int64_t min_allocation_size) + void allocate_new_buffer(int64_t min_allocation_size, int64_t min_alignment) { for (int64_t i : unused_borrowed_buffers_.index_range()) { Span<char> buffer = unused_borrowed_buffers_[i]; @@ -207,15 +209,29 @@ template<typename Allocator = GuardedAllocator> class LinearAllocator : NonCopya } } - const int64_t size_in_bytes = power_of_2_min_u( - std::max(min_allocation_size, next_min_alloc_size_)); - next_min_alloc_size_ = size_in_bytes * 2; + /* Possibly allocate more bytes than necessary for the current allocation. This way more small + * allocations can be packed together. Large buffers are allocated exactly to avoid wasting too + * much memory. */ + int64_t size_in_bytes = min_allocation_size; + if (size_in_bytes <= large_buffer_threshold) { + /* Gradually grow buffer size with each allocation, up to a maximum. */ + const int grow_size = 1 << std::min<int>(owned_buffers_.size() + 6, 20); + size_in_bytes = std::min(large_buffer_threshold, + std::max<int64_t>(size_in_bytes, grow_size)); + } - void *buffer = allocator_.allocate(size_in_bytes, 8, AT); + void *buffer = allocator_.allocate(size_in_bytes, min_alignment, __func__); owned_buffers_.append(buffer); current_begin_ = (uintptr_t)buffer; current_end_ = current_begin_ + size_in_bytes; } + + void *allocator_large_buffer(const int64_t size, const int64_t alignment) + { + void *buffer = allocator_.allocate(size, alignment, __func__); + owned_buffers_.append(buffer); + return buffer; + } }; } // namespace blender diff --git a/source/blender/blenlib/BLI_math_matrix.h b/source/blender/blenlib/BLI_math_matrix.h index eac7f25f11a..6324963f06a 100644 --- a/source/blender/blenlib/BLI_math_matrix.h +++ b/source/blender/blenlib/BLI_math_matrix.h @@ -331,6 +331,7 @@ void rescale_m4(float mat[4][4], const float scale[3]); void transform_pivot_set_m3(float mat[3][3], const float pivot[2]); void transform_pivot_set_m4(float mat[4][4], const float pivot[3]); +void mat4_to_rot(float rot[3][3], const float wmat[4][4]); void mat3_to_rot_size(float rot[3][3], float size[3], const float mat3[3][3]); void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], const float wmat[4][4]); void mat4_to_loc_quat(float loc[3], float quat[4], const float wmat[4][4]); diff --git a/source/blender/blenlib/BLI_memory_utils.hh b/source/blender/blenlib/BLI_memory_utils.hh index b3b6855089e..bdbbda9f0c7 100644 --- a/source/blender/blenlib/BLI_memory_utils.hh +++ b/source/blender/blenlib/BLI_memory_utils.hh @@ -28,6 +28,7 @@ #include <type_traits> #include "BLI_utildefines.h" +#include "MEM_guardedalloc.h" namespace blender { @@ -402,6 +403,50 @@ template<typename T, int64_t Size = 1> class TypedBuffer { } }; +/* A dynamic stack buffer can be used instead of #alloca when wants to allocate a dynamic amount of + * memory on the stack. Using this class has some advantages: + * - It falls back to heap allocation, when the size is too large. + * - It can be used in loops safely. + * - If the buffer is heap allocated, it is free automatically in the destructor. + */ +template<size_t ReservedSize = 64, size_t ReservedAlignment = 64> +class alignas(ReservedAlignment) DynamicStackBuffer { + private: + /* Don't create an empty array. This causes problems with some compilers. */ + char reserved_buffer_[(ReservedSize > 0) ? ReservedSize : 1]; + void *buffer_; + + public: + DynamicStackBuffer(const int64_t size, const int64_t alignment) + { + BLI_assert(size >= 0); + BLI_assert(alignment >= 0); + if (size <= ReservedSize && alignment <= ReservedAlignment) { + buffer_ = reserved_buffer_; + } + else { + buffer_ = MEM_mallocN_aligned(size, alignment, __func__); + } + } + ~DynamicStackBuffer() + { + if (buffer_ != reserved_buffer_) { + MEM_freeN(buffer_); + } + } + + /* Don't allow any copying or moving of this type. */ + DynamicStackBuffer(const DynamicStackBuffer &other) = delete; + DynamicStackBuffer(DynamicStackBuffer &&other) = delete; + DynamicStackBuffer &operator=(const DynamicStackBuffer &other) = delete; + DynamicStackBuffer &operator=(DynamicStackBuffer &&other) = delete; + + void *buffer() const + { + return buffer_; + } +}; + /** * This can be used by container constructors. A parameter of this type should be used to indicate * that the constructor does not construct the elements. diff --git a/source/blender/blenlib/BLI_mesh_boolean.hh b/source/blender/blenlib/BLI_mesh_boolean.hh index 94b2694893b..a55b2175527 100644 --- a/source/blender/blenlib/BLI_mesh_boolean.hh +++ b/source/blender/blenlib/BLI_mesh_boolean.hh @@ -59,6 +59,7 @@ IMesh boolean_mesh(IMesh &imesh, int nshapes, std::function<int(int)> shape_fn, bool use_self, + bool hole_tolerant, IMesh *imesh_triangulated, IMeshArena *arena); @@ -72,6 +73,7 @@ IMesh boolean_trimesh(IMesh &tm_in, int nshapes, std::function<int(int)> shape_fn, bool use_self, + bool hole_tolerant, IMeshArena *arena); } // namespace blender::meshintersect diff --git a/source/blender/blenlib/BLI_resource_collector.hh b/source/blender/blenlib/BLI_resource_collector.hh index ecae9b8c682..70804ceb1f1 100644 --- a/source/blender/blenlib/BLI_resource_collector.hh +++ b/source/blender/blenlib/BLI_resource_collector.hh @@ -130,9 +130,10 @@ class ResourceCollector : NonCopyable, NonMovable { */ template<typename T, typename... Args> T &construct(const char *name, Args &&... args) { - T *value = m_allocator.construct<T>(std::forward<Args>(args)...); - this->add(destruct_ptr<T>(value), name); - return *value; + destruct_ptr<T> value_ptr = m_allocator.construct<T>(std::forward<Args>(args)...); + T &value_ref = *value_ptr; + this->add(std::move(value_ptr), name); + return value_ref; } /** diff --git a/source/blender/blenlib/BLI_string_utils.h b/source/blender/blenlib/BLI_string_utils.h index 46fb096599f..1057e71a6b2 100644 --- a/source/blender/blenlib/BLI_string_utils.h +++ b/source/blender/blenlib/BLI_string_utils.h @@ -90,7 +90,7 @@ bool BLI_uniquename(struct ListBase *list, void *vlink, const char *defname, char delim, - int name_offs, + int name_offset, size_t len); #ifdef __cplusplus diff --git a/source/blender/blenlib/intern/array_utils.c b/source/blender/blenlib/intern/array_utils.c index 2da2bbbc2a5..5d35cf09c30 100644 --- a/source/blender/blenlib/intern/array_utils.c +++ b/source/blender/blenlib/intern/array_utils.c @@ -27,13 +27,13 @@ #include "MEM_guardedalloc.h" -#include "BLI_array_utils.h" - #include "BLI_alloca.h" +#include "BLI_math_base.h" +#include "BLI_strict_flags.h" #include "BLI_sys_types.h" #include "BLI_utildefines.h" -#include "BLI_strict_flags.h" +#include "BLI_array_utils.h" /** *In-place array reverse. @@ -318,3 +318,94 @@ bool _bli_array_is_zeroed(const void *arr_v, unsigned int arr_len, size_t arr_st } return true; } + +/** + * Smart function to sample a rect spiraling outside. + * Nice for selection ID. + * + * \param arr_shape: dimensions [w, h]. + * \param center: coordinates [x, y] indicating where to start transversing. + */ +bool _bli_array_iter_spiral_square(const void *arr_v, + const int arr_shape[2], + size_t elem_size, + const int center[2], + const bool (*test_fn)(const void *arr_item, void *user_data), + void *user_data) +{ + BLI_assert(center[0] >= 0 && center[1] >= 0 && center[0] < arr_shape[0] && + center[1] < arr_shape[1]); + + const char *arr = arr_v; + const int stride[2] = {arr_shape[1] * (int)elem_size, (int)elem_size}; + + /* Test center first. */ + int ofs[2] = {center[0] * stride[0], center[1] * stride[1]}; + if (test_fn(arr + ofs[0] + ofs[1], user_data)) { + return true; + } + + /* #steps_in and #steps_out are the "diameters" of the inscribed and ciscunscript squares in the + * rectangle. Each step smaller than #steps_in does not need to check bounds. */ + int steps_in, steps_out; + { + int x_minus = center[0]; + int x_plus = arr_shape[0] - center[0] - 1; + int y_minus = center[1]; + int y_plus = arr_shape[1] - center[1] - 1; + + steps_in = 2 * min_iiii(x_minus, x_plus, y_minus, y_plus); + steps_out = 2 * max_iiii(x_minus, x_plus, y_minus, y_plus); + } + + /* For check_bounds. */ + int limits[2] = {(arr_shape[0] - 1) * stride[0], stride[0] - stride[1]}; + + int steps = 0; + while (steps < steps_out) { + steps += 2; + + /* Move one step to the diagonal of the negative quadrant. */ + ofs[0] -= stride[0]; + ofs[1] -= stride[1]; + + bool check_bounds = steps > steps_in; + + /* sign: 0 neg; 1 pos; */ + for (int sign = 2; sign--;) { + /* axis: 0 x; 1 y; */ + for (int axis = 2; axis--;) { + int ofs_step = stride[axis]; + if (!sign) { + ofs_step *= -1; + } + + int ofs_iter = ofs[axis] + ofs_step; + int ofs_dest = ofs[axis] + steps * ofs_step; + int ofs_other = ofs[!axis]; + + ofs[axis] = ofs_dest; + if (check_bounds) { + if (ofs_other < 0 || ofs_other > limits[!axis]) { + /* Out of bounds. */ + continue; + } + + CLAMP(ofs_iter, 0, limits[axis]); + CLAMP(ofs_dest, 0, limits[axis]); + } + + while (true) { + if (test_fn(arr + ofs_other + ofs_iter, user_data)) { + return true; + } + if (ofs_iter == ofs_dest) { + break; + } + ofs_iter += ofs_step; + } + } + } + } + return false; +} diff --git a/source/blender/blenlib/intern/math_matrix.c b/source/blender/blenlib/intern/math_matrix.c index b460d75d77f..2ada05d2965 100644 --- a/source/blender/blenlib/intern/math_matrix.c +++ b/source/blender/blenlib/intern/math_matrix.c @@ -2140,6 +2140,16 @@ void mat3_to_rot_size(float rot[3][3], float size[3], const float mat3[3][3]) } } +void mat4_to_rot(float rot[3][3], const float wmat[4][4]) +{ + normalize_v3_v3(rot[0], wmat[0]); + normalize_v3_v3(rot[1], wmat[1]); + normalize_v3_v3(rot[2], wmat[2]); + if (UNLIKELY(is_negative_m3(rot))) { + negate_m3(rot); + } +} + void mat4_to_loc_rot_size(float loc[3], float rot[3][3], float size[3], const float wmat[4][4]) { float mat3[3][3]; /* wmat -> 3x3 */ diff --git a/source/blender/blenlib/intern/mesh_boolean.cc b/source/blender/blenlib/intern/mesh_boolean.cc index fcf5c5bfad3..cd7d0a812e4 100644 --- a/source/blender/blenlib/intern/mesh_boolean.cc +++ b/source/blender/blenlib/intern/mesh_boolean.cc @@ -2484,29 +2484,14 @@ static void test_tri_inside_shapes(const IMesh &tm, } /** - * Use the RayCast method for deciding if a triangle of the - * mesh is supposed to be included or excluded in the boolean result, - * and return the mesh that is the boolean result. - * The reason this is done on a triangle-by-triangle basis is that - * when the input is not PWN, some patches can be both inside and outside - * some shapes (e.g., a plane cutting through Suzanne's open eyes). + * Return a BVH Tree that contains all of the triangles of \a tm. + * The caller must free it. + * (We could possible reuse the BVH tree(s) built in TriOverlaps, + * in the mesh intersect function. A future TODO.) */ -static IMesh raycast_boolean(const IMesh &tm, - BoolOpType op, - int nshapes, - std::function<int(int)> shape_fn, - IMeshArena *arena) +static BVHTree *raycast_tree(const IMesh &tm) { - constexpr int dbg_level = 0; - if (dbg_level > 0) { - std::cout << "RAYCAST_BOOLEAN\n"; - } - IMesh ans; - - /* Build a BVH tree of tm's triangles. - * We could possibly reuse the BVH tree(s) build in TriOverlaps in - * the mesh intersect function. A future TODO. */ - BVHTree *tree = BLI_bvhtree_new(tm.face_size(), FLT_EPSILON, 8, 8); + BVHTree *tree = BLI_bvhtree_new(tm.face_size(), FLT_EPSILON, 4, 6); for (int i : tm.face_index_range()) { const Face *f = tm.face(i); float t_cos[9]; @@ -2519,7 +2504,70 @@ static IMesh raycast_boolean(const IMesh &tm, BLI_bvhtree_insert(tree, i, t_cos, 3); } BLI_bvhtree_balance(tree); + return tree; +} + +/** + * Should a face with given shape and given winding array be removed for given boolean op? + * Also return true in *r_do_flip if it retained by normals need to be flipped. + */ +static bool raycast_test_remove(BoolOpType op, Array<int> &winding, int shape, bool *r_do_flip) +{ + constexpr int dbg_level = 0; + /* Find out the "in the output volume" flag for each of the cases of winding[shape] == 0 + * and winding[shape] == 1. If the flags are different, this patch should be in the output. + * Also, if this is a Difference and the shape isn't the first one, need to flip the normals. + */ + winding[shape] = 0; + bool in_output_volume_0 = apply_bool_op(op, winding); + winding[shape] = 1; + bool in_output_volume_1 = apply_bool_op(op, winding); + bool do_remove = in_output_volume_0 == in_output_volume_1; + bool do_flip = !do_remove && op == BoolOpType::Difference && shape != 0; + if (dbg_level > 0) { + std::cout << "winding = "; + for (int i = 0; i < winding.size(); ++i) { + std::cout << winding[i] << " "; + } + std::cout << "\niv0=" << in_output_volume_0 << ", iv1=" << in_output_volume_1 << "\n"; + std::cout << " remove=" << do_remove << ", flip=" << do_flip << "\n"; + } + *r_do_flip = do_flip; + return do_remove; +} + +/** Add triangle a flipped version of tri to out_faces. */ +static void raycast_add_flipped(Vector<Face *> &out_faces, Face &tri, IMeshArena *arena) +{ + Array<const Vert *> flipped_vs = {tri[0], tri[2], tri[1]}; + Array<int> flipped_e_origs = {tri.edge_orig[2], tri.edge_orig[1], tri.edge_orig[0]}; + Array<bool> flipped_is_intersect = { + tri.is_intersect[2], tri.is_intersect[1], tri.is_intersect[0]}; + Face *flipped_f = arena->add_face(flipped_vs, tri.orig, flipped_e_origs, flipped_is_intersect); + out_faces.append(flipped_f); +} + +/** + * Use the RayCast method for deciding if a triangle of the + * mesh is supposed to be included or excluded in the boolean result, + * and return the mesh that is the boolean result. + * The reason this is done on a triangle-by-triangle basis is that + * when the input is not PWN, some patches can be both inside and outside + * some shapes (e.g., a plane cutting through Suzanne's open eyes). + */ +static IMesh raycast_tris_boolean(const IMesh &tm, + BoolOpType op, + int nshapes, + std::function<int(int)> shape_fn, + IMeshArena *arena) +{ + constexpr int dbg_level = 0; + if (dbg_level > 0) { + std::cout << "RAYCAST_TRIS_BOOLEAN\n"; + } + IMesh ans; + BVHTree *tree = raycast_tree(tm); Vector<Face *> out_faces; out_faces.reserve(tm.face_size()); Array<float> in_shape(nshapes, 0); @@ -2541,47 +2589,95 @@ static IMesh raycast_boolean(const IMesh &tm, * gives good results, but when shape is a cutter in a Difference * operation, we want to be pretty sure that the point is inside other_shape. * E.g., T75827. + * Also, when the operation is intersection, we also want high confidence. */ - bool need_high_confidence = (op == BoolOpType::Difference) && (shape != 0); + bool need_high_confidence = (op == BoolOpType::Difference && shape != 0) || + op == BoolOpType::Intersect; bool inside = in_shape[other_shape] >= (need_high_confidence ? 0.5f : 0.1f); if (dbg_level > 0) { std::cout << "test point is " << (inside ? "inside" : "outside") << " other_shape " - << other_shape << "\n"; + << other_shape << " val = " << in_shape[other_shape] << "\n"; } winding[other_shape] = inside; } - /* Find out the "in the output volume" flag for each of the cases of winding[shape] == 0 - * and winding[shape] == 1. If the flags are different, this patch should be in the output. - * Also, if this is a Difference and the shape isn't the first one, need to flip the normals. - */ - winding[shape] = 0; - bool in_output_volume_0 = apply_bool_op(op, winding); - winding[shape] = 1; - bool in_output_volume_1 = apply_bool_op(op, winding); - bool do_remove = in_output_volume_0 == in_output_volume_1; - bool do_flip = !do_remove && op == BoolOpType::Difference && shape != 0; - if (dbg_level > 0) { - std::cout << "winding = "; - for (int i = 0; i < nshapes; ++i) { - std::cout << winding[i] << " "; - } - std::cout << "\niv0=" << in_output_volume_0 << ", iv1=" << in_output_volume_1 << "\n"; - std::cout << "result for tri " << t << ": remove=" << do_remove << ", flip=" << do_flip - << "\n"; - } + bool do_flip; + bool do_remove = raycast_test_remove(op, winding, shape, &do_flip); if (!do_remove) { if (!do_flip) { out_faces.append(&tri); } else { - /* We need flipped version of tri. */ - Array<const Vert *> flipped_vs = {tri[0], tri[2], tri[1]}; - Array<int> flipped_e_origs = {tri.edge_orig[2], tri.edge_orig[1], tri.edge_orig[0]}; - Array<bool> flipped_is_intersect = { - tri.is_intersect[2], tri.is_intersect[1], tri.is_intersect[0]}; - Face *flipped_f = arena->add_face( - flipped_vs, tri.orig, flipped_e_origs, flipped_is_intersect); - out_faces.append(flipped_f); + raycast_add_flipped(out_faces, tri, arena); + } + } + } + BLI_bvhtree_free(tree); + ans.set_faces(out_faces); + return ans; +} + +/* This is (sometimes much faster) version of raycast boolean + * that does it per patch rather than per triangle. + * It may fail in cases where raycast_tri_boolean will succeed, + * but the latter can be very slow on huge meshes. */ +static IMesh raycast_patches_boolean(const IMesh &tm, + BoolOpType op, + int nshapes, + std::function<int(int)> shape_fn, + const PatchesInfo &pinfo, + IMeshArena *arena) +{ + constexpr int dbg_level = 0; + if (dbg_level > 0) { + std::cout << "RAYCAST_PATCHES_BOOLEAN\n"; + } + IMesh ans; + BVHTree *tree = raycast_tree(tm); + Vector<Face *> out_faces; + out_faces.reserve(tm.face_size()); + Array<float> in_shape(nshapes, 0); + Array<int> winding(nshapes, 0); + for (int p : pinfo.index_range()) { + const Patch &patch = pinfo.patch(p); + /* For test triangle, choose one in the middle of patch list + * as the ones near the beginning may be very near other patches. */ + int test_t_index = patch.tri(patch.tot_tri() / 2); + Face &tri_test = *tm.face(test_t_index); + /* Assume all triangles in a patch are in the same shape. */ + int shape = shape_fn(tri_test.orig); + if (dbg_level > 0) { + std::cout << "process patch " << p << " = " << patch << "\n"; + std::cout << "test tri = " << test_t_index << " = " << &tri_test << "\n"; + std::cout << "shape = " << shape << "\n"; + } + if (shape == -1) { + continue; + } + test_tri_inside_shapes(tm, shape_fn, nshapes, test_t_index, tree, in_shape); + for (int other_shape = 0; other_shape < nshapes; ++other_shape) { + if (other_shape == shape) { + continue; + } + bool need_high_confidence = (op == BoolOpType::Difference && shape != 0) || + op == BoolOpType::Intersect; + bool inside = in_shape[other_shape] >= (need_high_confidence ? 0.5f : 0.1f); + if (dbg_level > 0) { + std::cout << "test point is " << (inside ? "inside" : "outside") << " other_shape " + << other_shape << " val = " << in_shape[other_shape] << "\n"; + } + winding[other_shape] = inside; + } + bool do_flip; + bool do_remove = raycast_test_remove(op, winding, shape, &do_flip); + if (!do_remove) { + for (int t : patch.tris()) { + Face *f = tm.face(t); + if (!do_flip) { + out_faces.append(f); + } + else { + raycast_add_flipped(out_faces, *f, arena); + } } } } @@ -3341,6 +3437,7 @@ IMesh boolean_trimesh(IMesh &tm_in, int nshapes, std::function<int(int)> shape_fn, bool use_self, + bool hole_tolerant, IMeshArena *arena) { constexpr int dbg_level = 0; @@ -3391,7 +3488,13 @@ IMesh boolean_trimesh(IMesh &tm_in, if (dbg_level > 0) { std::cout << "Input is not PWN, using raycast method\n"; } - tm_out = raycast_boolean(tm_si, op, nshapes, shape_fn, arena); + if (hole_tolerant) { + tm_out = raycast_tris_boolean(tm_si, op, nshapes, shape_fn, arena); + } + else { + PatchesInfo pinfo = find_patches(tm_si, tm_si_topo); + tm_out = raycast_patches_boolean(tm_si, op, nshapes, shape_fn, pinfo, arena); + } # ifdef PERFDEBUG double raycast_time = PIL_check_seconds_timer(); std::cout << " raycast_boolean done, time = " << raycast_time - pwn_time << "\n"; @@ -3486,6 +3589,7 @@ IMesh boolean_mesh(IMesh &imesh, int nshapes, std::function<int(int)> shape_fn, bool use_self, + bool hole_tolerant, IMesh *imesh_triangulated, IMeshArena *arena) { @@ -3519,7 +3623,7 @@ IMesh boolean_mesh(IMesh &imesh, if (dbg_level > 1) { write_obj_mesh(*tm_in, "boolean_tm_in"); } - IMesh tm_out = boolean_trimesh(*tm_in, op, nshapes, shape_fn, use_self, arena); + IMesh tm_out = boolean_trimesh(*tm_in, op, nshapes, shape_fn, use_self, hole_tolerant, arena); # ifdef PERFDEBUG double bool_tri_time = PIL_check_seconds_timer(); std::cout << "boolean_trimesh done, time = " << bool_tri_time - tri_time << "\n"; diff --git a/source/blender/blenlib/intern/string_utils.c b/source/blender/blenlib/intern/string_utils.c index dbeb75570fb..c847f7e1921 100644 --- a/source/blender/blenlib/intern/string_utils.c +++ b/source/blender/blenlib/intern/string_utils.c @@ -333,27 +333,22 @@ bool BLI_uniquename_cb(UniquenameCheckCallback unique_check, return false; } -/* little helper macro for BLI_uniquename */ -#ifndef GIVE_STRADDR -# define GIVE_STRADDR(data, offset) (((char *)data) + offset) -#endif - /** * Generic function to set a unique name. It is only designed to be used in situations * where the name is part of the struct. * * For places where this is used, see constraint.c for example... * - * \param name_offs: should be calculated using offsetof(structname, membername) - * macro from stddef.h + * \param name_offset: should be calculated using `offsetof(structname, membername)` + * macro from `stddef.h` */ -static bool uniquename_find_dupe(ListBase *list, void *vlink, const char *name, int name_offs) +static bool uniquename_find_dupe(ListBase *list, void *vlink, const char *name, int name_offset) { Link *link; for (link = list->first; link; link = link->next) { if (link != vlink) { - if (STREQ(GIVE_STRADDR(link, name_offs), name)) { + if (STREQ(POINTER_OFFSET((const char *)link, name_offset), name)) { return true; } } @@ -367,9 +362,9 @@ static bool uniquename_unique_check(void *arg, const char *name) struct { ListBase *lb; void *vlink; - int name_offs; + int name_offset; } *data = arg; - return uniquename_find_dupe(data->lb, data->vlink, name, data->name_offs); + return uniquename_find_dupe(data->lb, data->vlink, name, data->name_offset); } /** @@ -380,20 +375,20 @@ static bool uniquename_unique_check(void *arg, const char *name) * \param vlink: The block to check the name for * \param defname: To initialize block name if latter is empty * \param delim: Delimits numeric suffix in name - * \param name_offs: Offset of name within block structure + * \param name_offset: Offset of name within block structure * \param name_len: Maximum length of name area */ bool BLI_uniquename( - ListBase *list, void *vlink, const char *defname, char delim, int name_offs, size_t name_len) + ListBase *list, void *vlink, const char *defname, char delim, int name_offset, size_t name_len) { struct { ListBase *lb; void *vlink; - int name_offs; + int name_offset; } data; data.lb = list; data.vlink = vlink; - data.name_offs = name_offs; + data.name_offset = name_offset; BLI_assert(name_len > 1); @@ -402,8 +397,12 @@ bool BLI_uniquename( return false; } - return BLI_uniquename_cb( - uniquename_unique_check, &data, defname, delim, GIVE_STRADDR(vlink, name_offs), name_len); + return BLI_uniquename_cb(uniquename_unique_check, + &data, + defname, + delim, + POINTER_OFFSET(vlink, name_offset), + name_len); } /* ------------------------------------------------------------------------- */ diff --git a/source/blender/blenlib/tests/BLI_linear_allocator_test.cc b/source/blender/blenlib/tests/BLI_linear_allocator_test.cc index a35fbf70711..977e5dba497 100644 --- a/source/blender/blenlib/tests/BLI_linear_allocator_test.cc +++ b/source/blender/blenlib/tests/BLI_linear_allocator_test.cc @@ -1,6 +1,7 @@ /* Apache License, Version 2.0 */ #include "BLI_linear_allocator.hh" +#include "BLI_rand.hh" #include "BLI_strict_flags.h" #include "testing/testing.h" @@ -78,7 +79,7 @@ TEST(linear_allocator, Construct) LinearAllocator<> allocator; std::array<int, 5> values = {1, 2, 3, 4, 5}; - Vector<int> *vector = allocator.construct<Vector<int>>(values); + Vector<int> *vector = allocator.construct<Vector<int>>(values).release(); EXPECT_EQ(vector->size(), 5); EXPECT_EQ((*vector)[3], 4); vector->~Vector(); @@ -115,4 +116,24 @@ TEST(linear_allocator, ConstructArrayCopy) EXPECT_EQ(span2[2], 3); } +TEST(linear_allocator, AllocateLarge) +{ + LinearAllocator<> allocator; + void *buffer1 = allocator.allocate(1024 * 1024, 8); + void *buffer2 = allocator.allocate(1024 * 1024, 8); + EXPECT_NE(buffer1, buffer2); +} + +TEST(linear_allocator, ManyAllocations) +{ + LinearAllocator<> allocator; + RandomNumberGenerator rng; + for (int i = 0; i < 1000; i++) { + int size = rng.get_int32(10000); + int alignment = 1 << (rng.get_int32(7)); + void *buffer = allocator.allocate(size, alignment); + EXPECT_NE(buffer, nullptr); + } +} + } // namespace blender::tests diff --git a/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc b/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc index e503ef8f264..d759f0c3be4 100644 --- a/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc +++ b/source/blender/blenlib/tests/BLI_mesh_boolean_test.cc @@ -113,7 +113,7 @@ TEST(boolean_trimesh, Empty) { IMeshArena arena; IMesh in; - IMesh out = boolean_trimesh(in, BoolOpType::None, 1, all_shape_zero, true, &arena); + IMesh out = boolean_trimesh(in, BoolOpType::None, 1, all_shape_zero, true, false, &arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 0); EXPECT_EQ(out.face_size(), 0); @@ -141,7 +141,8 @@ TEST(boolean_trimesh, TetTetTrimesh) )"; IMeshBuilder mb(spec); - IMesh out = boolean_trimesh(mb.imesh, BoolOpType::None, 1, all_shape_zero, true, &mb.arena); + IMesh out = boolean_trimesh( + mb.imesh, BoolOpType::None, 1, all_shape_zero, true, false, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 11); EXPECT_EQ(out.face_size(), 20); @@ -150,7 +151,8 @@ TEST(boolean_trimesh, TetTetTrimesh) } IMeshBuilder mb2(spec); - IMesh out2 = boolean_trimesh(mb2.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb2.arena); + IMesh out2 = boolean_trimesh( + mb2.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb2.arena); out2.populate_vert(); EXPECT_EQ(out2.vert_size(), 10); EXPECT_EQ(out2.face_size(), 16); @@ -160,7 +162,13 @@ TEST(boolean_trimesh, TetTetTrimesh) IMeshBuilder mb3(spec); IMesh out3 = boolean_trimesh( - mb3.imesh, BoolOpType::Union, 2, [](int t) { return t < 4 ? 0 : 1; }, false, &mb3.arena); + mb3.imesh, + BoolOpType::Union, + 2, + [](int t) { return t < 4 ? 0 : 1; }, + false, + false, + &mb3.arena); out3.populate_vert(); EXPECT_EQ(out3.vert_size(), 10); EXPECT_EQ(out3.face_size(), 16); @@ -170,7 +178,13 @@ TEST(boolean_trimesh, TetTetTrimesh) IMeshBuilder mb4(spec); IMesh out4 = boolean_trimesh( - mb4.imesh, BoolOpType::Union, 2, [](int t) { return t < 4 ? 0 : 1; }, true, &mb4.arena); + mb4.imesh, + BoolOpType::Union, + 2, + [](int t) { return t < 4 ? 0 : 1; }, + true, + false, + &mb4.arena); out4.populate_vert(); EXPECT_EQ(out4.vert_size(), 10); EXPECT_EQ(out4.face_size(), 16); @@ -180,7 +194,13 @@ TEST(boolean_trimesh, TetTetTrimesh) IMeshBuilder mb5(spec); IMesh out5 = boolean_trimesh( - mb5.imesh, BoolOpType::Intersect, 2, [](int t) { return t < 4 ? 0 : 1; }, false, &mb5.arena); + mb5.imesh, + BoolOpType::Intersect, + 2, + [](int t) { return t < 4 ? 0 : 1; }, + false, + false, + &mb5.arena); out5.populate_vert(); EXPECT_EQ(out5.vert_size(), 4); EXPECT_EQ(out5.face_size(), 4); @@ -195,6 +215,7 @@ TEST(boolean_trimesh, TetTetTrimesh) 2, [](int t) { return t < 4 ? 0 : 1; }, false, + false, &mb6.arena); out6.populate_vert(); EXPECT_EQ(out6.vert_size(), 6); @@ -210,6 +231,7 @@ TEST(boolean_trimesh, TetTetTrimesh) 2, [](int t) { return t < 4 ? 1 : 0; }, false, + false, &mb7.arena); out7.populate_vert(); EXPECT_EQ(out7.vert_size(), 8); @@ -241,7 +263,8 @@ TEST(boolean_trimesh, TetTet2Trimesh) )"; IMeshBuilder mb(spec); - IMesh out = boolean_trimesh(mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb.arena); + IMesh out = boolean_trimesh( + mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 10); EXPECT_EQ(out.face_size(), 16); @@ -284,7 +307,8 @@ TEST(boolean_trimesh, CubeTetTrimesh) )"; IMeshBuilder mb(spec); - IMesh out = boolean_trimesh(mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb.arena); + IMesh out = boolean_trimesh( + mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 14); EXPECT_EQ(out.face_size(), 24); @@ -316,7 +340,13 @@ TEST(boolean_trimesh, BinaryTetTetTrimesh) IMeshBuilder mb(spec); IMesh out = boolean_trimesh( - mb.imesh, BoolOpType::Intersect, 2, [](int t) { return t < 4 ? 0 : 1; }, false, &mb.arena); + mb.imesh, + BoolOpType::Intersect, + 2, + [](int t) { return t < 4 ? 0 : 1; }, + false, + false, + &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 4); EXPECT_EQ(out.face_size(), 4); @@ -347,7 +377,8 @@ TEST(boolean_trimesh, TetTetCoplanarTrimesh) )"; IMeshBuilder mb(spec); - IMesh out = boolean_trimesh(mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb.arena); + IMesh out = boolean_trimesh( + mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 5); EXPECT_EQ(out.face_size(), 6); @@ -378,7 +409,8 @@ TEST(boolean_trimesh, TetInsideTetTrimesh) )"; IMeshBuilder mb(spec); - IMesh out = boolean_trimesh(mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb.arena); + IMesh out = boolean_trimesh( + mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 4); EXPECT_EQ(out.face_size(), 4); @@ -409,7 +441,8 @@ TEST(boolean_trimesh, TetBesideTetTrimesh) )"; IMeshBuilder mb(spec); - IMesh out = boolean_trimesh(mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, &mb.arena); + IMesh out = boolean_trimesh( + mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 8); EXPECT_EQ(out.face_size(), 8); @@ -445,7 +478,13 @@ TEST(boolean_trimesh, DegenerateTris) IMeshBuilder mb(spec); IMesh out = boolean_trimesh( - mb.imesh, BoolOpType::Intersect, 2, [](int t) { return t < 5 ? 0 : 1; }, false, &mb.arena); + mb.imesh, + BoolOpType::Intersect, + 2, + [](int t) { return t < 5 ? 0 : 1; }, + false, + false, + &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 4); EXPECT_EQ(out.face_size(), 4); @@ -477,7 +516,7 @@ TEST(boolean_polymesh, TetTet) IMeshBuilder mb(spec); IMesh out = boolean_mesh( - mb.imesh, BoolOpType::None, 1, all_shape_zero, true, nullptr, &mb.arena); + mb.imesh, BoolOpType::None, 1, all_shape_zero, true, false, nullptr, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 11); EXPECT_EQ(out.face_size(), 13); @@ -492,6 +531,7 @@ TEST(boolean_polymesh, TetTet) 2, [](int t) { return t < 4 ? 0 : 1; }, false, + false, nullptr, &mb2.arena); out2.populate_vert(); @@ -540,7 +580,7 @@ TEST(boolean_polymesh, CubeCube) write_obj_mesh(mb.imesh, "cube_cube_in"); } IMesh out = boolean_mesh( - mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, nullptr, &mb.arena); + mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, nullptr, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 20); EXPECT_EQ(out.face_size(), 12); @@ -555,6 +595,7 @@ TEST(boolean_polymesh, CubeCube) 2, [](int t) { return t < 6 ? 0 : 1; }, false, + false, nullptr, &mb2.arena); out2.populate_vert(); @@ -597,7 +638,7 @@ TEST(boolean_polymesh, CubeCone) IMeshBuilder mb(spec); IMesh out = boolean_mesh( - mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, nullptr, &mb.arena); + mb.imesh, BoolOpType::Union, 1, all_shape_zero, true, false, nullptr, &mb.arena); out.populate_vert(); EXPECT_EQ(out.vert_size(), 14); EXPECT_EQ(out.face_size(), 12); @@ -646,6 +687,7 @@ TEST(boolean_polymesh, CubeCubeCoplanar) 2, [](int t) { return t < 6 ? 0 : 1; }, false, + false, nullptr, &mb.arena); out.populate_vert(); @@ -684,6 +726,7 @@ TEST(boolean_polymesh, TetTeTCoplanarDiff) 2, [](int t) { return t < 4 ? 0 : 1; }, false, + false, nullptr, &mb.arena); out.populate_vert(); @@ -734,6 +777,7 @@ TEST(boolean_polymesh, CubeCubeStep) 2, [](int t) { return t < 6 ? 0 : 1; }, false, + false, nullptr, &mb.arena); out.populate_vert(); @@ -784,6 +828,7 @@ TEST(boolean_polymesh, CubeCyl4) 2, [](int t) { return t < 6 ? 1 : 0; }, false, + false, nullptr, &mb.arena); out.populate_vert(); @@ -855,6 +900,7 @@ TEST(boolean_polymesh, CubeCubesubdivDiff) 2, [](int t) { return t < 16 ? 1 : 0; }, false, + false, nullptr, &mb.arena); out.populate_vert(); @@ -896,6 +942,7 @@ TEST(boolean_polymesh, CubePlane) 2, [](int t) { return t >= 1 ? 0 : 1; }, false, + false, nullptr, &mb.arena); out.populate_vert(); diff --git a/source/blender/blenloader/BLO_readfile.h b/source/blender/blenloader/BLO_readfile.h index c7f02de21ea..09f4c405613 100644 --- a/source/blender/blenloader/BLO_readfile.h +++ b/source/blender/blenloader/BLO_readfile.h @@ -182,6 +182,8 @@ struct LibraryLink_Params { struct Main *bmain; /** Options for linking, used for instantiating. */ int flag; + /** Additional tag for #ID.tag. */ + int id_tag_extra; /** Context for instancing objects (optional, no instantiation will be performed when NULL). */ struct { /** The scene in which to instantiate objects/collections. */ @@ -195,10 +197,12 @@ struct LibraryLink_Params { void BLO_library_link_params_init(struct LibraryLink_Params *params, struct Main *bmain, - const int flag); + const int flag, + const int id_tag_extra); void BLO_library_link_params_init_with_context(struct LibraryLink_Params *params, struct Main *bmain, const int flag, + const int id_tag_extra, struct Scene *scene, struct ViewLayer *view_layer, const struct View3D *v3d); diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 62188273457..353eb336c42 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -968,15 +968,15 @@ static BHead *blo_bhead_read_full(FileData *fd, BHead *thisblock) /* Warning! Caller's responsibility to ensure given bhead **is** an ID one! */ const char *blo_bhead_id_name(const FileData *fd, const BHead *bhead) { - return (const char *)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_name_offs); + return (const char *)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_name_offset); } /* Warning! Caller's responsibility to ensure given bhead **is** an ID one! */ AssetMetaData *blo_bhead_id_asset_data_address(const FileData *fd, const BHead *bhead) { BLI_assert(BKE_idtype_idcode_is_valid(bhead->code)); - return (fd->id_asset_data_offs >= 0) ? - *(AssetMetaData **)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_asset_data_offs) : + return (fd->id_asset_data_offset >= 0) ? + *(AssetMetaData **)POINTER_OFFSET(bhead, sizeof(*bhead) + fd->id_asset_data_offset) : NULL; } @@ -1055,9 +1055,9 @@ static bool read_file_dna(FileData *fd, const char **r_error_message) fd->reconstruct_info = DNA_reconstruct_info_create( fd->filesdna, fd->memsdna, fd->compflags); /* used to retrieve ID names from (bhead+1) */ - fd->id_name_offs = DNA_elem_offset(fd->filesdna, "ID", "char", "name[]"); - BLI_assert(fd->id_name_offs != -1); - fd->id_asset_data_offs = DNA_elem_offset( + fd->id_name_offset = DNA_elem_offset(fd->filesdna, "ID", "char", "name[]"); + BLI_assert(fd->id_name_offset != -1); + fd->id_asset_data_offset = DNA_elem_offset( fd->filesdna, "ID", "AssetMetaData", "*asset_data"); return true; @@ -2425,7 +2425,9 @@ static void direct_link_id_common( id->session_uuid = MAIN_ID_SESSION_UUID_UNSET; } - BKE_lib_libblock_session_uuid_ensure(id); + if ((tag & LIB_TAG_TEMP_MAIN) == 0) { + BKE_lib_libblock_session_uuid_ensure(id); + } id->lib = current_library; id->us = ID_FAKE_USERS(id); @@ -3169,7 +3171,9 @@ static ID *create_placeholder(Main *mainvar, const short idcode, const char *idn BLI_addtail(lb, ph_id); id_sort_by_name(lb, ph_id, NULL); - BKE_lib_libblock_session_uuid_ensure(ph_id); + if ((tag & LIB_TAG_TEMP_MAIN) == 0) { + BKE_lib_libblock_session_uuid_ensure(ph_id); + } return ph_id; } @@ -4412,7 +4416,7 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old) if (id == NULL) { /* ID has not been read yet, add placeholder to the main of the * library it belongs to, so that it will be read later. */ - read_libblock(fd, libmain, bhead, LIB_TAG_INDIRECT, false, NULL); + read_libblock(fd, libmain, bhead, fd->id_tag_extra | LIB_TAG_INDIRECT, false, NULL); /* commented because this can print way too much */ // if (G.debug & G_DEBUG) printf("expand_doit: other lib %s\n", lib->filepath); @@ -4467,7 +4471,12 @@ static void expand_doit_library(void *fdhandle, Main *mainvar, void *old) ID *id = is_yet_read(fd, mainvar, bhead); if (id == NULL) { - read_libblock(fd, mainvar, bhead, LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT, false, NULL); + read_libblock(fd, + mainvar, + bhead, + fd->id_tag_extra | LIB_TAG_NEED_EXPAND | LIB_TAG_INDIRECT, + false, + NULL); } else { /* Convert any previously read weak link to regular link @@ -4848,7 +4857,7 @@ static ID *link_named_part( id = is_yet_read(fd, mainl, bhead); if (id == NULL) { /* not read yet */ - const int tag = force_indirect ? LIB_TAG_INDIRECT : LIB_TAG_EXTERN; + const int tag = ((force_indirect ? LIB_TAG_INDIRECT : LIB_TAG_EXTERN) | fd->id_tag_extra); read_libblock(fd, mainl, bhead, tag | LIB_TAG_NEED_EXPAND, false, &id); if (id) { @@ -4989,10 +4998,18 @@ static void library_link_clear_tag(Main *mainvar, const int flag) } } -static Main *library_link_begin(Main *mainvar, FileData **fd, const char *filepath, const int flag) +static Main *library_link_begin( + Main *mainvar, FileData **fd, const char *filepath, const int flag, const int id_tag_extra) { Main *mainl; + /* Only allow specific tags to be set as extra, + * otherwise this could conflict with library loading logic. + * Other flags can be added here, as long as they are safe. */ + BLI_assert((id_tag_extra & ~LIB_TAG_TEMP_MAIN) == 0); + + (*fd)->id_tag_extra = id_tag_extra; + (*fd)->mainlist = MEM_callocN(sizeof(ListBase), "FileData.mainlist"); if (flag & BLO_LIBLINK_NEEDS_ID_TAG_DOIT) { @@ -5018,22 +5035,25 @@ static Main *library_link_begin(Main *mainvar, FileData **fd, const char *filepa void BLO_library_link_params_init(struct LibraryLink_Params *params, struct Main *bmain, - const int flag) + const int flag, + const int id_tag_extra) { memset(params, 0, sizeof(*params)); params->bmain = bmain; params->flag = flag; + params->id_tag_extra = id_tag_extra; } void BLO_library_link_params_init_with_context(struct LibraryLink_Params *params, struct Main *bmain, const int flag, + const int id_tag_extra, /* Context arguments. */ struct Scene *scene, struct ViewLayer *view_layer, const struct View3D *v3d) { - BLO_library_link_params_init(params, bmain, flag); + BLO_library_link_params_init(params, bmain, flag, id_tag_extra); if (scene != NULL) { /* Tagging is needed for instancing. */ params->flag |= BLO_LIBLINK_NEEDS_ID_TAG_DOIT; @@ -5058,7 +5078,7 @@ Main *BLO_library_link_begin(BlendHandle **bh, const struct LibraryLink_Params *params) { FileData *fd = (FileData *)(*bh); - return library_link_begin(params->bmain, &fd, filepath, params->flag); + return library_link_begin(params->bmain, &fd, filepath, params->flag, params->id_tag_extra); } static void split_main_newid(Main *mainptr, Main *main_newid) diff --git a/source/blender/blenloader/intern/readfile.h b/source/blender/blenloader/intern/readfile.h index b81d8bd9a2b..9682b5456d2 100644 --- a/source/blender/blenloader/intern/readfile.h +++ b/source/blender/blenloader/intern/readfile.h @@ -110,16 +110,24 @@ typedef struct FileData { int fileversion; /** Used to retrieve ID names from (bhead+1). */ - int id_name_offs; + int id_name_offset; /** Used to retrieve asset data from (bhead+1). NOTE: This may not be available in old files, * will be -1 then! */ - int id_asset_data_offs; + int id_asset_data_offset; /** For do_versions patching. */ int globalf, fileflags; /** Optionally skip some data-blocks when they're not needed. */ eBLOReadSkip skip_flags; + /** + * Tag to apply to all loaded ID data-blocks. + * + * \note This is initialized from #LibraryLink_Params.id_tag_extra since passing it as an + * argument would need an additional argument to be passed around when expanding library data. + */ + int id_tag_extra; + struct OldNewMap *datamap; struct OldNewMap *globmap; struct OldNewMap *libmap; diff --git a/source/blender/blenloader/intern/versioning_250.c b/source/blender/blenloader/intern/versioning_250.c index 983fdce15f1..467fd8b0399 100644 --- a/source/blender/blenloader/intern/versioning_250.c +++ b/source/blender/blenloader/intern/versioning_250.c @@ -449,7 +449,9 @@ static void versions_gpencil_add_main(ListBase *lb, ID *id, const char *name) BKE_id_new_name_validate(lb, id, name); /* alphabetic insertion: is in BKE_id_new_name_validate */ - BKE_lib_libblock_session_uuid_ensure(id); + if ((id->tag & LIB_TAG_TEMP_MAIN) == 0) { + BKE_lib_libblock_session_uuid_ensure(id); + } if (G.debug & G_DEBUG) { printf("Converted GPencil to ID: %s\n", id->name + 2); diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index ef2e196094e..1ecaee10e6a 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -3684,7 +3684,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) if (!MAIN_VERSION_ATLEAST(bmain, 280, 48)) { for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { /* Those are not currently used, but are accessible through RNA API and were not - * properly initialized previously. This is mere copy of BKE_init_scene() code. */ + * properly initialized previously. This is mere copy of #scene_init_data code. */ if (scene->r.im_format.view_settings.look[0] == '\0') { BKE_color_managed_display_settings_init(&scene->r.im_format.display_settings); BKE_color_managed_view_settings_init_render( diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index 07357dac69a..fc10e316aa1 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -1469,7 +1469,6 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) continue; } BKE_cryptomatte_matte_id_to_entries(storage, storage->matte_id); - MEM_SAFE_FREE(storage->matte_id); } } } @@ -1817,6 +1816,21 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) } } + if (!MAIN_VERSION_ATLEAST(bmain, 293, 11)) { + LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) { + if (ntree->type == NTREE_GEOMETRY) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (STREQ(node->idname, "GeometryNodeSubdivisionSurfaceSimple")) { + STRNCPY(node->idname, "GeometryNodeSubdivide"); + } + if (STREQ(node->idname, "GeometryNodeSubdivisionSurface")) { + STRNCPY(node->idname, "GeometryNodeSubdivideSmooth"); + } + } + } + } + } + /** * Versioning code until next subversion bump goes here. * diff --git a/source/blender/blenloader/intern/versioning_userdef.c b/source/blender/blenloader/intern/versioning_userdef.c index 3d39181cd32..ae22c5151cc 100644 --- a/source/blender/blenloader/intern/versioning_userdef.c +++ b/source/blender/blenloader/intern/versioning_userdef.c @@ -282,6 +282,8 @@ static void do_versions_theme(const UserDef *userdef, bTheme *btheme) FROM_DEFAULT_V4_UCHAR(space_info.info_property); FROM_DEFAULT_V4_UCHAR(space_info.info_error); FROM_DEFAULT_V4_UCHAR(space_info.info_operator); + + btheme->space_spreadsheet = btheme->space_outliner; } #undef FROM_DEFAULT_V4_UCHAR diff --git a/source/blender/bmesh/tools/bmesh_boolean.cc b/source/blender/bmesh/tools/bmesh_boolean.cc index ea5d66e195c..fec33a04e6f 100644 --- a/source/blender/bmesh/tools/bmesh_boolean.cc +++ b/source/blender/bmesh/tools/bmesh_boolean.cc @@ -354,6 +354,7 @@ static bool bmesh_boolean(BMesh *bm, const bool use_self, const bool use_separate_all, const bool keep_hidden, + const bool hole_tolerant, const BoolOpType boolean_mode) { IMeshArena arena; @@ -389,7 +390,7 @@ static bool bmesh_boolean(BMesh *bm, }; } IMesh m_out = boolean_mesh( - m_in, boolean_mode, nshapes, shape_fn, use_self, &m_triangulated, &arena); + m_in, boolean_mode, nshapes, shape_fn, use_self, hole_tolerant, &m_triangulated, &arena); # ifdef PERF_DEBUG double boolean_time = PIL_check_seconds_timer(); std::cout << "boolean done, time = " << boolean_time - mesh_time << "\n"; @@ -437,6 +438,7 @@ bool BM_mesh_boolean(BMesh *bm, const int nshapes, const bool use_self, const bool keep_hidden, + const bool hole_tolerant, const int boolean_mode) { return blender::meshintersect::bmesh_boolean( @@ -449,6 +451,7 @@ bool BM_mesh_boolean(BMesh *bm, use_self, false, keep_hidden, + hole_tolerant, static_cast<blender::meshintersect::BoolOpType>(boolean_mode)); } @@ -468,6 +471,7 @@ bool BM_mesh_boolean_knife(BMesh *bm, const int nshapes, const bool use_self, const bool use_separate_all, + const bool hole_tolerant, const bool keep_hidden) { return blender::meshintersect::bmesh_boolean(bm, @@ -479,6 +483,7 @@ bool BM_mesh_boolean_knife(BMesh *bm, use_self, use_separate_all, keep_hidden, + hole_tolerant, blender::meshintersect::BoolOpType::None); } #else @@ -490,6 +495,7 @@ bool BM_mesh_boolean(BMesh *UNUSED(bm), const int UNUSED(nshapes), const bool UNUSED(use_self), const bool UNUSED(keep_hidden), + const bool UNUSED(hole_tolerant), const int UNUSED(boolean_mode)) { UNUSED_VARS(looptris, test_fn); @@ -512,6 +518,7 @@ bool BM_mesh_boolean_knife(BMesh *UNUSED(bm), const int UNUSED(nshapes), const bool UNUSED(use_self), const bool UNUSED(use_separate_all), + const bool UNUSED(hole_tolerant), const bool UNUSED(keep_hidden)) { UNUSED_VARS(looptris, test_fn); diff --git a/source/blender/bmesh/tools/bmesh_boolean.h b/source/blender/bmesh/tools/bmesh_boolean.h index 2cc32e143fc..ed77242e14c 100644 --- a/source/blender/bmesh/tools/bmesh_boolean.h +++ b/source/blender/bmesh/tools/bmesh_boolean.h @@ -32,6 +32,7 @@ bool BM_mesh_boolean(BMesh *bm, const int nshapes, const bool use_self, const bool keep_hidden, + const bool hole_tolerant, const int boolean_mode); bool BM_mesh_boolean_knife(BMesh *bm, @@ -42,6 +43,7 @@ bool BM_mesh_boolean_knife(BMesh *bm, const int nshapes, const bool use_self, const bool use_separate_all, + const bool hole_tolerant, const bool keep_hidden); #ifdef __cplusplus diff --git a/source/blender/compositor/CMakeLists.txt b/source/blender/compositor/CMakeLists.txt index a226b009ec9..64033cbe5c4 100644 --- a/source/blender/compositor/CMakeLists.txt +++ b/source/blender/compositor/CMakeLists.txt @@ -49,504 +49,504 @@ set(SRC COM_compositor.h COM_defines.h - intern/COM_CPUDevice.cpp + intern/COM_CPUDevice.cc intern/COM_CPUDevice.h - intern/COM_ChunkOrder.cpp + intern/COM_ChunkOrder.cc intern/COM_ChunkOrder.h - intern/COM_ChunkOrderHotspot.cpp + intern/COM_ChunkOrderHotspot.cc intern/COM_ChunkOrderHotspot.h - intern/COM_CompositorContext.cpp + intern/COM_CompositorContext.cc intern/COM_CompositorContext.h - intern/COM_Converter.cpp + intern/COM_Converter.cc intern/COM_Converter.h - intern/COM_Debug.cpp + intern/COM_Debug.cc intern/COM_Debug.h - intern/COM_Device.cpp + intern/COM_Device.cc intern/COM_Device.h - intern/COM_ExecutionGroup.cpp + intern/COM_ExecutionGroup.cc intern/COM_ExecutionGroup.h - intern/COM_ExecutionSystem.cpp + intern/COM_ExecutionSystem.cc intern/COM_ExecutionSystem.h - intern/COM_MemoryBuffer.cpp + intern/COM_MemoryBuffer.cc intern/COM_MemoryBuffer.h - intern/COM_MemoryProxy.cpp + intern/COM_MemoryProxy.cc intern/COM_MemoryProxy.h - intern/COM_MetaData.cpp + intern/COM_MetaData.cc intern/COM_MetaData.h - intern/COM_Node.cpp + intern/COM_Node.cc intern/COM_Node.h - intern/COM_NodeConverter.cpp + intern/COM_NodeConverter.cc intern/COM_NodeConverter.h - intern/COM_NodeGraph.cpp + intern/COM_NodeGraph.cc intern/COM_NodeGraph.h - intern/COM_NodeOperation.cpp + intern/COM_NodeOperation.cc intern/COM_NodeOperation.h - intern/COM_NodeOperationBuilder.cpp + intern/COM_NodeOperationBuilder.cc intern/COM_NodeOperationBuilder.h - intern/COM_OpenCLDevice.cpp + intern/COM_OpenCLDevice.cc intern/COM_OpenCLDevice.h - intern/COM_SingleThreadedOperation.cpp + intern/COM_SingleThreadedOperation.cc intern/COM_SingleThreadedOperation.h - intern/COM_SocketReader.cpp + intern/COM_SocketReader.cc intern/COM_SocketReader.h - intern/COM_WorkPackage.cpp + intern/COM_WorkPackage.cc intern/COM_WorkPackage.h - intern/COM_WorkScheduler.cpp + intern/COM_WorkScheduler.cc intern/COM_WorkScheduler.h - intern/COM_compositor.cpp + intern/COM_compositor.cc - operations/COM_QualityStepHelper.cpp + operations/COM_QualityStepHelper.cc operations/COM_QualityStepHelper.h # Internal nodes - nodes/COM_SocketProxyNode.cpp + nodes/COM_SocketProxyNode.cc nodes/COM_SocketProxyNode.h # input nodes - nodes/COM_BokehImageNode.cpp + nodes/COM_BokehImageNode.cc nodes/COM_BokehImageNode.h - nodes/COM_ColorNode.cpp + nodes/COM_ColorNode.cc nodes/COM_ColorNode.h - nodes/COM_ImageNode.cpp + nodes/COM_ImageNode.cc nodes/COM_ImageNode.h - nodes/COM_MaskNode.cpp + nodes/COM_MaskNode.cc nodes/COM_MaskNode.h - nodes/COM_MovieClipNode.cpp + nodes/COM_MovieClipNode.cc nodes/COM_MovieClipNode.h - nodes/COM_OutputFileNode.cpp + nodes/COM_OutputFileNode.cc nodes/COM_OutputFileNode.h - nodes/COM_RenderLayersNode.cpp + nodes/COM_RenderLayersNode.cc nodes/COM_RenderLayersNode.h - nodes/COM_SwitchNode.cpp + nodes/COM_SwitchNode.cc nodes/COM_SwitchNode.h - nodes/COM_SwitchViewNode.cpp + nodes/COM_SwitchViewNode.cc nodes/COM_SwitchViewNode.h - nodes/COM_TextureNode.cpp + nodes/COM_TextureNode.cc nodes/COM_TextureNode.h - nodes/COM_TimeNode.cpp + nodes/COM_TimeNode.cc nodes/COM_TimeNode.h - nodes/COM_ValueNode.cpp + nodes/COM_ValueNode.cc nodes/COM_ValueNode.h # output nodes - nodes/COM_CompositorNode.cpp + nodes/COM_CompositorNode.cc nodes/COM_CompositorNode.h - nodes/COM_SplitViewerNode.cpp + nodes/COM_SplitViewerNode.cc nodes/COM_SplitViewerNode.h - nodes/COM_ViewLevelsNode.cpp + nodes/COM_ViewLevelsNode.cc nodes/COM_ViewLevelsNode.h - nodes/COM_ViewerNode.cpp + nodes/COM_ViewerNode.cc nodes/COM_ViewerNode.h - operations/COM_CalculateMeanOperation.cpp + operations/COM_CalculateMeanOperation.cc operations/COM_CalculateMeanOperation.h - operations/COM_CalculateStandardDeviationOperation.cpp + operations/COM_CalculateStandardDeviationOperation.cc operations/COM_CalculateStandardDeviationOperation.h # distort nodes - nodes/COM_FlipNode.cpp + nodes/COM_FlipNode.cc nodes/COM_FlipNode.h - nodes/COM_RotateNode.cpp + nodes/COM_RotateNode.cc nodes/COM_RotateNode.h - nodes/COM_ScaleNode.cpp + nodes/COM_ScaleNode.cc nodes/COM_ScaleNode.h - nodes/COM_TranslateNode.cpp + nodes/COM_TranslateNode.cc nodes/COM_TranslateNode.h - nodes/COM_DisplaceNode.cpp + nodes/COM_DisplaceNode.cc nodes/COM_DisplaceNode.h - nodes/COM_MapUVNode.cpp + nodes/COM_MapUVNode.cc nodes/COM_MapUVNode.h - nodes/COM_ChannelMatteNode.cpp + nodes/COM_ChannelMatteNode.cc nodes/COM_ChannelMatteNode.h - nodes/COM_ChromaMatteNode.cpp + nodes/COM_ChromaMatteNode.cc nodes/COM_ChromaMatteNode.h - nodes/COM_ColorMatteNode.cpp + nodes/COM_ColorMatteNode.cc nodes/COM_ColorMatteNode.h - nodes/COM_DifferenceMatteNode.cpp + nodes/COM_DifferenceMatteNode.cc nodes/COM_DifferenceMatteNode.h - nodes/COM_DistanceMatteNode.cpp + nodes/COM_DistanceMatteNode.cc nodes/COM_DistanceMatteNode.h - nodes/COM_LensDistortionNode.cpp + nodes/COM_LensDistortionNode.cc nodes/COM_LensDistortionNode.h - nodes/COM_LuminanceMatteNode.cpp + nodes/COM_LuminanceMatteNode.cc nodes/COM_LuminanceMatteNode.h - nodes/COM_GlareNode.cpp + nodes/COM_GlareNode.cc nodes/COM_GlareNode.h - nodes/COM_SunBeamsNode.cpp + nodes/COM_SunBeamsNode.cc nodes/COM_SunBeamsNode.h - operations/COM_SunBeamsOperation.cpp + operations/COM_SunBeamsOperation.cc operations/COM_SunBeamsOperation.h - nodes/COM_CryptomatteNode.cpp + nodes/COM_CryptomatteNode.cc nodes/COM_CryptomatteNode.h - operations/COM_CryptomatteOperation.cpp + operations/COM_CryptomatteOperation.cc operations/COM_CryptomatteOperation.h - nodes/COM_CornerPinNode.cpp + nodes/COM_CornerPinNode.cc nodes/COM_CornerPinNode.h - nodes/COM_PlaneTrackDeformNode.cpp + nodes/COM_PlaneTrackDeformNode.cc nodes/COM_PlaneTrackDeformNode.h - nodes/COM_CropNode.cpp + nodes/COM_CropNode.cc nodes/COM_CropNode.h - operations/COM_CropOperation.cpp + operations/COM_CropOperation.cc operations/COM_CropOperation.h - nodes/COM_DefocusNode.cpp + nodes/COM_DefocusNode.cc nodes/COM_DefocusNode.h - nodes/COM_MovieDistortionNode.cpp + nodes/COM_MovieDistortionNode.cc nodes/COM_MovieDistortionNode.h - nodes/COM_Stabilize2dNode.cpp + nodes/COM_Stabilize2dNode.cc nodes/COM_Stabilize2dNode.h - nodes/COM_TransformNode.cpp + nodes/COM_TransformNode.cc nodes/COM_TransformNode.h # color nodes - nodes/COM_AlphaOverNode.cpp + nodes/COM_AlphaOverNode.cc nodes/COM_AlphaOverNode.h - nodes/COM_BrightnessNode.cpp + nodes/COM_BrightnessNode.cc nodes/COM_BrightnessNode.h - nodes/COM_ColorBalanceNode.cpp + nodes/COM_ColorBalanceNode.cc nodes/COM_ColorBalanceNode.h - nodes/COM_ColorCorrectionNode.cpp + nodes/COM_ColorCorrectionNode.cc nodes/COM_ColorCorrectionNode.h - nodes/COM_ColorCurveNode.cpp + nodes/COM_ColorCurveNode.cc nodes/COM_ColorCurveNode.h - nodes/COM_ColorExposureNode.cpp + nodes/COM_ColorExposureNode.cc nodes/COM_ColorExposureNode.h - nodes/COM_ColorRampNode.cpp + nodes/COM_ColorRampNode.cc nodes/COM_ColorRampNode.h - nodes/COM_ColorToBWNode.cpp + nodes/COM_ColorToBWNode.cc nodes/COM_ColorToBWNode.h - nodes/COM_ConvertAlphaNode.cpp + nodes/COM_ConvertAlphaNode.cc nodes/COM_ConvertAlphaNode.h - nodes/COM_GammaNode.cpp + nodes/COM_GammaNode.cc nodes/COM_GammaNode.h - nodes/COM_HueSaturationValueCorrectNode.cpp + nodes/COM_HueSaturationValueCorrectNode.cc nodes/COM_HueSaturationValueCorrectNode.h - nodes/COM_HueSaturationValueNode.cpp + nodes/COM_HueSaturationValueNode.cc nodes/COM_HueSaturationValueNode.h - nodes/COM_InvertNode.cpp + nodes/COM_InvertNode.cc nodes/COM_InvertNode.h - nodes/COM_MixNode.cpp + nodes/COM_MixNode.cc nodes/COM_MixNode.h - nodes/COM_SetAlphaNode.cpp + nodes/COM_SetAlphaNode.cc nodes/COM_SetAlphaNode.h - nodes/COM_TonemapNode.cpp + nodes/COM_TonemapNode.cc nodes/COM_TonemapNode.h - nodes/COM_VectorCurveNode.cpp + nodes/COM_VectorCurveNode.cc nodes/COM_VectorCurveNode.h - nodes/COM_ZCombineNode.cpp + nodes/COM_ZCombineNode.cc nodes/COM_ZCombineNode.h - operations/COM_TonemapOperation.cpp + operations/COM_TonemapOperation.cc operations/COM_TonemapOperation.h # converter nodes - nodes/COM_CombineColorNode.cpp + nodes/COM_CombineColorNode.cc nodes/COM_CombineColorNode.h - nodes/COM_IDMaskNode.cpp + nodes/COM_IDMaskNode.cc nodes/COM_IDMaskNode.h - nodes/COM_SeparateColorNode.cpp + nodes/COM_SeparateColorNode.cc nodes/COM_SeparateColorNode.h - nodes/COM_MapRangeNode.cpp + nodes/COM_MapRangeNode.cc nodes/COM_MapRangeNode.h - nodes/COM_MapValueNode.cpp + nodes/COM_MapValueNode.cc nodes/COM_MapValueNode.h - nodes/COM_MathNode.cpp + nodes/COM_MathNode.cc nodes/COM_MathNode.h - nodes/COM_NormalNode.cpp + nodes/COM_NormalNode.cc nodes/COM_NormalNode.h - nodes/COM_NormalizeNode.cpp + nodes/COM_NormalizeNode.cc nodes/COM_NormalizeNode.h - operations/COM_NormalizeOperation.cpp + operations/COM_NormalizeOperation.cc operations/COM_NormalizeOperation.h - nodes/COM_PixelateNode.cpp + nodes/COM_PixelateNode.cc nodes/COM_PixelateNode.h - operations/COM_PixelateOperation.cpp + operations/COM_PixelateOperation.cc operations/COM_PixelateOperation.h # Filter nodes - nodes/COM_BilateralBlurNode.cpp + nodes/COM_BilateralBlurNode.cc nodes/COM_BilateralBlurNode.h - operations/COM_BilateralBlurOperation.cpp + operations/COM_BilateralBlurOperation.cc operations/COM_BilateralBlurOperation.h - nodes/COM_VectorBlurNode.cpp + nodes/COM_VectorBlurNode.cc nodes/COM_VectorBlurNode.h - operations/COM_VectorBlurOperation.cpp + operations/COM_VectorBlurOperation.cc operations/COM_VectorBlurOperation.h - nodes/COM_BlurNode.cpp + nodes/COM_BlurNode.cc nodes/COM_BlurNode.h - nodes/COM_BokehBlurNode.cpp + nodes/COM_BokehBlurNode.cc nodes/COM_BokehBlurNode.h - nodes/COM_DenoiseNode.cpp + nodes/COM_DenoiseNode.cc nodes/COM_DenoiseNode.h - nodes/COM_DespeckleNode.cpp + nodes/COM_DespeckleNode.cc nodes/COM_DespeckleNode.h - nodes/COM_DilateErodeNode.cpp + nodes/COM_DilateErodeNode.cc nodes/COM_DilateErodeNode.h - nodes/COM_DirectionalBlurNode.cpp + nodes/COM_DirectionalBlurNode.cc nodes/COM_DirectionalBlurNode.h - nodes/COM_FilterNode.cpp + nodes/COM_FilterNode.cc nodes/COM_FilterNode.h - nodes/COM_InpaintNode.cpp + nodes/COM_InpaintNode.cc nodes/COM_InpaintNode.h - operations/COM_BlurBaseOperation.cpp + operations/COM_BlurBaseOperation.cc operations/COM_BlurBaseOperation.h - operations/COM_BokehBlurOperation.cpp + operations/COM_BokehBlurOperation.cc operations/COM_BokehBlurOperation.h - operations/COM_DirectionalBlurOperation.cpp + operations/COM_DirectionalBlurOperation.cc operations/COM_DirectionalBlurOperation.h - operations/COM_FastGaussianBlurOperation.cpp + operations/COM_FastGaussianBlurOperation.cc operations/COM_FastGaussianBlurOperation.h - operations/COM_GammaCorrectOperation.cpp + operations/COM_GammaCorrectOperation.cc operations/COM_GammaCorrectOperation.h - operations/COM_GaussianAlphaXBlurOperation.cpp + operations/COM_GaussianAlphaXBlurOperation.cc operations/COM_GaussianAlphaXBlurOperation.h - operations/COM_GaussianAlphaYBlurOperation.cpp + operations/COM_GaussianAlphaYBlurOperation.cc operations/COM_GaussianAlphaYBlurOperation.h - operations/COM_GaussianBokehBlurOperation.cpp + operations/COM_GaussianBokehBlurOperation.cc operations/COM_GaussianBokehBlurOperation.h - operations/COM_GaussianXBlurOperation.cpp + operations/COM_GaussianXBlurOperation.cc operations/COM_GaussianXBlurOperation.h - operations/COM_GaussianYBlurOperation.cpp + operations/COM_GaussianYBlurOperation.cc operations/COM_GaussianYBlurOperation.h - operations/COM_MovieClipAttributeOperation.cpp + operations/COM_MovieClipAttributeOperation.cc operations/COM_MovieClipAttributeOperation.h - operations/COM_MovieDistortionOperation.cpp + operations/COM_MovieDistortionOperation.cc operations/COM_MovieDistortionOperation.h - operations/COM_VariableSizeBokehBlurOperation.cpp + operations/COM_VariableSizeBokehBlurOperation.cc operations/COM_VariableSizeBokehBlurOperation.h # Matte nodes - nodes/COM_BoxMaskNode.cpp + nodes/COM_BoxMaskNode.cc nodes/COM_BoxMaskNode.h - nodes/COM_ColorSpillNode.cpp + nodes/COM_ColorSpillNode.cc nodes/COM_ColorSpillNode.h - nodes/COM_DoubleEdgeMaskNode.cpp + nodes/COM_DoubleEdgeMaskNode.cc nodes/COM_DoubleEdgeMaskNode.h - nodes/COM_EllipseMaskNode.cpp + nodes/COM_EllipseMaskNode.cc nodes/COM_EllipseMaskNode.h - operations/COM_DoubleEdgeMaskOperation.cpp + operations/COM_DoubleEdgeMaskOperation.cc operations/COM_DoubleEdgeMaskOperation.h - nodes/COM_KeyingScreenNode.cpp + nodes/COM_KeyingScreenNode.cc nodes/COM_KeyingScreenNode.h - operations/COM_KeyingScreenOperation.cpp + operations/COM_KeyingScreenOperation.cc operations/COM_KeyingScreenOperation.h - nodes/COM_TrackPositionNode.cpp + nodes/COM_TrackPositionNode.cc nodes/COM_TrackPositionNode.h - operations/COM_TrackPositionOperation.cpp + operations/COM_TrackPositionOperation.cc operations/COM_TrackPositionOperation.h - nodes/COM_KeyingNode.cpp + nodes/COM_KeyingNode.cc nodes/COM_KeyingNode.h - operations/COM_KeyingBlurOperation.cpp + operations/COM_KeyingBlurOperation.cc operations/COM_KeyingBlurOperation.h - operations/COM_KeyingClipOperation.cpp + operations/COM_KeyingClipOperation.cc operations/COM_KeyingClipOperation.h - operations/COM_KeyingDespillOperation.cpp + operations/COM_KeyingDespillOperation.cc operations/COM_KeyingDespillOperation.h - operations/COM_KeyingOperation.cpp + operations/COM_KeyingOperation.cc operations/COM_KeyingOperation.h - operations/COM_ColorSpillOperation.cpp + operations/COM_ColorSpillOperation.cc operations/COM_ColorSpillOperation.h - operations/COM_RenderLayersProg.cpp + operations/COM_RenderLayersProg.cc operations/COM_RenderLayersProg.h - operations/COM_BokehImageOperation.cpp + operations/COM_BokehImageOperation.cc operations/COM_BokehImageOperation.h - operations/COM_ImageOperation.cpp + operations/COM_ImageOperation.cc operations/COM_ImageOperation.h - operations/COM_MultilayerImageOperation.cpp + operations/COM_MultilayerImageOperation.cc operations/COM_MultilayerImageOperation.h - operations/COM_TextureOperation.cpp + operations/COM_TextureOperation.cc operations/COM_TextureOperation.h - operations/COM_SocketProxyOperation.cpp + operations/COM_SocketProxyOperation.cc operations/COM_SocketProxyOperation.h - operations/COM_CompositorOperation.cpp + operations/COM_CompositorOperation.cc operations/COM_CompositorOperation.h - operations/COM_ConvertDepthToRadiusOperation.cpp + operations/COM_ConvertDepthToRadiusOperation.cc operations/COM_ConvertDepthToRadiusOperation.h - operations/COM_OutputFileMultiViewOperation.cpp + operations/COM_OutputFileMultiViewOperation.cc operations/COM_OutputFileMultiViewOperation.h - operations/COM_OutputFileOperation.cpp + operations/COM_OutputFileOperation.cc operations/COM_OutputFileOperation.h - operations/COM_PreviewOperation.cpp + operations/COM_PreviewOperation.cc operations/COM_PreviewOperation.h - operations/COM_SplitOperation.cpp + operations/COM_SplitOperation.cc operations/COM_SplitOperation.h - operations/COM_ViewerOperation.cpp + operations/COM_ViewerOperation.cc operations/COM_ViewerOperation.h - operations/COM_ZCombineOperation.cpp + operations/COM_ZCombineOperation.cc operations/COM_ZCombineOperation.h - operations/COM_ChangeHSVOperation.cpp + operations/COM_ChangeHSVOperation.cc operations/COM_ChangeHSVOperation.h - operations/COM_ChannelMatteOperation.cpp + operations/COM_ChannelMatteOperation.cc operations/COM_ChannelMatteOperation.h - operations/COM_ChromaMatteOperation.cpp + operations/COM_ChromaMatteOperation.cc operations/COM_ChromaMatteOperation.h - operations/COM_ColorCurveOperation.cpp + operations/COM_ColorCurveOperation.cc operations/COM_ColorCurveOperation.h - operations/COM_ColorExposureOperation.cpp + operations/COM_ColorExposureOperation.cc operations/COM_ColorExposureOperation.h - operations/COM_ColorMatteOperation.cpp + operations/COM_ColorMatteOperation.cc operations/COM_ColorMatteOperation.h - operations/COM_ColorRampOperation.cpp + operations/COM_ColorRampOperation.cc operations/COM_ColorRampOperation.h - operations/COM_CurveBaseOperation.cpp + operations/COM_CurveBaseOperation.cc operations/COM_CurveBaseOperation.h - operations/COM_DifferenceMatteOperation.cpp + operations/COM_DifferenceMatteOperation.cc operations/COM_DifferenceMatteOperation.h - operations/COM_DistanceRGBMatteOperation.cpp + operations/COM_DistanceRGBMatteOperation.cc operations/COM_DistanceRGBMatteOperation.h - operations/COM_DistanceYCCMatteOperation.cpp + operations/COM_DistanceYCCMatteOperation.cc operations/COM_DistanceYCCMatteOperation.h - operations/COM_HueSaturationValueCorrectOperation.cpp + operations/COM_HueSaturationValueCorrectOperation.cc operations/COM_HueSaturationValueCorrectOperation.h - operations/COM_LuminanceMatteOperation.cpp + operations/COM_LuminanceMatteOperation.cc operations/COM_LuminanceMatteOperation.h - operations/COM_VectorCurveOperation.cpp + operations/COM_VectorCurveOperation.cc operations/COM_VectorCurveOperation.h - operations/COM_BrightnessOperation.cpp + operations/COM_BrightnessOperation.cc operations/COM_BrightnessOperation.h - operations/COM_ColorCorrectionOperation.cpp + operations/COM_ColorCorrectionOperation.cc operations/COM_ColorCorrectionOperation.h - operations/COM_GammaOperation.cpp + operations/COM_GammaOperation.cc operations/COM_GammaOperation.h - operations/COM_MixOperation.cpp + operations/COM_MixOperation.cc operations/COM_MixOperation.h - operations/COM_ReadBufferOperation.cpp + operations/COM_ReadBufferOperation.cc operations/COM_ReadBufferOperation.h - operations/COM_SetColorOperation.cpp + operations/COM_SetColorOperation.cc operations/COM_SetColorOperation.h - operations/COM_SetValueOperation.cpp + operations/COM_SetValueOperation.cc operations/COM_SetValueOperation.h - operations/COM_SetVectorOperation.cpp + operations/COM_SetVectorOperation.cc operations/COM_SetVectorOperation.h - operations/COM_WriteBufferOperation.cpp + operations/COM_WriteBufferOperation.cc operations/COM_WriteBufferOperation.h - operations/COM_MathBaseOperation.cpp + operations/COM_MathBaseOperation.cc operations/COM_MathBaseOperation.h - operations/COM_AlphaOverKeyOperation.cpp + operations/COM_AlphaOverKeyOperation.cc operations/COM_AlphaOverKeyOperation.h - operations/COM_AlphaOverMixedOperation.cpp + operations/COM_AlphaOverMixedOperation.cc operations/COM_AlphaOverMixedOperation.h - operations/COM_AlphaOverPremultiplyOperation.cpp + operations/COM_AlphaOverPremultiplyOperation.cc operations/COM_AlphaOverPremultiplyOperation.h - operations/COM_ColorBalanceASCCDLOperation.cpp + operations/COM_ColorBalanceASCCDLOperation.cc operations/COM_ColorBalanceASCCDLOperation.h - operations/COM_ColorBalanceLGGOperation.cpp + operations/COM_ColorBalanceLGGOperation.cc operations/COM_ColorBalanceLGGOperation.h - operations/COM_InvertOperation.cpp + operations/COM_InvertOperation.cc operations/COM_InvertOperation.h - operations/COM_MapRangeOperation.cpp + operations/COM_MapRangeOperation.cc operations/COM_MapRangeOperation.h - operations/COM_MapValueOperation.cpp + operations/COM_MapValueOperation.cc operations/COM_MapValueOperation.h - operations/COM_SetAlphaMultiplyOperation.cpp + operations/COM_SetAlphaMultiplyOperation.cc operations/COM_SetAlphaMultiplyOperation.h - operations/COM_SetAlphaReplaceOperation.cpp + operations/COM_SetAlphaReplaceOperation.cc operations/COM_SetAlphaReplaceOperation.h # Distort operation - operations/COM_DisplaceOperation.cpp + operations/COM_DisplaceOperation.cc operations/COM_DisplaceOperation.h - operations/COM_DisplaceSimpleOperation.cpp + operations/COM_DisplaceSimpleOperation.cc operations/COM_DisplaceSimpleOperation.h - operations/COM_FlipOperation.cpp + operations/COM_FlipOperation.cc operations/COM_FlipOperation.h - operations/COM_MapUVOperation.cpp + operations/COM_MapUVOperation.cc operations/COM_MapUVOperation.h - operations/COM_PlaneCornerPinOperation.cpp + operations/COM_PlaneCornerPinOperation.cc operations/COM_PlaneCornerPinOperation.h - operations/COM_PlaneDistortCommonOperation.cpp + operations/COM_PlaneDistortCommonOperation.cc operations/COM_PlaneDistortCommonOperation.h - operations/COM_PlaneTrackOperation.cpp + operations/COM_PlaneTrackOperation.cc operations/COM_PlaneTrackOperation.h - operations/COM_ProjectorLensDistortionOperation.cpp + operations/COM_ProjectorLensDistortionOperation.cc operations/COM_ProjectorLensDistortionOperation.h - operations/COM_RotateOperation.cpp + operations/COM_RotateOperation.cc operations/COM_RotateOperation.h - operations/COM_ScaleOperation.cpp + operations/COM_ScaleOperation.cc operations/COM_ScaleOperation.h - operations/COM_ScreenLensDistortionOperation.cpp + operations/COM_ScreenLensDistortionOperation.cc operations/COM_ScreenLensDistortionOperation.h - operations/COM_TranslateOperation.cpp + operations/COM_TranslateOperation.cc operations/COM_TranslateOperation.h - operations/COM_WrapOperation.cpp + operations/COM_WrapOperation.cc operations/COM_WrapOperation.h # Filter operations - operations/COM_ConvolutionEdgeFilterOperation.cpp + operations/COM_ConvolutionEdgeFilterOperation.cc operations/COM_ConvolutionEdgeFilterOperation.h - operations/COM_ConvolutionFilterOperation.cpp + operations/COM_ConvolutionFilterOperation.cc operations/COM_ConvolutionFilterOperation.h - operations/COM_DenoiseOperation.cpp + operations/COM_DenoiseOperation.cc operations/COM_DenoiseOperation.h - operations/COM_DespeckleOperation.cpp + operations/COM_DespeckleOperation.cc operations/COM_DespeckleOperation.h - operations/COM_DilateErodeOperation.cpp + operations/COM_DilateErodeOperation.cc operations/COM_DilateErodeOperation.h - operations/COM_GlareBaseOperation.cpp + operations/COM_GlareBaseOperation.cc operations/COM_GlareBaseOperation.h - operations/COM_GlareFogGlowOperation.cpp + operations/COM_GlareFogGlowOperation.cc operations/COM_GlareFogGlowOperation.h - operations/COM_GlareGhostOperation.cpp + operations/COM_GlareGhostOperation.cc operations/COM_GlareGhostOperation.h - operations/COM_GlareSimpleStarOperation.cpp + operations/COM_GlareSimpleStarOperation.cc operations/COM_GlareSimpleStarOperation.h - operations/COM_GlareStreaksOperation.cpp + operations/COM_GlareStreaksOperation.cc operations/COM_GlareStreaksOperation.h - operations/COM_GlareThresholdOperation.cpp + operations/COM_GlareThresholdOperation.cc operations/COM_GlareThresholdOperation.h - operations/COM_InpaintOperation.cpp + operations/COM_InpaintOperation.cc operations/COM_InpaintOperation.h - operations/COM_SetSamplerOperation.cpp + operations/COM_SetSamplerOperation.cc operations/COM_SetSamplerOperation.h # Convert operations - operations/COM_ConvertOperation.cpp + operations/COM_ConvertOperation.cc operations/COM_ConvertOperation.h - operations/COM_IDMaskOperation.cpp + operations/COM_IDMaskOperation.cc operations/COM_IDMaskOperation.h - operations/COM_DotproductOperation.cpp + operations/COM_DotproductOperation.cc operations/COM_DotproductOperation.h # Matte operation - operations/COM_BoxMaskOperation.cpp + operations/COM_BoxMaskOperation.cc operations/COM_BoxMaskOperation.h - operations/COM_EllipseMaskOperation.cpp + operations/COM_EllipseMaskOperation.cc operations/COM_EllipseMaskOperation.h - operations/COM_ConvertColorProfileOperation.cpp + operations/COM_ConvertColorProfileOperation.cc operations/COM_ConvertColorProfileOperation.h - operations/COM_MovieClipOperation.cpp + operations/COM_MovieClipOperation.cc operations/COM_MovieClipOperation.h - operations/COM_AntiAliasOperation.cpp + operations/COM_AntiAliasOperation.cc operations/COM_AntiAliasOperation.h - operations/COM_MaskOperation.cpp + operations/COM_MaskOperation.cc operations/COM_MaskOperation.h ) diff --git a/source/blender/compositor/COM_compositor.h b/source/blender/compositor/COM_compositor.h index ba66d7f0dfe..4aae5471858 100644 --- a/source/blender/compositor/COM_compositor.h +++ b/source/blender/compositor/COM_compositor.h @@ -113,11 +113,11 @@ extern "C" { * * When the chunk-order is determined, the first few chunks will be checked if they can be scheduled. * Chunks can have three states: - * - [@ref ChunkExecutionState.COM_ES_NOT_SCHEDULED]: + * - [@ref eChunkExecutionState.NOT_SCHEDULED]: * Chunk is not yet scheduled, or dependencies are not met. - * - [@ref ChunkExecutionState.COM_ES_SCHEDULED]: + * - [@ref eChunkExecutionState.SCHEDULED]: * All dependencies are met, chunk is scheduled, but not finished. - * - [@ref ChunkExecutionState.COM_ES_EXECUTED]: + * - [@ref eChunkExecutionState.EXECUTED]: * Chunk is finished. * * \see ExecutionGroup.execute diff --git a/source/blender/compositor/intern/COM_CPUDevice.cpp b/source/blender/compositor/intern/COM_CPUDevice.cc index 7ea12866148..b520a437008 100644 --- a/source/blender/compositor/intern/COM_CPUDevice.cpp +++ b/source/blender/compositor/intern/COM_CPUDevice.cc @@ -24,8 +24,8 @@ CPUDevice::CPUDevice(int thread_id) : m_thread_id(thread_id) void CPUDevice::execute(WorkPackage *work) { - const unsigned int chunkNumber = work->getChunkNumber(); - ExecutionGroup *executionGroup = work->getExecutionGroup(); + const unsigned int chunkNumber = work->chunk_number; + ExecutionGroup *executionGroup = work->execution_group; rcti rect; executionGroup->determineChunkRect(&rect, chunkNumber); diff --git a/source/blender/compositor/intern/COM_ChunkOrder.cpp b/source/blender/compositor/intern/COM_ChunkOrder.cc index 3baa50da487..3baa50da487 100644 --- a/source/blender/compositor/intern/COM_ChunkOrder.cpp +++ b/source/blender/compositor/intern/COM_ChunkOrder.cc diff --git a/source/blender/compositor/intern/COM_ChunkOrderHotspot.cpp b/source/blender/compositor/intern/COM_ChunkOrderHotspot.cc index bbc98d086a6..d31ff518ecd 100644 --- a/source/blender/compositor/intern/COM_ChunkOrderHotspot.cpp +++ b/source/blender/compositor/intern/COM_ChunkOrderHotspot.cc @@ -19,18 +19,11 @@ #include "COM_ChunkOrderHotspot.h" #include <cmath> -ChunkOrderHotspot::ChunkOrderHotspot(int x, int y, float addition) -{ - x = x; - y = y; - addition = addition; -} - double ChunkOrderHotspot::calc_distance(int x, int y) { - int dx = x - x; - int dy = y - y; + int dx = this->x - x; + int dy = this->y - y; double result = sqrt((double)(dx * dx + dy * dy)); - result += (double)addition; + result += (double)this->addition; return result; } diff --git a/source/blender/compositor/intern/COM_ChunkOrderHotspot.h b/source/blender/compositor/intern/COM_ChunkOrderHotspot.h index af0cf897673..d7f40921836 100644 --- a/source/blender/compositor/intern/COM_ChunkOrderHotspot.h +++ b/source/blender/compositor/intern/COM_ChunkOrderHotspot.h @@ -27,8 +27,9 @@ struct ChunkOrderHotspot { int y; float addition; - public: - ChunkOrderHotspot(int x, int y, float addition); + ChunkOrderHotspot(int x, int y, float addition) : x(x), y(y), addition(addition) + { + } double calc_distance(int x, int y); diff --git a/source/blender/compositor/intern/COM_CompositorContext.cpp b/source/blender/compositor/intern/COM_CompositorContext.cc index 2e168221b7b..2e168221b7b 100644 --- a/source/blender/compositor/intern/COM_CompositorContext.cpp +++ b/source/blender/compositor/intern/COM_CompositorContext.cc diff --git a/source/blender/compositor/intern/COM_Converter.cpp b/source/blender/compositor/intern/COM_Converter.cc index 08035940667..7d897d29576 100644 --- a/source/blender/compositor/intern/COM_Converter.cpp +++ b/source/blender/compositor/intern/COM_Converter.cc @@ -115,9 +115,9 @@ #include "COM_ViewerNode.h" #include "COM_ZCombineNode.h" -bool Converter::is_fast_node(bNode *b_node) +bool COM_bnode_is_fast_node(const bNode &b_node) { - return !ELEM(b_node->type, + return !ELEM(b_node.type, CMP_NODE_BLUR, CMP_NODE_VECBLUR, CMP_NODE_BILATERALBLUR, @@ -132,7 +132,7 @@ bool Converter::is_fast_node(bNode *b_node) CMP_NODE_DENOISE); } -Node *Converter::convert(bNode *b_node) +Node *COM_convert_bnode(bNode *b_node) { Node *node = nullptr; @@ -419,36 +419,37 @@ Node *Converter::convert(bNode *b_node) return node; } -NodeOperation *Converter::convertDataType(NodeOperationOutput *from, NodeOperationInput *to) +/* TODO(jbakker): make this an std::optional<NodeOperation>. */ +NodeOperation *COM_convert_data_type(const NodeOperationOutput &from, const NodeOperationInput &to) { - DataType fromDatatype = from->getDataType(); - DataType toDatatype = to->getDataType(); + const DataType src_data_type = from.getDataType(); + const DataType dst_data_type = to.getDataType(); - if (fromDatatype == COM_DT_VALUE && toDatatype == COM_DT_COLOR) { + if (src_data_type == COM_DT_VALUE && dst_data_type == COM_DT_COLOR) { return new ConvertValueToColorOperation(); } - if (fromDatatype == COM_DT_VALUE && toDatatype == COM_DT_VECTOR) { + if (src_data_type == COM_DT_VALUE && dst_data_type == COM_DT_VECTOR) { return new ConvertValueToVectorOperation(); } - if (fromDatatype == COM_DT_COLOR && toDatatype == COM_DT_VALUE) { + if (src_data_type == COM_DT_COLOR && dst_data_type == COM_DT_VALUE) { return new ConvertColorToValueOperation(); } - if (fromDatatype == COM_DT_COLOR && toDatatype == COM_DT_VECTOR) { + if (src_data_type == COM_DT_COLOR && dst_data_type == COM_DT_VECTOR) { return new ConvertColorToVectorOperation(); } - if (fromDatatype == COM_DT_VECTOR && toDatatype == COM_DT_VALUE) { + if (src_data_type == COM_DT_VECTOR && dst_data_type == COM_DT_VALUE) { return new ConvertVectorToValueOperation(); } - if (fromDatatype == COM_DT_VECTOR && toDatatype == COM_DT_COLOR) { + if (src_data_type == COM_DT_VECTOR && dst_data_type == COM_DT_COLOR) { return new ConvertVectorToColorOperation(); } return nullptr; } -void Converter::convertResolution(NodeOperationBuilder &builder, - NodeOperationOutput *fromSocket, - NodeOperationInput *toSocket) +void COM_convert_resolution(NodeOperationBuilder &builder, + NodeOperationOutput *fromSocket, + NodeOperationInput *toSocket) { InputResizeMode mode = toSocket->getResizeMode(); diff --git a/source/blender/compositor/intern/COM_Converter.h b/source/blender/compositor/intern/COM_Converter.h index fe3b8b75ccc..59be34bf0e3 100644 --- a/source/blender/compositor/intern/COM_Converter.h +++ b/source/blender/compositor/intern/COM_Converter.h @@ -31,56 +31,37 @@ class NodeOperationOutput; class NodeOperationBuilder; /** - * \brief Conversion methods for the compositor + * \brief Wraps a bNode in its Node instance. + * + * For all nodetypes a wrapper class is created. + * + * \note When adding a new node to blender, this method needs to be changed to return the correct + * Node instance. + * + * \see Node */ -class Converter { - public: - /** - * \brief Convert/wraps a bNode in its Node instance. - * - * For all nodetypes a wrapper class is created. - * - * \note When adding a new node to blender, this method needs to be changed to return the correct - * Node instance. - * - * \see Node - */ - static Node *convert(bNode *b_node); - - /** - * \brief True if the node is considered 'fast'. - * - * Slow nodes will be skipped if fast execution is required. - */ - static bool is_fast_node(bNode *b_node); +Node *COM_convert_bnode(bNode *b_node); - /** - * \brief This method will add a datetype conversion rule when the to-socket does not support the - * from-socket actual data type. - * - * \note this method is called when conversion is needed. - * - * \param link: the NodeLink what needs conversion - * \param system: the ExecutionSystem to add the conversion to. - * \see NodeLink - a link between two sockets - */ - static NodeOperation *convertDataType(NodeOperationOutput *from, NodeOperationInput *to); +/** + * \brief True if the node is considered 'fast'. + * + * Slow nodes will be skipped if fast execution is required. + */ +bool COM_bnode_is_fast_node(const bNode &b_node); - /** - * \brief This method will add a resolution rule based on the settings of the NodeInput. - * - * \note Conversion logic is implemented in this method - * \see InputSocketResizeMode for the possible conversions. - * - * \param link: the NodeLink what needs conversion - * \param system: the ExecutionSystem to add the conversion to. - * \see NodeLink - a link between two sockets - */ - static void convertResolution(NodeOperationBuilder &builder, - NodeOperationOutput *fromSocket, - NodeOperationInput *toSocket); +/** + * \brief This function will add a datetype conversion rule when the to-socket does not support the + * from-socket actual data type. + */ +NodeOperation *COM_convert_data_type(const NodeOperationOutput &from, + const NodeOperationInput &to); -#ifdef WITH_CXX_GUARDEDALLOC - MEM_CXX_CLASS_ALLOC_FUNCS("COM:Converter") -#endif -}; +/** + * \brief This function will add a resolution rule based on the settings of the NodeInput. + * + * \note Conversion logic is implemented in this function. + * \see InputSocketResizeMode for the possible conversions. + */ +void COM_convert_resolution(NodeOperationBuilder &builder, + NodeOperationOutput *fromSocket, + NodeOperationInput *toSocket); diff --git a/source/blender/compositor/intern/COM_Debug.cpp b/source/blender/compositor/intern/COM_Debug.cc index b49d575cade..b49d575cade 100644 --- a/source/blender/compositor/intern/COM_Debug.cpp +++ b/source/blender/compositor/intern/COM_Debug.cc diff --git a/source/blender/compositor/intern/COM_Device.cpp b/source/blender/compositor/intern/COM_Device.cc index 38a22369005..38a22369005 100644 --- a/source/blender/compositor/intern/COM_Device.cpp +++ b/source/blender/compositor/intern/COM_Device.cc diff --git a/source/blender/compositor/intern/COM_Device.h b/source/blender/compositor/intern/COM_Device.h index bb95f1e953c..0b0f0f5c1c6 100644 --- a/source/blender/compositor/intern/COM_Device.h +++ b/source/blender/compositor/intern/COM_Device.h @@ -55,7 +55,7 @@ class Device { * \brief execute a WorkPackage * \param work: the WorkPackage to execute */ - virtual void execute(WorkPackage *work) = 0; + virtual void execute(struct WorkPackage *work) = 0; #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("COM:Device") diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.cpp b/source/blender/compositor/intern/COM_ExecutionGroup.cc index 9c21c91c370..37623228183 100644 --- a/source/blender/compositor/intern/COM_ExecutionGroup.cpp +++ b/source/blender/compositor/intern/COM_ExecutionGroup.cc @@ -43,20 +43,19 @@ ExecutionGroup::ExecutionGroup() { - this->m_isOutput = false; + this->m_is_output = false; this->m_complex = false; - this->m_chunkExecutionStates = nullptr; this->m_bTree = nullptr; this->m_height = 0; this->m_width = 0; - this->m_cachedMaxReadBufferOffset = 0; - this->m_numberOfXChunks = 0; - this->m_numberOfYChunks = 0; - this->m_numberOfChunks = 0; + this->m_max_read_buffer_offset = 0; + this->m_x_chunks_len = 0; + this->m_y_chunks_len = 0; + this->m_chunks_len = 0; this->m_initialized = false; this->m_openCL = false; this->m_singleThreaded = false; - this->m_chunksFinished = 0; + this->m_chunks_finished = 0; BLI_rcti_init(&this->m_viewerBorder, 0, 0, 0, 0); this->m_executionStartTime = 0; } @@ -108,7 +107,7 @@ bool ExecutionGroup::addOperation(NodeOperation *operation) m_initialized = true; } - m_operations.push_back(operation); + m_operations.append(operation); return true; } @@ -121,45 +120,36 @@ NodeOperation *ExecutionGroup::getOutputOperation() const void ExecutionGroup::initExecution() { - if (this->m_chunkExecutionStates != nullptr) { - MEM_freeN(this->m_chunkExecutionStates); - } - unsigned int index; + m_chunk_execution_states.clear(); determineNumberOfChunks(); - this->m_chunkExecutionStates = nullptr; - if (this->m_numberOfChunks != 0) { - this->m_chunkExecutionStates = (ChunkExecutionState *)MEM_mallocN( - sizeof(ChunkExecutionState) * this->m_numberOfChunks, __func__); - for (index = 0; index < this->m_numberOfChunks; index++) { - this->m_chunkExecutionStates[index] = COM_ES_NOT_SCHEDULED; + if (this->m_chunks_len != 0) { + m_chunk_execution_states.resize(this->m_chunks_len); + for (int index = 0; index < this->m_chunks_len; index++) { + m_chunk_execution_states[index] = eChunkExecutionState::NOT_SCHEDULED; } } - unsigned int maxNumber = 0; + unsigned int max_offset = 0; - for (index = 0; index < this->m_operations.size(); index++) { - NodeOperation *operation = this->m_operations[index]; + for (NodeOperation *operation : m_operations) { if (operation->isReadBufferOperation()) { - ReadBufferOperation *readOperation = (ReadBufferOperation *)operation; - this->m_cachedReadOperations.push_back(readOperation); - maxNumber = max(maxNumber, readOperation->getOffset()); + ReadBufferOperation *readOperation = static_cast<ReadBufferOperation *>(operation); + this->m_read_operations.append(readOperation); + max_offset = MAX2(max_offset, readOperation->getOffset()); } } - maxNumber++; - this->m_cachedMaxReadBufferOffset = maxNumber; + max_offset++; + this->m_max_read_buffer_offset = max_offset; } void ExecutionGroup::deinitExecution() { - if (this->m_chunkExecutionStates != nullptr) { - MEM_freeN(this->m_chunkExecutionStates); - this->m_chunkExecutionStates = nullptr; - } - this->m_numberOfChunks = 0; - this->m_numberOfXChunks = 0; - this->m_numberOfYChunks = 0; - this->m_cachedReadOperations.clear(); + m_chunk_execution_states.clear(); + this->m_chunks_len = 0; + this->m_x_chunks_len = 0; + this->m_y_chunks_len = 0; + this->m_read_operations.clear(); this->m_bTree = nullptr; } void ExecutionGroup::determineResolution(unsigned int resolution[2]) @@ -174,17 +164,17 @@ void ExecutionGroup::determineResolution(unsigned int resolution[2]) void ExecutionGroup::determineNumberOfChunks() { if (this->m_singleThreaded) { - this->m_numberOfXChunks = 1; - this->m_numberOfYChunks = 1; - this->m_numberOfChunks = 1; + this->m_x_chunks_len = 1; + this->m_y_chunks_len = 1; + this->m_chunks_len = 1; } else { const float chunkSizef = this->m_chunkSize; const int border_width = BLI_rcti_size_x(&this->m_viewerBorder); const int border_height = BLI_rcti_size_y(&this->m_viewerBorder); - this->m_numberOfXChunks = ceil(border_width / chunkSizef); - this->m_numberOfYChunks = ceil(border_height / chunkSizef); - this->m_numberOfChunks = this->m_numberOfXChunks * this->m_numberOfYChunks; + this->m_x_chunks_len = ceil(border_width / chunkSizef); + this->m_y_chunks_len = ceil(border_height / chunkSizef); + this->m_chunks_len = this->m_x_chunks_len * this->m_y_chunks_len; } } @@ -202,20 +192,20 @@ void ExecutionGroup::execute(ExecutionSystem *graph) if (bTree->test_break && bTree->test_break(bTree->tbh)) { return; } /** \note Early break out for blur and preview nodes. */ - if (this->m_numberOfChunks == 0) { + if (this->m_chunks_len == 0) { return; } /** \note Early break out. */ unsigned int chunkNumber; this->m_executionStartTime = PIL_check_seconds_timer(); - this->m_chunksFinished = 0; + this->m_chunks_finished = 0; this->m_bTree = bTree; unsigned int index; - unsigned int *chunkOrder = (unsigned int *)MEM_mallocN( - sizeof(unsigned int) * this->m_numberOfChunks, __func__); + unsigned int *chunkOrder = (unsigned int *)MEM_mallocN(sizeof(unsigned int) * this->m_chunks_len, + __func__); - for (chunkNumber = 0; chunkNumber < this->m_numberOfChunks; chunkNumber++) { + for (chunkNumber = 0; chunkNumber < this->m_chunks_len; chunkNumber++) { chunkOrder[chunkNumber] = chunkNumber; } NodeOperation *operation = this->getOutputOperation(); @@ -235,9 +225,9 @@ void ExecutionGroup::execute(ExecutionSystem *graph) switch (chunkorder) { case COM_TO_RANDOM: - for (index = 0; index < 2 * this->m_numberOfChunks; index++) { - int index1 = rand() % this->m_numberOfChunks; - int index2 = rand() % this->m_numberOfChunks; + for (index = 0; index < 2 * this->m_chunks_len; index++) { + int index1 = rand() % this->m_chunks_len; + int index2 = rand() % this->m_chunks_len; int s = chunkOrder[index1]; chunkOrder[index1] = chunkOrder[index2]; chunkOrder[index2] = s; @@ -247,9 +237,9 @@ void ExecutionGroup::execute(ExecutionSystem *graph) ChunkOrderHotspot *hotspots[1]; hotspots[0] = new ChunkOrderHotspot(border_width * centerX, border_height * centerY, 0.0f); rcti rect; - ChunkOrder *chunkOrders = (ChunkOrder *)MEM_mallocN( - sizeof(ChunkOrder) * this->m_numberOfChunks, __func__); - for (index = 0; index < this->m_numberOfChunks; index++) { + ChunkOrder *chunkOrders = (ChunkOrder *)MEM_mallocN(sizeof(ChunkOrder) * this->m_chunks_len, + __func__); + for (index = 0; index < this->m_chunks_len; index++) { determineChunkRect(&rect, index); chunkOrders[index].number = index; chunkOrders[index].x = rect.xmin - this->m_viewerBorder.xmin; @@ -257,8 +247,8 @@ void ExecutionGroup::execute(ExecutionSystem *graph) chunkOrders[index].update_distance(hotspots, 1); } - std::sort(&chunkOrders[0], &chunkOrders[this->m_numberOfChunks - 1]); - for (index = 0; index < this->m_numberOfChunks; index++) { + std::sort(&chunkOrders[0], &chunkOrders[this->m_chunks_len - 1]); + for (index = 0; index < this->m_chunks_len; index++) { chunkOrder[index] = chunkOrders[index].number; } @@ -275,7 +265,7 @@ void ExecutionGroup::execute(ExecutionSystem *graph) unsigned int bx = mx + 2 * tx; unsigned int by = my + 2 * ty; - float addition = this->m_numberOfChunks / COM_RULE_OF_THIRDS_DIVIDER; + float addition = this->m_chunks_len / COM_RULE_OF_THIRDS_DIVIDER; hotspots[0] = new ChunkOrderHotspot(mx, my, addition * 0); hotspots[1] = new ChunkOrderHotspot(tx, my, addition * 1); hotspots[2] = new ChunkOrderHotspot(bx, my, addition * 2); @@ -286,9 +276,9 @@ void ExecutionGroup::execute(ExecutionSystem *graph) hotspots[7] = new ChunkOrderHotspot(mx, ty, addition * 7); hotspots[8] = new ChunkOrderHotspot(mx, by, addition * 8); rcti rect; - ChunkOrder *chunkOrders = (ChunkOrder *)MEM_mallocN( - sizeof(ChunkOrder) * this->m_numberOfChunks, __func__); - for (index = 0; index < this->m_numberOfChunks; index++) { + ChunkOrder *chunkOrders = (ChunkOrder *)MEM_mallocN(sizeof(ChunkOrder) * this->m_chunks_len, + __func__); + for (index = 0; index < this->m_chunks_len; index++) { determineChunkRect(&rect, index); chunkOrders[index].number = index; chunkOrders[index].x = rect.xmin - this->m_viewerBorder.xmin; @@ -296,9 +286,9 @@ void ExecutionGroup::execute(ExecutionSystem *graph) chunkOrders[index].update_distance(hotspots, 9); } - std::sort(&chunkOrders[0], &chunkOrders[this->m_numberOfChunks]); + std::sort(&chunkOrders[0], &chunkOrders[this->m_chunks_len]); - for (index = 0; index < this->m_numberOfChunks; index++) { + for (index = 0; index < this->m_chunks_len; index++) { chunkOrder[index] = chunkOrders[index].number; } @@ -332,31 +322,35 @@ void ExecutionGroup::execute(ExecutionSystem *graph) finished = true; int numberEvaluated = 0; - for (index = startIndex; - index < this->m_numberOfChunks && numberEvaluated < maxNumberEvaluated; + for (index = startIndex; index < this->m_chunks_len && numberEvaluated < maxNumberEvaluated; index++) { chunkNumber = chunkOrder[index]; - int yChunk = chunkNumber / this->m_numberOfXChunks; - int xChunk = chunkNumber - (yChunk * this->m_numberOfXChunks); - const ChunkExecutionState state = this->m_chunkExecutionStates[chunkNumber]; - if (state == COM_ES_NOT_SCHEDULED) { - scheduleChunkWhenPossible(graph, xChunk, yChunk); - finished = false; - startEvaluated = true; - numberEvaluated++; - - if (bTree->update_draw) { - bTree->update_draw(bTree->udh); + int yChunk = chunkNumber / this->m_x_chunks_len; + int xChunk = chunkNumber - (yChunk * this->m_x_chunks_len); + switch (m_chunk_execution_states[chunkNumber]) { + case eChunkExecutionState::NOT_SCHEDULED: { + scheduleChunkWhenPossible(graph, xChunk, yChunk); + finished = false; + startEvaluated = true; + numberEvaluated++; + + if (bTree->update_draw) { + bTree->update_draw(bTree->udh); + } + break; } - } - else if (state == COM_ES_SCHEDULED) { - finished = false; - startEvaluated = true; - numberEvaluated++; - } - else if (state == COM_ES_EXECUTED && !startEvaluated) { - startIndex = index + 1; - } + case eChunkExecutionState::SCHEDULED: { + finished = false; + startEvaluated = true; + numberEvaluated++; + break; + } + case eChunkExecutionState::EXECUTED: { + if (!startEvaluated) { + startIndex = index + 1; + } + } + }; } WorkScheduler::finish(); @@ -374,17 +368,14 @@ void ExecutionGroup::execute(ExecutionSystem *graph) MemoryBuffer **ExecutionGroup::getInputBuffersOpenCL(int chunkNumber) { rcti rect; - vector<MemoryProxy *> memoryproxies; - unsigned int index; + std::vector<MemoryProxy *> memoryproxies; determineChunkRect(&rect, chunkNumber); this->determineDependingMemoryProxies(&memoryproxies); MemoryBuffer **memoryBuffers = (MemoryBuffer **)MEM_callocN( - sizeof(MemoryBuffer *) * this->m_cachedMaxReadBufferOffset, __func__); + sizeof(MemoryBuffer *) * this->m_max_read_buffer_offset, __func__); rcti output; - for (index = 0; index < this->m_cachedReadOperations.size(); index++) { - ReadBufferOperation *readOperation = - (ReadBufferOperation *)this->m_cachedReadOperations[index]; + for (ReadBufferOperation *readOperation : m_read_operations) { MemoryProxy *memoryProxy = readOperation->getMemoryProxy(); this->determineDependingAreaOfInterest(&rect, readOperation, &output); MemoryBuffer *memoryBuffer = memoryProxy->getExecutor()->constructConsolidatedMemoryBuffer( @@ -405,13 +396,13 @@ MemoryBuffer *ExecutionGroup::constructConsolidatedMemoryBuffer(MemoryProxy *mem void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memoryBuffers) { - if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_SCHEDULED) { - this->m_chunkExecutionStates[chunkNumber] = COM_ES_EXECUTED; + if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::SCHEDULED) { + this->m_chunk_execution_states[chunkNumber] = eChunkExecutionState::EXECUTED; } - atomic_add_and_fetch_u(&this->m_chunksFinished, 1); + atomic_add_and_fetch_u(&this->m_chunks_finished, 1); if (memoryBuffers) { - for (unsigned int index = 0; index < this->m_cachedMaxReadBufferOffset; index++) { + for (unsigned int index = 0; index < this->m_max_read_buffer_offset; index++) { MemoryBuffer *buffer = memoryBuffers[index]; if (buffer) { if (buffer->isTemporarily()) { @@ -424,16 +415,16 @@ void ExecutionGroup::finalizeChunkExecution(int chunkNumber, MemoryBuffer **memo } if (this->m_bTree) { // status report is only performed for top level Execution Groups. - float progress = this->m_chunksFinished; - progress /= this->m_numberOfChunks; + float progress = this->m_chunks_finished; + progress /= this->m_chunks_len; this->m_bTree->progress(this->m_bTree->prh, progress); char buf[128]; BLI_snprintf(buf, sizeof(buf), TIP_("Compositing | Tile %u-%u"), - this->m_chunksFinished, - this->m_numberOfChunks); + this->m_chunks_finished, + this->m_chunks_len); this->m_bTree->stats_draw(this->m_bTree->sdh, buf); } } @@ -452,20 +443,20 @@ inline void ExecutionGroup::determineChunkRect(rcti *rect, else { const unsigned int minx = xChunk * this->m_chunkSize + this->m_viewerBorder.xmin; const unsigned int miny = yChunk * this->m_chunkSize + this->m_viewerBorder.ymin; - const unsigned int width = min((unsigned int)this->m_viewerBorder.xmax, this->m_width); - const unsigned int height = min((unsigned int)this->m_viewerBorder.ymax, this->m_height); + const unsigned int width = MIN2((unsigned int)this->m_viewerBorder.xmax, this->m_width); + const unsigned int height = MIN2((unsigned int)this->m_viewerBorder.ymax, this->m_height); BLI_rcti_init(rect, - min(minx, this->m_width), - min(minx + this->m_chunkSize, width), - min(miny, this->m_height), - min(miny + this->m_chunkSize, height)); + MIN2(minx, this->m_width), + MIN2(minx + this->m_chunkSize, width), + MIN2(miny, this->m_height), + MIN2(miny + this->m_chunkSize, height)); } } void ExecutionGroup::determineChunkRect(rcti *rect, const unsigned int chunkNumber) const { - const unsigned int yChunk = chunkNumber / this->m_numberOfXChunks; - const unsigned int xChunk = chunkNumber - (yChunk * this->m_numberOfXChunks); + const unsigned int yChunk = chunkNumber / this->m_x_chunks_len; + const unsigned int xChunk = chunkNumber - (yChunk * this->m_x_chunks_len); determineChunkRect(rect, xChunk, yChunk); } @@ -500,8 +491,8 @@ bool ExecutionGroup::scheduleAreaWhenPossible(ExecutionSystem *graph, rcti *area int maxychunk = (maxy + (int)m_chunkSize - 1) / (int)m_chunkSize; minxchunk = max_ii(minxchunk, 0); minychunk = max_ii(minychunk, 0); - maxxchunk = min_ii(maxxchunk, (int)m_numberOfXChunks); - maxychunk = min_ii(maxychunk, (int)m_numberOfYChunks); + maxxchunk = min_ii(maxxchunk, (int)m_x_chunks_len); + maxychunk = min_ii(maxychunk, (int)m_y_chunks_len); bool result = true; for (indexx = minxchunk; indexx < maxxchunk; indexx++) { @@ -517,8 +508,8 @@ bool ExecutionGroup::scheduleAreaWhenPossible(ExecutionSystem *graph, rcti *area bool ExecutionGroup::scheduleChunk(unsigned int chunkNumber) { - if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_NOT_SCHEDULED) { - this->m_chunkExecutionStates[chunkNumber] = COM_ES_SCHEDULED; + if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::NOT_SCHEDULED) { + this->m_chunk_execution_states[chunkNumber] = eChunkExecutionState::SCHEDULED; WorkScheduler::schedule(this, chunkNumber); return true; } @@ -527,25 +518,25 @@ bool ExecutionGroup::scheduleChunk(unsigned int chunkNumber) bool ExecutionGroup::scheduleChunkWhenPossible(ExecutionSystem *graph, int xChunk, int yChunk) { - if (xChunk < 0 || xChunk >= (int)this->m_numberOfXChunks) { + if (xChunk < 0 || xChunk >= (int)this->m_x_chunks_len) { return true; } - if (yChunk < 0 || yChunk >= (int)this->m_numberOfYChunks) { + if (yChunk < 0 || yChunk >= (int)this->m_y_chunks_len) { return true; } - int chunkNumber = yChunk * this->m_numberOfXChunks + xChunk; + int chunkNumber = yChunk * this->m_x_chunks_len + xChunk; // chunk is already executed - if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_EXECUTED) { + if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::EXECUTED) { return true; } // chunk is scheduled, but not executed - if (this->m_chunkExecutionStates[chunkNumber] == COM_ES_SCHEDULED) { + if (this->m_chunk_execution_states[chunkNumber] == eChunkExecutionState::SCHEDULED) { return false; } // chunk is nor executed nor scheduled. - vector<MemoryProxy *> memoryProxies; + std::vector<MemoryProxy *> memoryProxies; this->determineDependingMemoryProxies(&memoryProxies); rcti rect; @@ -554,9 +545,8 @@ bool ExecutionGroup::scheduleChunkWhenPossible(ExecutionSystem *graph, int xChun bool canBeExecuted = true; rcti area; - for (index = 0; index < this->m_cachedReadOperations.size(); index++) { - ReadBufferOperation *readOperation = - (ReadBufferOperation *)this->m_cachedReadOperations[index]; + for (index = 0; index < m_read_operations.size(); index++) { + ReadBufferOperation *readOperation = m_read_operations[index]; BLI_rcti_init(&area, 0, 0, 0, 0); MemoryProxy *memoryProxy = memoryProxies[index]; determineDependingAreaOfInterest(&rect, readOperation, &area); @@ -586,12 +576,9 @@ void ExecutionGroup::determineDependingAreaOfInterest(rcti *input, this->getOutputOperation()->determineDependingAreaOfInterest(input, readOperation, output); } -void ExecutionGroup::determineDependingMemoryProxies(vector<MemoryProxy *> *memoryProxies) +void ExecutionGroup::determineDependingMemoryProxies(std::vector<MemoryProxy *> *memoryProxies) { - unsigned int index; - for (index = 0; index < this->m_cachedReadOperations.size(); index++) { - ReadBufferOperation *readOperation = - (ReadBufferOperation *)this->m_cachedReadOperations[index]; + for (ReadBufferOperation *readOperation : m_read_operations) { memoryProxies->push_back(readOperation->getMemoryProxy()); } } diff --git a/source/blender/compositor/intern/COM_ExecutionGroup.h b/source/blender/compositor/intern/COM_ExecutionGroup.h index dd079415d09..f73f4473b5d 100644 --- a/source/blender/compositor/intern/COM_ExecutionGroup.h +++ b/source/blender/compositor/intern/COM_ExecutionGroup.h @@ -23,6 +23,8 @@ #endif #include "BLI_rect.h" +#include "BLI_vector.hh" + #include "COM_CompositorContext.h" #include "COM_Device.h" #include "COM_MemoryProxy.h" @@ -30,8 +32,6 @@ #include "COM_NodeOperation.h" #include <vector> -using std::vector; - class ExecutionSystem; class MemoryProxy; class ReadBufferOperation; @@ -41,20 +41,20 @@ class Device; * \brief the execution state of a chunk in an ExecutionGroup * \ingroup Execution */ -typedef enum ChunkExecutionState { +enum class eChunkExecutionState { /** * \brief chunk is not yet scheduled */ - COM_ES_NOT_SCHEDULED = 0, + NOT_SCHEDULED = 0, /** * \brief chunk is scheduled, but not yet executed */ - COM_ES_SCHEDULED = 1, + SCHEDULED = 1, /** * \brief chunk is executed. */ - COM_ES_EXECUTED = 2, -} ChunkExecutionState; + EXECUTED = 2, +}; /** * \brief Class ExecutionGroup is a group of Operations that are executed as one. @@ -63,23 +63,20 @@ typedef enum ChunkExecutionState { * \ingroup Execution */ class ExecutionGroup { - public: - typedef std::vector<NodeOperation *> Operations; - private: // fields /** * \brief list of operations in this ExecutionGroup */ - Operations m_operations; + blender::Vector<NodeOperation *> m_operations; /** * \brief is this ExecutionGroup an input ExecutionGroup * an input execution group is a group that is at the end of the calculation * (the output is important for the user). */ - int m_isOutput; + bool m_is_output; /** * \brief Width of the output @@ -100,17 +97,17 @@ class ExecutionGroup { /** * \brief number of chunks in the x-axis */ - unsigned int m_numberOfXChunks; + unsigned int m_x_chunks_len; /** * \brief number of chunks in the y-axis */ - unsigned int m_numberOfYChunks; + unsigned int m_y_chunks_len; /** * \brief total number of chunks */ - unsigned int m_numberOfChunks; + unsigned int m_chunks_len; /** * \brief contains this ExecutionGroup a complex NodeOperation. @@ -131,12 +128,12 @@ class ExecutionGroup { * \brief what is the maximum number field of all ReadBufferOperation in this ExecutionGroup. * \note this is used to construct the MemoryBuffers that will be passed during execution. */ - unsigned int m_cachedMaxReadBufferOffset; + unsigned int m_max_read_buffer_offset; /** - * \brief a cached vector of all read operations in the execution group. + * \brief All read operations of this execution group. */ - Operations m_cachedReadOperations; + blender::Vector<ReadBufferOperation *> m_read_operations; /** * \brief reference to the original bNodeTree, @@ -148,15 +145,15 @@ class ExecutionGroup { /** * \brief total number of chunks that have been calculated for this ExecutionGroup */ - unsigned int m_chunksFinished; + unsigned int m_chunks_finished; /** - * \brief the chunkExecutionStates holds per chunk the execution state. this state can be - * - COM_ES_NOT_SCHEDULED: not scheduled - * - COM_ES_SCHEDULED: scheduled - * - COM_ES_EXECUTED: executed + * \brief m_chunk_execution_states holds per chunk the execution state. this state can be + * - eChunkExecutionState::NOT_SCHEDULED: not scheduled + * - eChunkExecutionState::SCHEDULED: scheduled + * - eChunkExecutionState::EXECUTED: executed */ - ChunkExecutionState *m_chunkExecutionStates; + blender::Vector<eChunkExecutionState> m_chunk_execution_states; /** * \brief indicator when this ExecutionGroup has valid Operations in its vector for Execution @@ -272,18 +269,18 @@ class ExecutionGroup { * \note ViewerOperation, CompositeOperation, PreviewOperation. * \see NodeOperation.isOutputOperation */ - int isOutputExecutionGroup() const + bool isOutputExecutionGroup() const { - return this->m_isOutput; + return this->m_is_output; } /** * \brief set whether this ExecutionGroup is an output * \param isOutput: */ - void setOutputExecutionGroup(int isOutput) + void setOutputExecutionGroup(bool is_output) { - this->m_isOutput = isOutput; + this->m_is_output = is_output; } /** @@ -405,7 +402,7 @@ class ExecutionGroup { * \note the area of the MemoryProxy.creator that has to be executed. * \param memoryProxies: result */ - void determineDependingMemoryProxies(vector<MemoryProxy *> *memoryProxies); + void determineDependingMemoryProxies(std::vector<MemoryProxy *> *memoryProxies); /** * \brief Determine the rect (minx, maxx, miny, maxy) of a chunk. diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.cpp b/source/blender/compositor/intern/COM_ExecutionSystem.cc index 4c0c7d2103e..6691e5feb5f 100644 --- a/source/blender/compositor/intern/COM_ExecutionSystem.cpp +++ b/source/blender/compositor/intern/COM_ExecutionSystem.cc @@ -121,7 +121,8 @@ ExecutionSystem::~ExecutionSystem() this->m_groups.clear(); } -void ExecutionSystem::set_operations(const Operations &operations, const Groups &groups) +void ExecutionSystem::set_operations(const blender::Vector<NodeOperation *> &operations, + const blender::Vector<ExecutionGroup *> &groups) { m_operations = operations; m_groups = groups; @@ -135,10 +136,7 @@ void ExecutionSystem::execute() DebugInfo::execute_started(this); unsigned int order = 0; - for (vector<NodeOperation *>::iterator iter = this->m_operations.begin(); - iter != this->m_operations.end(); - ++iter) { - NodeOperation *operation = *iter; + for (NodeOperation *operation : m_operations) { if (operation->isReadBufferOperation()) { ReadBufferOperation *readOperation = (ReadBufferOperation *)operation; readOperation->setOffset(order); @@ -179,10 +177,10 @@ void ExecutionSystem::execute() WorkScheduler::start(this->m_context); - executeGroups(COM_PRIORITY_HIGH); + execute_groups(COM_PRIORITY_HIGH); if (!this->getContext().isFastCalculation()) { - executeGroups(COM_PRIORITY_MEDIUM); - executeGroups(COM_PRIORITY_LOW); + execute_groups(COM_PRIORITY_MEDIUM); + execute_groups(COM_PRIORITY_LOW); } WorkScheduler::finish(); @@ -199,37 +197,23 @@ void ExecutionSystem::execute() } } -void ExecutionSystem::executeGroups(CompositorPriority priority) +void ExecutionSystem::execute_groups(CompositorPriority priority) { - unsigned int index; - vector<ExecutionGroup *> executionGroups; - this->findOutputExecutionGroup(&executionGroups, priority); - - for (index = 0; index < executionGroups.size(); index++) { - ExecutionGroup *group = executionGroups[index]; + blender::Vector<ExecutionGroup *> execution_groups = find_output_execution_groups(priority); + for (ExecutionGroup *group : execution_groups) { group->execute(this); } } -void ExecutionSystem::findOutputExecutionGroup(vector<ExecutionGroup *> *result, - CompositorPriority priority) const +blender::Vector<ExecutionGroup *> ExecutionSystem::find_output_execution_groups( + CompositorPriority priority) const { - unsigned int index; - for (index = 0; index < this->m_groups.size(); index++) { - ExecutionGroup *group = this->m_groups[index]; - if (group->isOutputExecutionGroup() && group->getRenderPriotrity() == priority) { - result->push_back(group); - } - } -} + blender::Vector<ExecutionGroup *> result; -void ExecutionSystem::findOutputExecutionGroup(vector<ExecutionGroup *> *result) const -{ - unsigned int index; - for (index = 0; index < this->m_groups.size(); index++) { - ExecutionGroup *group = this->m_groups[index]; - if (group->isOutputExecutionGroup()) { - result->push_back(group); + for (ExecutionGroup *group : m_groups) { + if (group->isOutputExecutionGroup() && group->getRenderPriotrity() == priority) { + result.append(group); } } + return result; } diff --git a/source/blender/compositor/intern/COM_ExecutionSystem.h b/source/blender/compositor/intern/COM_ExecutionSystem.h index 44b47787b06..9a51baf55d7 100644 --- a/source/blender/compositor/intern/COM_ExecutionSystem.h +++ b/source/blender/compositor/intern/COM_ExecutionSystem.h @@ -21,12 +21,16 @@ class ExecutionGroup; #pragma once #include "BKE_text.h" + #include "COM_ExecutionGroup.h" #include "COM_Node.h" #include "COM_NodeOperation.h" + #include "DNA_color_types.h" #include "DNA_node_types.h" +#include "BLI_vector.hh" + /** * \page execution Execution model * In order to get to an efficient model for execution, several steps are being done. these steps @@ -79,7 +83,7 @@ class ExecutionGroup; * - [@ref InputSocketResizeMode.COM_SC_NO_RESIZE]: * Bottom left of the images are aligned. * - * \see Converter.convertDataType Datatype conversions + * \see COM_convert_data_type Datatype conversions * \see Converter.convertResolution Image size conversions * * \section EM_Step4 Step4: group operations in executions groups @@ -113,9 +117,6 @@ class ExecutionGroup; * \brief the ExecutionSystem contains the whole compositor tree. */ class ExecutionSystem { - public: - typedef std::vector<NodeOperation *> Operations; - typedef std::vector<ExecutionGroup *> Groups; private: /** @@ -126,24 +127,19 @@ class ExecutionSystem { /** * \brief vector of operations */ - Operations m_operations; + blender::Vector<NodeOperation *> m_operations; /** * \brief vector of groups */ - Groups m_groups; + blender::Vector<ExecutionGroup *> m_groups; private: // methods /** * find all execution group with output nodes */ - void findOutputExecutionGroup(vector<ExecutionGroup *> *result, - CompositorPriority priority) const; - - /** - * find all execution group with output nodes - */ - void findOutputExecutionGroup(vector<ExecutionGroup *> *result) const; + blender::Vector<ExecutionGroup *> find_output_execution_groups( + CompositorPriority priority) const; public: /** @@ -167,7 +163,8 @@ class ExecutionSystem { */ ~ExecutionSystem(); - void set_operations(const Operations &operations, const Groups &groups); + void set_operations(const blender::Vector<NodeOperation *> &operations, + const blender::Vector<ExecutionGroup *> &groups); /** * \brief execute this system @@ -186,7 +183,7 @@ class ExecutionSystem { } private: - void executeGroups(CompositorPriority priority); + void execute_groups(CompositorPriority priority); /* allow the DebugInfo class to look at internals */ friend class DebugInfo; diff --git a/source/blender/compositor/intern/COM_MemoryBuffer.cpp b/source/blender/compositor/intern/COM_MemoryBuffer.cc index a13db6bb09e..17a73efeab2 100644 --- a/source/blender/compositor/intern/COM_MemoryBuffer.cpp +++ b/source/blender/compositor/intern/COM_MemoryBuffer.cc @@ -20,9 +20,6 @@ #include "MEM_guardedalloc.h" -using std::max; -using std::min; - static unsigned int determine_num_channels(DataType datatype) { switch (datatype) { @@ -156,10 +153,10 @@ void MemoryBuffer::copyContentFrom(MemoryBuffer *otherBuffer) return; } unsigned int otherY; - unsigned int minX = max(this->m_rect.xmin, otherBuffer->m_rect.xmin); - unsigned int maxX = min(this->m_rect.xmax, otherBuffer->m_rect.xmax); - unsigned int minY = max(this->m_rect.ymin, otherBuffer->m_rect.ymin); - unsigned int maxY = min(this->m_rect.ymax, otherBuffer->m_rect.ymax); + unsigned int minX = MAX2(this->m_rect.xmin, otherBuffer->m_rect.xmin); + unsigned int maxX = MIN2(this->m_rect.xmax, otherBuffer->m_rect.xmax); + unsigned int minY = MAX2(this->m_rect.ymin, otherBuffer->m_rect.ymin); + unsigned int maxY = MIN2(this->m_rect.ymax, otherBuffer->m_rect.ymax); int offset; int otherOffset; diff --git a/source/blender/compositor/intern/COM_MemoryProxy.cpp b/source/blender/compositor/intern/COM_MemoryProxy.cc index 7d590cd0ef6..7d590cd0ef6 100644 --- a/source/blender/compositor/intern/COM_MemoryProxy.cpp +++ b/source/blender/compositor/intern/COM_MemoryProxy.cc diff --git a/source/blender/compositor/intern/COM_MetaData.cpp b/source/blender/compositor/intern/COM_MetaData.cc index a6306f6c657..a6306f6c657 100644 --- a/source/blender/compositor/intern/COM_MetaData.cpp +++ b/source/blender/compositor/intern/COM_MetaData.cc diff --git a/source/blender/compositor/intern/COM_Node.cpp b/source/blender/compositor/intern/COM_Node.cc index 897d4e1df02..897d4e1df02 100644 --- a/source/blender/compositor/intern/COM_Node.cpp +++ b/source/blender/compositor/intern/COM_Node.cc diff --git a/source/blender/compositor/intern/COM_NodeConverter.cpp b/source/blender/compositor/intern/COM_NodeConverter.cc index 2db31bd4133..2db31bd4133 100644 --- a/source/blender/compositor/intern/COM_NodeConverter.cpp +++ b/source/blender/compositor/intern/COM_NodeConverter.cc diff --git a/source/blender/compositor/intern/COM_NodeGraph.cpp b/source/blender/compositor/intern/COM_NodeGraph.cc index b604b8ced88..421a762d9b5 100644 --- a/source/blender/compositor/intern/COM_NodeGraph.cpp +++ b/source/blender/compositor/intern/COM_NodeGraph.cc @@ -90,7 +90,7 @@ void NodeGraph::add_node(Node *node, void NodeGraph::add_link(NodeOutput *fromSocket, NodeInput *toSocket) { - m_links.push_back(Link(fromSocket, toSocket)); + m_links.append(Link(fromSocket, toSocket)); /* register with the input */ toSocket->setLink(fromSocket); @@ -132,7 +132,7 @@ void NodeGraph::add_bNode(const CompositorContext &context, } /* replace slow nodes with proxies for fast execution */ - if (context.isFastCalculation() && !Converter::is_fast_node(b_node)) { + if (context.isFastCalculation() && !COM_bnode_is_fast_node(*b_node)) { add_proxies_skip(b_ntree, b_node, key, is_active_group); return; } @@ -146,7 +146,7 @@ void NodeGraph::add_bNode(const CompositorContext &context, } else { /* regular nodes, handled in Converter */ - Node *node = Converter::convert(b_node); + Node *node = COM_convert_bnode(b_node); if (node) { add_node(node, b_ntree, key, is_active_group); } diff --git a/source/blender/compositor/intern/COM_NodeGraph.h b/source/blender/compositor/intern/COM_NodeGraph.h index 7252d546fce..990e3a30831 100644 --- a/source/blender/compositor/intern/COM_NodeGraph.h +++ b/source/blender/compositor/intern/COM_NodeGraph.h @@ -18,6 +18,8 @@ #pragma once +#include "BLI_vector.hh" + #include <map> #include <set> #include <vector> @@ -39,33 +41,21 @@ class NodeOutput; */ class NodeGraph { public: - class Link { - private: - NodeOutput *m_from; - NodeInput *m_to; - - public: - Link(NodeOutput *from, NodeInput *to) : m_from(from), m_to(to) - { - } + struct Link { + NodeOutput *from; + NodeInput *to; - NodeOutput *getFromSocket() const - { - return m_from; - } - NodeInput *getToSocket() const + Link(NodeOutput *from, NodeInput *to) : from(from), to(to) { - return m_to; } }; typedef std::vector<Node *> Nodes; typedef Nodes::iterator NodeIterator; - typedef std::vector<Link> Links; private: Nodes m_nodes; - Links m_links; + blender::Vector<Link> m_links; public: NodeGraph(); @@ -75,7 +65,7 @@ class NodeGraph { { return m_nodes; } - const Links &links() const + const blender::Vector<Link> &links() const { return m_links; } diff --git a/source/blender/compositor/intern/COM_NodeOperation.cpp b/source/blender/compositor/intern/COM_NodeOperation.cc index 1a30806f28c..ce7d3a6389e 100644 --- a/source/blender/compositor/intern/COM_NodeOperation.cpp +++ b/source/blender/compositor/intern/COM_NodeOperation.cc @@ -182,10 +182,10 @@ bool NodeOperation::determineDependingAreaOfInterest(rcti *input, first = false; } else { - output->xmin = min(output->xmin, tempOutput.xmin); - output->ymin = min(output->ymin, tempOutput.ymin); - output->xmax = max(output->xmax, tempOutput.xmax); - output->ymax = max(output->ymax, tempOutput.ymax); + output->xmin = MIN2(output->xmin, tempOutput.xmin); + output->ymin = MIN2(output->ymin, tempOutput.ymin); + output->xmax = MAX2(output->xmax, tempOutput.xmax); + output->ymax = MAX2(output->ymax, tempOutput.ymax); } } } diff --git a/source/blender/compositor/intern/COM_NodeOperation.h b/source/blender/compositor/intern/COM_NodeOperation.h index 0ce7c1389bd..f26279e2869 100644 --- a/source/blender/compositor/intern/COM_NodeOperation.h +++ b/source/blender/compositor/intern/COM_NodeOperation.h @@ -33,10 +33,6 @@ #include "clew.h" -using std::list; -using std::max; -using std::min; - class OpenCLDevice; class ReadBufferOperation; class WriteBufferOperation; @@ -239,8 +235,8 @@ class NodeOperation : public SocketReader { MemoryBuffer * /*outputMemoryBuffer*/, cl_mem /*clOutputBuffer*/, MemoryBuffer ** /*inputMemoryBuffers*/, - list<cl_mem> * /*clMemToCleanUp*/, - list<cl_kernel> * /*clKernelsToCleanUp*/) + std::list<cl_mem> * /*clMemToCleanUp*/, + std::list<cl_kernel> * /*clKernelsToCleanUp*/) { } virtual void deinitExecution(); diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp b/source/blender/compositor/intern/COM_NodeOperationBuilder.cc index 35a3314db3b..688b693080f 100644 --- a/source/blender/compositor/intern/COM_NodeOperationBuilder.cpp +++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.cc @@ -72,11 +72,9 @@ void NodeOperationBuilder::convertToOperations(ExecutionSystem *system) inverse_input_map[it->second].push_back(it->first); } - for (NodeGraph::Links::const_iterator it = m_graph.links().begin(); it != m_graph.links().end(); - ++it) { - const NodeGraph::Link &link = *it; - NodeOutput *from = link.getFromSocket(); - NodeInput *to = link.getToSocket(); + for (const NodeGraph::Link &link : m_graph.links()) { + NodeOutput *from = link.from; + NodeInput *to = link.to; NodeOperationOutput *op_from = find_operation_output(m_output_map, from); const OpInputs &op_to_list = find_operation_inputs(inverse_input_map, to); @@ -125,7 +123,7 @@ void NodeOperationBuilder::convertToOperations(ExecutionSystem *system) void NodeOperationBuilder::addOperation(NodeOperation *operation) { - m_operations.push_back(operation); + m_operations.append(operation); } void NodeOperationBuilder::mapInputSocket(NodeInput *node_socket, @@ -288,7 +286,7 @@ void NodeOperationBuilder::add_datatype_conversions() } for (Links::const_iterator it = convert_links.begin(); it != convert_links.end(); ++it) { const Link &link = *it; - NodeOperation *converter = Converter::convertDataType(link.from(), link.to()); + NodeOperation *converter = COM_convert_data_type(*link.from(), *link.to()); if (converter) { addOperation(converter); @@ -306,8 +304,7 @@ void NodeOperationBuilder::add_operation_input_constants() */ using Inputs = std::vector<NodeOperationInput *>; Inputs pending_inputs; - for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) { - NodeOperation *op = *it; + for (NodeOperation *op : m_operations) { for (int k = 0; k < op->getNumberOfInputSockets(); ++k) { NodeOperationInput *input = op->getInputSocket(k); if (!input->isConnected()) { @@ -408,9 +405,7 @@ void NodeOperationBuilder::resolve_proxies() void NodeOperationBuilder::determineResolutions() { /* determine all resolutions of the operations (Width/Height) */ - for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) { - NodeOperation *op = *it; - + for (NodeOperation *op : m_operations) { if (op->isOutputOperation(m_context->isRendering()) && !op->isPreviewOperation()) { unsigned int resolution[2] = {0, 0}; unsigned int preferredResolution[2] = {0, 0}; @@ -419,9 +414,7 @@ void NodeOperationBuilder::determineResolutions() } } - for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) { - NodeOperation *op = *it; - + for (NodeOperation *op : m_operations) { if (op->isOutputOperation(m_context->isRendering()) && op->isPreviewOperation()) { unsigned int resolution[2] = {0, 0}; unsigned int preferredResolution[2] = {0, 0}; @@ -446,7 +439,7 @@ void NodeOperationBuilder::determineResolutions() } for (Links::const_iterator it = convert_links.begin(); it != convert_links.end(); ++it) { const Link &link = *it; - Converter::convertResolution(*this, link.from(), link.to()); + COM_convert_resolution(*this, link.from(), link.to()); } } } @@ -575,16 +568,14 @@ void NodeOperationBuilder::add_complex_operation_buffers() /* note: complex ops and get cached here first, since adding operations * will invalidate iterators over the main m_operations */ - Operations complex_ops; - for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) { - if ((*it)->isComplex()) { - complex_ops.push_back(*it); + blender::Vector<NodeOperation *> complex_ops; + for (NodeOperation *operation : m_operations) { + if (operation->isComplex()) { + complex_ops.append(operation); } } - for (Operations::const_iterator it = complex_ops.begin(); it != complex_ops.end(); ++it) { - NodeOperation *op = *it; - + for (NodeOperation *op : complex_ops) { DebugInfo::operation_read_write_buffer(op); for (int index = 0; index < op->getNumberOfInputSockets(); index++) { @@ -624,9 +615,7 @@ static void find_reachable_operations_recursive(Tags &reachable, NodeOperation * void NodeOperationBuilder::prune_operations() { Tags reachable; - for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) { - NodeOperation *op = *it; - + for (NodeOperation *op : m_operations) { /* output operations are primary executed operations */ if (op->isOutputOperation(m_context->isRendering())) { find_reachable_operations_recursive(reachable, op); @@ -634,12 +623,10 @@ void NodeOperationBuilder::prune_operations() } /* delete unreachable operations */ - Operations reachable_ops; - for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) { - NodeOperation *op = *it; - + blender::Vector<NodeOperation *> reachable_ops; + for (NodeOperation *op : m_operations) { if (reachable.find(op) != reachable.end()) { - reachable_ops.push_back(op); + reachable_ops.append(op); } else { delete op; @@ -650,7 +637,7 @@ void NodeOperationBuilder::prune_operations() } /* topological (depth-first) sorting of operations */ -static void sort_operations_recursive(NodeOperationBuilder::Operations &sorted, +static void sort_operations_recursive(blender::Vector<NodeOperation *> &sorted, Tags &visited, NodeOperation *op) { @@ -666,17 +653,17 @@ static void sort_operations_recursive(NodeOperationBuilder::Operations &sorted, } } - sorted.push_back(op); + sorted.append(op); } void NodeOperationBuilder::sort_operations() { - Operations sorted; + blender::Vector<NodeOperation *> sorted; sorted.reserve(m_operations.size()); Tags visited; - for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) { - sort_operations_recursive(sorted, visited, *it); + for (NodeOperation *operation : m_operations) { + sort_operations_recursive(sorted, visited, operation); } m_operations = sorted; @@ -705,7 +692,7 @@ static void add_group_operations_recursive(Tags &visited, NodeOperation *op, Exe ExecutionGroup *NodeOperationBuilder::make_group(NodeOperation *op) { ExecutionGroup *group = new ExecutionGroup(); - m_groups.push_back(group); + m_groups.append(group); Tags visited; add_group_operations_recursive(visited, op, group); @@ -715,9 +702,7 @@ ExecutionGroup *NodeOperationBuilder::make_group(NodeOperation *op) void NodeOperationBuilder::group_operations() { - for (Operations::const_iterator it = m_operations.begin(); it != m_operations.end(); ++it) { - NodeOperation *op = *it; - + for (NodeOperation *op : m_operations) { if (op->isOutputOperation(m_context->isRendering())) { ExecutionGroup *group = make_group(op); group->setOutputExecutionGroup(true); diff --git a/source/blender/compositor/intern/COM_NodeOperationBuilder.h b/source/blender/compositor/intern/COM_NodeOperationBuilder.h index 5dd4022b127..b502a12d9b1 100644 --- a/source/blender/compositor/intern/COM_NodeOperationBuilder.h +++ b/source/blender/compositor/intern/COM_NodeOperationBuilder.h @@ -24,8 +24,6 @@ #include "COM_NodeGraph.h" -using std::vector; - class CompositorContext; class Node; @@ -64,9 +62,7 @@ class NodeOperationBuilder { } }; - typedef std::vector<NodeOperation *> Operations; typedef std::vector<Link> Links; - typedef std::vector<ExecutionGroup *> Groups; typedef std::map<NodeOperationInput *, NodeInput *> InputSocketMap; typedef std::map<NodeOutput *, NodeOperationOutput *> OutputSocketMap; @@ -78,9 +74,9 @@ class NodeOperationBuilder { const CompositorContext *m_context; NodeGraph m_graph; - Operations m_operations; + blender::Vector<NodeOperation *> m_operations; Links m_links; - Groups m_groups; + blender::Vector<ExecutionGroup *> m_groups; /** Maps operation inputs to node inputs */ InputSocketMap m_input_map; diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.cpp b/source/blender/compositor/intern/COM_OpenCLDevice.cc index acfe800e433..34450366aec 100644 --- a/source/blender/compositor/intern/COM_OpenCLDevice.cpp +++ b/source/blender/compositor/intern/COM_OpenCLDevice.cc @@ -61,8 +61,8 @@ void OpenCLDevice::deinitialize() void OpenCLDevice::execute(WorkPackage *work) { - const unsigned int chunkNumber = work->getChunkNumber(); - ExecutionGroup *executionGroup = work->getExecutionGroup(); + const unsigned int chunkNumber = work->chunk_number; + ExecutionGroup *executionGroup = work->execution_group; rcti rect; executionGroup->determineChunkRect(&rect, chunkNumber); @@ -79,7 +79,7 @@ void OpenCLDevice::execute(WorkPackage *work) cl_mem OpenCLDevice::COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel, int parameterIndex, int offsetIndex, - list<cl_mem> *cleanup, + std::list<cl_mem> *cleanup, MemoryBuffer **inputMemoryBuffers, SocketReader *reader) { @@ -111,7 +111,7 @@ const cl_image_format *OpenCLDevice::determineImageFormat(MemoryBuffer *memoryBu cl_mem OpenCLDevice::COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel, int parameterIndex, int offsetIndex, - list<cl_mem> *cleanup, + std::list<cl_mem> *cleanup, MemoryBuffer **inputMemoryBuffers, ReadBufferOperation *reader) { @@ -258,7 +258,7 @@ void OpenCLDevice::COM_clEnqueueRange(cl_kernel kernel, } cl_kernel OpenCLDevice::COM_clCreateKernel(const char *kernelname, - list<cl_kernel> *clKernelsToCleanUp) + std::list<cl_kernel> *clKernelsToCleanUp) { cl_int error; cl_kernel kernel = clCreateKernel(this->m_program, kernelname, &error); diff --git a/source/blender/compositor/intern/COM_OpenCLDevice.h b/source/blender/compositor/intern/COM_OpenCLDevice.h index d502f5aa34b..e4fd397b4e8 100644 --- a/source/blender/compositor/intern/COM_OpenCLDevice.h +++ b/source/blender/compositor/intern/COM_OpenCLDevice.h @@ -25,8 +25,6 @@ class OpenCLDevice; #include "COM_WorkScheduler.h" #include "clew.h" -using std::list; - /** * \brief device representing an GPU OpenCL device. * an instance of this class represents a single cl_device @@ -107,13 +105,13 @@ class OpenCLDevice : public Device { cl_mem COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel, int parameterIndex, int offsetIndex, - list<cl_mem> *cleanup, + std::list<cl_mem> *cleanup, MemoryBuffer **inputMemoryBuffers, SocketReader *reader); cl_mem COM_clAttachMemoryBufferToKernelParameter(cl_kernel kernel, int parameterIndex, int offsetIndex, - list<cl_mem> *cleanup, + std::list<cl_mem> *cleanup, MemoryBuffer **inputMemoryBuffers, ReadBufferOperation *reader); void COM_clAttachMemoryBufferOffsetToKernelParameter(cl_kernel kernel, @@ -130,5 +128,5 @@ class OpenCLDevice : public Device { MemoryBuffer *outputMemoryBuffer, int offsetIndex, NodeOperation *operation); - cl_kernel COM_clCreateKernel(const char *kernelname, list<cl_kernel> *clKernelsToCleanUp); + cl_kernel COM_clCreateKernel(const char *kernelname, std::list<cl_kernel> *clKernelsToCleanUp); }; diff --git a/source/blender/compositor/intern/COM_SingleThreadedOperation.cpp b/source/blender/compositor/intern/COM_SingleThreadedOperation.cc index 5febf3802de..5febf3802de 100644 --- a/source/blender/compositor/intern/COM_SingleThreadedOperation.cpp +++ b/source/blender/compositor/intern/COM_SingleThreadedOperation.cc diff --git a/source/blender/compositor/intern/COM_SocketReader.cpp b/source/blender/compositor/intern/COM_SocketReader.cc index 93c8a143b86..93c8a143b86 100644 --- a/source/blender/compositor/intern/COM_SocketReader.cpp +++ b/source/blender/compositor/intern/COM_SocketReader.cc diff --git a/source/blender/compositor/intern/COM_WorkPackage.cpp b/source/blender/compositor/intern/COM_WorkPackage.cc index 795f8d88d50..60684f2c45c 100644 --- a/source/blender/compositor/intern/COM_WorkPackage.cpp +++ b/source/blender/compositor/intern/COM_WorkPackage.cc @@ -18,8 +18,8 @@ #include "COM_WorkPackage.h" -WorkPackage::WorkPackage(ExecutionGroup *group, unsigned int chunkNumber) +WorkPackage::WorkPackage(ExecutionGroup *execution_group, unsigned int chunk_number) { - this->m_executionGroup = group; - this->m_chunkNumber = chunkNumber; + this->execution_group = execution_group; + this->chunk_number = chunk_number; } diff --git a/source/blender/compositor/intern/COM_WorkPackage.h b/source/blender/compositor/intern/COM_WorkPackage.h index f4370aa41be..db5eb3d3072 100644 --- a/source/blender/compositor/intern/COM_WorkPackage.h +++ b/source/blender/compositor/intern/COM_WorkPackage.h @@ -16,8 +16,6 @@ * Copyright 2011, Blender Foundation. */ -class WorkPackage; - #pragma once class ExecutionGroup; @@ -27,41 +25,23 @@ class ExecutionGroup; * \brief contains data about work that can be scheduled * \see WorkScheduler */ -class WorkPackage { - private: +struct WorkPackage { /** * \brief executionGroup with the operations-setup to be evaluated */ - ExecutionGroup *m_executionGroup; + ExecutionGroup *execution_group; /** * \brief number of the chunk to be executed */ - unsigned int m_chunkNumber; + unsigned int chunk_number; - public: /** * constructor * \param group: the ExecutionGroup - * \param chunkNumber: the number of the chunk - */ - WorkPackage(ExecutionGroup *group, unsigned int chunkNumber); - - /** - * \brief get the ExecutionGroup - */ - ExecutionGroup *getExecutionGroup() const - { - return this->m_executionGroup; - } - - /** - * \brief get the number of the chunk + * \param chunk_number: the number of the chunk */ - unsigned int getChunkNumber() const - { - return this->m_chunkNumber; - } + WorkPackage(ExecutionGroup *group, unsigned int chunk_number); #ifdef WITH_CXX_GUARDEDALLOC MEM_CXX_CLASS_ALLOC_FUNCS("COM:WorkPackage") diff --git a/source/blender/compositor/intern/COM_WorkScheduler.cpp b/source/blender/compositor/intern/COM_WorkScheduler.cc index 9ca704afdea..a70b6ba4abe 100644 --- a/source/blender/compositor/intern/COM_WorkScheduler.cpp +++ b/source/blender/compositor/intern/COM_WorkScheduler.cc @@ -48,7 +48,7 @@ static ThreadLocal(CPUDevice *) g_thread_device; static struct { /** \brief list of all CPUDevices. for every hardware thread an instance of CPUDevice is created */ - vector<CPUDevice *> cpu_devices; + std::vector<CPUDevice *> cpu_devices; #if COM_CURRENT_THREADING_MODEL == COM_TM_QUEUE /** \brief list of all thread for every CPUDevice in cpudevices a thread exists. */ @@ -62,7 +62,7 @@ static struct { cl_program opencl_program; /** \brief list of all OpenCLDevices. for every OpenCL GPU device an instance of OpenCLDevice is * created. */ - vector<OpenCLDevice *> gpu_devices; + std::vector<OpenCLDevice *> gpu_devices; /** \brief list of all thread for every GPUDevice in cpudevices a thread exists. */ ListBase gpu_threads; /** \brief all scheduled work for the GPU. */ diff --git a/source/blender/compositor/intern/COM_compositor.cpp b/source/blender/compositor/intern/COM_compositor.cc index 68e4f80f91f..68e4f80f91f 100644 --- a/source/blender/compositor/intern/COM_compositor.cpp +++ b/source/blender/compositor/intern/COM_compositor.cc diff --git a/source/blender/compositor/nodes/COM_AlphaOverNode.cpp b/source/blender/compositor/nodes/COM_AlphaOverNode.cc index 640fbf49808..640fbf49808 100644 --- a/source/blender/compositor/nodes/COM_AlphaOverNode.cpp +++ b/source/blender/compositor/nodes/COM_AlphaOverNode.cc diff --git a/source/blender/compositor/nodes/COM_BilateralBlurNode.cpp b/source/blender/compositor/nodes/COM_BilateralBlurNode.cc index e8037f923f2..e8037f923f2 100644 --- a/source/blender/compositor/nodes/COM_BilateralBlurNode.cpp +++ b/source/blender/compositor/nodes/COM_BilateralBlurNode.cc diff --git a/source/blender/compositor/nodes/COM_BlurNode.cpp b/source/blender/compositor/nodes/COM_BlurNode.cc index b82bede8443..b82bede8443 100644 --- a/source/blender/compositor/nodes/COM_BlurNode.cpp +++ b/source/blender/compositor/nodes/COM_BlurNode.cc diff --git a/source/blender/compositor/nodes/COM_BokehBlurNode.cpp b/source/blender/compositor/nodes/COM_BokehBlurNode.cc index 5096dbef608..5096dbef608 100644 --- a/source/blender/compositor/nodes/COM_BokehBlurNode.cpp +++ b/source/blender/compositor/nodes/COM_BokehBlurNode.cc diff --git a/source/blender/compositor/nodes/COM_BokehImageNode.cpp b/source/blender/compositor/nodes/COM_BokehImageNode.cc index 87fe4979c1d..87fe4979c1d 100644 --- a/source/blender/compositor/nodes/COM_BokehImageNode.cpp +++ b/source/blender/compositor/nodes/COM_BokehImageNode.cc diff --git a/source/blender/compositor/nodes/COM_BoxMaskNode.cpp b/source/blender/compositor/nodes/COM_BoxMaskNode.cc index fe59bd32939..fe59bd32939 100644 --- a/source/blender/compositor/nodes/COM_BoxMaskNode.cpp +++ b/source/blender/compositor/nodes/COM_BoxMaskNode.cc diff --git a/source/blender/compositor/nodes/COM_BrightnessNode.cpp b/source/blender/compositor/nodes/COM_BrightnessNode.cc index fcd2a6de1f4..fcd2a6de1f4 100644 --- a/source/blender/compositor/nodes/COM_BrightnessNode.cpp +++ b/source/blender/compositor/nodes/COM_BrightnessNode.cc diff --git a/source/blender/compositor/nodes/COM_ChannelMatteNode.cpp b/source/blender/compositor/nodes/COM_ChannelMatteNode.cc index 598cd7b7745..598cd7b7745 100644 --- a/source/blender/compositor/nodes/COM_ChannelMatteNode.cpp +++ b/source/blender/compositor/nodes/COM_ChannelMatteNode.cc diff --git a/source/blender/compositor/nodes/COM_ChromaMatteNode.cpp b/source/blender/compositor/nodes/COM_ChromaMatteNode.cc index 83e88b35f92..83e88b35f92 100644 --- a/source/blender/compositor/nodes/COM_ChromaMatteNode.cpp +++ b/source/blender/compositor/nodes/COM_ChromaMatteNode.cc diff --git a/source/blender/compositor/nodes/COM_ColorBalanceNode.cpp b/source/blender/compositor/nodes/COM_ColorBalanceNode.cc index 596d9631297..596d9631297 100644 --- a/source/blender/compositor/nodes/COM_ColorBalanceNode.cpp +++ b/source/blender/compositor/nodes/COM_ColorBalanceNode.cc diff --git a/source/blender/compositor/nodes/COM_ColorCorrectionNode.cpp b/source/blender/compositor/nodes/COM_ColorCorrectionNode.cc index 92b334fddb9..92b334fddb9 100644 --- a/source/blender/compositor/nodes/COM_ColorCorrectionNode.cpp +++ b/source/blender/compositor/nodes/COM_ColorCorrectionNode.cc diff --git a/source/blender/compositor/nodes/COM_ColorCurveNode.cpp b/source/blender/compositor/nodes/COM_ColorCurveNode.cc index e1888f3f0bc..e1888f3f0bc 100644 --- a/source/blender/compositor/nodes/COM_ColorCurveNode.cpp +++ b/source/blender/compositor/nodes/COM_ColorCurveNode.cc diff --git a/source/blender/compositor/nodes/COM_ColorExposureNode.cpp b/source/blender/compositor/nodes/COM_ColorExposureNode.cc index cd0285ac373..cd0285ac373 100644 --- a/source/blender/compositor/nodes/COM_ColorExposureNode.cpp +++ b/source/blender/compositor/nodes/COM_ColorExposureNode.cc diff --git a/source/blender/compositor/nodes/COM_ColorMatteNode.cpp b/source/blender/compositor/nodes/COM_ColorMatteNode.cc index 865eee5427f..865eee5427f 100644 --- a/source/blender/compositor/nodes/COM_ColorMatteNode.cpp +++ b/source/blender/compositor/nodes/COM_ColorMatteNode.cc diff --git a/source/blender/compositor/nodes/COM_ColorNode.cpp b/source/blender/compositor/nodes/COM_ColorNode.cc index e6f8bfa01fe..e6f8bfa01fe 100644 --- a/source/blender/compositor/nodes/COM_ColorNode.cpp +++ b/source/blender/compositor/nodes/COM_ColorNode.cc diff --git a/source/blender/compositor/nodes/COM_ColorRampNode.cpp b/source/blender/compositor/nodes/COM_ColorRampNode.cc index 1504a76cee7..1504a76cee7 100644 --- a/source/blender/compositor/nodes/COM_ColorRampNode.cpp +++ b/source/blender/compositor/nodes/COM_ColorRampNode.cc diff --git a/source/blender/compositor/nodes/COM_ColorSpillNode.cpp b/source/blender/compositor/nodes/COM_ColorSpillNode.cc index d1a3099e998..d1a3099e998 100644 --- a/source/blender/compositor/nodes/COM_ColorSpillNode.cpp +++ b/source/blender/compositor/nodes/COM_ColorSpillNode.cc diff --git a/source/blender/compositor/nodes/COM_ColorToBWNode.cpp b/source/blender/compositor/nodes/COM_ColorToBWNode.cc index 4115bad5d3f..4115bad5d3f 100644 --- a/source/blender/compositor/nodes/COM_ColorToBWNode.cpp +++ b/source/blender/compositor/nodes/COM_ColorToBWNode.cc diff --git a/source/blender/compositor/nodes/COM_CombineColorNode.cpp b/source/blender/compositor/nodes/COM_CombineColorNode.cc index 12968f06a10..12968f06a10 100644 --- a/source/blender/compositor/nodes/COM_CombineColorNode.cpp +++ b/source/blender/compositor/nodes/COM_CombineColorNode.cc diff --git a/source/blender/compositor/nodes/COM_CompositorNode.cpp b/source/blender/compositor/nodes/COM_CompositorNode.cc index 32ac1fccec9..32ac1fccec9 100644 --- a/source/blender/compositor/nodes/COM_CompositorNode.cpp +++ b/source/blender/compositor/nodes/COM_CompositorNode.cc diff --git a/source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp b/source/blender/compositor/nodes/COM_ConvertAlphaNode.cc index 2921b44c95b..2921b44c95b 100644 --- a/source/blender/compositor/nodes/COM_ConvertAlphaNode.cpp +++ b/source/blender/compositor/nodes/COM_ConvertAlphaNode.cc diff --git a/source/blender/compositor/nodes/COM_CornerPinNode.cpp b/source/blender/compositor/nodes/COM_CornerPinNode.cc index efe847bbfbf..efe847bbfbf 100644 --- a/source/blender/compositor/nodes/COM_CornerPinNode.cpp +++ b/source/blender/compositor/nodes/COM_CornerPinNode.cc diff --git a/source/blender/compositor/nodes/COM_CropNode.cpp b/source/blender/compositor/nodes/COM_CropNode.cc index 0f0883b0151..0f0883b0151 100644 --- a/source/blender/compositor/nodes/COM_CropNode.cpp +++ b/source/blender/compositor/nodes/COM_CropNode.cc diff --git a/source/blender/compositor/nodes/COM_CryptomatteNode.cpp b/source/blender/compositor/nodes/COM_CryptomatteNode.cc index 27ef98af8f3..27ef98af8f3 100644 --- a/source/blender/compositor/nodes/COM_CryptomatteNode.cpp +++ b/source/blender/compositor/nodes/COM_CryptomatteNode.cc diff --git a/source/blender/compositor/nodes/COM_DefocusNode.cpp b/source/blender/compositor/nodes/COM_DefocusNode.cc index 393b1f2dabb..393b1f2dabb 100644 --- a/source/blender/compositor/nodes/COM_DefocusNode.cpp +++ b/source/blender/compositor/nodes/COM_DefocusNode.cc diff --git a/source/blender/compositor/nodes/COM_DenoiseNode.cpp b/source/blender/compositor/nodes/COM_DenoiseNode.cc index 1aae81e1e7b..1aae81e1e7b 100644 --- a/source/blender/compositor/nodes/COM_DenoiseNode.cpp +++ b/source/blender/compositor/nodes/COM_DenoiseNode.cc diff --git a/source/blender/compositor/nodes/COM_DespeckleNode.cpp b/source/blender/compositor/nodes/COM_DespeckleNode.cc index 58734917831..58734917831 100644 --- a/source/blender/compositor/nodes/COM_DespeckleNode.cpp +++ b/source/blender/compositor/nodes/COM_DespeckleNode.cc diff --git a/source/blender/compositor/nodes/COM_DifferenceMatteNode.cpp b/source/blender/compositor/nodes/COM_DifferenceMatteNode.cc index 3d538e9b4a0..3d538e9b4a0 100644 --- a/source/blender/compositor/nodes/COM_DifferenceMatteNode.cpp +++ b/source/blender/compositor/nodes/COM_DifferenceMatteNode.cc diff --git a/source/blender/compositor/nodes/COM_DilateErodeNode.cpp b/source/blender/compositor/nodes/COM_DilateErodeNode.cc index e90707618e5..e90707618e5 100644 --- a/source/blender/compositor/nodes/COM_DilateErodeNode.cpp +++ b/source/blender/compositor/nodes/COM_DilateErodeNode.cc diff --git a/source/blender/compositor/nodes/COM_DirectionalBlurNode.cpp b/source/blender/compositor/nodes/COM_DirectionalBlurNode.cc index f8d0eaf4675..f8d0eaf4675 100644 --- a/source/blender/compositor/nodes/COM_DirectionalBlurNode.cpp +++ b/source/blender/compositor/nodes/COM_DirectionalBlurNode.cc diff --git a/source/blender/compositor/nodes/COM_DisplaceNode.cpp b/source/blender/compositor/nodes/COM_DisplaceNode.cc index 0c0c3aad646..0c0c3aad646 100644 --- a/source/blender/compositor/nodes/COM_DisplaceNode.cpp +++ b/source/blender/compositor/nodes/COM_DisplaceNode.cc diff --git a/source/blender/compositor/nodes/COM_DistanceMatteNode.cpp b/source/blender/compositor/nodes/COM_DistanceMatteNode.cc index 37aeb5c8504..37aeb5c8504 100644 --- a/source/blender/compositor/nodes/COM_DistanceMatteNode.cpp +++ b/source/blender/compositor/nodes/COM_DistanceMatteNode.cc diff --git a/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cpp b/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cc index 907a9f49353..907a9f49353 100644 --- a/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cpp +++ b/source/blender/compositor/nodes/COM_DoubleEdgeMaskNode.cc diff --git a/source/blender/compositor/nodes/COM_EllipseMaskNode.cpp b/source/blender/compositor/nodes/COM_EllipseMaskNode.cc index 1ae855c0f1d..1ae855c0f1d 100644 --- a/source/blender/compositor/nodes/COM_EllipseMaskNode.cpp +++ b/source/blender/compositor/nodes/COM_EllipseMaskNode.cc diff --git a/source/blender/compositor/nodes/COM_FilterNode.cpp b/source/blender/compositor/nodes/COM_FilterNode.cc index 1147c11794f..1147c11794f 100644 --- a/source/blender/compositor/nodes/COM_FilterNode.cpp +++ b/source/blender/compositor/nodes/COM_FilterNode.cc diff --git a/source/blender/compositor/nodes/COM_FlipNode.cpp b/source/blender/compositor/nodes/COM_FlipNode.cc index d89e6b7b844..d89e6b7b844 100644 --- a/source/blender/compositor/nodes/COM_FlipNode.cpp +++ b/source/blender/compositor/nodes/COM_FlipNode.cc diff --git a/source/blender/compositor/nodes/COM_GammaNode.cpp b/source/blender/compositor/nodes/COM_GammaNode.cc index 1ce17faa0dc..1ce17faa0dc 100644 --- a/source/blender/compositor/nodes/COM_GammaNode.cpp +++ b/source/blender/compositor/nodes/COM_GammaNode.cc diff --git a/source/blender/compositor/nodes/COM_GlareNode.cpp b/source/blender/compositor/nodes/COM_GlareNode.cc index ef088e42205..ef088e42205 100644 --- a/source/blender/compositor/nodes/COM_GlareNode.cpp +++ b/source/blender/compositor/nodes/COM_GlareNode.cc diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp b/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cc index 00125ba2ea5..00125ba2ea5 100644 --- a/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cpp +++ b/source/blender/compositor/nodes/COM_HueSaturationValueCorrectNode.cc diff --git a/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp b/source/blender/compositor/nodes/COM_HueSaturationValueNode.cc index dc2e5187e8f..dc2e5187e8f 100644 --- a/source/blender/compositor/nodes/COM_HueSaturationValueNode.cpp +++ b/source/blender/compositor/nodes/COM_HueSaturationValueNode.cc diff --git a/source/blender/compositor/nodes/COM_IDMaskNode.cpp b/source/blender/compositor/nodes/COM_IDMaskNode.cc index 5ba54d75bcd..5ba54d75bcd 100644 --- a/source/blender/compositor/nodes/COM_IDMaskNode.cpp +++ b/source/blender/compositor/nodes/COM_IDMaskNode.cc diff --git a/source/blender/compositor/nodes/COM_ImageNode.cpp b/source/blender/compositor/nodes/COM_ImageNode.cc index 69729e018d7..69729e018d7 100644 --- a/source/blender/compositor/nodes/COM_ImageNode.cpp +++ b/source/blender/compositor/nodes/COM_ImageNode.cc diff --git a/source/blender/compositor/nodes/COM_InpaintNode.cpp b/source/blender/compositor/nodes/COM_InpaintNode.cc index 40fe63ec9f3..40fe63ec9f3 100644 --- a/source/blender/compositor/nodes/COM_InpaintNode.cpp +++ b/source/blender/compositor/nodes/COM_InpaintNode.cc diff --git a/source/blender/compositor/nodes/COM_InvertNode.cpp b/source/blender/compositor/nodes/COM_InvertNode.cc index 913452c42c8..913452c42c8 100644 --- a/source/blender/compositor/nodes/COM_InvertNode.cpp +++ b/source/blender/compositor/nodes/COM_InvertNode.cc diff --git a/source/blender/compositor/nodes/COM_KeyingNode.cpp b/source/blender/compositor/nodes/COM_KeyingNode.cc index 9b493d3f332..9b493d3f332 100644 --- a/source/blender/compositor/nodes/COM_KeyingNode.cpp +++ b/source/blender/compositor/nodes/COM_KeyingNode.cc diff --git a/source/blender/compositor/nodes/COM_KeyingScreenNode.cpp b/source/blender/compositor/nodes/COM_KeyingScreenNode.cc index 93a9a071226..93a9a071226 100644 --- a/source/blender/compositor/nodes/COM_KeyingScreenNode.cpp +++ b/source/blender/compositor/nodes/COM_KeyingScreenNode.cc diff --git a/source/blender/compositor/nodes/COM_LensDistortionNode.cpp b/source/blender/compositor/nodes/COM_LensDistortionNode.cc index 34d2fba6433..34d2fba6433 100644 --- a/source/blender/compositor/nodes/COM_LensDistortionNode.cpp +++ b/source/blender/compositor/nodes/COM_LensDistortionNode.cc diff --git a/source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp b/source/blender/compositor/nodes/COM_LuminanceMatteNode.cc index 8bfea1eff49..8bfea1eff49 100644 --- a/source/blender/compositor/nodes/COM_LuminanceMatteNode.cpp +++ b/source/blender/compositor/nodes/COM_LuminanceMatteNode.cc diff --git a/source/blender/compositor/nodes/COM_MapRangeNode.cpp b/source/blender/compositor/nodes/COM_MapRangeNode.cc index 352bc0dd48d..352bc0dd48d 100644 --- a/source/blender/compositor/nodes/COM_MapRangeNode.cpp +++ b/source/blender/compositor/nodes/COM_MapRangeNode.cc diff --git a/source/blender/compositor/nodes/COM_MapUVNode.cpp b/source/blender/compositor/nodes/COM_MapUVNode.cc index feb9c75ec56..feb9c75ec56 100644 --- a/source/blender/compositor/nodes/COM_MapUVNode.cpp +++ b/source/blender/compositor/nodes/COM_MapUVNode.cc diff --git a/source/blender/compositor/nodes/COM_MapValueNode.cpp b/source/blender/compositor/nodes/COM_MapValueNode.cc index e07df8ad367..e07df8ad367 100644 --- a/source/blender/compositor/nodes/COM_MapValueNode.cpp +++ b/source/blender/compositor/nodes/COM_MapValueNode.cc diff --git a/source/blender/compositor/nodes/COM_MaskNode.cpp b/source/blender/compositor/nodes/COM_MaskNode.cc index a6415a3992e..a6415a3992e 100644 --- a/source/blender/compositor/nodes/COM_MaskNode.cpp +++ b/source/blender/compositor/nodes/COM_MaskNode.cc diff --git a/source/blender/compositor/nodes/COM_MathNode.cpp b/source/blender/compositor/nodes/COM_MathNode.cc index 0edf880400f..0edf880400f 100644 --- a/source/blender/compositor/nodes/COM_MathNode.cpp +++ b/source/blender/compositor/nodes/COM_MathNode.cc diff --git a/source/blender/compositor/nodes/COM_MixNode.cpp b/source/blender/compositor/nodes/COM_MixNode.cc index d082590d21b..d082590d21b 100644 --- a/source/blender/compositor/nodes/COM_MixNode.cpp +++ b/source/blender/compositor/nodes/COM_MixNode.cc diff --git a/source/blender/compositor/nodes/COM_MovieClipNode.cpp b/source/blender/compositor/nodes/COM_MovieClipNode.cc index 7cc8f2ea19c..7cc8f2ea19c 100644 --- a/source/blender/compositor/nodes/COM_MovieClipNode.cpp +++ b/source/blender/compositor/nodes/COM_MovieClipNode.cc diff --git a/source/blender/compositor/nodes/COM_MovieDistortionNode.cpp b/source/blender/compositor/nodes/COM_MovieDistortionNode.cc index ebace6d5fff..ebace6d5fff 100644 --- a/source/blender/compositor/nodes/COM_MovieDistortionNode.cpp +++ b/source/blender/compositor/nodes/COM_MovieDistortionNode.cc diff --git a/source/blender/compositor/nodes/COM_NormalNode.cpp b/source/blender/compositor/nodes/COM_NormalNode.cc index 1f48a26fd75..1f48a26fd75 100644 --- a/source/blender/compositor/nodes/COM_NormalNode.cpp +++ b/source/blender/compositor/nodes/COM_NormalNode.cc diff --git a/source/blender/compositor/nodes/COM_NormalizeNode.cpp b/source/blender/compositor/nodes/COM_NormalizeNode.cc index 72459fd477c..72459fd477c 100644 --- a/source/blender/compositor/nodes/COM_NormalizeNode.cpp +++ b/source/blender/compositor/nodes/COM_NormalizeNode.cc diff --git a/source/blender/compositor/nodes/COM_OutputFileNode.cpp b/source/blender/compositor/nodes/COM_OutputFileNode.cc index dcc1fbdec67..dcc1fbdec67 100644 --- a/source/blender/compositor/nodes/COM_OutputFileNode.cpp +++ b/source/blender/compositor/nodes/COM_OutputFileNode.cc diff --git a/source/blender/compositor/nodes/COM_PixelateNode.cpp b/source/blender/compositor/nodes/COM_PixelateNode.cc index f238f68727e..f238f68727e 100644 --- a/source/blender/compositor/nodes/COM_PixelateNode.cpp +++ b/source/blender/compositor/nodes/COM_PixelateNode.cc diff --git a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cc index 6b9b51631ec..6b9b51631ec 100644 --- a/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cpp +++ b/source/blender/compositor/nodes/COM_PlaneTrackDeformNode.cc diff --git a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp b/source/blender/compositor/nodes/COM_RenderLayersNode.cc index 6be86c04c4d..6be86c04c4d 100644 --- a/source/blender/compositor/nodes/COM_RenderLayersNode.cpp +++ b/source/blender/compositor/nodes/COM_RenderLayersNode.cc diff --git a/source/blender/compositor/nodes/COM_RotateNode.cpp b/source/blender/compositor/nodes/COM_RotateNode.cc index cbade778bcb..cbade778bcb 100644 --- a/source/blender/compositor/nodes/COM_RotateNode.cpp +++ b/source/blender/compositor/nodes/COM_RotateNode.cc diff --git a/source/blender/compositor/nodes/COM_ScaleNode.cpp b/source/blender/compositor/nodes/COM_ScaleNode.cc index 9ffcd5306b0..9ffcd5306b0 100644 --- a/source/blender/compositor/nodes/COM_ScaleNode.cpp +++ b/source/blender/compositor/nodes/COM_ScaleNode.cc diff --git a/source/blender/compositor/nodes/COM_SeparateColorNode.cpp b/source/blender/compositor/nodes/COM_SeparateColorNode.cc index 203aa25c9e9..203aa25c9e9 100644 --- a/source/blender/compositor/nodes/COM_SeparateColorNode.cpp +++ b/source/blender/compositor/nodes/COM_SeparateColorNode.cc diff --git a/source/blender/compositor/nodes/COM_SetAlphaNode.cpp b/source/blender/compositor/nodes/COM_SetAlphaNode.cc index 233a5e96ff4..233a5e96ff4 100644 --- a/source/blender/compositor/nodes/COM_SetAlphaNode.cpp +++ b/source/blender/compositor/nodes/COM_SetAlphaNode.cc diff --git a/source/blender/compositor/nodes/COM_SocketProxyNode.cpp b/source/blender/compositor/nodes/COM_SocketProxyNode.cc index a84dbf680fe..a84dbf680fe 100644 --- a/source/blender/compositor/nodes/COM_SocketProxyNode.cpp +++ b/source/blender/compositor/nodes/COM_SocketProxyNode.cc diff --git a/source/blender/compositor/nodes/COM_SplitViewerNode.cpp b/source/blender/compositor/nodes/COM_SplitViewerNode.cc index 75703876d9e..75703876d9e 100644 --- a/source/blender/compositor/nodes/COM_SplitViewerNode.cpp +++ b/source/blender/compositor/nodes/COM_SplitViewerNode.cc diff --git a/source/blender/compositor/nodes/COM_Stabilize2dNode.cpp b/source/blender/compositor/nodes/COM_Stabilize2dNode.cc index 38db080a154..38db080a154 100644 --- a/source/blender/compositor/nodes/COM_Stabilize2dNode.cpp +++ b/source/blender/compositor/nodes/COM_Stabilize2dNode.cc diff --git a/source/blender/compositor/nodes/COM_SunBeamsNode.cpp b/source/blender/compositor/nodes/COM_SunBeamsNode.cc index d899a54c03c..d899a54c03c 100644 --- a/source/blender/compositor/nodes/COM_SunBeamsNode.cpp +++ b/source/blender/compositor/nodes/COM_SunBeamsNode.cc diff --git a/source/blender/compositor/nodes/COM_SwitchNode.cpp b/source/blender/compositor/nodes/COM_SwitchNode.cc index 947774e98ae..947774e98ae 100644 --- a/source/blender/compositor/nodes/COM_SwitchNode.cpp +++ b/source/blender/compositor/nodes/COM_SwitchNode.cc diff --git a/source/blender/compositor/nodes/COM_SwitchViewNode.cpp b/source/blender/compositor/nodes/COM_SwitchViewNode.cc index e4a946e2e9d..e534ebfac9a 100644 --- a/source/blender/compositor/nodes/COM_SwitchViewNode.cpp +++ b/source/blender/compositor/nodes/COM_SwitchViewNode.cc @@ -33,7 +33,7 @@ void SwitchViewNode::convertToOperations(NodeConverter &converter, /* get the internal index of the socket with a matching name */ int nr = BLI_findstringindex(&bnode->inputs, viewName, offsetof(bNodeSocket, name)); - nr = max(nr, 0); + nr = MAX2(nr, 0); result = converter.addInputProxy(getInputSocket(nr), false); converter.mapOutputSocket(getOutputSocket(0), result); diff --git a/source/blender/compositor/nodes/COM_TextureNode.cpp b/source/blender/compositor/nodes/COM_TextureNode.cc index 3381b5098d7..3381b5098d7 100644 --- a/source/blender/compositor/nodes/COM_TextureNode.cpp +++ b/source/blender/compositor/nodes/COM_TextureNode.cc diff --git a/source/blender/compositor/nodes/COM_TimeNode.cpp b/source/blender/compositor/nodes/COM_TimeNode.cc index 247e0d11df6..247e0d11df6 100644 --- a/source/blender/compositor/nodes/COM_TimeNode.cpp +++ b/source/blender/compositor/nodes/COM_TimeNode.cc diff --git a/source/blender/compositor/nodes/COM_TonemapNode.cpp b/source/blender/compositor/nodes/COM_TonemapNode.cc index db329e56f9b..db329e56f9b 100644 --- a/source/blender/compositor/nodes/COM_TonemapNode.cpp +++ b/source/blender/compositor/nodes/COM_TonemapNode.cc diff --git a/source/blender/compositor/nodes/COM_TrackPositionNode.cpp b/source/blender/compositor/nodes/COM_TrackPositionNode.cc index 52e7f7d832b..52e7f7d832b 100644 --- a/source/blender/compositor/nodes/COM_TrackPositionNode.cpp +++ b/source/blender/compositor/nodes/COM_TrackPositionNode.cc diff --git a/source/blender/compositor/nodes/COM_TransformNode.cpp b/source/blender/compositor/nodes/COM_TransformNode.cc index cd5ba8ba201..cd5ba8ba201 100644 --- a/source/blender/compositor/nodes/COM_TransformNode.cpp +++ b/source/blender/compositor/nodes/COM_TransformNode.cc diff --git a/source/blender/compositor/nodes/COM_TranslateNode.cpp b/source/blender/compositor/nodes/COM_TranslateNode.cc index 0e9bf825787..0e9bf825787 100644 --- a/source/blender/compositor/nodes/COM_TranslateNode.cpp +++ b/source/blender/compositor/nodes/COM_TranslateNode.cc diff --git a/source/blender/compositor/nodes/COM_ValueNode.cpp b/source/blender/compositor/nodes/COM_ValueNode.cc index 4227db0d10e..4227db0d10e 100644 --- a/source/blender/compositor/nodes/COM_ValueNode.cpp +++ b/source/blender/compositor/nodes/COM_ValueNode.cc diff --git a/source/blender/compositor/nodes/COM_VectorBlurNode.cpp b/source/blender/compositor/nodes/COM_VectorBlurNode.cc index a92991c8b49..a92991c8b49 100644 --- a/source/blender/compositor/nodes/COM_VectorBlurNode.cpp +++ b/source/blender/compositor/nodes/COM_VectorBlurNode.cc diff --git a/source/blender/compositor/nodes/COM_VectorCurveNode.cpp b/source/blender/compositor/nodes/COM_VectorCurveNode.cc index 1201a9f9613..1201a9f9613 100644 --- a/source/blender/compositor/nodes/COM_VectorCurveNode.cpp +++ b/source/blender/compositor/nodes/COM_VectorCurveNode.cc diff --git a/source/blender/compositor/nodes/COM_ViewLevelsNode.cpp b/source/blender/compositor/nodes/COM_ViewLevelsNode.cc index 7b86fb1d64d..7b86fb1d64d 100644 --- a/source/blender/compositor/nodes/COM_ViewLevelsNode.cpp +++ b/source/blender/compositor/nodes/COM_ViewLevelsNode.cc diff --git a/source/blender/compositor/nodes/COM_ViewerNode.cpp b/source/blender/compositor/nodes/COM_ViewerNode.cc index fa6c1bc3c28..fa6c1bc3c28 100644 --- a/source/blender/compositor/nodes/COM_ViewerNode.cpp +++ b/source/blender/compositor/nodes/COM_ViewerNode.cc diff --git a/source/blender/compositor/nodes/COM_ZCombineNode.cpp b/source/blender/compositor/nodes/COM_ZCombineNode.cc index b61c018d029..b61c018d029 100644 --- a/source/blender/compositor/nodes/COM_ZCombineNode.cpp +++ b/source/blender/compositor/nodes/COM_ZCombineNode.cc diff --git a/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cpp b/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cc index 668d07c7c3d..668d07c7c3d 100644 --- a/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cpp +++ b/source/blender/compositor/operations/COM_AlphaOverKeyOperation.cc diff --git a/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cpp b/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cc index b8465ab7ccf..b8465ab7ccf 100644 --- a/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cpp +++ b/source/blender/compositor/operations/COM_AlphaOverMixedOperation.cc diff --git a/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cpp b/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cc index 4510c027d46..4510c027d46 100644 --- a/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cpp +++ b/source/blender/compositor/operations/COM_AlphaOverPremultiplyOperation.cc diff --git a/source/blender/compositor/operations/COM_AntiAliasOperation.cpp b/source/blender/compositor/operations/COM_AntiAliasOperation.cc index 684485c40cb..684485c40cb 100644 --- a/source/blender/compositor/operations/COM_AntiAliasOperation.cpp +++ b/source/blender/compositor/operations/COM_AntiAliasOperation.cc diff --git a/source/blender/compositor/operations/COM_BilateralBlurOperation.cpp b/source/blender/compositor/operations/COM_BilateralBlurOperation.cc index 35b0092fa5f..35b0092fa5f 100644 --- a/source/blender/compositor/operations/COM_BilateralBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_BilateralBlurOperation.cc diff --git a/source/blender/compositor/operations/COM_BlurBaseOperation.cpp b/source/blender/compositor/operations/COM_BlurBaseOperation.cc index 612a71037f7..612a71037f7 100644 --- a/source/blender/compositor/operations/COM_BlurBaseOperation.cpp +++ b/source/blender/compositor/operations/COM_BlurBaseOperation.cc diff --git a/source/blender/compositor/operations/COM_BokehBlurOperation.cpp b/source/blender/compositor/operations/COM_BokehBlurOperation.cc index f7b7816e1a1..a8ad2a11790 100644 --- a/source/blender/compositor/operations/COM_BokehBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_BokehBlurOperation.cc @@ -62,7 +62,7 @@ void BokehBlurOperation::initExecution() int width = this->m_inputBokehProgram->getWidth(); int height = this->m_inputBokehProgram->getHeight(); - float dimension = min(width, height); + float dimension = MIN2(width, height); this->m_bokehMidX = width / 2.0f; this->m_bokehMidY = height / 2.0f; @@ -84,7 +84,7 @@ void BokehBlurOperation::executePixel(float output[4], int x, int y, void *data) int bufferwidth = inputBuffer->getWidth(); int bufferstartx = inputBuffer->getRect()->xmin; int bufferstarty = inputBuffer->getRect()->ymin; - const float max_dim = max(this->getWidth(), this->getHeight()); + const float max_dim = MAX2(this->getWidth(), this->getHeight()); int pixelSize = this->m_size * max_dim / 100.0f; zero_v4(color_accum); @@ -99,10 +99,10 @@ void BokehBlurOperation::executePixel(float output[4], int x, int y, void *data) int maxy = y + pixelSize; int minx = x - pixelSize; int maxx = x + pixelSize; - miny = max(miny, inputBuffer->getRect()->ymin); - minx = max(minx, inputBuffer->getRect()->xmin); - maxy = min(maxy, inputBuffer->getRect()->ymax); - maxx = min(maxx, inputBuffer->getRect()->xmax); + miny = MAX2(miny, inputBuffer->getRect()->ymin); + minx = MAX2(minx, inputBuffer->getRect()->xmin); + maxy = MIN2(maxy, inputBuffer->getRect()->ymax); + maxx = MIN2(maxx, inputBuffer->getRect()->xmax); int step = getStep(); int offsetadd = getOffsetAdd() * COM_NUM_CHANNELS_COLOR; @@ -144,7 +144,7 @@ bool BokehBlurOperation::determineDependingAreaOfInterest(rcti *input, { rcti newInput; rcti bokehInput; - const float max_dim = max(this->getWidth(), this->getHeight()); + const float max_dim = MAX2(this->getWidth(), this->getHeight()); if (this->m_sizeavailable) { newInput.xmax = input->xmax + (this->m_size * max_dim / 100.0f); @@ -193,14 +193,14 @@ void BokehBlurOperation::executeOpenCL(OpenCLDevice *device, MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list<cl_mem> *clMemToCleanUp, - list<cl_kernel> * /*clKernelsToCleanUp*/) + std::list<cl_mem> *clMemToCleanUp, + std::list<cl_kernel> * /*clKernelsToCleanUp*/) { cl_kernel kernel = device->COM_clCreateKernel("bokehBlurKernel", nullptr); if (!this->m_sizeavailable) { updateSize(); } - const float max_dim = max(this->getWidth(), this->getHeight()); + const float max_dim = MAX2(this->getWidth(), this->getHeight()); cl_int radius = this->m_size * max_dim / 100.0f; cl_int step = this->getStep(); @@ -235,7 +235,7 @@ void BokehBlurOperation::determineResolution(unsigned int resolution[2], { NodeOperation::determineResolution(resolution, preferredResolution); if (this->m_extend_bounds) { - const float max_dim = max(resolution[0], resolution[1]); + const float max_dim = MAX2(resolution[0], resolution[1]); resolution[0] += 2 * this->m_size * max_dim / 100.0f; resolution[1] += 2 * this->m_size * max_dim / 100.0f; } diff --git a/source/blender/compositor/operations/COM_BokehBlurOperation.h b/source/blender/compositor/operations/COM_BokehBlurOperation.h index 335574a381d..a2e320dfdad 100644 --- a/source/blender/compositor/operations/COM_BokehBlurOperation.h +++ b/source/blender/compositor/operations/COM_BokehBlurOperation.h @@ -67,8 +67,8 @@ class BokehBlurOperation : public NodeOperation, public QualityStepHelper { MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list<cl_mem> *clMemToCleanUp, - list<cl_kernel> *clKernelsToCleanUp); + std::list<cl_mem> *clMemToCleanUp, + std::list<cl_kernel> *clKernelsToCleanUp); void setExtendBounds(bool extend_bounds) { diff --git a/source/blender/compositor/operations/COM_BokehImageOperation.cpp b/source/blender/compositor/operations/COM_BokehImageOperation.cc index 473a43c1776..473a43c1776 100644 --- a/source/blender/compositor/operations/COM_BokehImageOperation.cpp +++ b/source/blender/compositor/operations/COM_BokehImageOperation.cc diff --git a/source/blender/compositor/operations/COM_BoxMaskOperation.cpp b/source/blender/compositor/operations/COM_BoxMaskOperation.cc index 662b08bdee9..bb10f3425e2 100644 --- a/source/blender/compositor/operations/COM_BoxMaskOperation.cpp +++ b/source/blender/compositor/operations/COM_BoxMaskOperation.cc @@ -64,7 +64,7 @@ void BoxMaskOperation::executePixelSampled(float output[4], float x, float y, Pi switch (this->m_maskType) { case CMP_NODE_MASKTYPE_ADD: if (inside) { - output[0] = max(inputMask[0], inputValue[0]); + output[0] = MAX2(inputMask[0], inputValue[0]); } else { output[0] = inputMask[0]; diff --git a/source/blender/compositor/operations/COM_BrightnessOperation.cpp b/source/blender/compositor/operations/COM_BrightnessOperation.cc index 3ae1b4aaef4..3ae1b4aaef4 100644 --- a/source/blender/compositor/operations/COM_BrightnessOperation.cpp +++ b/source/blender/compositor/operations/COM_BrightnessOperation.cc diff --git a/source/blender/compositor/operations/COM_CalculateMeanOperation.cpp b/source/blender/compositor/operations/COM_CalculateMeanOperation.cc index 9ccf9d7f1ef..9ccf9d7f1ef 100644 --- a/source/blender/compositor/operations/COM_CalculateMeanOperation.cpp +++ b/source/blender/compositor/operations/COM_CalculateMeanOperation.cc diff --git a/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cpp b/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cc index 9a1e48177ed..9a1e48177ed 100644 --- a/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cpp +++ b/source/blender/compositor/operations/COM_CalculateStandardDeviationOperation.cc diff --git a/source/blender/compositor/operations/COM_ChangeHSVOperation.cpp b/source/blender/compositor/operations/COM_ChangeHSVOperation.cc index 6bc9fa53c31..6bc9fa53c31 100644 --- a/source/blender/compositor/operations/COM_ChangeHSVOperation.cpp +++ b/source/blender/compositor/operations/COM_ChangeHSVOperation.cc diff --git a/source/blender/compositor/operations/COM_ChannelMatteOperation.cpp b/source/blender/compositor/operations/COM_ChannelMatteOperation.cc index a2c6fd47771..15375589888 100644 --- a/source/blender/compositor/operations/COM_ChannelMatteOperation.cpp +++ b/source/blender/compositor/operations/COM_ChannelMatteOperation.cc @@ -95,7 +95,7 @@ void ChannelMatteOperation::executePixelSampled(float output[4], this->m_inputImageProgram->readSampled(inColor, x, y, sampler); /* matte operation */ - alpha = inColor[this->m_ids[0]] - max(inColor[this->m_ids[1]], inColor[this->m_ids[2]]); + alpha = inColor[this->m_ids[0]] - MAX2(inColor[this->m_ids[1]], inColor[this->m_ids[2]]); /* flip because 0.0 is transparent, not 1.0 */ alpha = 1.0f - alpha; @@ -116,5 +116,5 @@ void ChannelMatteOperation::executePixelSampled(float output[4], */ /* Don't make something that was more transparent less transparent. */ - output[0] = min(alpha, inColor[3]); + output[0] = MIN2(alpha, inColor[3]); } diff --git a/source/blender/compositor/operations/COM_ChannelMatteOperation.h b/source/blender/compositor/operations/COM_ChannelMatteOperation.h index 24a5e03a1bf..9a0b888b5a2 100644 --- a/source/blender/compositor/operations/COM_ChannelMatteOperation.h +++ b/source/blender/compositor/operations/COM_ChannelMatteOperation.h @@ -38,12 +38,12 @@ class ChannelMatteOperation : public NodeOperation { float m_limit_range; /** ids to use for the operations (max and simple) - * alpha = in[ids[0]] - max(in[ids[1]], in[ids[2]]) + * alpha = in[ids[0]] - MAX2(in[ids[1]], in[ids[2]]) * the simple operation is using: * alpha = in[ids[0]] - in[ids[1]] * but to use the same formula and operation for both we do: * ids[2] = ids[1] - * alpha = in[ids[0]] - max(in[ids[1]], in[ids[2]]) + * alpha = in[ids[0]] - MAX2(in[ids[1]], in[ids[2]]) */ int m_ids[3]; diff --git a/source/blender/compositor/operations/COM_ChromaMatteOperation.cpp b/source/blender/compositor/operations/COM_ChromaMatteOperation.cc index 52de0198a00..52de0198a00 100644 --- a/source/blender/compositor/operations/COM_ChromaMatteOperation.cpp +++ b/source/blender/compositor/operations/COM_ChromaMatteOperation.cc diff --git a/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cpp b/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc index f9eaaf6f7a0..44eef1e19cd 100644 --- a/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cpp +++ b/source/blender/compositor/operations/COM_ColorBalanceASCCDLOperation.cc @@ -59,7 +59,7 @@ void ColorBalanceASCCDLOperation::executePixelSampled(float output[4], this->m_inputColorOperation->readSampled(inputColor, x, y, sampler); float fac = value[0]; - fac = min(1.0f, fac); + fac = MIN2(1.0f, fac); const float mfac = 1.0f - fac; output[0] = mfac * inputColor[0] + diff --git a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc index df44e87a86a..934b7e51aee 100644 --- a/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cpp +++ b/source/blender/compositor/operations/COM_ColorBalanceLGGOperation.cc @@ -64,7 +64,7 @@ void ColorBalanceLGGOperation::executePixelSampled(float output[4], this->m_inputColorOperation->readSampled(inputColor, x, y, sampler); float fac = value[0]; - fac = min(1.0f, fac); + fac = MIN2(1.0f, fac); const float mfac = 1.0f - fac; output[0] = mfac * inputColor[0] + diff --git a/source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp b/source/blender/compositor/operations/COM_ColorCorrectionOperation.cc index 60343c28662..02c109e8acd 100644 --- a/source/blender/compositor/operations/COM_ColorCorrectionOperation.cpp +++ b/source/blender/compositor/operations/COM_ColorCorrectionOperation.cc @@ -66,7 +66,7 @@ void ColorCorrectionOperation::executePixelSampled(float output[4], float r, g, b; float value = inputMask[0]; - value = min(1.0f, value); + value = MIN2(1.0f, value); const float mvalue = 1.0f - value; float levelShadows = 0.0; diff --git a/source/blender/compositor/operations/COM_ColorCurveOperation.cpp b/source/blender/compositor/operations/COM_ColorCurveOperation.cc index ed107a88953..ed107a88953 100644 --- a/source/blender/compositor/operations/COM_ColorCurveOperation.cpp +++ b/source/blender/compositor/operations/COM_ColorCurveOperation.cc diff --git a/source/blender/compositor/operations/COM_ColorExposureOperation.cpp b/source/blender/compositor/operations/COM_ColorExposureOperation.cc index a11039852a1..a11039852a1 100644 --- a/source/blender/compositor/operations/COM_ColorExposureOperation.cpp +++ b/source/blender/compositor/operations/COM_ColorExposureOperation.cc diff --git a/source/blender/compositor/operations/COM_ColorMatteOperation.cpp b/source/blender/compositor/operations/COM_ColorMatteOperation.cc index 17ada8d89b2..17ada8d89b2 100644 --- a/source/blender/compositor/operations/COM_ColorMatteOperation.cpp +++ b/source/blender/compositor/operations/COM_ColorMatteOperation.cc diff --git a/source/blender/compositor/operations/COM_ColorRampOperation.cpp b/source/blender/compositor/operations/COM_ColorRampOperation.cc index 4d62a293b78..4d62a293b78 100644 --- a/source/blender/compositor/operations/COM_ColorRampOperation.cpp +++ b/source/blender/compositor/operations/COM_ColorRampOperation.cc diff --git a/source/blender/compositor/operations/COM_ColorSpillOperation.cpp b/source/blender/compositor/operations/COM_ColorSpillOperation.cc index 050792d8dab..8139d71c637 100644 --- a/source/blender/compositor/operations/COM_ColorSpillOperation.cpp +++ b/source/blender/compositor/operations/COM_ColorSpillOperation.cc @@ -90,7 +90,7 @@ void ColorSpillOperation::executePixelSampled(float output[4], float input[4]; this->m_inputFacReader->readSampled(fac, x, y, sampler); this->m_inputImageReader->readSampled(input, x, y, sampler); - float rfac = min(1.0f, fac[0]); + float rfac = MIN2(1.0f, fac[0]); float map; switch (this->m_spillMethod) { diff --git a/source/blender/compositor/operations/COM_CompositorOperation.cpp b/source/blender/compositor/operations/COM_CompositorOperation.cc index 6a16872cae2..6a16872cae2 100644 --- a/source/blender/compositor/operations/COM_CompositorOperation.cpp +++ b/source/blender/compositor/operations/COM_CompositorOperation.cc diff --git a/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cpp b/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cc index 44468e04ae9..44468e04ae9 100644 --- a/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cpp +++ b/source/blender/compositor/operations/COM_ConvertColorProfileOperation.cc diff --git a/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cpp b/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cc index fe395ecae9e..abf423cc48a 100644 --- a/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cpp +++ b/source/blender/compositor/operations/COM_ConvertDepthToRadiusOperation.cc @@ -63,13 +63,13 @@ void ConvertDepthToRadiusOperation::initExecution() (this->getHeight() / (float)this->getWidth()) : (this->getWidth() / (float)this->getHeight()); this->m_aperture = 0.5f * (this->m_cam_lens / (this->m_aspect * cam_sensor)) / this->m_fStop; - const float minsz = min(getWidth(), getHeight()); + const float minsz = MIN2(getWidth(), getHeight()); this->m_dof_sp = minsz / ((cam_sensor / 2.0f) / - this->m_cam_lens); // <- == aspect * min(img->x, img->y) / tan(0.5f * fov); + this->m_cam_lens); // <- == aspect * MIN2(img->x, img->y) / tan(0.5f * fov); if (this->m_blurPostOperation) { - m_blurPostOperation->setSigma(min(m_aperture * 128.0f, this->m_maxRadius)); + m_blurPostOperation->setSigma(MIN2(m_aperture * 128.0f, this->m_maxRadius)); } } diff --git a/source/blender/compositor/operations/COM_ConvertOperation.cpp b/source/blender/compositor/operations/COM_ConvertOperation.cc index cccfd407752..cccfd407752 100644 --- a/source/blender/compositor/operations/COM_ConvertOperation.cpp +++ b/source/blender/compositor/operations/COM_ConvertOperation.cc diff --git a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cc index 1c2570cd251..a5f2ae404e3 100644 --- a/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cpp +++ b/source/blender/compositor/operations/COM_ConvolutionEdgeFilterOperation.cc @@ -92,8 +92,8 @@ void ConvolutionEdgeFilterOperation::executePixel(float output[4], int x, int y, output[3] = in2[3]; /* Make sure we don't return negative color. */ - output[0] = max(output[0], 0.0f); - output[1] = max(output[1], 0.0f); - output[2] = max(output[2], 0.0f); - output[3] = max(output[3], 0.0f); + output[0] = MAX2(output[0], 0.0f); + output[1] = MAX2(output[1], 0.0f); + output[2] = MAX2(output[2], 0.0f); + output[3] = MAX2(output[3], 0.0f); } diff --git a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cc index 7e35f6fb4f6..425e87ffa7e 100644 --- a/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cpp +++ b/source/blender/compositor/operations/COM_ConvolutionFilterOperation.cc @@ -105,10 +105,10 @@ void ConvolutionFilterOperation::executePixel(float output[4], int x, int y, voi output[3] = output[3] * value[0] + in2[3] * mval; /* Make sure we don't return negative color. */ - output[0] = max(output[0], 0.0f); - output[1] = max(output[1], 0.0f); - output[2] = max(output[2], 0.0f); - output[3] = max(output[3], 0.0f); + output[0] = MAX2(output[0], 0.0f); + output[1] = MAX2(output[1], 0.0f); + output[2] = MAX2(output[2], 0.0f); + output[3] = MAX2(output[3], 0.0f); } bool ConvolutionFilterOperation::determineDependingAreaOfInterest( diff --git a/source/blender/compositor/operations/COM_CropOperation.cpp b/source/blender/compositor/operations/COM_CropOperation.cc index 408f588871e..9364557169c 100644 --- a/source/blender/compositor/operations/COM_CropOperation.cpp +++ b/source/blender/compositor/operations/COM_CropOperation.cc @@ -54,10 +54,10 @@ void CropBaseOperation::updateArea() local_settings.y2 = height - 1; } - this->m_xmax = max(local_settings.x1, local_settings.x2) + 1; - this->m_xmin = min(local_settings.x1, local_settings.x2); - this->m_ymax = max(local_settings.y1, local_settings.y2) + 1; - this->m_ymin = min(local_settings.y1, local_settings.y2); + this->m_xmax = MAX2(local_settings.x1, local_settings.x2) + 1; + this->m_xmin = MIN2(local_settings.x1, local_settings.x2); + this->m_ymax = MAX2(local_settings.y1, local_settings.y2) + 1; + this->m_ymin = MIN2(local_settings.y1, local_settings.y2); } else { this->m_xmax = 0; diff --git a/source/blender/compositor/operations/COM_CryptomatteOperation.cpp b/source/blender/compositor/operations/COM_CryptomatteOperation.cc index ccd291697cf..ccd291697cf 100644 --- a/source/blender/compositor/operations/COM_CryptomatteOperation.cpp +++ b/source/blender/compositor/operations/COM_CryptomatteOperation.cc diff --git a/source/blender/compositor/operations/COM_CurveBaseOperation.cpp b/source/blender/compositor/operations/COM_CurveBaseOperation.cc index b58efcf0cca..b58efcf0cca 100644 --- a/source/blender/compositor/operations/COM_CurveBaseOperation.cpp +++ b/source/blender/compositor/operations/COM_CurveBaseOperation.cc diff --git a/source/blender/compositor/operations/COM_DenoiseOperation.cpp b/source/blender/compositor/operations/COM_DenoiseOperation.cc index d08f238c4c1..d08f238c4c1 100644 --- a/source/blender/compositor/operations/COM_DenoiseOperation.cpp +++ b/source/blender/compositor/operations/COM_DenoiseOperation.cc diff --git a/source/blender/compositor/operations/COM_DespeckleOperation.cpp b/source/blender/compositor/operations/COM_DespeckleOperation.cc index 901445c6875..901445c6875 100644 --- a/source/blender/compositor/operations/COM_DespeckleOperation.cpp +++ b/source/blender/compositor/operations/COM_DespeckleOperation.cc diff --git a/source/blender/compositor/operations/COM_DifferenceMatteOperation.cpp b/source/blender/compositor/operations/COM_DifferenceMatteOperation.cc index cca99a42c0c..cca99a42c0c 100644 --- a/source/blender/compositor/operations/COM_DifferenceMatteOperation.cpp +++ b/source/blender/compositor/operations/COM_DifferenceMatteOperation.cc diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.cpp b/source/blender/compositor/operations/COM_DilateErodeOperation.cc index b2dfb558028..fbe9fe8ea27 100644 --- a/source/blender/compositor/operations/COM_DilateErodeOperation.cpp +++ b/source/blender/compositor/operations/COM_DilateErodeOperation.cc @@ -41,7 +41,7 @@ void DilateErodeThresholdOperation::initExecution() } else { if (this->m_inset * 2 > this->m_distance) { - this->m_scope = max(this->m_inset * 2 - this->m_distance, this->m_distance); + this->m_scope = MAX2(this->m_inset * 2 - this->m_distance, this->m_distance); } else { this->m_scope = this->m_distance; @@ -71,10 +71,10 @@ void DilateErodeThresholdOperation::executePixel(float output[4], int x, int y, MemoryBuffer *inputBuffer = (MemoryBuffer *)data; float *buffer = inputBuffer->getBuffer(); rcti *rect = inputBuffer->getRect(); - const int minx = max(x - this->m_scope, rect->xmin); - const int miny = max(y - this->m_scope, rect->ymin); - const int maxx = min(x + this->m_scope, rect->xmax); - const int maxy = min(y + this->m_scope, rect->ymax); + const int minx = MAX2(x - this->m_scope, rect->xmin); + const int miny = MAX2(y - this->m_scope, rect->ymin); + const int maxx = MIN2(x + this->m_scope, rect->xmax); + const int maxy = MIN2(y + this->m_scope, rect->ymax); const int bufferWidth = BLI_rcti_size_x(rect); int offset; @@ -87,7 +87,7 @@ void DilateErodeThresholdOperation::executePixel(float output[4], int x, int y, if (buffer[offset] < sw) { const float dx = xi - x; const float dis = dx * dx + dy * dy; - mindist = min(mindist, dis); + mindist = MIN2(mindist, dis); } offset++; } @@ -102,7 +102,7 @@ void DilateErodeThresholdOperation::executePixel(float output[4], int x, int y, if (buffer[offset] > sw) { const float dx = xi - x; const float dis = dx * dx + dy * dy; - mindist = min(mindist, dis); + mindist = MIN2(mindist, dis); } offset++; } @@ -191,10 +191,10 @@ void DilateDistanceOperation::executePixel(float output[4], int x, int y, void * MemoryBuffer *inputBuffer = (MemoryBuffer *)data; float *buffer = inputBuffer->getBuffer(); rcti *rect = inputBuffer->getRect(); - const int minx = max(x - this->m_scope, rect->xmin); - const int miny = max(y - this->m_scope, rect->ymin); - const int maxx = min(x + this->m_scope, rect->xmax); - const int maxy = min(y + this->m_scope, rect->ymax); + const int minx = MAX2(x - this->m_scope, rect->xmin); + const int miny = MAX2(y - this->m_scope, rect->ymin); + const int maxx = MIN2(x + this->m_scope, rect->xmax); + const int maxy = MIN2(y + this->m_scope, rect->ymax); const int bufferWidth = BLI_rcti_size_x(rect); int offset; @@ -207,7 +207,7 @@ void DilateDistanceOperation::executePixel(float output[4], int x, int y, void * const float dx = xi - x; const float dis = dx * dx + dy * dy; if (dis <= mindist) { - value = max(buffer[offset], value); + value = MAX2(buffer[offset], value); } offset++; } @@ -238,8 +238,8 @@ void DilateDistanceOperation::executeOpenCL(OpenCLDevice *device, MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list<cl_mem> *clMemToCleanUp, - list<cl_kernel> * /*clKernelsToCleanUp*/) + std::list<cl_mem> *clMemToCleanUp, + std::list<cl_kernel> * /*clKernelsToCleanUp*/) { cl_kernel dilateKernel = device->COM_clCreateKernel("dilateKernel", nullptr); @@ -270,10 +270,10 @@ void ErodeDistanceOperation::executePixel(float output[4], int x, int y, void *d MemoryBuffer *inputBuffer = (MemoryBuffer *)data; float *buffer = inputBuffer->getBuffer(); rcti *rect = inputBuffer->getRect(); - const int minx = max(x - this->m_scope, rect->xmin); - const int miny = max(y - this->m_scope, rect->ymin); - const int maxx = min(x + this->m_scope, rect->xmax); - const int maxy = min(y + this->m_scope, rect->ymax); + const int minx = MAX2(x - this->m_scope, rect->xmin); + const int miny = MAX2(y - this->m_scope, rect->ymin); + const int maxx = MIN2(x + this->m_scope, rect->xmax); + const int maxy = MIN2(y + this->m_scope, rect->ymax); const int bufferWidth = BLI_rcti_size_x(rect); int offset; @@ -286,7 +286,7 @@ void ErodeDistanceOperation::executePixel(float output[4], int x, int y, void *d const float dx = xi - x; const float dis = dx * dx + dy * dy; if (dis <= mindist) { - value = min(buffer[offset], value); + value = MIN2(buffer[offset], value); } offset++; } @@ -298,8 +298,8 @@ void ErodeDistanceOperation::executeOpenCL(OpenCLDevice *device, MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list<cl_mem> *clMemToCleanUp, - list<cl_kernel> * /*clKernelsToCleanUp*/) + std::list<cl_mem> *clMemToCleanUp, + std::list<cl_kernel> * /*clKernelsToCleanUp*/) { cl_kernel erodeKernel = device->COM_clCreateKernel("erodeKernel", nullptr); @@ -360,10 +360,10 @@ void *DilateStepOperation::initializeTileData(rcti *rect) int half_window = this->m_iterations; int window = half_window * 2 + 1; - int xmin = max(0, rect->xmin - half_window); - int ymin = max(0, rect->ymin - half_window); - int xmax = min(width, rect->xmax + half_window); - int ymax = min(height, rect->ymax + half_window); + int xmin = MAX2(0, rect->xmin - half_window); + int ymin = MAX2(0, rect->ymin - half_window); + int xmax = MIN2(width, rect->xmax + half_window); + int ymax = MIN2(height, rect->ymax + half_window); int bwidth = rect->xmax - rect->xmin; int bheight = rect->ymax - rect->ymin; @@ -378,7 +378,7 @@ void *DilateStepOperation::initializeTileData(rcti *rect) // single row or column of input values, padded with FLT_MAX's to // simplify the logic. float *temp = (float *)MEM_mallocN(sizeof(float) * (2 * window - 1), "dilate erode temp"); - float *buf = (float *)MEM_mallocN(sizeof(float) * (max(bwidth, bheight) + 5 * half_window), + float *buf = (float *)MEM_mallocN(sizeof(float) * (MAX2(bwidth, bheight) + 5 * half_window), "dilate erode buf"); // The following is based on the van Herk/Gil-Werman algorithm for morphology operations. @@ -396,13 +396,13 @@ void *DilateStepOperation::initializeTileData(rcti *rect) temp[window - 1] = buf[start]; for (x = 1; x < window; x++) { - temp[window - 1 - x] = max(temp[window - x], buf[start - x]); - temp[window - 1 + x] = max(temp[window + x - 2], buf[start + x]); + temp[window - 1 - x] = MAX2(temp[window - x], buf[start - x]); + temp[window - 1 + x] = MAX2(temp[window + x - 2], buf[start + x]); } start = half_window + (i - 1) * window + 1; - for (x = -min(0, start); x < window - max(0, start + window - bwidth); x++) { - rectf[bwidth * (y - ymin) + (start + x)] = max(temp[x], temp[x + window - 1]); + for (x = -MIN2(0, start); x < window - MAX2(0, start + window - bwidth); x++) { + rectf[bwidth * (y - ymin) + (start + x)] = MAX2(temp[x], temp[x + window - 1]); } } } @@ -421,13 +421,14 @@ void *DilateStepOperation::initializeTileData(rcti *rect) temp[window - 1] = buf[start]; for (y = 1; y < window; y++) { - temp[window - 1 - y] = max(temp[window - y], buf[start - y]); - temp[window - 1 + y] = max(temp[window + y - 2], buf[start + y]); + temp[window - 1 - y] = MAX2(temp[window - y], buf[start - y]); + temp[window - 1 + y] = MAX2(temp[window + y - 2], buf[start + y]); } start = half_window + (i - 1) * window + 1; - for (y = -min(0, start); y < window - max(0, start + window - bheight); y++) { - rectf[bwidth * (y + start + (rect->ymin - ymin)) + x] = max(temp[y], temp[y + window - 1]); + for (y = -MIN2(0, start); y < window - MAX2(0, start + window - bheight); y++) { + rectf[bwidth * (y + start + (rect->ymin - ymin)) + x] = MAX2(temp[y], + temp[y + window - 1]); } } } @@ -489,10 +490,10 @@ void *ErodeStepOperation::initializeTileData(rcti *rect) int half_window = this->m_iterations; int window = half_window * 2 + 1; - int xmin = max(0, rect->xmin - half_window); - int ymin = max(0, rect->ymin - half_window); - int xmax = min(width, rect->xmax + half_window); - int ymax = min(height, rect->ymax + half_window); + int xmin = MAX2(0, rect->xmin - half_window); + int ymin = MAX2(0, rect->ymin - half_window); + int xmax = MIN2(width, rect->xmax + half_window); + int ymax = MIN2(height, rect->ymax + half_window); int bwidth = rect->xmax - rect->xmin; int bheight = rect->ymax - rect->ymin; @@ -507,7 +508,7 @@ void *ErodeStepOperation::initializeTileData(rcti *rect) // single row or column of input values, padded with FLT_MAX's to // simplify the logic. float *temp = (float *)MEM_mallocN(sizeof(float) * (2 * window - 1), "dilate erode temp"); - float *buf = (float *)MEM_mallocN(sizeof(float) * (max(bwidth, bheight) + 5 * half_window), + float *buf = (float *)MEM_mallocN(sizeof(float) * (MAX2(bwidth, bheight) + 5 * half_window), "dilate erode buf"); // The following is based on the van Herk/Gil-Werman algorithm for morphology operations. @@ -525,13 +526,13 @@ void *ErodeStepOperation::initializeTileData(rcti *rect) temp[window - 1] = buf[start]; for (x = 1; x < window; x++) { - temp[window - 1 - x] = min(temp[window - x], buf[start - x]); - temp[window - 1 + x] = min(temp[window + x - 2], buf[start + x]); + temp[window - 1 - x] = MIN2(temp[window - x], buf[start - x]); + temp[window - 1 + x] = MIN2(temp[window + x - 2], buf[start + x]); } start = half_window + (i - 1) * window + 1; - for (x = -min(0, start); x < window - max(0, start + window - bwidth); x++) { - rectf[bwidth * (y - ymin) + (start + x)] = min(temp[x], temp[x + window - 1]); + for (x = -MIN2(0, start); x < window - MAX2(0, start + window - bwidth); x++) { + rectf[bwidth * (y - ymin) + (start + x)] = MIN2(temp[x], temp[x + window - 1]); } } } @@ -550,13 +551,14 @@ void *ErodeStepOperation::initializeTileData(rcti *rect) temp[window - 1] = buf[start]; for (y = 1; y < window; y++) { - temp[window - 1 - y] = min(temp[window - y], buf[start - y]); - temp[window - 1 + y] = min(temp[window + y - 2], buf[start + y]); + temp[window - 1 - y] = MIN2(temp[window - y], buf[start - y]); + temp[window - 1 + y] = MIN2(temp[window + y - 2], buf[start + y]); } start = half_window + (i - 1) * window + 1; - for (y = -min(0, start); y < window - max(0, start + window - bheight); y++) { - rectf[bwidth * (y + start + (rect->ymin - ymin)) + x] = min(temp[y], temp[y + window - 1]); + for (y = -MIN2(0, start); y < window - MAX2(0, start + window - bheight); y++) { + rectf[bwidth * (y + start + (rect->ymin - ymin)) + x] = MIN2(temp[y], + temp[y + window - 1]); } } } diff --git a/source/blender/compositor/operations/COM_DilateErodeOperation.h b/source/blender/compositor/operations/COM_DilateErodeOperation.h index 2af5c8990ee..35f9be89220 100644 --- a/source/blender/compositor/operations/COM_DilateErodeOperation.h +++ b/source/blender/compositor/operations/COM_DilateErodeOperation.h @@ -115,8 +115,8 @@ class DilateDistanceOperation : public NodeOperation { MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list<cl_mem> *clMemToCleanUp, - list<cl_kernel> *clKernelsToCleanUp); + std::list<cl_mem> *clMemToCleanUp, + std::list<cl_kernel> *clKernelsToCleanUp); }; class ErodeDistanceOperation : public DilateDistanceOperation { public: @@ -131,8 +131,8 @@ class ErodeDistanceOperation : public DilateDistanceOperation { MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list<cl_mem> *clMemToCleanUp, - list<cl_kernel> *clKernelsToCleanUp); + std::list<cl_mem> *clMemToCleanUp, + std::list<cl_kernel> *clKernelsToCleanUp); }; class DilateStepOperation : public NodeOperation { diff --git a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cc index c0b9c9b6f1d..3f0cd4ef255 100644 --- a/source/blender/compositor/operations/COM_DirectionalBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_DirectionalBlurOperation.cc @@ -100,8 +100,8 @@ void DirectionalBlurOperation::executeOpenCL(OpenCLDevice *device, MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list<cl_mem> *clMemToCleanUp, - list<cl_kernel> * /*clKernelsToCleanUp*/) + std::list<cl_mem> *clMemToCleanUp, + std::list<cl_kernel> * /*clKernelsToCleanUp*/) { cl_kernel directionalBlurKernel = device->COM_clCreateKernel("directionalBlurKernel", nullptr); diff --git a/source/blender/compositor/operations/COM_DirectionalBlurOperation.h b/source/blender/compositor/operations/COM_DirectionalBlurOperation.h index fdb7b82779e..0c220f0e239 100644 --- a/source/blender/compositor/operations/COM_DirectionalBlurOperation.h +++ b/source/blender/compositor/operations/COM_DirectionalBlurOperation.h @@ -61,6 +61,6 @@ class DirectionalBlurOperation : public NodeOperation, public QualityStepHelper MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list<cl_mem> *clMemToCleanUp, - list<cl_kernel> *clKernelsToCleanUp); + std::list<cl_mem> *clMemToCleanUp, + std::list<cl_kernel> *clKernelsToCleanUp); }; diff --git a/source/blender/compositor/operations/COM_DisplaceOperation.cpp b/source/blender/compositor/operations/COM_DisplaceOperation.cc index fcc8bc4670e..fcc8bc4670e 100644 --- a/source/blender/compositor/operations/COM_DisplaceOperation.cpp +++ b/source/blender/compositor/operations/COM_DisplaceOperation.cc diff --git a/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cpp b/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc index bbc4d63305b..bbc4d63305b 100644 --- a/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cpp +++ b/source/blender/compositor/operations/COM_DisplaceSimpleOperation.cc diff --git a/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cpp b/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cc index ecc2fc2e85f..ecc2fc2e85f 100644 --- a/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cpp +++ b/source/blender/compositor/operations/COM_DistanceRGBMatteOperation.cc diff --git a/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cpp b/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cc index f333cc1ecd9..f333cc1ecd9 100644 --- a/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cpp +++ b/source/blender/compositor/operations/COM_DistanceYCCMatteOperation.cc diff --git a/source/blender/compositor/operations/COM_DotproductOperation.cpp b/source/blender/compositor/operations/COM_DotproductOperation.cc index 5914be21453..5914be21453 100644 --- a/source/blender/compositor/operations/COM_DotproductOperation.cpp +++ b/source/blender/compositor/operations/COM_DotproductOperation.cc diff --git a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc index b548a684ba5..b548a684ba5 100644 --- a/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cpp +++ b/source/blender/compositor/operations/COM_DoubleEdgeMaskOperation.cc diff --git a/source/blender/compositor/operations/COM_EllipseMaskOperation.cpp b/source/blender/compositor/operations/COM_EllipseMaskOperation.cc index 38541f91fc8..a6985a40625 100644 --- a/source/blender/compositor/operations/COM_EllipseMaskOperation.cpp +++ b/source/blender/compositor/operations/COM_EllipseMaskOperation.cc @@ -73,7 +73,7 @@ void EllipseMaskOperation::executePixelSampled(float output[4], switch (this->m_maskType) { case CMP_NODE_MASKTYPE_ADD: if (inside) { - output[0] = max(inputMask[0], inputValue[0]); + output[0] = MAX2(inputMask[0], inputValue[0]); } else { output[0] = inputMask[0]; diff --git a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc index 157c595afcb..b3c1b6b4413 100644 --- a/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_FastGaussianBlurOperation.cc @@ -209,7 +209,7 @@ void FastGaussianBlurOperation::IIR_gauss(MemoryBuffer *src, (void)0 // intermediate buffers - sz = max(src_width, src_height); + sz = MAX2(src_width, src_height); X = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss X buf"); Y = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss Y buf"); W = (double *)MEM_callocN(sz * sizeof(double), "IIR_gauss W buf"); diff --git a/source/blender/compositor/operations/COM_FlipOperation.cpp b/source/blender/compositor/operations/COM_FlipOperation.cc index 37eaf4868d3..37eaf4868d3 100644 --- a/source/blender/compositor/operations/COM_FlipOperation.cpp +++ b/source/blender/compositor/operations/COM_FlipOperation.cc diff --git a/source/blender/compositor/operations/COM_GammaCorrectOperation.cpp b/source/blender/compositor/operations/COM_GammaCorrectOperation.cc index d67d67f8e57..d67d67f8e57 100644 --- a/source/blender/compositor/operations/COM_GammaCorrectOperation.cpp +++ b/source/blender/compositor/operations/COM_GammaCorrectOperation.cc diff --git a/source/blender/compositor/operations/COM_GammaOperation.cpp b/source/blender/compositor/operations/COM_GammaOperation.cc index 6baa52a290c..6baa52a290c 100644 --- a/source/blender/compositor/operations/COM_GammaOperation.cpp +++ b/source/blender/compositor/operations/COM_GammaOperation.cc diff --git a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc index 4d3efec7c85..4d3efec7c85 100644 --- a/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_GaussianAlphaXBlurOperation.cc diff --git a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc index a722a879b8d..a722a879b8d 100644 --- a/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_GaussianAlphaYBlurOperation.cc diff --git a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cc index d489c64953e..ca3173001cb 100644 --- a/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_GaussianBokehBlurOperation.cc @@ -256,7 +256,7 @@ void GaussianBlurReferenceOperation::initExecution() void GaussianBlurReferenceOperation::updateGauss() { int i; - int x = max(m_filtersizex, m_filtersizey); + int x = MAX2(m_filtersizex, m_filtersizey); m_maintabs = (float **)MEM_mallocN(x * sizeof(float *), "gauss array"); for (i = 0; i < x; i++) { m_maintabs[i] = make_gausstab(i + 1, i + 1); @@ -333,7 +333,7 @@ void GaussianBlurReferenceOperation::executePixel(float output[4], int x, int y, void GaussianBlurReferenceOperation::deinitExecution() { int x, i; - x = max(this->m_filtersizex, this->m_filtersizey); + x = MAX2(this->m_filtersizex, this->m_filtersizey); for (i = 0; i < x; i++) { MEM_freeN(this->m_maintabs[i]); } diff --git a/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianXBlurOperation.cc index 90333f7dd79..596d439658c 100644 --- a/source/blender/compositor/operations/COM_GaussianXBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_GaussianXBlurOperation.cc @@ -122,8 +122,8 @@ void GaussianXBlurOperation::executeOpenCL(OpenCLDevice *device, MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list<cl_mem> *clMemToCleanUp, - list<cl_kernel> * /*clKernelsToCleanUp*/) + std::list<cl_mem> *clMemToCleanUp, + std::list<cl_kernel> * /*clKernelsToCleanUp*/) { cl_kernel gaussianXBlurOperationKernel = device->COM_clCreateKernel( "gaussianXBlurOperationKernel", nullptr); diff --git a/source/blender/compositor/operations/COM_GaussianXBlurOperation.h b/source/blender/compositor/operations/COM_GaussianXBlurOperation.h index b2bcd79e716..78ea6aa3cc2 100644 --- a/source/blender/compositor/operations/COM_GaussianXBlurOperation.h +++ b/source/blender/compositor/operations/COM_GaussianXBlurOperation.h @@ -42,8 +42,8 @@ class GaussianXBlurOperation : public BlurBaseOperation { MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list<cl_mem> *clMemToCleanUp, - list<cl_kernel> *clKernelsToCleanUp); + std::list<cl_mem> *clMemToCleanUp, + std::list<cl_kernel> *clKernelsToCleanUp); /** * \brief initialize the execution diff --git a/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp b/source/blender/compositor/operations/COM_GaussianYBlurOperation.cc index c5b3cf24239..55c1551ca42 100644 --- a/source/blender/compositor/operations/COM_GaussianYBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_GaussianYBlurOperation.cc @@ -122,8 +122,8 @@ void GaussianYBlurOperation::executeOpenCL(OpenCLDevice *device, MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list<cl_mem> *clMemToCleanUp, - list<cl_kernel> * /*clKernelsToCleanUp*/) + std::list<cl_mem> *clMemToCleanUp, + std::list<cl_kernel> * /*clKernelsToCleanUp*/) { cl_kernel gaussianYBlurOperationKernel = device->COM_clCreateKernel( "gaussianYBlurOperationKernel", nullptr); diff --git a/source/blender/compositor/operations/COM_GaussianYBlurOperation.h b/source/blender/compositor/operations/COM_GaussianYBlurOperation.h index d921780876a..8e7440b6fe4 100644 --- a/source/blender/compositor/operations/COM_GaussianYBlurOperation.h +++ b/source/blender/compositor/operations/COM_GaussianYBlurOperation.h @@ -42,8 +42,8 @@ class GaussianYBlurOperation : public BlurBaseOperation { MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list<cl_mem> *clMemToCleanUp, - list<cl_kernel> *clKernelsToCleanUp); + std::list<cl_mem> *clMemToCleanUp, + std::list<cl_kernel> *clKernelsToCleanUp); /** * \brief initialize the execution diff --git a/source/blender/compositor/operations/COM_GlareBaseOperation.cpp b/source/blender/compositor/operations/COM_GlareBaseOperation.cc index 7b4d38fba3e..7b4d38fba3e 100644 --- a/source/blender/compositor/operations/COM_GlareBaseOperation.cpp +++ b/source/blender/compositor/operations/COM_GlareBaseOperation.cc diff --git a/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp b/source/blender/compositor/operations/COM_GlareFogGlowOperation.cc index 362905761bb..362905761bb 100644 --- a/source/blender/compositor/operations/COM_GlareFogGlowOperation.cpp +++ b/source/blender/compositor/operations/COM_GlareFogGlowOperation.cc diff --git a/source/blender/compositor/operations/COM_GlareGhostOperation.cpp b/source/blender/compositor/operations/COM_GlareGhostOperation.cc index 760b833d1e1..760b833d1e1 100644 --- a/source/blender/compositor/operations/COM_GlareGhostOperation.cpp +++ b/source/blender/compositor/operations/COM_GlareGhostOperation.cc diff --git a/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp b/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cc index 75c2ae51bde..75c2ae51bde 100644 --- a/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cpp +++ b/source/blender/compositor/operations/COM_GlareSimpleStarOperation.cc diff --git a/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp b/source/blender/compositor/operations/COM_GlareStreaksOperation.cc index 4fccb62e3df..4fccb62e3df 100644 --- a/source/blender/compositor/operations/COM_GlareStreaksOperation.cpp +++ b/source/blender/compositor/operations/COM_GlareStreaksOperation.cc diff --git a/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp b/source/blender/compositor/operations/COM_GlareThresholdOperation.cc index 1a1922f828c..cfa4b99cd70 100644 --- a/source/blender/compositor/operations/COM_GlareThresholdOperation.cpp +++ b/source/blender/compositor/operations/COM_GlareThresholdOperation.cc @@ -54,9 +54,9 @@ void GlareThresholdOperation::executePixelSampled(float output[4], output[1] -= threshold; output[2] -= threshold; - output[0] = max(output[0], 0.0f); - output[1] = max(output[1], 0.0f); - output[2] = max(output[2], 0.0f); + output[0] = MAX2(output[0], 0.0f); + output[1] = MAX2(output[1], 0.0f); + output[2] = MAX2(output[2], 0.0f); } else { zero_v3(output); diff --git a/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cpp b/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cc index df30e75cf27..df30e75cf27 100644 --- a/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cpp +++ b/source/blender/compositor/operations/COM_HueSaturationValueCorrectOperation.cc diff --git a/source/blender/compositor/operations/COM_IDMaskOperation.cpp b/source/blender/compositor/operations/COM_IDMaskOperation.cc index 8113adb9bbc..8113adb9bbc 100644 --- a/source/blender/compositor/operations/COM_IDMaskOperation.cpp +++ b/source/blender/compositor/operations/COM_IDMaskOperation.cc diff --git a/source/blender/compositor/operations/COM_ImageOperation.cpp b/source/blender/compositor/operations/COM_ImageOperation.cc index ae5b7293a8c..ae5b7293a8c 100644 --- a/source/blender/compositor/operations/COM_ImageOperation.cpp +++ b/source/blender/compositor/operations/COM_ImageOperation.cc diff --git a/source/blender/compositor/operations/COM_InpaintOperation.cpp b/source/blender/compositor/operations/COM_InpaintOperation.cc index 502b33d7e14..502b33d7e14 100644 --- a/source/blender/compositor/operations/COM_InpaintOperation.cpp +++ b/source/blender/compositor/operations/COM_InpaintOperation.cc diff --git a/source/blender/compositor/operations/COM_InvertOperation.cpp b/source/blender/compositor/operations/COM_InvertOperation.cc index d9f436a3e28..d9f436a3e28 100644 --- a/source/blender/compositor/operations/COM_InvertOperation.cpp +++ b/source/blender/compositor/operations/COM_InvertOperation.cc diff --git a/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp b/source/blender/compositor/operations/COM_KeyingBlurOperation.cc index 72bf86facfb..c9cc8ebc045 100644 --- a/source/blender/compositor/operations/COM_KeyingBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_KeyingBlurOperation.cc @@ -50,7 +50,7 @@ void KeyingBlurOperation::executePixel(float output[4], int x, int y, void *data float average = 0.0f; if (this->m_axis == 0) { - const int start = max(0, x - this->m_size + 1), end = min(bufferWidth, x + this->m_size); + const int start = MAX2(0, x - this->m_size + 1), end = MIN2(bufferWidth, x + this->m_size); for (int cx = start; cx < end; cx++) { int bufferIndex = (y * bufferWidth + cx); average += buffer[bufferIndex]; @@ -58,8 +58,8 @@ void KeyingBlurOperation::executePixel(float output[4], int x, int y, void *data } } else { - const int start = max(0, y - this->m_size + 1), - end = min(inputBuffer->getHeight(), y + this->m_size); + const int start = MAX2(0, y - this->m_size + 1), + end = MIN2(inputBuffer->getHeight(), y + this->m_size); for (int cy = start; cy < end; cy++) { int bufferIndex = (cy * bufferWidth + x); average += buffer[bufferIndex]; diff --git a/source/blender/compositor/operations/COM_KeyingClipOperation.cpp b/source/blender/compositor/operations/COM_KeyingClipOperation.cc index 592f116c451..592f116c451 100644 --- a/source/blender/compositor/operations/COM_KeyingClipOperation.cpp +++ b/source/blender/compositor/operations/COM_KeyingClipOperation.cc diff --git a/source/blender/compositor/operations/COM_KeyingDespillOperation.cpp b/source/blender/compositor/operations/COM_KeyingDespillOperation.cc index b9bb316462d..f4d0d6c6a00 100644 --- a/source/blender/compositor/operations/COM_KeyingDespillOperation.cpp +++ b/source/blender/compositor/operations/COM_KeyingDespillOperation.cc @@ -63,8 +63,8 @@ void KeyingDespillOperation::executePixelSampled(float output[4], const int other_1 = (screen_primary_channel + 1) % 3; const int other_2 = (screen_primary_channel + 2) % 3; - const int min_channel = min(other_1, other_2); - const int max_channel = max(other_1, other_2); + const int min_channel = MIN2(other_1, other_2); + const int max_channel = MAX2(other_1, other_2); float average_value, amount; diff --git a/source/blender/compositor/operations/COM_KeyingOperation.cpp b/source/blender/compositor/operations/COM_KeyingOperation.cc index 9ef4217d300..94e65181207 100644 --- a/source/blender/compositor/operations/COM_KeyingOperation.cpp +++ b/source/blender/compositor/operations/COM_KeyingOperation.cc @@ -30,8 +30,8 @@ static float get_pixel_saturation(const float pixelColor[4], const int other_1 = (primary_channel + 1) % 3; const int other_2 = (primary_channel + 2) % 3; - const int min_channel = min(other_1, other_2); - const int max_channel = max(other_1, other_2); + const int min_channel = MIN2(other_1, other_2); + const int max_channel = MAX2(other_1, other_2); const float val = screen_balance * pixelColor[min_channel] + (1.0f - screen_balance) * pixelColor[max_channel]; diff --git a/source/blender/compositor/operations/COM_KeyingScreenOperation.cpp b/source/blender/compositor/operations/COM_KeyingScreenOperation.cc index 463a6fe49c0..463a6fe49c0 100644 --- a/source/blender/compositor/operations/COM_KeyingScreenOperation.cpp +++ b/source/blender/compositor/operations/COM_KeyingScreenOperation.cc diff --git a/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp b/source/blender/compositor/operations/COM_LuminanceMatteOperation.cc index 096930d0a83..2bd7493625e 100644 --- a/source/blender/compositor/operations/COM_LuminanceMatteOperation.cpp +++ b/source/blender/compositor/operations/COM_LuminanceMatteOperation.cc @@ -54,7 +54,7 @@ void LuminanceMatteOperation::executePixelSampled(float output[4], float alpha; /* one line thread-friend algorithm: - * output[0] = min(inputValue[3], min(1.0f, max(0.0f, ((luminance - low) / (high - low)))); + * output[0] = MIN2(inputValue[3], MIN2(1.0f, MAX2(0.0f, ((luminance - low) / (high - low)))); */ /* test range */ diff --git a/source/blender/compositor/operations/COM_MapRangeOperation.cpp b/source/blender/compositor/operations/COM_MapRangeOperation.cc index 95b3c27ac2f..95b3c27ac2f 100644 --- a/source/blender/compositor/operations/COM_MapRangeOperation.cpp +++ b/source/blender/compositor/operations/COM_MapRangeOperation.cc diff --git a/source/blender/compositor/operations/COM_MapUVOperation.cpp b/source/blender/compositor/operations/COM_MapUVOperation.cc index 32ab63ae028..32ab63ae028 100644 --- a/source/blender/compositor/operations/COM_MapUVOperation.cpp +++ b/source/blender/compositor/operations/COM_MapUVOperation.cc diff --git a/source/blender/compositor/operations/COM_MapValueOperation.cpp b/source/blender/compositor/operations/COM_MapValueOperation.cc index 7f2044b9139..7f2044b9139 100644 --- a/source/blender/compositor/operations/COM_MapValueOperation.cpp +++ b/source/blender/compositor/operations/COM_MapValueOperation.cc diff --git a/source/blender/compositor/operations/COM_MaskOperation.cpp b/source/blender/compositor/operations/COM_MaskOperation.cc index ab908590c55..ab908590c55 100644 --- a/source/blender/compositor/operations/COM_MaskOperation.cpp +++ b/source/blender/compositor/operations/COM_MaskOperation.cc diff --git a/source/blender/compositor/operations/COM_MaskOperation.h b/source/blender/compositor/operations/COM_MaskOperation.h index eba14d10373..67e6b64315c 100644 --- a/source/blender/compositor/operations/COM_MaskOperation.h +++ b/source/blender/compositor/operations/COM_MaskOperation.h @@ -84,7 +84,7 @@ class MaskOperation : public NodeOperation { void setMotionBlurSamples(int samples) { - this->m_rasterMaskHandleTot = min(max(1, samples), CMP_NODE_MASK_MBLUR_SAMPLES_MAX); + this->m_rasterMaskHandleTot = MIN2(MAX2(1, samples), CMP_NODE_MASK_MBLUR_SAMPLES_MAX); } void setMotionBlurShutter(float shutter) { diff --git a/source/blender/compositor/operations/COM_MathBaseOperation.cpp b/source/blender/compositor/operations/COM_MathBaseOperation.cc index dbec6dd1874..692c1e70462 100644 --- a/source/blender/compositor/operations/COM_MathBaseOperation.cpp +++ b/source/blender/compositor/operations/COM_MathBaseOperation.cc @@ -351,7 +351,7 @@ void MathMinimumOperation::executePixelSampled(float output[4], this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - output[0] = min(inputValue1[0], inputValue2[0]); + output[0] = MIN2(inputValue1[0], inputValue2[0]); clampIfNeeded(output); } @@ -367,7 +367,7 @@ void MathMaximumOperation::executePixelSampled(float output[4], this->m_inputValue1Operation->readSampled(inputValue1, x, y, sampler); this->m_inputValue2Operation->readSampled(inputValue2, x, y, sampler); - output[0] = max(inputValue1[0], inputValue2[0]); + output[0] = MAX2(inputValue1[0], inputValue2[0]); clampIfNeeded(output); } diff --git a/source/blender/compositor/operations/COM_MixOperation.cpp b/source/blender/compositor/operations/COM_MixOperation.cc index 76a66727a75..11df0900345 100644 --- a/source/blender/compositor/operations/COM_MixOperation.cpp +++ b/source/blender/compositor/operations/COM_MixOperation.cc @@ -523,9 +523,9 @@ void MixGlareOperation::executePixelSampled(float output[4], inputColor1[2] = 0.0f; } - output[0] = mf * max(inputColor1[0] + value * (inputColor2[0] - inputColor1[0]), 0.0f); - output[1] = mf * max(inputColor1[1] + value * (inputColor2[1] - inputColor1[1]), 0.0f); - output[2] = mf * max(inputColor1[2] + value * (inputColor2[2] - inputColor1[2]), 0.0f); + output[0] = mf * MAX2(inputColor1[0] + value * (inputColor2[0] - inputColor1[0]), 0.0f); + output[1] = mf * MAX2(inputColor1[1] + value * (inputColor2[1] - inputColor1[1]), 0.0f); + output[2] = mf * MAX2(inputColor1[2] + value * (inputColor2[2] - inputColor1[2]), 0.0f); output[3] = inputColor1[3]; clampIfNeeded(output); diff --git a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc index 725aacc7d34..725aacc7d34 100644 --- a/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cpp +++ b/source/blender/compositor/operations/COM_MovieClipAttributeOperation.cc diff --git a/source/blender/compositor/operations/COM_MovieClipOperation.cpp b/source/blender/compositor/operations/COM_MovieClipOperation.cc index 4f819bf27af..4f819bf27af 100644 --- a/source/blender/compositor/operations/COM_MovieClipOperation.cpp +++ b/source/blender/compositor/operations/COM_MovieClipOperation.cc diff --git a/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp b/source/blender/compositor/operations/COM_MovieDistortionOperation.cc index 5031d590720..5031d590720 100644 --- a/source/blender/compositor/operations/COM_MovieDistortionOperation.cpp +++ b/source/blender/compositor/operations/COM_MovieDistortionOperation.cc diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp b/source/blender/compositor/operations/COM_MultilayerImageOperation.cc index 60936ee1939..60936ee1939 100644 --- a/source/blender/compositor/operations/COM_MultilayerImageOperation.cpp +++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.cc diff --git a/source/blender/compositor/operations/COM_MultilayerImageOperation.h b/source/blender/compositor/operations/COM_MultilayerImageOperation.h index f5176b0a4db..bfc59cabdbf 100644 --- a/source/blender/compositor/operations/COM_MultilayerImageOperation.h +++ b/source/blender/compositor/operations/COM_MultilayerImageOperation.h @@ -28,7 +28,7 @@ class MultilayerBaseOperation : public BaseImageOperation { protected: RenderLayer *m_renderLayer; RenderPass *m_renderPass; - ImBuf *getImBuf(); + ImBuf *getImBuf() override; public: /** @@ -44,7 +44,7 @@ class MultilayerColorOperation : public MultilayerBaseOperation { { this->addOutputSocket(COM_DT_COLOR); } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; std::unique_ptr<MetaData> getMetaData() const override; }; @@ -55,7 +55,7 @@ class MultilayerValueOperation : public MultilayerBaseOperation { { this->addOutputSocket(COM_DT_VALUE); } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; class MultilayerVectorOperation : public MultilayerBaseOperation { @@ -65,5 +65,5 @@ class MultilayerVectorOperation : public MultilayerBaseOperation { { this->addOutputSocket(COM_DT_VECTOR); } - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; }; diff --git a/source/blender/compositor/operations/COM_NormalizeOperation.cpp b/source/blender/compositor/operations/COM_NormalizeOperation.cc index a8448685332..a8448685332 100644 --- a/source/blender/compositor/operations/COM_NormalizeOperation.cpp +++ b/source/blender/compositor/operations/COM_NormalizeOperation.cc diff --git a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc index 7044fe402eb..7044fe402eb 100644 --- a/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cpp +++ b/source/blender/compositor/operations/COM_OutputFileMultiViewOperation.cc diff --git a/source/blender/compositor/operations/COM_OutputFileOperation.cpp b/source/blender/compositor/operations/COM_OutputFileOperation.cc index bb1b312ffec..bb1b312ffec 100644 --- a/source/blender/compositor/operations/COM_OutputFileOperation.cpp +++ b/source/blender/compositor/operations/COM_OutputFileOperation.cc diff --git a/source/blender/compositor/operations/COM_PixelateOperation.cpp b/source/blender/compositor/operations/COM_PixelateOperation.cc index 0d810c80ab4..0d810c80ab4 100644 --- a/source/blender/compositor/operations/COM_PixelateOperation.cpp +++ b/source/blender/compositor/operations/COM_PixelateOperation.cc diff --git a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc index d4f2ca7bbe8..d4f2ca7bbe8 100644 --- a/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cpp +++ b/source/blender/compositor/operations/COM_PlaneCornerPinOperation.cc diff --git a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc index c395f795a22..c395f795a22 100644 --- a/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cpp +++ b/source/blender/compositor/operations/COM_PlaneDistortCommonOperation.cc diff --git a/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp b/source/blender/compositor/operations/COM_PlaneTrackOperation.cc index 81a598e937b..81a598e937b 100644 --- a/source/blender/compositor/operations/COM_PlaneTrackOperation.cpp +++ b/source/blender/compositor/operations/COM_PlaneTrackOperation.cc diff --git a/source/blender/compositor/operations/COM_PreviewOperation.cpp b/source/blender/compositor/operations/COM_PreviewOperation.cc index 063421f6525..063421f6525 100644 --- a/source/blender/compositor/operations/COM_PreviewOperation.cpp +++ b/source/blender/compositor/operations/COM_PreviewOperation.cc diff --git a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cpp b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc index 7d459b76cb9..7d459b76cb9 100644 --- a/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cpp +++ b/source/blender/compositor/operations/COM_ProjectorLensDistortionOperation.cc diff --git a/source/blender/compositor/operations/COM_QualityStepHelper.cpp b/source/blender/compositor/operations/COM_QualityStepHelper.cc index 3eb8d528f7a..3eb8d528f7a 100644 --- a/source/blender/compositor/operations/COM_QualityStepHelper.cpp +++ b/source/blender/compositor/operations/COM_QualityStepHelper.cc diff --git a/source/blender/compositor/operations/COM_ReadBufferOperation.cpp b/source/blender/compositor/operations/COM_ReadBufferOperation.cc index 2977e6685d2..2977e6685d2 100644 --- a/source/blender/compositor/operations/COM_ReadBufferOperation.cpp +++ b/source/blender/compositor/operations/COM_ReadBufferOperation.cc diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.cpp b/source/blender/compositor/operations/COM_RenderLayersProg.cc index 73de60f4c34..73de60f4c34 100644 --- a/source/blender/compositor/operations/COM_RenderLayersProg.cpp +++ b/source/blender/compositor/operations/COM_RenderLayersProg.cc diff --git a/source/blender/compositor/operations/COM_RotateOperation.cpp b/source/blender/compositor/operations/COM_RotateOperation.cc index 7a21e960c13..9a1f54a6e10 100644 --- a/source/blender/compositor/operations/COM_RotateOperation.cpp +++ b/source/blender/compositor/operations/COM_RotateOperation.cc @@ -93,10 +93,10 @@ bool RotateOperation::determineDependingAreaOfInterest(rcti *input, const float y2 = this->m_centerY + (-this->m_sine * dxmax + this->m_cosine * dymin); const float y3 = this->m_centerY + (-this->m_sine * dxmin + this->m_cosine * dymax); const float y4 = this->m_centerY + (-this->m_sine * dxmax + this->m_cosine * dymax); - const float minx = min(x1, min(x2, min(x3, x4))); - const float maxx = max(x1, max(x2, max(x3, x4))); - const float miny = min(y1, min(y2, min(y3, y4))); - const float maxy = max(y1, max(y2, max(y3, y4))); + const float minx = MIN2(x1, MIN2(x2, MIN2(x3, x4))); + const float maxx = MAX2(x1, MAX2(x2, MAX2(x3, x4))); + const float miny = MIN2(y1, MIN2(y2, MIN2(y3, y4))); + const float maxy = MAX2(y1, MAX2(y2, MAX2(y3, y4))); newInput.xmax = ceil(maxx) + 1; newInput.xmin = floor(minx) - 1; diff --git a/source/blender/compositor/operations/COM_ScaleOperation.cpp b/source/blender/compositor/operations/COM_ScaleOperation.cc index 9ec4e474ccd..9ec4e474ccd 100644 --- a/source/blender/compositor/operations/COM_ScaleOperation.cpp +++ b/source/blender/compositor/operations/COM_ScaleOperation.cc diff --git a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc index 158ffd4a8c0..158ffd4a8c0 100644 --- a/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cpp +++ b/source/blender/compositor/operations/COM_ScreenLensDistortionOperation.cc diff --git a/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cpp b/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cc index 17029cb3049..17029cb3049 100644 --- a/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cpp +++ b/source/blender/compositor/operations/COM_SetAlphaMultiplyOperation.cc diff --git a/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cpp b/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cc index cd6e82902cc..cd6e82902cc 100644 --- a/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cpp +++ b/source/blender/compositor/operations/COM_SetAlphaReplaceOperation.cc diff --git a/source/blender/compositor/operations/COM_SetColorOperation.cpp b/source/blender/compositor/operations/COM_SetColorOperation.cc index ffbc20fde9c..ffbc20fde9c 100644 --- a/source/blender/compositor/operations/COM_SetColorOperation.cpp +++ b/source/blender/compositor/operations/COM_SetColorOperation.cc diff --git a/source/blender/compositor/operations/COM_SetSamplerOperation.cpp b/source/blender/compositor/operations/COM_SetSamplerOperation.cc index 942d717d19c..942d717d19c 100644 --- a/source/blender/compositor/operations/COM_SetSamplerOperation.cpp +++ b/source/blender/compositor/operations/COM_SetSamplerOperation.cc diff --git a/source/blender/compositor/operations/COM_SetValueOperation.cpp b/source/blender/compositor/operations/COM_SetValueOperation.cc index d72a2dfe23d..d72a2dfe23d 100644 --- a/source/blender/compositor/operations/COM_SetValueOperation.cpp +++ b/source/blender/compositor/operations/COM_SetValueOperation.cc diff --git a/source/blender/compositor/operations/COM_SetVectorOperation.cpp b/source/blender/compositor/operations/COM_SetVectorOperation.cc index a0341dbc4df..a0341dbc4df 100644 --- a/source/blender/compositor/operations/COM_SetVectorOperation.cpp +++ b/source/blender/compositor/operations/COM_SetVectorOperation.cc diff --git a/source/blender/compositor/operations/COM_SocketProxyOperation.cpp b/source/blender/compositor/operations/COM_SocketProxyOperation.cc index 53f5fea8795..53f5fea8795 100644 --- a/source/blender/compositor/operations/COM_SocketProxyOperation.cpp +++ b/source/blender/compositor/operations/COM_SocketProxyOperation.cc diff --git a/source/blender/compositor/operations/COM_SplitOperation.cpp b/source/blender/compositor/operations/COM_SplitOperation.cc index fb6214c7522..fb6214c7522 100644 --- a/source/blender/compositor/operations/COM_SplitOperation.cpp +++ b/source/blender/compositor/operations/COM_SplitOperation.cc diff --git a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp b/source/blender/compositor/operations/COM_SunBeamsOperation.cc index 7cfa4de7a61..28811d479a5 100644 --- a/source/blender/compositor/operations/COM_SunBeamsOperation.cpp +++ b/source/blender/compositor/operations/COM_SunBeamsOperation.cc @@ -33,7 +33,7 @@ void SunBeamsOperation::initExecution() /* convert to pixels */ this->m_source_px[0] = this->m_data.source[0] * this->getWidth(); this->m_source_px[1] = this->m_data.source[1] * this->getHeight(); - this->m_ray_length_px = this->m_data.ray_length * max(this->getWidth(), this->getHeight()); + this->m_ray_length_px = this->m_data.ray_length * MAX2(this->getWidth(), this->getHeight()); } /** diff --git a/source/blender/compositor/operations/COM_TextureOperation.cpp b/source/blender/compositor/operations/COM_TextureOperation.cc index e66cd57cb3f..e66cd57cb3f 100644 --- a/source/blender/compositor/operations/COM_TextureOperation.cpp +++ b/source/blender/compositor/operations/COM_TextureOperation.cc diff --git a/source/blender/compositor/operations/COM_TonemapOperation.cpp b/source/blender/compositor/operations/COM_TonemapOperation.cc index cb0fc747dcb..4c1d285a69f 100644 --- a/source/blender/compositor/operations/COM_TonemapOperation.cpp +++ b/source/blender/compositor/operations/COM_TonemapOperation.cc @@ -51,9 +51,9 @@ void TonemapOperation::executePixel(float output[4], int x, int y, void *data) output[2] /= ((db == 0.0f) ? 1.0f : db); const float igm = avg->igm; if (igm != 0.0f) { - output[0] = powf(max(output[0], 0.0f), igm); - output[1] = powf(max(output[1], 0.0f), igm); - output[2] = powf(max(output[2], 0.0f), igm); + output[0] = powf(MAX2(output[0], 0.0f), igm); + output[1] = powf(MAX2(output[1], 0.0f), igm); + output[2] = powf(MAX2(output[2], 0.0f), igm); } } void PhotoreceptorTonemapOperation::executePixel(float output[4], int x, int y, void *data) diff --git a/source/blender/compositor/operations/COM_TrackPositionOperation.cpp b/source/blender/compositor/operations/COM_TrackPositionOperation.cc index ddabfb7cf6c..ddabfb7cf6c 100644 --- a/source/blender/compositor/operations/COM_TrackPositionOperation.cpp +++ b/source/blender/compositor/operations/COM_TrackPositionOperation.cc diff --git a/source/blender/compositor/operations/COM_TranslateOperation.cpp b/source/blender/compositor/operations/COM_TranslateOperation.cc index 286004cd49b..286004cd49b 100644 --- a/source/blender/compositor/operations/COM_TranslateOperation.cpp +++ b/source/blender/compositor/operations/COM_TranslateOperation.cc diff --git a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc index 414b5bd980a..909a2f73d25 100644 --- a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.cc @@ -74,7 +74,7 @@ void *VariableSizeBokehBlurOperation::initializeTileData(rcti *rect) this->determineDependingAreaOfInterest( rect, (ReadBufferOperation *)this->m_inputSizeProgram, &rect2); - const float max_dim = max(m_width, m_height); + const float max_dim = MAX2(m_width, m_height); const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f; data->maxBlurScalar = (int)(data->size->getMaximumValue(&rect2) * scalar); @@ -102,7 +102,7 @@ void VariableSizeBokehBlurOperation::executePixel(float output[4], int x, int y, float multiplier_accum[4]; float color_accum[4]; - const float max_dim = max(m_width, m_height); + const float max_dim = MAX2(m_width, m_height); const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f; int maxBlurScalar = tileData->maxBlurScalar; @@ -120,10 +120,10 @@ void VariableSizeBokehBlurOperation::executePixel(float output[4], int x, int y, int maxx = search[2]; int maxy = search[3]; #else - int minx = max(x - maxBlurScalar, 0); - int miny = max(y - maxBlurScalar, 0); - int maxx = min(x + maxBlurScalar, (int)m_width); - int maxy = min(y + maxBlurScalar, (int)m_height); + int minx = MAX2(x - maxBlurScalar, 0); + int miny = MAX2(y - maxBlurScalar, 0); + int maxx = MIN2(x + maxBlurScalar, (int)m_width); + int maxy = MIN2(y + maxBlurScalar, (int)m_height); #endif { inputSizeBuffer->readNoCheck(tempSize, x, y); @@ -145,7 +145,7 @@ void VariableSizeBokehBlurOperation::executePixel(float output[4], int x, int y, int offsetColorNxNy = offsetValueNxNy * COM_NUM_CHANNELS_COLOR; for (int nx = minx; nx < maxx; nx += addXStepValue) { if (nx != x || ny != y) { - float size = min(inputSizeFloatBuffer[offsetValueNxNy] * scalar, size_center); + float size = MIN2(inputSizeFloatBuffer[offsetValueNxNy] * scalar, size_center); if (size > this->m_threshold) { float dx = nx - x; if (size > fabsf(dx) && size > fabsf(dy)) { @@ -185,8 +185,8 @@ void VariableSizeBokehBlurOperation::executeOpenCL(OpenCLDevice *device, MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list<cl_mem> *clMemToCleanUp, - list<cl_kernel> * /*clKernelsToCleanUp*/) + std::list<cl_mem> *clMemToCleanUp, + std::list<cl_kernel> * /*clKernelsToCleanUp*/) { cl_kernel defocusKernel = device->COM_clCreateKernel("defocusKernel", nullptr); @@ -197,7 +197,7 @@ void VariableSizeBokehBlurOperation::executeOpenCL(OpenCLDevice *device, MemoryBuffer *sizeMemoryBuffer = this->m_inputSizeProgram->getInputMemoryBuffer( inputMemoryBuffers); - const float max_dim = max(m_width, m_height); + const float max_dim = MAX2(m_width, m_height); cl_float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f; maxBlur = (cl_int)min_ff(sizeMemoryBuffer->getMaximumValue() * scalar, (float)this->m_maxBlur); @@ -235,7 +235,7 @@ bool VariableSizeBokehBlurOperation::determineDependingAreaOfInterest( rcti newInput; rcti bokehInput; - const float max_dim = max(m_width, m_height); + const float max_dim = MAX2(m_width, m_height); const float scalar = this->m_do_size_scale ? (max_dim / 100.0f) : 1.0f; int maxBlurScalar = this->m_maxBlur * scalar; diff --git a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h index 258b5d385c0..fe927f791fa 100644 --- a/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h +++ b/source/blender/compositor/operations/COM_VariableSizeBokehBlurOperation.h @@ -80,8 +80,8 @@ class VariableSizeBokehBlurOperation : public NodeOperation, public QualityStepH MemoryBuffer *outputMemoryBuffer, cl_mem clOutputBuffer, MemoryBuffer **inputMemoryBuffers, - list<cl_mem> *clMemToCleanUp, - list<cl_kernel> *clKernelsToCleanUp); + std::list<cl_mem> *clMemToCleanUp, + std::list<cl_kernel> *clKernelsToCleanUp); }; #ifdef COM_DEFOCUS_SEARCH diff --git a/source/blender/compositor/operations/COM_VectorBlurOperation.cpp b/source/blender/compositor/operations/COM_VectorBlurOperation.cc index d6894dfc8ad..d6894dfc8ad 100644 --- a/source/blender/compositor/operations/COM_VectorBlurOperation.cpp +++ b/source/blender/compositor/operations/COM_VectorBlurOperation.cc diff --git a/source/blender/compositor/operations/COM_VectorCurveOperation.cpp b/source/blender/compositor/operations/COM_VectorCurveOperation.cc index a883237f870..a883237f870 100644 --- a/source/blender/compositor/operations/COM_VectorCurveOperation.cpp +++ b/source/blender/compositor/operations/COM_VectorCurveOperation.cc diff --git a/source/blender/compositor/operations/COM_ViewerOperation.cpp b/source/blender/compositor/operations/COM_ViewerOperation.cc index 025dde8e866..025dde8e866 100644 --- a/source/blender/compositor/operations/COM_ViewerOperation.cpp +++ b/source/blender/compositor/operations/COM_ViewerOperation.cc diff --git a/source/blender/compositor/operations/COM_WrapOperation.cpp b/source/blender/compositor/operations/COM_WrapOperation.cc index 37b7d68d495..37b7d68d495 100644 --- a/source/blender/compositor/operations/COM_WrapOperation.cpp +++ b/source/blender/compositor/operations/COM_WrapOperation.cc diff --git a/source/blender/compositor/operations/COM_WriteBufferOperation.cpp b/source/blender/compositor/operations/COM_WriteBufferOperation.cc index 9fb995bf463..8d38dbfe180 100644 --- a/source/blender/compositor/operations/COM_WriteBufferOperation.cpp +++ b/source/blender/compositor/operations/COM_WriteBufferOperation.cc @@ -143,9 +143,9 @@ void WriteBufferOperation::executeOpenCLRegion(OpenCLDevice *device, } // STEP 2 - list<cl_mem> *clMemToCleanUp = new list<cl_mem>(); + std::list<cl_mem> *clMemToCleanUp = new std::list<cl_mem>(); clMemToCleanUp->push_back(clOutputBuffer); - list<cl_kernel> *clKernelsToCleanUp = new list<cl_kernel>(); + std::list<cl_kernel> *clKernelsToCleanUp = new std::list<cl_kernel>(); this->m_input->executeOpenCL(device, outputBuffer, diff --git a/source/blender/compositor/operations/COM_ZCombineOperation.cpp b/source/blender/compositor/operations/COM_ZCombineOperation.cc index 22a37a4583e..26d3f2c7dc4 100644 --- a/source/blender/compositor/operations/COM_ZCombineOperation.cpp +++ b/source/blender/compositor/operations/COM_ZCombineOperation.cc @@ -83,7 +83,7 @@ void ZCombineAlphaOperation::executePixelSampled(float output[4], output[0] = fac * color1[0] + ifac * color2[0]; output[1] = fac * color1[1] + ifac * color2[1]; output[2] = fac * color1[2] + ifac * color2[2]; - output[3] = max(color1[3], color2[3]); + output[3] = MAX2(color1[3], color2[3]); } void ZCombineOperation::deinitExecution() @@ -149,7 +149,7 @@ void ZCombineMaskAlphaOperation::executePixelSampled(float output[4], output[0] = color1[0] * mfac + color2[0] * fac; output[1] = color1[1] * mfac + color2[1] * fac; output[2] = color1[2] * mfac + color2[2] * fac; - output[3] = max(color1[3], color2[3]); + output[3] = MAX2(color1[3], color2[3]); } void ZCombineMaskOperation::deinitExecution() diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index 18d3e453c5d..25aedd2cdde 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -44,7 +44,7 @@ static struct { #define SETUP_BUFFER(tex, fb, fb_color) \ { \ eGPUTextureFormat format = (DRW_state_is_scene_render()) ? GPU_RGBA32F : GPU_RGBA16F; \ - DRW_texture_ensure_fullscreen_2d(&tex, format, DRW_TEX_FILTER | DRW_TEX_MIPMAP); \ + DRW_texture_ensure_fullscreen_2d(&tex, format, DRW_TEX_FILTER); \ GPU_framebuffer_ensure_config(&fb, \ { \ GPU_ATTACHMENT_TEXTURE(dtxl->depth), \ @@ -117,20 +117,27 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, /** * MinMax Pyramid */ - const bool half_res_hiz = true; - int size[2], div; - common_data->hiz_mip_offset = (half_res_hiz) ? 1 : 0; - div = (half_res_hiz) ? 2 : 1; - size[0] = max_ii(size_fs[0] / div, 1); - size[1] = max_ii(size_fs[1] / div, 1); + int div = 1 << MAX_SCREEN_BUFFERS_LOD_LEVEL; + effects->hiz_size[0] = divide_ceil_u(size_fs[0], div) * div; + effects->hiz_size[1] = divide_ceil_u(size_fs[1], div) * div; if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) { - /* Intel gpu seems to have problem rendering to only depth format */ - DRW_texture_ensure_2d(&txl->maxzbuffer, size[0], size[1], GPU_R32F, DRW_TEX_MIPMAP); + /* Intel gpu seems to have problem rendering to only depth hiz_format */ + DRW_texture_ensure_2d(&txl->maxzbuffer, UNPACK2(effects->hiz_size), GPU_R32F, DRW_TEX_MIPMAP); + GPU_framebuffer_ensure_config(&fbl->maxzbuffer_fb, + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(txl->maxzbuffer), + }); } else { DRW_texture_ensure_2d( - &txl->maxzbuffer, size[0], size[1], GPU_DEPTH_COMPONENT24, DRW_TEX_MIPMAP); + &txl->maxzbuffer, UNPACK2(effects->hiz_size), GPU_DEPTH_COMPONENT24, DRW_TEX_MIPMAP); + GPU_framebuffer_ensure_config(&fbl->maxzbuffer_fb, + { + GPU_ATTACHMENT_TEXTURE(txl->maxzbuffer), + GPU_ATTACHMENT_NONE, + }); } if (fbl->downsample_fb == NULL) { @@ -138,13 +145,35 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, } /** - * Compute Mipmap texel alignment. + * Compute hiZ texel alignment. + */ + common_data->hiz_uv_scale[0] = viewport_size[0] / effects->hiz_size[0]; + common_data->hiz_uv_scale[1] = viewport_size[1] / effects->hiz_size[1]; + common_data->hiz_uv_scale[2] = 1.0f / effects->hiz_size[0]; + common_data->hiz_uv_scale[3] = 1.0f / effects->hiz_size[1]; + + /* Compute pixel size. Size is multiplied by 2 because it is applied in NDC [-1..1] range. */ + sldata->common_data.ssr_pixelsize[0] = 2.0f / size_fs[0]; + sldata->common_data.ssr_pixelsize[1] = 2.0f / size_fs[1]; + + /** + * Color buffer with correct downsampling alignment. + * Used for SSReflections & SSRefractions. */ - for (int i = 0; i < 10; i++) { - int mip_size[3]; - GPU_texture_get_mipmap_size(txl->color, i, mip_size); - common_data->mip_ratio[i][0] = viewport_size[0] / (mip_size[0] * powf(2.0f, i)); - common_data->mip_ratio[i][1] = viewport_size[1] / (mip_size[1] * powf(2.0f, i)); + if ((effects->enabled_effects & EFFECT_RADIANCE_BUFFER) != 0) { + DRW_texture_ensure_2d(&txl->filtered_radiance, + UNPACK2(effects->hiz_size), + GPU_R11F_G11F_B10F, + DRW_TEX_FILTER | DRW_TEX_MIPMAP); + + GPU_framebuffer_ensure_config(&fbl->radiance_filtered_fb, + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(txl->filtered_radiance), + }); + } + else { + txl->filtered_radiance = NULL; } /** @@ -210,7 +239,7 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) EEVEE_TextureList *txl = vedata->txl; EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; - DRWState downsample_write = DRW_STATE_WRITE_DEPTH; + DRWState downsample_write = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS; DRWShadingGroup *grp; /* Intel gpu seems to have problem rendering to only depth format. @@ -221,12 +250,17 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) struct GPUBatch *quad = DRW_cache_fullscreen_quad_get(); - { + if (effects->enabled_effects & EFFECT_RADIANCE_BUFFER) { + DRW_PASS_CREATE(psl->color_copy_ps, DRW_STATE_WRITE_COLOR); + grp = DRW_shgroup_create(EEVEE_shaders_effect_color_copy_sh_get(), psl->color_copy_ps); + DRW_shgroup_uniform_texture_ref_ex(grp, "source", &e_data.color_src, GPU_SAMPLER_DEFAULT); + DRW_shgroup_uniform_float(grp, "fireflyFactor", &sldata->common_data.ssr_firefly_fac, 1); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + DRW_PASS_CREATE(psl->color_downsample_ps, DRW_STATE_WRITE_COLOR); grp = DRW_shgroup_create(EEVEE_shaders_effect_downsample_sh_get(), psl->color_downsample_ps); - DRW_shgroup_uniform_texture_ref(grp, "source", &e_data.color_src); - DRW_shgroup_uniform_float(grp, "fireflyFactor", &sldata->common_data.ssr_firefly_fac, 1); - DRW_shgroup_call(grp, quad, NULL); + DRW_shgroup_uniform_texture_ex(grp, "source", txl->filtered_radiance, GPU_SAMPLER_FILTER); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } { @@ -241,34 +275,21 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { /* Perform min/max down-sample. */ - DRW_PASS_CREATE(psl->maxz_downlevel_ps, downsample_write | DRW_STATE_DEPTH_ALWAYS); + DRW_PASS_CREATE(psl->maxz_downlevel_ps, downsample_write); grp = DRW_shgroup_create(EEVEE_shaders_effect_maxz_downlevel_sh_get(), psl->maxz_downlevel_ps); - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &txl->maxzbuffer); - DRW_shgroup_call(grp, quad, NULL); - - /* Copy depth buffer to halfres top level of HiZ */ - - DRW_PASS_CREATE(psl->maxz_downdepth_ps, downsample_write | DRW_STATE_DEPTH_ALWAYS); - grp = DRW_shgroup_create(EEVEE_shaders_effect_maxz_downdepth_sh_get(), psl->maxz_downdepth_ps); - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src); - DRW_shgroup_call(grp, quad, NULL); - - DRW_PASS_CREATE(psl->maxz_downdepth_layer_ps, downsample_write | DRW_STATE_DEPTH_ALWAYS); - grp = DRW_shgroup_create(EEVEE_shaders_effect_maxz_downdepth_layer_sh_get(), - psl->maxz_downdepth_layer_ps); - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src); - DRW_shgroup_uniform_int(grp, "depthLayer", &e_data.depth_src_layer, 1); + DRW_shgroup_uniform_texture_ref_ex(grp, "depthBuffer", &txl->maxzbuffer, GPU_SAMPLER_DEFAULT); DRW_shgroup_call(grp, quad, NULL); - DRW_PASS_CREATE(psl->maxz_copydepth_ps, downsample_write | DRW_STATE_DEPTH_ALWAYS); + /* Copy depth buffer to top level of HiZ */ + DRW_PASS_CREATE(psl->maxz_copydepth_ps, downsample_write); grp = DRW_shgroup_create(EEVEE_shaders_effect_maxz_copydepth_sh_get(), psl->maxz_copydepth_ps); - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src); + DRW_shgroup_uniform_texture_ref_ex(grp, "depthBuffer", &e_data.depth_src, GPU_SAMPLER_DEFAULT); DRW_shgroup_call(grp, quad, NULL); - DRW_PASS_CREATE(psl->maxz_copydepth_layer_ps, downsample_write | DRW_STATE_DEPTH_ALWAYS); + DRW_PASS_CREATE(psl->maxz_copydepth_layer_ps, downsample_write); grp = DRW_shgroup_create(EEVEE_shaders_effect_maxz_copydepth_layer_sh_get(), psl->maxz_copydepth_layer_ps); - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src); + DRW_shgroup_uniform_texture_ref_ex(grp, "depthBuffer", &e_data.depth_src, GPU_SAMPLER_DEFAULT); DRW_shgroup_uniform_int(grp, "depthLayer", &e_data.depth_src_layer, 1); DRW_shgroup_call(grp, quad, NULL); } @@ -331,12 +352,6 @@ static void max_downsample_cb(void *vedata, int UNUSED(level)) DRW_draw_pass(psl->maxz_downlevel_ps); } -static void simple_downsample_cb(void *vedata, int UNUSED(level)) -{ - EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; - DRW_draw_pass(psl->color_downsample_ps); -} - static void simple_downsample_cube_cb(void *vedata, int level) { EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; @@ -348,58 +363,22 @@ void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, GPUTexture *depth_src, int l { EEVEE_PassList *psl = vedata->psl; EEVEE_FramebufferList *fbl = vedata->fbl; - EEVEE_TextureList *txl = vedata->txl; e_data.depth_src = depth_src; e_data.depth_src_layer = layer; -#if 0 /* Not required for now */ - DRW_stats_group_start("Min buffer"); - /* Copy depth buffer to min texture top level */ - GPU_framebuffer_texture_attach(fbl->downsample_fb, stl->g_data->minzbuffer, 0, 0); - GPU_framebuffer_bind(fbl->downsample_fb); - if (layer >= 0) { - DRW_draw_pass(psl->minz_downdepth_layer_ps); - } - else { - DRW_draw_pass(psl->minz_downdepth_ps); - } - GPU_framebuffer_texture_detach(stl->g_data->minzbuffer); - - /* Create lower levels */ - GPU_framebuffer_recursive_downsample( - fbl->downsample_fb, stl->g_data->minzbuffer, 8, &min_downsample_cb, vedata); - DRW_stats_group_end(); -#endif - int minmax_size[3], depth_size[3]; - GPU_texture_get_mipmap_size(depth_src, 0, depth_size); - GPU_texture_get_mipmap_size(txl->maxzbuffer, 0, minmax_size); - bool is_full_res_minmaxz = equals_v2v2_int(minmax_size, depth_size); - DRW_stats_group_start("Max buffer"); /* Copy depth buffer to max texture top level */ - GPU_framebuffer_texture_attach(fbl->downsample_fb, txl->maxzbuffer, 0, 0); - GPU_framebuffer_bind(fbl->downsample_fb); + GPU_framebuffer_bind(fbl->maxzbuffer_fb); if (layer >= 0) { - if (is_full_res_minmaxz) { - DRW_draw_pass(psl->maxz_copydepth_layer_ps); - } - else { - DRW_draw_pass(psl->maxz_downdepth_layer_ps); - } + DRW_draw_pass(psl->maxz_copydepth_layer_ps); } else { - if (is_full_res_minmaxz) { - DRW_draw_pass(psl->maxz_copydepth_ps); - } - else { - DRW_draw_pass(psl->maxz_downdepth_ps); - } + DRW_draw_pass(psl->maxz_copydepth_ps); } - /* Create lower levels */ - GPU_framebuffer_recursive_downsample(fbl->downsample_fb, 8, &max_downsample_cb, vedata); - GPU_framebuffer_texture_detach(fbl->downsample_fb, txl->maxzbuffer); + GPU_framebuffer_recursive_downsample( + fbl->maxzbuffer_fb, MAX_SCREEN_BUFFERS_LOD_LEVEL, &max_downsample_cb, vedata); DRW_stats_group_end(); /* Restore */ @@ -412,19 +391,28 @@ void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, GPUTexture *depth_src, int l } } +static void downsample_radiance_cb(void *vedata, int UNUSED(level)) +{ + EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; + DRW_draw_pass(psl->color_downsample_ps); +} + /** * Simple down-sampling algorithm. Reconstruct mip chain up to mip level. */ -void EEVEE_downsample_buffer(EEVEE_Data *vedata, GPUTexture *texture_src, int level) +void EEVEE_effects_downsample_radiance_buffer(EEVEE_Data *vedata, GPUTexture *texture_src) { + EEVEE_PassList *psl = vedata->psl; EEVEE_FramebufferList *fbl = vedata->fbl; + e_data.color_src = texture_src; + DRW_stats_group_start("Downsample Radiance"); - /* Create lower levels */ - DRW_stats_group_start("Downsample buffer"); - GPU_framebuffer_texture_attach(fbl->downsample_fb, texture_src, 0, 0); - GPU_framebuffer_recursive_downsample(fbl->downsample_fb, level, &simple_downsample_cb, vedata); - GPU_framebuffer_texture_detach(fbl->downsample_fb, texture_src); + GPU_framebuffer_bind(fbl->radiance_filtered_fb); + DRW_draw_pass(psl->color_copy_ps); + + GPU_framebuffer_recursive_downsample( + fbl->radiance_filtered_fb, MAX_SCREEN_BUFFERS_LOD_LEVEL, &downsample_radiance_cb, vedata); DRW_stats_group_end(); } diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index 7688039d0a8..0ce94b8f1b1 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -112,19 +112,20 @@ static struct GPUTexture *create_hammersley_sample_texture(int samples) static void planar_pool_ensure_alloc(EEVEE_Data *vedata, int num_planar_ref) { EEVEE_TextureList *txl = vedata->txl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *fx = stl->effects; /* XXX TODO OPTIMIZATION: This is a complete waist of texture memory. * Instead of allocating each planar probe for each viewport, * only alloc them once using the biggest viewport resolution. */ - const float *viewport_size = DRW_viewport_size_get(); /* TODO get screen percentage from layer setting */ // const DRWContextState *draw_ctx = DRW_context_state_get(); // ViewLayer *view_layer = draw_ctx->view_layer; - float screen_percentage = 1.0f; + int screen_divider = 1; - int width = max_ii(1, (int)(viewport_size[0] * screen_percentage)); - int height = max_ii(1, (int)(viewport_size[1] * screen_percentage)); + int width = max_ii(1, fx->hiz_size[0] / screen_divider); + int height = max_ii(1, fx->hiz_size[1] / screen_divider); /* Fix case were the pool was allocated width the dummy size (1,1,1). */ if (txl->planar_pool && (num_planar_ref > 0) && @@ -139,12 +140,12 @@ static void planar_pool_ensure_alloc(EEVEE_Data *vedata, int num_planar_ref) if (num_planar_ref > 0) { txl->planar_pool = DRW_texture_create_2d_array(width, height, - max_ii(1, num_planar_ref), + num_planar_ref, GPU_R11F_G11F_B10F, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL); txl->planar_depth = DRW_texture_create_2d_array( - width, height, max_ii(1, num_planar_ref), GPU_DEPTH_COMPONENT24, 0, NULL); + width, height, num_planar_ref, GPU_DEPTH_COMPONENT24, 0, NULL); } else if (num_planar_ref == 0) { /* Makes Opengl Happy : Create a placeholder texture that will never be sampled but still @@ -674,10 +675,12 @@ static void lightbake_planar_ensure_view(EEVEE_PlanarReflection *eplanar, const DRWView *main_view, DRWView **r_planar_view) { - float winmat[4][4], viewmat[4][4]; + float winmat[4][4], viewmat[4][4], persmat[4][4]; DRW_view_viewmat_get(main_view, viewmat, false); /* Temporal sampling jitter should be already applied to the DRW_MAT_WIN. */ DRW_view_winmat_get(main_view, winmat, false); + DRW_view_persmat_get(main_view, persmat, false); + /* Invert X to avoid flipping the triangle facing direction. */ winmat[0][0] = -winmat[0][0]; winmat[1][0] = -winmat[1][0]; @@ -729,7 +732,6 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved /* For shading, save max level of the octahedron map */ sldata->common_data.prb_lod_cube_max = (float)light_cache->mips_len; - sldata->common_data.prb_lod_planar_max = (float)MAX_PLANAR_LOD_LEVEL; sldata->common_data.prb_irradiance_vis_size = light_cache->vis_res; sldata->common_data.prb_irradiance_smooth = square_f(scene_eval->eevee.gi_irradiance_smoothing); sldata->common_data.prb_num_render_cube = max_ii(1, light_cache->cube_len); @@ -1220,7 +1222,7 @@ static void EEVEE_lightbake_filter_planar(EEVEE_Data *vedata) {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->planar_pool)}); GPU_framebuffer_recursive_downsample( - fbl->planar_downsample_fb, MAX_PLANAR_LOD_LEVEL, &downsample_planar, vedata); + fbl->planar_downsample_fb, MAX_SCREEN_BUFFERS_LOD_LEVEL, &downsample_planar, vedata); DRW_stats_group_end(); } diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index 9d74d916265..bc7db4b5df6 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -128,7 +128,7 @@ void EEVEE_material_bind_resources(DRWShadingGroup *shgrp, DRW_shgroup_uniform_float_copy( shgrp, "refractionDepth", (refract_depth) ? *refract_depth : 0.0); if (use_ssrefraction) { - DRW_shgroup_uniform_texture_ref(shgrp, "colorBuffer", &vedata->txl->refract_color); + DRW_shgroup_uniform_texture_ref(shgrp, "colorBuffer", &vedata->txl->filtered_radiance); } } if (use_alpha_blend) { diff --git a/source/blender/draw/engines/eevee/eevee_occlusion.c b/source/blender/draw/engines/eevee/eevee_occlusion.c index a3b581357e0..a7874440895 100644 --- a/source/blender/draw/engines/eevee/eevee_occlusion.c +++ b/source/blender/draw/engines/eevee/eevee_occlusion.c @@ -62,7 +62,7 @@ int EEVEE_occlusion_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) common_data->ao_dist = scene_eval->eevee.gtao_distance; common_data->ao_factor = scene_eval->eevee.gtao_factor; - common_data->ao_quality = 1.0f - scene_eval->eevee.gtao_quality; + common_data->ao_quality = scene_eval->eevee.gtao_quality; if (scene_eval->eevee.flag & SCE_EEVEE_GTAO_ENABLED) { common_data->ao_settings = 1.0f; /* USE_AO */ diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 4e32854dedc..45afee31591 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -161,7 +161,7 @@ BLI_INLINE bool eevee_hdri_preview_overlay_enabled(const View3D *v3d) ((v3d->shading.flag & V3D_SHADING_SCENE_WORLD_RENDER) == 0)))) #define MIN_CUBE_LOD_LEVEL 3 -#define MAX_PLANAR_LOD_LEVEL 9 +#define MAX_SCREEN_BUFFERS_LOD_LEVEL 6 /* All the renderpasses that use the GPUMaterial for accumulation */ #define EEVEE_RENDERPASSES_MATERIAL \ @@ -308,6 +308,7 @@ typedef struct EEVEE_PassList { struct DRWPass *sss_blur_ps; struct DRWPass *sss_resolve_ps; struct DRWPass *sss_translucency_ps; + struct DRWPass *color_copy_ps; struct DRWPass *color_downsample_ps; struct DRWPass *color_downsample_cube_ps; struct DRWPass *velocity_object; @@ -320,13 +321,7 @@ typedef struct EEVEE_PassList { struct DRWPass *alpha_checker; /* HiZ */ - struct DRWPass *minz_downlevel_ps; struct DRWPass *maxz_downlevel_ps; - struct DRWPass *minz_downdepth_ps; - struct DRWPass *maxz_downdepth_ps; - struct DRWPass *minz_downdepth_layer_ps; - struct DRWPass *maxz_downdepth_layer_ps; - struct DRWPass *minz_copydepth_ps; struct DRWPass *maxz_copydepth_ps; struct DRWPass *maxz_copydepth_layer_ps; @@ -362,6 +357,7 @@ typedef struct EEVEE_FramebufferList { struct GPUFrameBuffer *gtao_fb; struct GPUFrameBuffer *gtao_debug_fb; struct GPUFrameBuffer *downsample_fb; + struct GPUFrameBuffer *maxzbuffer_fb; struct GPUFrameBuffer *bloom_blit_fb; struct GPUFrameBuffer *bloom_down_fb[MAX_BLOOM_STEP]; struct GPUFrameBuffer *bloom_accum_fb[MAX_BLOOM_STEP - 1]; @@ -394,7 +390,6 @@ typedef struct EEVEE_FramebufferList { struct GPUFrameBuffer *volumetric_integ_fb; struct GPUFrameBuffer *volumetric_accum_fb; struct GPUFrameBuffer *screen_tracing_fb; - struct GPUFrameBuffer *refract_fb; struct GPUFrameBuffer *mist_accum_fb; struct GPUFrameBuffer *material_accum_fb; struct GPUFrameBuffer *renderpass_fb; @@ -412,6 +407,7 @@ typedef struct EEVEE_FramebufferList { struct GPUFrameBuffer *main_color_fb; struct GPUFrameBuffer *effect_fb; struct GPUFrameBuffer *effect_color_fb; + struct GPUFrameBuffer *radiance_filtered_fb; struct GPUFrameBuffer *double_buffer_fb; struct GPUFrameBuffer *double_buffer_color_fb; struct GPUFrameBuffer *double_buffer_depth_fb; @@ -436,7 +432,6 @@ typedef struct EEVEE_TextureList { struct GPUTexture *ssr_accum; struct GPUTexture *shadow_accum; struct GPUTexture *cryptomatte; - struct GPUTexture *refract_color; struct GPUTexture *taa_history; /* Could not be pool texture because of mipmapping. */ struct GPUTexture *dof_reduced_color; @@ -460,6 +455,7 @@ typedef struct EEVEE_TextureList { struct GPUTexture *planar_depth; struct GPUTexture *maxzbuffer; + struct GPUTexture *filtered_radiance; struct GPUTexture *renderpass; @@ -618,7 +614,7 @@ typedef struct EEVEE_LightProbesInfo { float roughness; float firefly_fac; float lodfactor; - float lod_rt_max, lod_cube_max, lod_planar_max; + float lod_rt_max, lod_cube_max; float visibility_range; float visibility_blur; float intensity_fac; @@ -708,8 +704,9 @@ typedef enum EEVEE_EffectsFlag { EFFECT_REFRACT = (1 << 6), EFFECT_GTAO = (1 << 7), EFFECT_TAA = (1 << 8), - EFFECT_POST_BUFFER = (1 << 9), /* Not really an effect but a feature */ - EFFECT_NORMAL_BUFFER = (1 << 10), /* Not really an effect but a feature */ + EFFECT_POST_BUFFER = (1 << 9), /* Not really an effect but a feature */ + EFFECT_NORMAL_BUFFER = (1 << 10), /* Not really an effect but a feature */ + EFFECT_RADIANCE_BUFFER = (1 << 10), /* Not really an effect but a feature */ EFFECT_SSS = (1 << 11), EFFECT_VELOCITY_BUFFER = (1 << 12), /* Not really an effect but a feature */ EFFECT_TAA_REPROJECT = (1 << 13), /* should be mutually exclusive with EFFECT_TAA */ @@ -817,11 +814,10 @@ typedef struct EEVEE_EffectsInfo { struct GPUTexture *dof_scatter_src_tx; struct GPUTexture *dof_reduce_input_coc_tx; /* Just references to actual textures. */ struct GPUTexture *dof_reduce_input_color_tx; - /* Alpha Checker */ - float color_checker_dark[4]; - float color_checker_light[4]; /* Other */ float prev_persmat[4][4]; + /* Size used by all fullscreen buffers using mipmaps. */ + int hiz_size[2]; /* Lookdev */ int sphere_size; eDRWLevelOfDetail sphere_lod; @@ -859,7 +855,7 @@ typedef struct EEVEE_EffectsInfo { * - sizeof(bool) == sizeof(int) in GLSL so use int in C */ typedef struct EEVEE_CommonUniformBuffer { float prev_persmat[4][4]; /* mat4 */ - float mip_ratio[10][4]; /* vec2[10] */ + float hiz_uv_scale[4]; /* vec4 */ /* Ambient Occlusion */ /* -- 16 byte aligned -- */ float ao_dist, pad1, ao_factor, pad2; /* vec4 */ @@ -899,15 +895,15 @@ typedef struct EEVEE_CommonUniformBuffer { int prb_irradiance_vis_size; /* int */ float prb_irradiance_smooth; /* float */ float prb_lod_cube_max; /* float */ - float prb_lod_planar_max; /* float */ /* Misc */ - int hiz_mip_offset; /* int */ int ray_type; /* int */ float ray_depth; /* float */ float alpha_hash_offset; /* float */ float alpha_hash_scale; /* float */ float pad7; /* float */ float pad8; /* float */ + float pad9; /* float */ + float pad10; /* float */ } EEVEE_CommonUniformBuffer; BLI_STATIC_ASSERT_ALIGN(EEVEE_CommonUniformBuffer, 16) @@ -1201,6 +1197,7 @@ struct GPUShader *EEVEE_shaders_depth_of_field_gather_get(EEVEE_DofGatherPass pa struct GPUShader *EEVEE_shaders_depth_of_field_filter_get(void); struct GPUShader *EEVEE_shaders_depth_of_field_scatter_get(bool is_foreground, bool bokeh_tx); struct GPUShader *EEVEE_shaders_depth_of_field_resolve_get(bool use_bokeh_tx, bool use_hq_gather); +struct GPUShader *EEVEE_shaders_effect_color_copy_sh_get(void); struct GPUShader *EEVEE_shaders_effect_downsample_sh_get(void); struct GPUShader *EEVEE_shaders_effect_downsample_cube_sh_get(void); struct GPUShader *EEVEE_shaders_effect_minz_downlevel_sh_get(void); @@ -1472,8 +1469,8 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, const bool minimal); void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_effects_draw_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_effects_downsample_radiance_buffer(EEVEE_Data *vedata, struct GPUTexture *texture_src); void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, struct GPUTexture *depth_src, int layer); -void EEVEE_downsample_buffer(EEVEE_Data *vedata, struct GPUTexture *texture_src, int level); void EEVEE_downsample_cube_buffer(EEVEE_Data *vedata, struct GPUTexture *texture_src, int level); void EEVEE_draw_effects(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c index f9e22f5c08d..80a1c9fcbe5 100644 --- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c +++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c @@ -42,29 +42,15 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; EEVEE_StorageList *stl = vedata->stl; EEVEE_FramebufferList *fbl = vedata->fbl; - EEVEE_TextureList *txl = vedata->txl; EEVEE_EffectsInfo *effects = stl->effects; const float *viewport_size = DRW_viewport_size_get(); const DRWContextState *draw_ctx = DRW_context_state_get(); const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); - /* Compute pixel size, (shared with contact shadows) */ - copy_v2_v2(common_data->ssr_pixelsize, viewport_size); - invert_v2(common_data->ssr_pixelsize); - if (scene_eval->eevee.flag & SCE_EEVEE_SSR_ENABLED) { const bool use_refraction = (scene_eval->eevee.flag & SCE_EEVEE_SSR_REFRACTION) != 0; - if (use_refraction) { - /* TODO: Opti: Could be shared. */ - DRW_texture_ensure_fullscreen_2d( - &txl->refract_color, GPU_R11F_G11F_B10F, DRW_TEX_FILTER | DRW_TEX_MIPMAP); - - GPU_framebuffer_ensure_config( - &fbl->refract_fb, {GPU_ATTACHMENT_NONE, GPU_ATTACHMENT_TEXTURE(txl->refract_color)}); - } - const bool is_persp = DRW_view_is_persp_get(NULL); if (effects->ssr_was_persp != is_persp) { effects->ssr_was_persp = is_persp; @@ -117,8 +103,7 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) GPU_ATTACHMENT_TEXTURE(effects->ssr_hit_output), GPU_ATTACHMENT_TEXTURE(effects->ssr_pdf_output)}); - /* Enable double buffering to be able to read previous frame color */ - return EFFECT_SSR | EFFECT_NORMAL_BUFFER | EFFECT_DOUBLE_BUFFER | + return EFFECT_SSR | EFFECT_NORMAL_BUFFER | EFFECT_RADIANCE_BUFFER | EFFECT_DOUBLE_BUFFER | ((use_refraction) ? EFFECT_REFRACT : 0); } @@ -189,7 +174,7 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v DRW_shgroup_uniform_texture_ref(grp, "planarDepth", &vedata->txl->planar_depth); DRW_shgroup_uniform_texture_ref(grp, "hitBuffer", &effects->ssr_hit_output); DRW_shgroup_uniform_texture_ref(grp, "pdfBuffer", &effects->ssr_pdf_output); - DRW_shgroup_uniform_texture_ref(grp, "prevColorBuffer", &txl->color_double_buffer); + DRW_shgroup_uniform_texture_ref(grp, "prevColorBuffer", &txl->filtered_radiance); DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer); DRW_shgroup_uniform_texture_ref(grp, "shadowCubeTexture", &sldata->shadow_cube_pool); DRW_shgroup_uniform_texture_ref(grp, "shadowCascadeTexture", &sldata->shadow_cascade_pool); @@ -216,8 +201,7 @@ void EEVEE_refraction_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v EEVEE_EffectsInfo *effects = stl->effects; if ((effects->enabled_effects & EFFECT_REFRACT) != 0) { - GPU_framebuffer_blit(fbl->main_fb, 0, fbl->refract_fb, 0, GPU_COLOR_BIT); - EEVEE_downsample_buffer(vedata, txl->refract_color, 9); + EEVEE_effects_downsample_radiance_buffer(vedata, txl->color); /* Restore */ GPU_framebuffer_bind(fbl->main_fb); @@ -242,7 +226,7 @@ void EEVEE_reflection_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v GPU_framebuffer_bind(fbl->screen_tracing_fb); DRW_draw_pass(psl->ssr_raytrace); - EEVEE_downsample_buffer(vedata, txl->color_double_buffer, 9); + EEVEE_effects_downsample_radiance_buffer(vedata, txl->color_double_buffer); /* Resolve at fullres */ int samp = (DRW_state_is_image_render()) ? effects->taa_render_sample : diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c index a3e9236dc79..74c4803928a 100644 --- a/source/blender/draw/engines/eevee/eevee_shaders.c +++ b/source/blender/draw/engines/eevee/eevee_shaders.c @@ -103,7 +103,8 @@ static struct { struct GPUShader *minz_copydepth_sh; struct GPUShader *maxz_copydepth_sh; - /* Simple Down-sample */ + /* Simple Down-sample. */ + struct GPUShader *color_copy_sh; struct GPUShader *downsample_sh; struct GPUShader *downsample_cube_sh; @@ -452,10 +453,20 @@ GPUShader *EEVEE_shaders_probe_planar_display_sh_get(void) /** \name Down-sampling * \{ */ +GPUShader *EEVEE_shaders_effect_color_copy_sh_get(void) +{ + if (e_data.color_copy_sh == NULL) { + e_data.color_copy_sh = DRW_shader_create_fullscreen_with_shaderlib( + datatoc_effect_downsample_frag_glsl, e_data.lib, "#define COPY_SRC\n"); + } + return e_data.color_copy_sh; +} + GPUShader *EEVEE_shaders_effect_downsample_sh_get(void) { if (e_data.downsample_sh == NULL) { - e_data.downsample_sh = DRW_shader_create_fullscreen(datatoc_effect_downsample_frag_glsl, NULL); + e_data.downsample_sh = DRW_shader_create_fullscreen_with_shaderlib( + datatoc_effect_downsample_frag_glsl, e_data.lib, NULL); } return e_data.downsample_sh; } @@ -1537,6 +1548,7 @@ void EEVEE_shaders_free(void) MEM_SAFE_FREE(e_data.surface_geom_barycentric); DRW_SHADER_FREE_SAFE(e_data.lookdev_background); DRW_SHADER_FREE_SAFE(e_data.update_noise_sh); + DRW_SHADER_FREE_SAFE(e_data.color_copy_sh); DRW_SHADER_FREE_SAFE(e_data.downsample_sh); DRW_SHADER_FREE_SAFE(e_data.downsample_cube_sh); DRW_SHADER_FREE_SAFE(e_data.minz_downlevel_sh); diff --git a/source/blender/draw/engines/eevee/eevee_shadows.c b/source/blender/draw/engines/eevee/eevee_shadows.c index f6fe9a76c70..1f27d2dce34 100644 --- a/source/blender/draw/engines/eevee/eevee_shadows.c +++ b/source/blender/draw/engines/eevee/eevee_shadows.c @@ -53,7 +53,7 @@ void EEVEE_shadows_init(EEVEE_ViewLayerData *sldata) sldata->shadow_ubo = GPU_uniformbuf_create_ex(shadow_ubo_size, NULL, "evShadow"); for (int i = 0; i < 2; i++) { - sldata->shcasters_buffers[i].bbox = MEM_callocN( + sldata->shcasters_buffers[i].bbox = MEM_mallocN( sizeof(EEVEE_BoundBox) * SH_CASTER_ALLOC_CHUNK, __func__); sldata->shcasters_buffers[i].update = BLI_BITMAP_NEW(SH_CASTER_ALLOC_CHUNK, __func__); sldata->shcasters_buffers[i].alloc_count = SH_CASTER_ALLOC_CHUNK; @@ -133,8 +133,9 @@ void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, Object *ob) int id = frontbuffer->count; /* Make sure shadow_casters is big enough. */ - if (id + 1 >= frontbuffer->alloc_count) { - frontbuffer->alloc_count += SH_CASTER_ALLOC_CHUNK; + if (id >= frontbuffer->alloc_count) { + /* Double capacity to prevent exponential slowdown. */ + frontbuffer->alloc_count *= 2; frontbuffer->bbox = MEM_reallocN(frontbuffer->bbox, sizeof(EEVEE_BoundBox) * frontbuffer->alloc_count); BLI_BITMAP_RESIZE(frontbuffer->update, frontbuffer->alloc_count); @@ -173,6 +174,7 @@ void EEVEE_shadows_caster_register(EEVEE_ViewLayerData *sldata, Object *ob) } EEVEE_BoundBox *aabb = &frontbuffer->bbox[id]; + /* Note that *aabb has not been initialised yet. */ add_v3_v3v3(aabb->center, min, max); mul_v3_fl(aabb->center, 0.5f); sub_v3_v3v3(aabb->halfdim, aabb->center, max); diff --git a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl index 473990e1683..a0bfd440dd9 100644 --- a/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/ambient_occlusion_lib.glsl @@ -31,7 +31,6 @@ uniform sampler2D horizonBuffer; #define USE_BENT_NORMAL 2 #define USE_DENOISE 4 -#define MAX_LOD 6.0 #define NO_OCCLUSION_DATA OcclusionData(vec4(M_PI, -M_PI, M_PI, -M_PI), 1.0) struct OcclusionData { @@ -61,7 +60,11 @@ vec2 get_ao_area(float view_depth, float radius) vec2 get_ao_noise(void) { - return texelfetch_noise_tex(gl_FragCoord.xy).xy; + vec2 noise = texelfetch_noise_tex(gl_FragCoord.xy).xy; + /* Decorrelate noise from AA. */ + /* TODO(fclem) we should use a more general approach for more random number dimentions. */ + noise = fract(noise * 6.1803402007); + return noise; } vec2 get_ao_dir(float jitter) @@ -77,25 +80,37 @@ vec2 get_ao_dir(float jitter) float search_horizon(vec3 vI, vec3 vP, float noise, - vec2 uv_start, - vec2 uv_dir, + ScreenSpaceRay ssray, sampler2D depth_tx, const float inverted, float radius, const float sample_count) { - float sample_count_inv = 1.0 / sample_count; /* Init at cos(M_PI). */ float h = (inverted != 0.0) ? 1.0 : -1.0; - /* TODO(fclem) samples steps should be using the same approach as raytrace. (DDA line algo.) */ - for (float i = 0.0; i < sample_count; i++) { - float t = ((i + noise) * sample_count_inv); - vec2 uv = uv_start + uv_dir * t; - float lod = min(MAX_LOD, max(i - noise, 0.0) * aoQuality); + ssray.max_time -= 1.0; - int mip = int(lod) + hizMipOffset; - float depth = textureLod(depth_tx, uv * mipRatio[mip].xy, floor(lod)).r; + if (ssray.max_time <= 2.0) { + /* Produces self shadowing under this threshold. */ + return fast_acos(h); + } + + float prev_time, time = 0.0; + for (float iter = 0.0; time < ssray.max_time && iter < sample_count; iter++) { + prev_time = time; + /* Gives us good precision at center and ensure we cross at least one pixel per iteration. */ + time = 1.0 + iter + sqr((iter + noise) / sample_count) * ssray.max_time; + float stride = time - prev_time; + float lod = (log2(stride) - noise) / (1.0 + aoQuality); + + vec2 uv = ssray.origin.xy + ssray.direction.xy * time; + float depth = textureLod(depth_tx, uv * hizUvScale.xy, floor(lod)).r; + + if (depth == 1.0 && inverted == 0.0) { + /* Skip background. This avoids issues with the thickness heuristic. */ + continue; + } /* Bias depth a bit to avoid self shadowing issues. */ const float bias = 2.0 * 2.4e-7; @@ -108,25 +123,16 @@ float search_horizon(vec3 vI, float s_h = dot(vI, omega_s / len); /* Blend weight to fade artifacts. */ float dist_ratio = abs(len) / radius; - /* TODO(fclem) parameter. */ - float dist_fac = sqr(saturate(dist_ratio * 2.0 - 1.0)); + /* Sphere falloff. */ + float dist_fac = sqr(saturate(dist_ratio)); + /* Unbiased, gives too much hard cut behind objects */ + // float dist_fac = step(0.999, dist_ratio); - /* Thickness heuristic (Eq. 9). */ if (inverted != 0.0) { h = min(h, s_h); } else { - /* TODO This need to take the stride distance into account. Now it works because stride is - * constant. */ - if (s_h < h) { - /* TODO(fclem) parameter. */ - const float thickness_fac = 0.2; - s_h = mix(h, s_h, thickness_fac); - } - else { - s_h = max(h, s_h); - } - h = mix(s_h, h, dist_fac); + h = mix(max(h, s_h), h, dist_fac); } } return fast_acos(h); @@ -151,22 +157,22 @@ OcclusionData occlusion_search( NO_OCCLUSION_DATA; for (int i = 0; i < 2; i++) { - /* View > NDC > Uv space. */ - vec2 uv_dir = dir * area * 0.5; - /* Offset the start one pixel to avoid self shadowing. */ - /* TODO(fclem) Using DDA line algo should fix this. */ - vec2 px_dir = uv_dir * textureSize(depth_tx, 0); - float max_px_dir = max_v2(abs(px_dir)); - vec2 uv_ofs = (px_dir / max_px_dir) / textureSize(depth_tx, 0); - /* No need to trace more. */ - uv_dir -= uv_ofs; - - if (max_px_dir > 1.0) { - data.horizons[0 + i * 2] = search_horizon( - vI, vP, noise.y, uv + uv_ofs, uv_dir, depth_tx, inverted, radius, dir_sample_count); - data.horizons[1 + i * 2] = -search_horizon( - vI, vP, noise.y, uv - uv_ofs, -uv_dir, depth_tx, inverted, radius, dir_sample_count); - } + Ray ray; + ray.origin = vP; + ray.direction = vec3(dir * radius, 0.0); + + ScreenSpaceRay ssray; + + ssray = raytrace_screenspace_ray_create(ray); + data.horizons[0 + i * 2] = search_horizon( + vI, vP, noise.y, ssray, depth_tx, inverted, radius, dir_sample_count); + + ray.direction = -ray.direction; + + ssray = raytrace_screenspace_ray_create(ray); + data.horizons[1 + i * 2] = -search_horizon( + vI, vP, noise.y, ssray, depth_tx, inverted, radius, dir_sample_count); + /* Rotate 90 degrees. */ dir = vec2(-dir.y, dir.x); } @@ -389,7 +395,7 @@ OcclusionData occlusion_load(vec3 vP, float custom_occlusion) data = unpack_occlusion_data(texelFetch(horizonBuffer, ivec2(gl_FragCoord.xy), 0)); } #else - /* For blended surfaces and */ + /* For blended surfaces. */ data = occlusion_search(vP, maxzBuffer, aoDistance, 0.0, 8.0); #endif diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl index 4abc313d7e3..bbc79a2d05b 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_sampling_lib.glsl @@ -36,7 +36,7 @@ vec3 sample_ggx(vec3 rand, float a2) { /* Theta is the cone angle. */ float z = sqrt((1.0 - rand.x) / (1.0 + a2 * rand.x - rand.x)); /* cos theta */ - float r = sqrt(max(0.0, 1.0f - z * z)); /* sin theta */ + float r = sqrt(max(0.0, 1.0 - z * z)); /* sin theta */ float x = r * rand.y; float y = r * rand.z; @@ -51,6 +51,23 @@ vec3 sample_ggx(vec3 rand, float a2, vec3 N, vec3 T, vec3 B, out float NH) return tangent_to_world(Ht, N, T, B); } +vec3 sample_hemisphere(vec3 rand) +{ + /* Theta is the cone angle. */ + float z = rand.x; /* cos theta */ + float r = sqrt(max(0.0, 1.0 - z * z)); /* sin theta */ + float x = r * rand.y; + float y = r * rand.z; + + return vec3(x, y, z); +} + +vec3 sample_hemisphere(vec3 rand, vec3 N, vec3 T, vec3 B) +{ + vec3 Ht = sample_hemisphere(rand); + return tangent_to_world(Ht, N, T, B); +} + #ifdef HAMMERSLEY_SIZE vec3 sample_ggx(float nsample, float inv_sample_count, float a2, vec3 N, vec3 T, vec3 B) { @@ -62,14 +79,7 @@ vec3 sample_ggx(float nsample, float inv_sample_count, float a2, vec3 N, vec3 T, vec3 sample_hemisphere(float nsample, float inv_sample_count, vec3 N, vec3 T, vec3 B) { vec3 Xi = hammersley_3d(nsample, inv_sample_count); - - float z = Xi.x; /* cos theta */ - float r = sqrt(max(0.0, 1.0f - z * z)); /* sin theta */ - float x = r * Xi.y; - float y = r * Xi.z; - - vec3 Ht = vec3(x, y, z); - + vec3 Ht = sample_hemisphere(Xi); return tangent_to_world(Ht, N, T, B); } @@ -77,8 +87,8 @@ vec3 sample_cone(float nsample, float inv_sample_count, float angle, vec3 N, vec { vec3 Xi = hammersley_3d(nsample, inv_sample_count); - float z = cos(angle * Xi.x); /* cos theta */ - float r = sqrt(max(0.0, 1.0f - z * z)); /* sin theta */ + float z = cos(angle * Xi.x); /* cos theta */ + float r = sqrt(max(0.0, 1.0 - z * z)); /* sin theta */ float x = r * Xi.y; float y = r * Xi.z; diff --git a/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl b/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl index a6c9eebaff2..24de4520207 100644 --- a/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/common_uniforms_lib.glsl @@ -2,7 +2,7 @@ layout(std140) uniform common_block { mat4 pastViewProjectionMatrix; - vec2 mipRatio[10]; /* To correct mip level texel misalignment */ + vec4 hizUvScale; /* To correct mip level texel misalignment */ /* Ambient Occlusion */ vec4 aoParameters[2]; /* Volumetric */ @@ -37,15 +37,15 @@ layout(std140) uniform common_block int prbIrradianceVisSize; float prbIrradianceSmooth; float prbLodCubeMax; - float prbLodPlanarMax; /* Misc*/ - int hizMipOffset; int rayType; float rayDepth; float alphaHashOffset; float alphaHashScale; + float pad6; float pad7; float pad8; + float pad9; }; /* rayType (keep in sync with ray_type) */ @@ -69,9 +69,3 @@ layout(std140) uniform common_block #define ssrQuality ssrParameters.x #define ssrThickness ssrParameters.y #define ssrPixelSize ssrParameters.zw - -vec2 mip_ratio_interp(float mip) -{ - float low_mip = floor(mip); - return mix(mipRatio[int(low_mip)], mipRatio[int(low_mip + 1.0)], mip - low_mip); -} diff --git a/source/blender/draw/engines/eevee/shaders/effect_dof_lib.glsl b/source/blender/draw/engines/eevee/shaders/effect_dof_lib.glsl index 88d83cd913a..3ad3c90d27a 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_dof_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_dof_lib.glsl @@ -62,12 +62,6 @@ const vec2 quad_offsets[4] = vec2[4]( #define dof_coc_from_zdepth(d) calculate_coc(linear_depth(d)) -vec4 safe_color(vec4 c) -{ - /* Clamp to avoid black square artifacts if a pixel goes NaN. */ - return clamp(c, vec4(0.0), vec4(1e20)); /* 1e20 arbitrary. */ -} - float dof_hdr_color_weight(vec4 color) { /* From UE4. Very fast "luma" weighting. */ diff --git a/source/blender/draw/engines/eevee/shaders/effect_downsample_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_downsample_frag.glsl index a4637b9df91..5bf850fe229 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_downsample_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_downsample_frag.glsl @@ -1,5 +1,9 @@ + +#pragma BLENDER_REQUIRE(common_math_lib.glsl) + /** - * Simple down-sample shader. Takes the average of the 4 texels of lower mip. + * Simple down-sample shader. + * Do a gaussian filter using 4 bilinear texture samples. */ uniform sampler2D source; @@ -14,24 +18,25 @@ float brightness(vec3 c) void main() { -#if 0 - /* Reconstructing Target uvs like this avoid missing pixels if NPO2 */ - vec2 uvs = gl_FragCoord.xy * 2.0 / vec2(textureSize(source, 0)); + vec2 texel_size = 1.0 / vec2(textureSize(source, 0)); + vec2 uvs = gl_FragCoord.xy * texel_size; +#ifdef COPY_SRC FragColor = textureLod(source, uvs, 0.0); + FragColor = safe_color(FragColor); + + /* Clamped brightness. */ + float luma = max(1e-8, brightness(FragColor.rgb)); + FragColor *= 1.0 - max(0.0, luma - fireflyFactor) / luma; + #else - vec2 texel_size = 1.0 / vec2(textureSize(source, 0)); - vec2 uvs = gl_FragCoord.xy * 2.0 * texel_size; vec4 ofs = texel_size.xyxy * vec4(0.75, 0.75, -0.75, -0.75); + uvs *= 2.0; FragColor = textureLod(source, uvs + ofs.xy, 0.0); FragColor += textureLod(source, uvs + ofs.xw, 0.0); FragColor += textureLod(source, uvs + ofs.zy, 0.0); FragColor += textureLod(source, uvs + ofs.zw, 0.0); FragColor *= 0.25; - - /* Clamped brightness. */ - float luma = max(1e-8, brightness(FragColor.rgb)); - FragColor *= 1.0 - max(0.0, luma - fireflyFactor) / luma; #endif } diff --git a/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl index 19ae0acc443..16b1a7ffeaa 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl @@ -99,9 +99,12 @@ void main() OcclusionData data = occlusion_load(vP, 1.0); - float visibility = diffuse_occlusion(data, V, N, Ng); - - FragColor = vec4(visibility); + if (min_v4(abs(data.horizons)) != M_PI) { + FragColor = vec4(diffuse_occlusion(data, V, N, Ng)); + } + else { + FragColor = vec4(1.0); + } } } diff --git a/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl index b99037b1e80..ccb65d2e5a6 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl @@ -2,6 +2,9 @@ * Shader that down-sample depth buffer, * saving min and max value of each texel in the above mipmaps. * Adapted from http://rastergrid.com/blog/2010/10/hierarchical-z-map-based-occlusion-culling/ + * + * Major simplification has been made since we pad the buffer to always be bigger than input to + * avoid mipmapping misalignement. */ #ifdef LAYERED @@ -12,10 +15,10 @@ uniform sampler2D depthBuffer; #endif #ifdef LAYERED -# define sampleLowerMip(t) texelFetch(depthBuffer, ivec3(t, depthLayer), 0).r +# define sampleLowerMip(t) texture(depthBuffer, vec3(t, depthLayer)).r # define gatherLowerMip(t) textureGather(depthBuffer, vec3(t, depthLayer)) #else -# define sampleLowerMip(t) texelFetch(depthBuffer, t, 0).r +# define sampleLowerMip(t) texture(depthBuffer, t).r # define gatherLowerMip(t) textureGather(depthBuffer, t) #endif @@ -37,54 +40,27 @@ out vec4 fragColor; void main() { - ivec2 texelPos = ivec2(gl_FragCoord.xy); - ivec2 mipsize = textureSize(depthBuffer, 0).xy; - -#ifndef COPY_DEPTH - texelPos *= 2; -#endif + vec2 texel = gl_FragCoord.xy; + vec2 texel_size = 1.0 / vec2(textureSize(depthBuffer, 0).xy); #ifdef COPY_DEPTH - float val = sampleLowerMip(texelPos); + vec2 uv = texel * texel_size; + + float val = sampleLowerMip(uv); #else + vec2 uv = texel * 2.0 * texel_size; + vec4 samp; # ifdef GPU_ARB_texture_gather - /* + 1.0 to gather at the center of target 4 texels. */ - samp = gatherLowerMip((vec2(texelPos) + 1.0) / vec2(mipsize)); + samp = gatherLowerMip(uv); # else - samp.x = sampleLowerMip(texelPos); - samp.y = sampleLowerMip(texelPos + ivec2(1, 0)); - samp.z = sampleLowerMip(texelPos + ivec2(1, 1)); - samp.w = sampleLowerMip(texelPos + ivec2(0, 1)); + samp.x = sampleLowerMip(uv + vec2(-0.5, -0.5) * texel_size); + samp.y = sampleLowerMip(uv + vec2(-0.5, 0.5) * texel_size); + samp.z = sampleLowerMip(uv + vec2(0.5, -0.5) * texel_size); + samp.w = sampleLowerMip(uv + vec2(0.5, 0.5) * texel_size); # endif float val = minmax4(samp.x, samp.y, samp.z, samp.w); - - /* if we are reducing an odd-width texture then fetch the edge texels */ - if (((mipsize.x & 1) != 0) && (texelPos.x == mipsize.x - 3)) { - /* if both edges are odd, fetch the top-left corner texel */ - if (((mipsize.y & 1) != 0) && (texelPos.y == mipsize.y - 3)) { - samp.x = sampleLowerMip(texelPos + ivec2(2, 2)); - val = minmax2(val, samp.x); - } -# ifdef GPU_ARB_texture_gather - samp = gatherLowerMip((vec2(texelPos) + vec2(2.0, 1.0)) / vec2(mipsize)); -# else - samp.y = sampleLowerMip(texelPos + ivec2(2, 0)); - samp.z = sampleLowerMip(texelPos + ivec2(2, 1)); -# endif - val = minmax3(val, samp.y, samp.z); - } - /* if we are reducing an odd-height texture then fetch the edge texels */ - if (((mipsize.y & 1) != 0) && (texelPos.y == mipsize.y - 3)) { -# ifdef GPU_ARB_texture_gather - samp = gatherLowerMip((vec2(texelPos) + vec2(1.0, 2.0)) / vec2(mipsize)); -# else - samp.x = sampleLowerMip(texelPos + ivec2(0, 2)); - samp.y = sampleLowerMip(texelPos + ivec2(1, 2)); -# endif - val = minmax3(val, samp.x, samp.y); - } #endif #if defined(GPU_INTEL) || defined(GPU_ATI) diff --git a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl index ecff28dcd38..66183e1bc02 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_ssr_frag.glsl @@ -63,14 +63,19 @@ void do_planar_ssr( pdfData = min(1024e32, pdf); /* Theoretical limit of 16bit float */ - /* Since viewspace hit position can land behind the camera in this case, - * we save the reflected view position (visualize it as the hit position - * below the reflection plane). This way it's garanted that the hit will - * be in front of the camera. That let us tag the bad rays with a negative - * sign in the Z component. */ - vec3 hit_pos = raycast(index, vP, R * 1e16, 1e16, rand.y, ssrQuality, a2, false); - - hitData = encode_hit_data(hit_pos.xy, (hit_pos.z > 0.0), true); + Ray ray; + ray.origin = vP; + ray.direction = R * 1e16; + + RayTraceParameters params; + params.jitter = rand.y; + params.trace_quality = ssrQuality; + params.roughness = a2; + + vec3 hit_pos; + bool hit = raytrace_planar(ray, params, index, hit_pos); + + hitData = encode_hit_data(hit_pos.xy, hit, true); } void do_ssr(vec3 V, vec3 N, vec3 T, vec3 B, vec3 vP, float a2, vec4 rand) @@ -104,22 +109,30 @@ void do_ssr(vec3 V, vec3 N, vec3 T, vec3 B, vec3 vP, float a2, vec4 rand) pdfData = min(1024e32, pdf_ggx_reflect(NH, a2)); /* Theoretical limit of 16bit float */ - vec3 hit_pos = raycast(-1, vP, R * 1e16, ssrThickness, rand.y, ssrQuality, a2, true); + vP = raytrace_offset(vP, vNg); + + Ray ray; + ray.origin = vP; + ray.direction = R * 1e16; - hitData = encode_hit_data(hit_pos.xy, (hit_pos.z > 0.0), false); + RayTraceParameters params; + params.thickness = ssrThickness; + params.jitter = rand.y; + params.trace_quality = ssrQuality; + params.roughness = a2; + + vec3 hit_pos; + bool hit = raytrace(ray, params, true, hit_pos); + + hitData = encode_hit_data(hit_pos.xy, hit, false); } +in vec4 uvcoordsvar; + void main() { -# ifdef FULLRES - ivec2 fullres_texel = ivec2(gl_FragCoord.xy); - ivec2 halfres_texel = fullres_texel; -# else - ivec2 fullres_texel = ivec2(gl_FragCoord.xy) * 2 + halfresOffset; - ivec2 halfres_texel = ivec2(gl_FragCoord.xy); -# endif - - float depth = texelFetch(depthBuffer, fullres_texel, 0).r; + vec2 uvs = uvcoordsvar.xy; + float depth = textureLod(depthBuffer, uvs, 0.0).r; /* Default: not hits. */ hitData = encode_hit_data(vec2(0.5), false, false); @@ -131,18 +144,16 @@ void main() return; } - vec2 uvs = vec2(fullres_texel) / vec2(textureSize(depthBuffer, 0)); - /* Using view space */ vec3 vP = get_view_space_from_depth(uvs, depth); vec3 P = transform_point(ViewMatrixInverse, vP); vec3 vV = viewCameraVec(vP); vec3 V = cameraVec(P); - vec3 vN = normal_decode(texelFetch(normalBuffer, fullres_texel, 0).rg, vV); + vec3 vN = normal_decode(texture(normalBuffer, uvs, 0).rg, vV); vec3 N = transform_direction(ViewMatrixInverse, vN); /* Retrieve pixel data */ - vec4 speccol_roughness = texelFetch(specroughBuffer, fullres_texel, 0).rgba; + vec4 speccol_roughness = texture(specroughBuffer, uvs, 0).rgba; /* Early out */ if (dot(speccol_roughness.rgb, vec3(1.0)) == 0.0) { @@ -158,7 +169,7 @@ void main() return; } - vec4 rand = texelfetch_noise_tex(halfres_texel); + vec4 rand = texelfetch_noise_tex(vec2(gl_FragCoord.xy)); /* Gives *perfect* reflection for very small roughness */ if (roughness < 0.04) { @@ -189,11 +200,6 @@ void main() } } - /* Constant bias (due to depth buffer precision). Helps with self intersection. */ - /* Magic numbers for 24bits of precision. - * From http://terathon.com/gdc07_lengyel.pdf (slide 26) */ - vP.z = get_view_z_from_depth(depth - mix(2.4e-7, 4.8e-7, depth)); - do_ssr(vV, vN, vT, vB, vP, a2, rand); } @@ -325,10 +331,10 @@ vec3 get_hit_vector(vec3 hit_pos, vec3 get_scene_color(vec2 ref_uvs, float mip, float planar_index, bool is_planar) { if (is_planar) { - return textureLod(probePlanars, vec3(ref_uvs, planar_index), min(mip, prbLodPlanarMax)).rgb; + return textureLod(probePlanars, vec3(ref_uvs, planar_index), mip).rgb; } else { - return textureLod(prevColorBuffer, ref_uvs, mip).rgb; + return textureLod(prevColorBuffer, ref_uvs * hizUvScale.xy, mip).rgb; } } @@ -351,6 +357,8 @@ vec4 get_ssr_samples(vec4 hit_pdf, hit_co[1].xy = decode_hit_data(hit_data[1].xy, has_hit.z, is_planar.z); hit_co[1].zw = decode_hit_data(hit_data[1].zw, has_hit.w, is_planar.w); + /* TODO/FIXME(fclem) This is giving precision issues due to refined intersection. This is most + * noticeable on rough surfaces. */ vec4 hit_depth; hit_depth.x = get_sample_depth(hit_co[0].xy, is_planar.x, planar_index); hit_depth.y = get_sample_depth(hit_co[0].zw, is_planar.y, planar_index); @@ -403,12 +411,6 @@ vec4 get_ssr_samples(vec4 hit_pdf, vec4 mip = log2(cone_footprint * max_v2(vec2(textureSize(depthBuffer, 0)))); mip = clamp(mip, 0.0, MAX_MIP); - /* Correct UVs for mipmaping mis-alignment */ - hit_co[0].xy *= mip_ratio_interp(mip.x); - hit_co[0].zw *= mip_ratio_interp(mip.y); - hit_co[1].xy *= mip_ratio_interp(mip.z); - hit_co[1].zw *= mip_ratio_interp(mip.w); - /* Slide 54 */ vec4 bsdf; bsdf.x = bsdf_ggx(N, hit_pos[0], V, roughnessSquared); diff --git a/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl b/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl index 28947e971d2..165aed2a46f 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_temporal_aa.glsl @@ -10,12 +10,6 @@ uniform mat4 prevViewProjectionMatrix; out vec4 FragColor; -vec4 safe_color(vec4 c) -{ - /* Clamp to avoid black square artifacts if a pixel goes NaN. */ - return clamp(c, vec4(0.0), vec4(1e20)); /* 1e20 arbitrary. */ -} - #ifdef USE_REPROJECTION /** diff --git a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl index 04ad53eabb7..bd752d33819 100644 --- a/source/blender/draw/engines/eevee/shaders/lights_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/lights_lib.glsl @@ -276,31 +276,30 @@ float light_contact_shadows( /* Only compute if not already in shadow. */ if (sd.sh_contact_dist > 0.0) { /* Contact Shadows. */ - vec3 ray_ori, ray_dir; - float trace_distance; + Ray ray; if (ld.l_type == SUN) { - trace_distance = sd.sh_contact_dist; - ray_dir = shadows_cascade_data[int(sd.sh_data_index)].sh_shadow_vec * trace_distance; + ray.direction = shadows_cascade_data[int(sd.sh_data_index)].sh_shadow_vec * + sd.sh_contact_dist; } else { - ray_dir = shadows_cube_data[int(sd.sh_data_index)].position.xyz - P; - float len = length(ray_dir); - trace_distance = min(sd.sh_contact_dist, len); - ray_dir *= trace_distance / len; + ray.direction = shadows_cube_data[int(sd.sh_data_index)].position.xyz - P; + ray.direction *= saturate(sd.sh_contact_dist * safe_rcp(length(ray.direction))); } - ray_dir = transform_direction(ViewMatrix, ray_dir); - ray_ori = vec3(vP.xy, tracing_depth) + vNg * sd.sh_contact_offset; + ray.direction = transform_direction(ViewMatrix, ray.direction); + ray.origin = vP + vNg * sd.sh_contact_offset; - vec3 hit_pos = raycast( - -1, ray_ori, ray_dir, sd.sh_contact_thickness, rand_x, 0.1, 0.001, false); + RayTraceParameters params; + params.thickness = sd.sh_contact_thickness; + params.jitter = rand_x; + params.trace_quality = 0.1; + params.roughness = 0.001; - if (hit_pos.z > 0.0) { - hit_pos = get_view_space_from_depth(hit_pos.xy, hit_pos.z); - float hit_dist = distance(vP, hit_pos); - float dist_ratio = hit_dist / trace_distance; - return saturate(dist_ratio * 3.0 - 2.0); + vec3 hit_position_unused; + + if (raytrace(ray, params, false, hit_position_unused)) { + return 0.0; } } } diff --git a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl index aebd1c3aef3..7c375aabb62 100644 --- a/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/raytrace_lib.glsl @@ -3,261 +3,217 @@ #pragma BLENDER_REQUIRE(common_math_lib.glsl) #pragma BLENDER_REQUIRE(common_uniforms_lib.glsl) +/** + * Screen-Space Raytracing functions. + */ + uniform sampler2D maxzBuffer; uniform sampler2DArray planarDepth; -#define MAX_STEP 256 +struct Ray { + vec3 origin; + vec3 direction; +}; -float sample_depth(vec2 uv, int index, float lod) +vec3 raytrace_offset(vec3 P, vec3 Ng) { -#ifdef PLANAR_PROBE_RAYTRACE - if (index > -1) { - return textureLod(planarDepth, vec3(uv, index), 0.0).r; - } - else { -#endif - lod = clamp(floor(lod), 0.0, 8.0); - /* Correct UVs for mipmaping mis-alignment */ - uv *= mipRatio[int(lod) + hizMipOffset]; - return textureLod(maxzBuffer, uv, lod).r; -#ifdef PLANAR_PROBE_RAYTRACE - } -#endif + /* TODO(fclem) better offset */ + const float epsilon_f = 1e-4; + return P + epsilon_f * Ng; } -vec4 sample_depth_grouped(vec4 uv1, vec4 uv2, int index, float lod) +/* Inputs expected to be in viewspace. */ +void raytrace_clip_ray_to_near_plane(inout Ray ray) { - vec4 depths; -#ifdef PLANAR_PROBE_RAYTRACE - if (index > -1) { - depths.x = textureLod(planarDepth, vec3(uv1.xy, index), 0.0).r; - depths.y = textureLod(planarDepth, vec3(uv1.zw, index), 0.0).r; - depths.z = textureLod(planarDepth, vec3(uv2.xy, index), 0.0).r; - depths.w = textureLod(planarDepth, vec3(uv2.zw, index), 0.0).r; + float near_dist = get_view_z_from_depth(0.0); + if ((ray.origin.z + ray.direction.z) > near_dist) { + ray.direction *= abs((near_dist - ray.origin.z) / ray.direction.z); } - else { -#endif - depths.x = textureLod(maxzBuffer, uv1.xy, lod).r; - depths.y = textureLod(maxzBuffer, uv1.zw, lod).r; - depths.z = textureLod(maxzBuffer, uv2.xy, lod).r; - depths.w = textureLod(maxzBuffer, uv2.zw, lod).r; -#ifdef PLANAR_PROBE_RAYTRACE - } -#endif - return depths; } -float refine_isect(float prev_delta, float curr_delta) -{ - /** - * Simplification of 2D intersection : - * r0 = (0.0, prev_ss_ray.z); - * r1 = (1.0, curr_ss_ray.z); - * d0 = (0.0, prev_hit_depth_sample); - * d1 = (1.0, curr_hit_depth_sample); - * vec2 r = r1 - r0; - * vec2 d = d1 - d0; - * vec2 isect = ((d * cross(r1, r0)) - (r * cross(d1, d0))) / cross(r,d); - * - * We only want isect.x to know how much stride we need. So it simplifies : - * - * isect_x = (cross(r1, r0) - cross(d1, d0)) / cross(r,d); - * isect_x = (prev_ss_ray.z - prev_hit_depth_sample.z) / cross(r,d); - */ - return saturate(prev_delta / (prev_delta - curr_delta)); -} +/* Screenspace ray ([0..1] "uv" range) where direction is normalize to be as small as one + * full-resolution pixel. The ray is also clipped to all frustum sides. + */ +struct ScreenSpaceRay { + vec4 origin; + vec4 direction; + float max_time; +}; -void prepare_raycast(vec3 ray_origin, - vec3 ray_dir, - float thickness, - int index, - out vec4 ss_step, - out vec4 ss_ray, - out float max_time) +void raytrace_screenspace_ray_finalize(inout ScreenSpaceRay ray) { - /* Negate the ray direction if it goes towards the camera. - * This way we don't need to care if the projected point - * is behind the near plane. */ - float z_sign = -sign(ray_dir.z); - vec3 ray_end = ray_origin + z_sign * ray_dir; - - /* Project into screen space. */ - vec4 ss_start, ss_end; - ss_start.xyz = project_point(ProjectionMatrix, ray_origin); - ss_end.xyz = project_point(ProjectionMatrix, ray_end); - - /* We interpolate the ray Z + thickness values to check if depth is within threshold. */ - ray_origin.z -= thickness; - ray_end.z -= thickness; - ss_start.w = project_point(ProjectionMatrix, ray_origin).z; - ss_end.w = project_point(ProjectionMatrix, ray_end).z; - - /* XXX This is a hack. A better method is welcome! */ - /* We take the delta between the offsetted depth and the depth and subtract it from the ray - * depth. This will change the world space thickness appearance a bit but we can have negative - * values without worries. We cannot do this in viewspace because of the perspective division. */ - ss_start.w = 2.0 * ss_start.z - ss_start.w; - ss_end.w = 2.0 * ss_end.z - ss_end.w; - - ss_step = ss_end - ss_start; - max_time = length(ss_step.xyz); - ss_step = z_sign * ss_step / length(ss_step.xyz); - + /* Constant bias (due to depth buffer precision). Helps with self intersection. */ + /* Magic numbers for 24bits of precision. + * From http://terathon.com/gdc07_lengyel.pdf (slide 26) */ + const float bias = -2.4e-7 * 2.0; + ray.origin.zw += bias; + ray.direction.zw += bias; + + ray.direction -= ray.origin; + float ray_len_sqr = len_squared(ray.direction.xyz); /* If the line is degenerate, make it cover at least one pixel * to not have to handle zero-pixel extent as a special case later */ - if (dot(ss_step.xy, ss_step.xy) < 0.00001) { - ss_step.xy = vec2(0.0, 0.0001); + if (ray_len_sqr < 0.00001) { + ray.direction.xy = vec2(0.0, 0.0001); } - - /* Make ss_step cover one pixel. */ - ss_step /= max(abs(ss_step.x), abs(ss_step.y)); - ss_step *= (abs(ss_step.x) > abs(ss_step.y)) ? ssrPixelSize.x : ssrPixelSize.y; - + /* Make ray.direction cover one pixel. */ + bool is_more_vertical = abs(ray.direction.x) < abs(ray.direction.y); + ray.direction /= (is_more_vertical) ? abs(ray.direction.y) : abs(ray.direction.x); + ray.direction *= (is_more_vertical) ? ssrPixelSize.y : ssrPixelSize.x; /* Clip to segment's end. */ - max_time /= length(ss_step.xyz); + ray.max_time = sqrt(ray_len_sqr * safe_rcp(len_squared(ray.direction.xyz))); /* Clipping to frustum sides. */ - max_time = min(max_time, line_unit_box_intersect_dist(ss_start.xyz, ss_step.xyz)); - /* Avoid no iteration. */ - max_time = max(max_time, 1.0); + float clip_dist = line_unit_box_intersect_dist(ray.origin.xyz, ray.direction.xyz); + ray.max_time = min(ray.max_time, clip_dist); + /* Convert to texture coords [0..1] range. */ + ray.origin = ray.origin * 0.5 + 0.5; + ray.direction *= 0.5; +} - /* Convert to texture coords. Z component included - * since this is how it's stored in the depth buffer. - * 4th component how far we are on the ray */ -#ifdef PLANAR_PROBE_RAYTRACE - /* Planar Reflections have X mirrored. */ - vec2 m = (index > -1) ? vec2(-0.5, 0.5) : vec2(0.5); -#else - const vec2 m = vec2(0.5); -#endif - ss_ray = ss_start * m.xyyy + 0.5; - ss_step *= m.xyyy; - - /* take the center of the texel. */ - // ss_ray.xy += sign(ss_ray.xy) * m * ssrPixelSize * (1.0 + hizMipOffset); +ScreenSpaceRay raytrace_screenspace_ray_create(Ray ray) +{ + ScreenSpaceRay ssray; + ssray.origin.xyz = project_point(ProjectionMatrix, ray.origin); + ssray.direction.xyz = project_point(ProjectionMatrix, ray.origin + ray.direction); + + raytrace_screenspace_ray_finalize(ssray); + return ssray; } -/* See times_and_deltas. */ -#define curr_time times_and_deltas.x -#define prev_time times_and_deltas.y -#define curr_delta times_and_deltas.z -#define prev_delta times_and_deltas.w +ScreenSpaceRay raytrace_screenspace_ray_create(Ray ray, float thickness) +{ + ScreenSpaceRay ssray; + ssray.origin.xyz = project_point(ProjectionMatrix, ray.origin); + ssray.direction.xyz = project_point(ProjectionMatrix, ray.origin + ray.direction); + /* Interpolate thickness in screen space. + * Calculate thickness further away to avoid near plane clipping issues. */ + ssray.origin.w = get_depth_from_view_z(ray.origin.z - thickness) * 2.0 - 1.0; + ssray.direction.w = get_depth_from_view_z(ray.origin.z + ray.direction.z - thickness) * 2.0 - + 1.0; + + raytrace_screenspace_ray_finalize(ssray); + return ssray; +} -// #define GROUPED_FETCHES /* is still slower, need to see where is the bottleneck. */ -/* Return the hit position, and negate the z component (making it positive) if not hit occurred. */ +struct RayTraceParameters { + /** ViewSpace thickness the objects */ + float thickness; + /** Jitter along the ray to avoid banding artifact when steps are too large. */ + float jitter; + /** Determine how fast the sample steps are getting bigger. */ + float trace_quality; + /** Determine how we can use lower depth mipmaps to make the tracing faster. */ + float roughness; +}; + +/* Return true on hit. */ /* __ray_dir__ is the ray direction premultiplied by its maximum length */ -vec3 raycast(int index, - vec3 ray_origin, - vec3 ray_dir, - float thickness, - float ray_jitter, - float trace_quality, - float roughness, - const bool discard_backface) +/* TODO fclem remove the backface check and do it the SSR resolve code. */ +bool raytrace(Ray ray, + RayTraceParameters params, + const bool discard_backface, + out vec3 hit_position) { - vec4 ss_step, ss_start; - float max_time; - prepare_raycast(ray_origin, ray_dir, thickness, index, ss_step, ss_start, max_time); - - float max_trace_time = max(0.01, max_time - 0.01); + /* Clip to near plane for perspective view where there is a singularity at the camera origin. */ + if (ProjectionMatrix[3][3] == 0.0) { + raytrace_clip_ray_to_near_plane(ray); + } -#ifdef GROUPED_FETCHES - ray_jitter *= 0.25; -#endif + ScreenSpaceRay ssray = raytrace_screenspace_ray_create(ray, params.thickness); + /* Avoid no iteration. */ + ssray.max_time = max(ssray.max_time, 1.1); - /* x : current_time, y: previous_time, z: current_delta, w: previous_delta */ - vec4 times_and_deltas = vec4(0.0); + float prev_delta = 0.0, prev_time = 0.0; + float depth_sample = get_depth_from_view_z(ray.origin.z); + float delta = depth_sample - ssray.origin.z; - float ray_time = 0.0; - float depth_sample = sample_depth(ss_start.xy, index, 0.0); - curr_delta = depth_sample - ss_start.z; + float lod_fac = saturate(fast_sqrt(params.roughness) * 2.0 - 0.4); - float lod_fac = saturate(fast_sqrt(roughness) * 2.0 - 0.4); + /* Cross at least one pixel. */ + float t = 1.001, time = 1.001; bool hit = false; - float iter; - for (iter = 1.0; !hit && (ray_time < max_time) && (iter < MAX_STEP); iter++) { - /* Minimum stride of 2 because we are using half res minmax zbuffer. */ - /* WORKAROUND: Factor is a bit higher than 2 to avoid some banding. To investigate. */ - float stride = max(1.0, iter * trace_quality) * (2.0 + 0.05); - float lod = log2(stride * 0.5 * trace_quality) * lod_fac; - ray_time += stride; - - /* Save previous values. */ - times_and_deltas.xyzw = times_and_deltas.yxwz; - -#ifdef GROUPED_FETCHES - stride *= 4.0; - vec4 jit_stride = mix(vec4(2.0), vec4(stride), vec4(0.0, 0.25, 0.5, 0.75) + ray_jitter); - - vec4 times = min(vec4(ray_time) + jit_stride, vec4(max_trace_time)); - - vec4 uv1 = ss_start.xyxy + ss_step.xyxy * times.xxyy; - vec4 uv2 = ss_start.xyxy + ss_step.xyxy * times.zzww; - - vec4 depth_samples = sample_depth_grouped(uv1, uv2, index, lod); - - vec4 ray_z = ss_start.zzzz + ss_step.zzzz * times.xyzw; - vec4 ray_w = ss_start.wwww + ss_step.wwww * vec4(prev_time, times.xyz); - - vec4 deltas = depth_samples - ray_z; - /* Same as component wise (curr_delta <= 0.0) && (prev_w <= depth_sample). */ - bvec4 test = equal(step(deltas, vec4(0.0)) * step(ray_w, depth_samples), vec4(1.0)); - hit = any(test); - - if (hit) { - vec2 m = vec2(1.0, 0.0); /* Mask */ - - vec4 ret_times_and_deltas = times.wzzz * m.xxyy + deltas.wwwz * m.yyxx; - ret_times_and_deltas = (test.z) ? times.zyyy * m.xxyy + deltas.zzzy * m.yyxx : - ret_times_and_deltas; - ret_times_and_deltas = (test.y) ? times.yxxx * m.xxyy + deltas.yyyx * m.yyxx : - ret_times_and_deltas; - times_and_deltas = (test.x) ? times.xxxx * m.xyyy + deltas.xxxx * m.yyxy + - times_and_deltas.yyww * m.yxyx : - ret_times_and_deltas; - - depth_sample = depth_samples.w; - depth_sample = (test.z) ? depth_samples.z : depth_sample; - depth_sample = (test.y) ? depth_samples.y : depth_sample; - depth_sample = (test.x) ? depth_samples.x : depth_sample; - } - else { - curr_time = times.w; - curr_delta = deltas.w; - } -#else - float jit_stride = mix(2.0, stride, ray_jitter); - - curr_time = min(ray_time + jit_stride, max_trace_time); - vec4 ss_ray = ss_start + ss_step * curr_time; - - depth_sample = sample_depth(ss_ray.xy, index, lod); - - float prev_w = ss_start.w + ss_step.w * prev_time; - curr_delta = depth_sample - ss_ray.z; - hit = (curr_delta <= 0.0) && (prev_w <= depth_sample); -#endif - } + const float max_steps = 255.0; + for (float iter = 1.0; !hit && (time < ssray.max_time) && (iter < max_steps); iter++) { + float stride = 1.0 + iter * params.trace_quality; + float lod = log2(stride) * lod_fac; - /* Discard backface hits. Only do this if the ray traveled enough to avoid losing intricate - * contact reflections. This is only used for SSReflections. */ - if (discard_backface && prev_delta < 0.0 && curr_time > 4.1) { - hit = false; - } + prev_time = time; + prev_delta = delta; + time = min(t + stride * params.jitter, ssray.max_time); + t += stride; + + vec4 ss_p = ssray.origin + ssray.direction * time; + depth_sample = textureLod(maxzBuffer, ss_p.xy * hizUvScale.xy, floor(lod)).r; + + delta = depth_sample - ss_p.z; + /* Check if the ray is below the surface ... */ + hit = (delta < 0.0); + /* ... and above it with the added thickness. */ + hit = hit && (delta > ss_p.z - ss_p.w); + } + /* Discard backface hits. */ + hit = hit && !(discard_backface && prev_delta < 0.0); /* Reject hit if background. */ hit = hit && (depth_sample != 1.0); + /* Refine hit using intersection between the sampled heightfield and the ray. + * This simplifies nicely to this single line. */ + time = mix(prev_time, time, saturate(prev_delta / (prev_delta - delta))); + + hit_position = ssray.origin.xyz + ssray.direction.xyz * time; + + return hit; +} + +bool raytrace_planar(Ray ray, RayTraceParameters params, int planar_ref_id, out vec3 hit_position) +{ + /* Clip to near plane for perspective view where there is a singularity at the camera origin. */ + if (ProjectionMatrix[3][3] == 0.0) { + raytrace_clip_ray_to_near_plane(ray); + } + + ScreenSpaceRay ssray = raytrace_screenspace_ray_create(ray); + /* Avoid no iteration. */ + ssray.max_time = max(ssray.max_time, 1.1); - curr_time = (hit) ? mix(prev_time, curr_time, refine_isect(prev_delta, curr_delta)) : curr_time; - ray_time = (hit) ? curr_time : ray_time; + /* Planar Reflections have X mirrored. */ + ssray.origin.x = 1.0 - ssray.origin.x; + ssray.direction.x = -ssray.direction.x; + + float prev_delta = 0.0, prev_time = 0.0; + float depth_sample = get_depth_from_view_z(ray.origin.z); + float delta = depth_sample - ssray.origin.z; + + /* Cross at least one pixel. */ + float t = 1.001, time = 1.001; + bool hit = false; + const float max_steps = 255.0; + for (float iter = 1.0; !hit && (time < ssray.max_time) && (iter < max_steps); iter++) { + float stride = 1.0 + iter * params.trace_quality; + + prev_time = time; + prev_delta = delta; + + time = min(t + stride * params.jitter, ssray.max_time); + t += stride; - /* Clip to frustum. */ - ray_time = max(0.001, min(ray_time, max_time - 1.5)); + vec4 ss_ray = ssray.origin + ssray.direction * time; + + depth_sample = texture(planarDepth, vec3(ss_ray.xy, planar_ref_id)).r; + + delta = depth_sample - ss_ray.z; + /* Check if the ray is below the surface. */ + hit = (delta < 0.0); + } + /* Reject hit if background. */ + hit = hit && (depth_sample != 1.0); + /* Refine hit using intersection between the sampled heightfield and the ray. + * This simplifies nicely to this single line. */ + time = mix(prev_time, time, saturate(prev_delta / (prev_delta - delta))); - vec4 ss_ray = ss_start + ss_step * ray_time; + hit_position = ssray.origin.xyz + ssray.direction.xyz * time; - /* Tag Z if ray failed. */ - ss_ray.z *= (hit) ? 1.0 : -1.0; - return ss_ray.xyz; + return hit; } float screen_border_mask(vec2 hit_co) diff --git a/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl b/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl index 15c28efe622..5a09120916a 100644 --- a/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/ssr_lib.glsl @@ -39,10 +39,20 @@ vec4 screen_space_refraction(vec3 vP, vec3 N, vec3 V, float ior, float roughness R = transform_direction(ViewMatrix, R); - vec3 hit_pos = raycast( - -1, vP, R * 1e16, ssrThickness, rand.y, ssrQuality, roughnessSquared, false); + Ray ray; + ray.origin = vP; + ray.direction = R * 1e16; - if ((hit_pos.z > 0.0) && (F_eta(ior, dot(H, V)) < 1.0)) { + RayTraceParameters params; + params.thickness = ssrThickness; + params.jitter = rand.y; + params.trace_quality = ssrQuality; + params.roughness = roughnessSquared; + + vec3 hit_pos; + bool hit = raytrace(ray, params, false, hit_pos); + + if (hit && (F_eta(ior, dot(H, V)) < 1.0)) { hit_pos = get_view_space_from_depth(hit_pos.xy, hit_pos.z); float hit_dist = distance(hit_pos, vP); @@ -68,10 +78,7 @@ vec4 screen_space_refraction(vec3 vP, vec3 N, vec3 V, float ior, float roughness vec2 texture_size = vec2(textureSize(colorBuffer, 0).xy); float mip = clamp(log2(cone_footprint * max(texture_size.x, texture_size.y)), 0.0, 9.0); - /* Correct UVs for mipmaping mis-alignment */ - hit_uvs *= mip_ratio_interp(mip); - - vec3 spec = textureLod(colorBuffer, hit_uvs, mip).xyz; + vec3 spec = textureLod(colorBuffer, hit_uvs * hizUvScale.xy, mip).xyz; float mask = screen_border_mask(hit_uvs); return vec4(spec, mask); diff --git a/source/blender/draw/intern/draw_select_buffer.c b/source/blender/draw/intern/draw_select_buffer.c index b5151293c1b..d7438b7e0f0 100644 --- a/source/blender/draw/intern/draw_select_buffer.c +++ b/source/blender/draw/intern/draw_select_buffer.c @@ -24,6 +24,7 @@ #include "MEM_guardedalloc.h" +#include "BLI_array_utils.h" #include "BLI_bitmap.h" #include "BLI_bitmap_draw_2d.h" #include "BLI_rect.h" @@ -336,6 +337,26 @@ uint DRW_select_buffer_sample_point(struct Depsgraph *depsgraph, return ret; } +struct SelectReadData { + const void *val_ptr; + uint id_min; + uint id_max; + uint r_index; +}; + +static bool select_buffer_test_fn(const void *__restrict value, void *__restrict userdata) +{ + struct SelectReadData *data = userdata; + uint hit_id = *(uint *)value; + if (hit_id && hit_id >= data->id_min && hit_id < data->id_max) { + /* Start at 1 to confirm. */ + data->val_ptr = value; + data->r_index = (hit_id - data->id_min) + 1; + return true; + } + return false; +} + /** * Find the selection id closest to \a center. * \param dist: Use to initialize the distance, @@ -349,13 +370,8 @@ uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph, const uint id_max, uint *dist) { - /* Smart function to sample a rect spiraling outside, nice for selection ID. */ - /* Create region around center (typically the mouse cursor). - * This must be square and have an odd width, - * the spiraling algorithm does not work with arbitrary rectangles. */ - - uint index = 0; + * This must be square and have an odd width. */ rcti rect; BLI_rcti_init_pt_radius(&rect, center, *dist); @@ -364,7 +380,6 @@ uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph, int width = BLI_rcti_size_x(&rect); int height = width; - BLI_assert(width == height); /* Read from selection framebuffer. */ @@ -372,64 +387,23 @@ uint DRW_select_buffer_find_nearest_to_point(struct Depsgraph *depsgraph, const uint *buf = DRW_select_buffer_read(depsgraph, region, v3d, &rect, &buf_len); if (buf == NULL) { - return index; + return 0; } - BLI_assert(width * height == buf_len); - - /* Spiral, starting from center of buffer. */ - int spiral_offset = height * (int)(width / 2) + (height / 2); - int spiral_direction = 0; - - for (int nr = 1; nr <= height; nr++) { - for (int a = 0; a < 2; a++) { - for (int b = 0; b < nr; b++) { - /* Find hit within the specified range. */ - uint hit_id = buf[spiral_offset]; - - if (hit_id && hit_id >= id_min && hit_id < id_max) { - /* Get x/y from spiral offset. */ - int hit_x = spiral_offset % width; - int hit_y = spiral_offset / width; - - int center_x = width / 2; - int center_y = height / 2; + const int shape[2] = {height, width}; + const int center_yx[2] = {(height - 1) / 2, (width - 1) / 2}; + struct SelectReadData data = {NULL, id_min, id_max, 0}; + BLI_array_iter_spiral_square(buf, shape, center_yx, select_buffer_test_fn, &data); - /* Manhattan distance in keeping with other screen-based selection. */ - *dist = (uint)(abs(hit_x - center_x) + abs(hit_y - center_y)); - - /* Indices start at 1 here. */ - index = (hit_id - id_min) + 1; - goto exit; - } - - /* Next spiral step. */ - if (spiral_direction == 0) { - spiral_offset += 1; /* right */ - } - else if (spiral_direction == 1) { - spiral_offset -= width; /* down */ - } - else if (spiral_direction == 2) { - spiral_offset -= 1; /* left */ - } - else { - spiral_offset += width; /* up */ - } - - /* Stop if we are outside the buffer. */ - if (spiral_offset < 0 || spiral_offset >= buf_len) { - goto exit; - } - } - - spiral_direction = (spiral_direction + 1) % 4; - } + if (data.val_ptr) { + size_t offset = ((size_t)data.val_ptr - (size_t)buf) / sizeof(*buf); + int hit_x = offset % width; + int hit_y = offset / width; + *dist = (uint)(abs(hit_y - center_yx[0]) + abs(hit_x - center_yx[1])); } -exit: MEM_freeN((void *)buf); - return index; + return data.r_index; } /** \} */ diff --git a/source/blender/draw/intern/shaders/common_math_lib.glsl b/source/blender/draw/intern/shaders/common_math_lib.glsl index d02fd27f35f..0344b977139 100644 --- a/source/blender/draw/intern/shaders/common_math_lib.glsl +++ b/source/blender/draw/intern/shaders/common_math_lib.glsl @@ -128,6 +128,12 @@ vec3 normalize_len(vec3 v, out float len) return v / len; } +vec4 safe_color(vec4 c) +{ + /* Clamp to avoid black square artifacts if a pixel goes NaN. */ + return clamp(c, vec4(0.0), vec4(1e20)); /* 1e20 arbitrary. */ +} + /** \} */ /* ---------------------------------------------------------------------- */ diff --git a/source/blender/editors/CMakeLists.txt b/source/blender/editors/CMakeLists.txt index 23f85756e4b..fd54d531eeb 100644 --- a/source/blender/editors/CMakeLists.txt +++ b/source/blender/editors/CMakeLists.txt @@ -53,6 +53,7 @@ if(WITH_BLENDER) add_subdirectory(space_outliner) add_subdirectory(space_script) add_subdirectory(space_sequencer) + add_subdirectory(space_spreadsheet) add_subdirectory(space_statusbar) add_subdirectory(space_text) add_subdirectory(space_topbar) diff --git a/source/blender/editors/animation/anim_markers.c b/source/blender/editors/animation/anim_markers.c index 2ab809c3633..7adddf8f4ae 100644 --- a/source/blender/editors/animation/anim_markers.c +++ b/source/blender/editors/animation/anim_markers.c @@ -762,9 +762,9 @@ static void ed_marker_move_update_header(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); MarkerMove *mm = op->customdata; TimeMarker *marker, *selmarker = NULL; - const int offs = RNA_int_get(op->ptr, "frames"); + const int ofs = RNA_int_get(op->ptr, "frames"); char str[UI_MAX_DRAW_STR]; - char str_offs[NUM_STR_REP_LEN]; + char str_ofs[NUM_STR_REP_LEN]; int totmark; const bool use_time = ed_marker_move_use_time(mm); @@ -776,27 +776,27 @@ static void ed_marker_move_update_header(bContext *C, wmOperator *op) } if (hasNumInput(&mm->num)) { - outputNumInput(&mm->num, str_offs, &scene->unit); + outputNumInput(&mm->num, str_ofs, &scene->unit); } else if (use_time) { - BLI_snprintf(str_offs, sizeof(str_offs), "%.2f", FRA2TIME(offs)); + BLI_snprintf(str_ofs, sizeof(str_ofs), "%.2f", FRA2TIME(ofs)); } else { - BLI_snprintf(str_offs, sizeof(str_offs), "%d", offs); + BLI_snprintf(str_ofs, sizeof(str_ofs), "%d", ofs); } if (totmark == 1 && selmarker) { /* we print current marker value */ if (use_time) { BLI_snprintf( - str, sizeof(str), TIP_("Marker %.2f offset %s"), FRA2TIME(selmarker->frame), str_offs); + str, sizeof(str), TIP_("Marker %.2f offset %s"), FRA2TIME(selmarker->frame), str_ofs); } else { - BLI_snprintf(str, sizeof(str), TIP_("Marker %d offset %s"), selmarker->frame, str_offs); + BLI_snprintf(str, sizeof(str), TIP_("Marker %d offset %s"), selmarker->frame, str_ofs); } } else { - BLI_snprintf(str, sizeof(str), TIP_("Marker offset %s"), str_offs); + BLI_snprintf(str, sizeof(str), TIP_("Marker offset %s"), str_ofs); } ED_area_status_text(CTX_wm_area(C), str); @@ -907,12 +907,12 @@ static void ed_marker_move_apply(bContext *C, wmOperator *op) #endif MarkerMove *mm = op->customdata; TimeMarker *marker; - int a, offs; + int a, ofs; - offs = RNA_int_get(op->ptr, "frames"); + ofs = RNA_int_get(op->ptr, "frames"); for (a = 0, marker = mm->markers->first; marker; marker = marker->next) { if (marker->flag & SELECT) { - marker->frame = mm->oldframe[a] + offs; + marker->frame = mm->oldframe[a] + ofs; a++; } } diff --git a/source/blender/editors/animation/fmodifier_ui.c b/source/blender/editors/animation/fmodifier_ui.c index 1809daa3fcb..653bd72b364 100644 --- a/source/blender/editors/animation/fmodifier_ui.c +++ b/source/blender/editors/animation/fmodifier_ui.c @@ -173,15 +173,11 @@ static PanelType *fmodifier_panel_register(ARegionType *region_type, PanelTypePollFn poll, const char *id_prefix) { - /* Get the name for the modifier's panel. */ - char panel_idname[BKE_ST_MAXNAME]; - const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(type); - BLI_snprintf(panel_idname, BKE_ST_MAXNAME, "%s_PT_%s", id_prefix, fmi->name); - - PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname); + PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__); /* Intentionally leave the label field blank. The header is filled with buttons. */ - BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME); + const FModifierTypeInfo *fmi = get_fmodifier_typeinfo(type); + BLI_snprintf(panel_type->idname, BKE_ST_MAXNAME, "%s_PT_%s", id_prefix, fmi->name); BLI_strncpy(panel_type->category, "Modifiers", BKE_ST_MAXNAME); BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME); @@ -215,13 +211,9 @@ static PanelType *fmodifier_subpanel_register(ARegionType *region_type, PanelTypePollFn poll, PanelType *parent) { - /* Create the subpanel's ID name. */ - char panel_idname[BKE_ST_MAXNAME]; - BLI_snprintf(panel_idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name); - - PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname); + PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__); - BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME); + BLI_snprintf(panel_type->idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name); BLI_strncpy(panel_type->label, label, BKE_ST_MAXNAME); BLI_strncpy(panel_type->category, "Modifiers", BKE_ST_MAXNAME); BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME); diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index 60fe8ee7dee..226253cc063 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -644,8 +644,8 @@ static int selectbuffer_ret_hits_12(uint *UNUSED(buffer), const int hits12) static int selectbuffer_ret_hits_5(uint *buffer, const int hits12, const int hits5) { - const int offs = 4 * hits12; - memcpy(buffer, buffer + offs, 4 * hits5 * sizeof(uint)); + const int ofs = 4 * hits12; + memcpy(buffer, buffer + ofs, 4 * hits5 * sizeof(uint)); return hits5; } @@ -704,17 +704,12 @@ static EditBone *get_nearest_editbonepoint( goto cache_end; } else if (hits12 > 0) { - int offs; + int ofs; - offs = 4 * hits12; + ofs = 4 * hits12; BLI_rcti_init_pt_radius(&rect, vc->mval, 5); - const int hits5 = view3d_opengl_select_with_id_filter(vc, - buffer + offs, - MAXPICKBUF - offs, - &rect, - select_mode, - select_filter, - select_id_ignore); + const int hits5 = view3d_opengl_select_with_id_filter( + vc, buffer + ofs, MAXPICKBUF - ofs, &rect, select_mode, select_filter, select_id_ignore); if (hits5 == 1) { hits = selectbuffer_ret_hits_5(buffer, hits12, hits5); diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c index d636f0d68af..93d36abe792 100644 --- a/source/blender/editors/armature/pose_slide.c +++ b/source/blender/editors/armature/pose_slide.c @@ -873,12 +873,12 @@ static void pose_slide_draw_status(tPoseSlideOp *pso) if (hasNumInput(&pso->num)) { Scene *scene = pso->scene; - char str_offs[NUM_STR_REP_LEN]; + char str_ofs[NUM_STR_REP_LEN]; - outputNumInput(&pso->num, str_offs, &scene->unit); + outputNumInput(&pso->num, str_ofs, &scene->unit); BLI_snprintf( - status_str, sizeof(status_str), "%s: %s | %s", mode_str, str_offs, limits_str); + status_str, sizeof(status_str), "%s: %s | %s", mode_str, str_ofs, limits_str); } else { BLI_snprintf(status_str, diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c index 7c541f61d75..3b7c80cee07 100644 --- a/source/blender/editors/gpencil/gpencil_interpolate.c +++ b/source/blender/editors/gpencil/gpencil_interpolate.c @@ -599,10 +599,10 @@ static void gpencil_interpolate_status_indicators(bContext *C, tGPDinterpolate * BLI_strncpy(msg_str, TIP_("GPencil Interpolation: "), UI_MAX_DRAW_STR); if (hasNumInput(&p->num)) { - char str_offs[NUM_STR_REP_LEN]; + char str_ofs[NUM_STR_REP_LEN]; - outputNumInput(&p->num, str_offs, &scene->unit); - BLI_snprintf(status_str, sizeof(status_str), "%s%s", msg_str, str_offs); + outputNumInput(&p->num, str_ofs, &scene->unit); + BLI_snprintf(status_str, sizeof(status_str), "%s%s", msg_str, str_ofs); } else { BLI_snprintf(status_str, diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index b29ef2e7ee2..dfff0ce639e 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -466,10 +466,10 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi GP_STROKE_BOX, GP_STROKE_POLYLINE)) { if (hasNumInput(&tgpi->num)) { - char str_offs[NUM_STR_REP_LEN]; + char str_ofs[NUM_STR_REP_LEN]; - outputNumInput(&tgpi->num, str_offs, &scene->unit); - BLI_snprintf(status_str, sizeof(status_str), "%s: %s", msg_str, str_offs); + outputNumInput(&tgpi->num, str_ofs, &scene->unit); + BLI_snprintf(status_str, sizeof(status_str), "%s: %s", msg_str, str_ofs); } else { if (tgpi->flag == IN_PROGRESS) { diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h index 7538dac1354..983ae94b637 100644 --- a/source/blender/editors/include/ED_fileselect.h +++ b/source/blender/editors/include/ED_fileselect.h @@ -145,6 +145,13 @@ void ED_fileselect_exit(struct wmWindowManager *wm, struct SpaceFile *sfile); bool ED_fileselect_is_asset_browser(const struct SpaceFile *sfile); +struct ID *ED_fileselect_active_asset_get(const struct SpaceFile *sfile); + +/* Activate the file that corresponds to the given ID. + * Pass deferred=true to wait for the next refresh before activating. */ +void ED_fileselect_activate_by_id(struct SpaceFile *sfile, + struct ID *asset_id, + const bool deferred); void ED_fileselect_window_params_get(const struct wmWindow *win, int win_size[2], diff --git a/source/blender/editors/include/ED_space_api.h b/source/blender/editors/include/ED_space_api.h index fc474ea464d..1a3aa7e5496 100644 --- a/source/blender/editors/include/ED_space_api.h +++ b/source/blender/editors/include/ED_space_api.h @@ -55,6 +55,7 @@ void ED_spacetype_userpref(void); void ED_spacetype_clip(void); void ED_spacetype_statusbar(void); void ED_spacetype_topbar(void); +void ED_spacetype_spreadsheet(void); /* calls for instancing and freeing spacetype static data * called in WM_init_exit */ diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 042f10ddded..834be49b2b3 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -5246,8 +5246,8 @@ static bool ui_numedit_but_SLI(uiBut *but, (but->softmax - but->softmin + but->a1); } else { - const float offs = (BLI_rctf_size_y(&but->rect) / 2.0f); - cursor_x_range = (BLI_rctf_size_x(&but->rect) - offs); + const float ofs = (BLI_rctf_size_y(&but->rect) / 2.0f); + cursor_x_range = (BLI_rctf_size_x(&but->rect) - ofs); } f = (mx_fl - data->dragstartx) / cursor_x_range + data->dragfstart; diff --git a/source/blender/editors/interface/interface_template_search_menu.c b/source/blender/editors/interface/interface_template_search_menu.c index e1f8f63dcbf..74668b2f3a3 100644 --- a/source/blender/editors/interface/interface_template_search_menu.c +++ b/source/blender/editors/interface/interface_template_search_menu.c @@ -642,6 +642,7 @@ static struct MenuSearch_Data *menu_items_from_ui_create( SPACE_MENU_NOP(SPACE_SCRIPT); SPACE_MENU_NOP(SPACE_STATUSBAR); SPACE_MENU_NOP(SPACE_TOPBAR); + SPACE_MENU_NOP(SPACE_SPREADSHEET); } } for (int i = 0; i < idname_array_len; i++) { diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 06b87dd857f..1d7d10b6d0c 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -3667,16 +3667,16 @@ static void widget_progressbar( /* round corners */ const float value = but_progressbar->progress; - const float offs = wcol->roundness * BLI_rcti_size_y(&rect_prog); + const float ofs = wcol->roundness * BLI_rcti_size_y(&rect_prog); float w = value * BLI_rcti_size_x(&rect_prog); /* Ensure minimum size. */ - w = MAX2(w, offs); + w = MAX2(w, ofs); rect_bar.xmax = rect_bar.xmin + w; - round_box_edges(&wtb, roundboxalign, &rect_prog, offs); - round_box_edges(&wtb_bar, roundboxalign, &rect_bar, offs); + round_box_edges(&wtb, roundboxalign, &rect_prog, ofs); + round_box_edges(&wtb_bar, roundboxalign, &rect_bar, ofs); wtb.draw_outline = true; widgetbase_draw(&wtb, wcol); @@ -3733,9 +3733,9 @@ static void widget_numslider( widget_init(&wtb1); /* Backdrop first. */ - const float offs = wcol->roundness * BLI_rcti_size_y(rect); - const float toffs = offs * 0.75f; - round_box_edges(&wtb, roundboxalign, rect, offs); + const float ofs = wcol->roundness * BLI_rcti_size_y(rect); + const float toffs = ofs * 0.75f; + round_box_edges(&wtb, roundboxalign, rect, ofs); wtb.draw_outline = false; widgetbase_draw(&wtb, wcol); @@ -3768,13 +3768,13 @@ static void widget_numslider( const float width = (float)BLI_rcti_size_x(rect); factor_ui = factor * width; - if (factor_ui <= offs) { + if (factor_ui <= ofs) { /* Left part only. */ roundboxalign_slider &= ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT); - rect1.xmax = rect1.xmin + offs; - factor_discard = factor_ui / offs; + rect1.xmax = rect1.xmin + ofs; + factor_discard = factor_ui / ofs; } - else if (factor_ui <= width - offs) { + else if (factor_ui <= width - ofs) { /* Left part + middle part. */ roundboxalign_slider &= ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT); rect1.xmax = rect1.xmin + factor_ui; @@ -3784,7 +3784,7 @@ static void widget_numslider( factor_discard = factor; } - round_box_edges(&wtb1, roundboxalign_slider, &rect1, offs); + round_box_edges(&wtb1, roundboxalign_slider, &rect1, ofs); wtb1.draw_outline = false; widgetbase_set_uniform_discard_factor(&wtb1, factor_discard); widgetbase_draw(&wtb1, wcol); diff --git a/source/blender/editors/interface/resources.c b/source/blender/editors/interface/resources.c index 80e54f4f92f..afac254f542 100644 --- a/source/blender/editors/interface/resources.c +++ b/source/blender/editors/interface/resources.c @@ -160,6 +160,9 @@ const uchar *UI_ThemeGetColorPtr(bTheme *btheme, int spacetype, int colorid) case SPACE_STATUSBAR: ts = &btheme->space_statusbar; break; + case SPACE_SPREADSHEET: + ts = &btheme->space_spreadsheet; + break; default: ts = &btheme->space_view3d; break; diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c index 1e66a86c8fd..bf20c1f6438 100644 --- a/source/blender/editors/io/io_cache.c +++ b/source/blender/editors/io/io_cache.c @@ -130,8 +130,8 @@ void CACHEFILE_OT_open(wmOperatorType *ot) WM_operator_properties_filesel(ot, FILE_TYPE_ALEMBIC | FILE_TYPE_FOLDER, FILE_BLENDER, - FILE_SAVE, - WM_FILESEL_FILEPATH, + FILE_OPENFILE, + WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, FILE_DEFAULTDISPLAY, FILE_SORT_DEFAULT); } diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c index d60d83850a5..582ff01173a 100644 --- a/source/blender/editors/mesh/editmesh_add.c +++ b/source/blender/editors/mesh/editmesh_add.c @@ -75,11 +75,8 @@ static Object *make_prim_init(bContext *C, ED_object_new_primitive_matrix(C, obedit, loc, rot, r_creation_data->mat); - if (scale && !equals_v3v3(scale, (const float[3]){1.0f, 1.0f, 1.0f})) { - float scale_half[3]; - copy_v3_v3(scale_half, scale); - mul_v3_fl(scale_half, 0.5f); - rescale_m4(r_creation_data->mat, scale_half); + if (scale) { + rescale_m4(r_creation_data->mat, scale); } return obedit; diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c index b269a4f0514..0e3cc22d358 100644 --- a/source/blender/editors/mesh/editmesh_intersect.c +++ b/source/blender/editors/mesh/editmesh_intersect.c @@ -212,6 +212,7 @@ static int edbm_intersect_exec(bContext *C, wmOperator *op) nshapes, use_self, use_separate_all, + false, true); } else { @@ -375,8 +376,16 @@ static int edbm_intersect_boolean_exec(bContext *C, wmOperator *op) } if (use_exact) { - has_isect = BM_mesh_boolean( - em->bm, em->looptris, em->tottri, test_fn, NULL, 2, use_self, true, boolean_operation); + has_isect = BM_mesh_boolean(em->bm, + em->looptris, + em->tottri, + test_fn, + NULL, + 2, + use_self, + true, + false, + boolean_operation); } else { has_isect = BM_mesh_intersect(em->bm, diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.c index 9811b7caa38..1b7209b164b 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.c @@ -1342,7 +1342,7 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat * already there. Very expensive for large images. Need to find a way to * only get existing ibuf */ ibuf = BKE_image_acquire_ibuf(ima, &iuser, NULL); - if (ibuf == NULL || ibuf->rect == NULL) { + if (ibuf == NULL || (ibuf->rect == NULL && ibuf->rect_float == NULL)) { BKE_image_release_ibuf(ima, ibuf, NULL); return; } diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index bfad79a1da9..b4cac58db1f 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -1074,6 +1074,11 @@ static int view_layer_remove_aov_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); + + if (view_layer->active_aov == NULL) { + return OPERATOR_FINISHED; + } + BKE_view_layer_remove_aov(view_layer, view_layer->active_aov); RenderEngineType *engine_type = RE_engines_find(scene->r.engine); diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c index 26e2bcc42cf..966f2ace931 100644 --- a/source/blender/editors/sculpt_paint/paint_mask.c +++ b/source/blender/editors/sculpt_paint/paint_mask.c @@ -1292,7 +1292,8 @@ static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext) BLI_assert(false); break; } - BM_mesh_boolean(bm, looptris, tottri, bm_face_isect_pair, NULL, 2, true, true, boolean_mode); + BM_mesh_boolean( + bm, looptris, tottri, bm_face_isect_pair, NULL, 2, true, true, false, boolean_mode); } MEM_freeN(looptris); diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 631327ddfe8..0b30303de91 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -76,11 +76,6 @@ #include "IMB_colormanagement.h" -#include "GPU_immediate.h" -#include "GPU_immediate_util.h" -#include "GPU_matrix.h" -#include "GPU_state.h" - #include "WM_api.h" #include "WM_message.h" #include "WM_toolsystem.h" @@ -89,7 +84,6 @@ #include "ED_object.h" #include "ED_screen.h" #include "ED_sculpt.h" -#include "ED_space_api.h" #include "ED_view3d.h" #include "paint_intern.h" #include "sculpt_intern.h" @@ -9433,335 +9427,6 @@ static void SCULPT_OT_mask_by_color(wmOperatorType *ot) 1.0f); } -/* -------------------------------------------------------------------- */ -/** \name Dyntopo Detail Size Edit Operator - * \{ */ - -/* Defines how much the mouse movement will modify the detail size value. */ -#define DETAIL_SIZE_DELTA_SPEED 0.08f -#define DETAIL_SIZE_DELTA_ACCURATE_SPEED 0.004f - -typedef struct DyntopoDetailSizeEditCustomData { - void *draw_handle; - Object *active_object; - - float init_mval[2]; - float accurate_mval[2]; - - float outline_col[4]; - - bool accurate_mode; - bool sample_mode; - - float init_detail_size; - float accurate_detail_size; - float detail_size; - float radius; - - float preview_tri[3][3]; - float gizmo_mat[4][4]; -} DyntopoDetailSizeEditCustomData; - -static void dyntopo_detail_size_parallel_lines_draw(uint pos3d, - DyntopoDetailSizeEditCustomData *cd, - const float start_co[3], - const float end_co[3], - bool flip, - const float angle) -{ - float object_space_constant_detail = 1.0f / - (cd->detail_size * mat4_to_scale(cd->active_object->obmat)); - - /* The constant detail represents the maximum edge length allowed before subdividing it. If the - * triangle grid preview is created with this value it will represent an ideal mesh density where - * all edges have the exact maximum length, which never happens in practice. As the minimum edge - * length for dyntopo is 0.4 * max_edge_length, this adjust the detail size to the average - * between max and min edge length so the preview is more accurate. */ - object_space_constant_detail *= 0.7f; - - const float total_len = len_v3v3(cd->preview_tri[0], cd->preview_tri[1]); - const int tot_lines = (int)(total_len / object_space_constant_detail) + 1; - const float tot_lines_fl = total_len / object_space_constant_detail; - float spacing_disp[3]; - sub_v3_v3v3(spacing_disp, end_co, start_co); - normalize_v3(spacing_disp); - - float line_disp[3]; - rotate_v2_v2fl(line_disp, spacing_disp, DEG2RAD(angle)); - mul_v3_fl(spacing_disp, total_len / tot_lines_fl); - - immBegin(GPU_PRIM_LINES, (uint)tot_lines * 2); - for (int i = 0; i < tot_lines; i++) { - float line_length; - if (flip) { - line_length = total_len * ((float)i / (float)tot_lines_fl); - } - else { - line_length = total_len * (1.0f - ((float)i / (float)tot_lines_fl)); - } - float line_start[3]; - copy_v3_v3(line_start, start_co); - madd_v3_v3v3fl(line_start, line_start, spacing_disp, i); - float line_end[3]; - madd_v3_v3v3fl(line_end, line_start, line_disp, line_length); - immVertex3fv(pos3d, line_start); - immVertex3fv(pos3d, line_end); - } - immEnd(); -} - -static void dyntopo_detail_size_edit_draw(const bContext *UNUSED(C), - ARegion *UNUSED(ar), - void *arg) -{ - DyntopoDetailSizeEditCustomData *cd = arg; - GPU_blend(GPU_BLEND_ALPHA); - GPU_line_smooth(true); - - uint pos3d = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); - immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); - GPU_matrix_push(); - GPU_matrix_mul(cd->gizmo_mat); - - /* Draw Cursor */ - immUniformColor4fv(cd->outline_col); - GPU_line_width(3.0f); - - imm_draw_circle_wire_3d(pos3d, 0, 0, cd->radius, 80); - - /* Draw Triangle. */ - immUniformColor4f(0.9f, 0.9f, 0.9f, 0.8f); - immBegin(GPU_PRIM_LINES, 6); - immVertex3fv(pos3d, cd->preview_tri[0]); - immVertex3fv(pos3d, cd->preview_tri[1]); - - immVertex3fv(pos3d, cd->preview_tri[1]); - immVertex3fv(pos3d, cd->preview_tri[2]); - - immVertex3fv(pos3d, cd->preview_tri[2]); - immVertex3fv(pos3d, cd->preview_tri[0]); - immEnd(); - - /* Draw Grid */ - GPU_line_width(1.0f); - dyntopo_detail_size_parallel_lines_draw( - pos3d, cd, cd->preview_tri[0], cd->preview_tri[1], false, 60.0f); - dyntopo_detail_size_parallel_lines_draw( - pos3d, cd, cd->preview_tri[0], cd->preview_tri[1], true, 120.0f); - dyntopo_detail_size_parallel_lines_draw( - pos3d, cd, cd->preview_tri[0], cd->preview_tri[2], false, -60.0f); - - immUnbindProgram(); - GPU_matrix_pop(); - GPU_blend(GPU_BLEND_NONE); - GPU_line_smooth(false); -} - -static void dyntopo_detail_size_edit_cancel(bContext *C, wmOperator *op) -{ - Object *active_object = CTX_data_active_object(C); - SculptSession *ss = active_object->sculpt; - ARegion *region = CTX_wm_region(C); - DyntopoDetailSizeEditCustomData *cd = op->customdata; - ED_region_draw_cb_exit(region->type, cd->draw_handle); - ss->draw_faded_cursor = false; - MEM_freeN(op->customdata); - ED_workspace_status_text(C, NULL); -} - -static void dyntopo_detail_size_sample_from_surface(Object *ob, - DyntopoDetailSizeEditCustomData *cd) -{ - SculptSession *ss = ob->sculpt; - const int active_vertex = SCULPT_active_vertex_get(ss); - - float len_accum = 0; - int num_neighbors = 0; - SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, active_vertex, ni) { - len_accum += len_v3v3(SCULPT_vertex_co_get(ss, active_vertex), - SCULPT_vertex_co_get(ss, ni.index)); - num_neighbors++; - } - SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); - - if (num_neighbors > 0) { - const float avg_edge_len = len_accum / num_neighbors; - /* Use 0.7 as the average of min and max dyntopo edge length. */ - const float detail_size = 0.7f / (avg_edge_len * mat4_to_scale(cd->active_object->obmat)); - cd->detail_size = clamp_f(detail_size, 1.0f, 500.0f); - } -} - -static void dyntopo_detail_size_update_from_mouse_delta(DyntopoDetailSizeEditCustomData *cd, - const wmEvent *event) -{ - const float mval[2] = {event->mval[0], event->mval[1]}; - - float detail_size_delta; - if (cd->accurate_mode) { - detail_size_delta = mval[0] - cd->accurate_mval[0]; - cd->detail_size = cd->accurate_detail_size + - detail_size_delta * DETAIL_SIZE_DELTA_ACCURATE_SPEED; - } - else { - detail_size_delta = mval[0] - cd->init_mval[0]; - cd->detail_size = cd->init_detail_size + detail_size_delta * DETAIL_SIZE_DELTA_SPEED; - } - - if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_PRESS) { - cd->accurate_mode = true; - copy_v2_v2(cd->accurate_mval, mval); - cd->accurate_detail_size = cd->detail_size; - } - if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_RELEASE) { - cd->accurate_mode = false; - cd->accurate_detail_size = 0.0f; - } - - cd->detail_size = clamp_f(cd->detail_size, 1.0f, 500.0f); -} - -static int dyntopo_detail_size_edit_modal(bContext *C, wmOperator *op, const wmEvent *event) -{ - Object *active_object = CTX_data_active_object(C); - SculptSession *ss = active_object->sculpt; - ARegion *region = CTX_wm_region(C); - DyntopoDetailSizeEditCustomData *cd = op->customdata; - Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - - /* Cancel modal operator */ - if ((event->type == EVT_ESCKEY && event->val == KM_PRESS) || - (event->type == RIGHTMOUSE && event->val == KM_PRESS)) { - dyntopo_detail_size_edit_cancel(C, op); - ED_region_tag_redraw(region); - return OPERATOR_FINISHED; - } - - /* Finish modal operator */ - if ((event->type == LEFTMOUSE && event->val == KM_RELEASE) || - (event->type == EVT_RETKEY && event->val == KM_PRESS) || - (event->type == EVT_PADENTER && event->val == KM_PRESS)) { - ED_region_draw_cb_exit(region->type, cd->draw_handle); - sd->constant_detail = cd->detail_size; - ss->draw_faded_cursor = false; - MEM_freeN(op->customdata); - ED_region_tag_redraw(region); - ED_workspace_status_text(C, NULL); - return OPERATOR_FINISHED; - } - - ED_region_tag_redraw(region); - - if (event->type == EVT_LEFTCTRLKEY && event->val == KM_PRESS) { - cd->sample_mode = true; - } - if (event->type == EVT_LEFTCTRLKEY && event->val == KM_RELEASE) { - cd->sample_mode = false; - } - - /* Sample mode sets the detail size sampling the average edge length under the surface. */ - if (cd->sample_mode) { - dyntopo_detail_size_sample_from_surface(active_object, cd); - return OPERATOR_RUNNING_MODAL; - } - /* Regular mode, changes the detail size by moving the cursor. */ - dyntopo_detail_size_update_from_mouse_delta(cd, event); - - return OPERATOR_RUNNING_MODAL; -} - -static int dyntopo_detail_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - ARegion *region = CTX_wm_region(C); - Object *active_object = CTX_data_active_object(C); - Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - - DyntopoDetailSizeEditCustomData *cd = MEM_callocN(sizeof(DyntopoDetailSizeEditCustomData), - "Dyntopo Detail Size Edit OP Custom Data"); - - /* Initial operator Custom Data setup. */ - cd->draw_handle = ED_region_draw_cb_activate( - region->type, dyntopo_detail_size_edit_draw, cd, REGION_DRAW_POST_VIEW); - cd->active_object = active_object; - cd->init_mval[0] = event->mval[0]; - cd->init_mval[1] = event->mval[1]; - cd->detail_size = sd->constant_detail; - cd->init_detail_size = sd->constant_detail; - copy_v4_v4(cd->outline_col, brush->add_col); - op->customdata = cd; - - SculptSession *ss = active_object->sculpt; - cd->radius = ss->cursor_radius; - - /* Generates the matrix to position the gizmo in the surface of the mesh using the same location - * and orientation as the brush cursor. */ - float cursor_trans[4][4], cursor_rot[4][4]; - const float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f}; - float quat[4]; - copy_m4_m4(cursor_trans, active_object->obmat); - translate_m4( - cursor_trans, ss->cursor_location[0], ss->cursor_location[1], ss->cursor_location[2]); - - float cursor_normal[3]; - if (!is_zero_v3(ss->cursor_sampled_normal)) { - copy_v3_v3(cursor_normal, ss->cursor_sampled_normal); - } - else { - copy_v3_v3(cursor_normal, ss->cursor_normal); - } - - rotation_between_vecs_to_quat(quat, z_axis, cursor_normal); - quat_to_mat4(cursor_rot, quat); - copy_m4_m4(cd->gizmo_mat, cursor_trans); - mul_m4_m4_post(cd->gizmo_mat, cursor_rot); - - /* Initialize the position of the triangle vertices. */ - const float y_axis[3] = {0.0f, cd->radius, 0.0f}; - for (int i = 0; i < 3; i++) { - zero_v3(cd->preview_tri[i]); - rotate_v2_v2fl(cd->preview_tri[i], y_axis, DEG2RAD(120.0f * i)); - } - - SCULPT_vertex_random_access_ensure(ss); - - WM_event_add_modal_handler(C, op); - ED_region_tag_redraw(region); - - ss->draw_faded_cursor = true; - - const char *status_str = TIP_( - "Move the mouse to change the dyntopo detail size. LMB: confirm size, ESC/RMB: cancel"); - ED_workspace_status_text(C, status_str); - - return OPERATOR_RUNNING_MODAL; -} - -static bool dyntopo_detail_size_edit_poll(bContext *C) -{ - Object *ob = CTX_data_active_object(C); - Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - - return SCULPT_mode_poll(C) && ob->sculpt->bm && (sd->flags & SCULPT_DYNTOPO_DETAIL_CONSTANT); -} - -static void SCULPT_OT_dyntopo_detail_size_edit(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Edit Dyntopo Detail Size"; - ot->description = "Modify the constant detail size of dyntopo interactively"; - ot->idname = "SCULPT_OT_dyntopo_detail_size_edit"; - - /* api callbacks */ - ot->poll = dyntopo_detail_size_edit_poll; - ot->invoke = dyntopo_detail_size_edit_invoke; - ot->modal = dyntopo_detail_size_edit_modal; - ot->cancel = dyntopo_detail_size_edit_cancel; - - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - void ED_operatortypes_sculpt(void) { WM_operatortype_append(SCULPT_OT_brush_stroke); diff --git a/source/blender/editors/sculpt_paint/sculpt_boundary.c b/source/blender/editors/sculpt_paint/sculpt_boundary.c index f1fb402ae41..f79621ccffd 100644 --- a/source/blender/editors/sculpt_paint/sculpt_boundary.c +++ b/source/blender/editors/sculpt_paint/sculpt_boundary.c @@ -589,6 +589,7 @@ static void sculpt_boundary_slide_data_init(SculptSession *ss, SculptBoundary *b for (int i = 0; i < totvert; i++) { if (boundary->edit_info[i].num_propagation_steps != boundary->max_propagation_steps) { + continue; } sub_v3_v3v3(boundary->slide.directions[boundary->edit_info[i].original_vertex], SCULPT_vertex_co_get(ss, boundary->edit_info[i].original_vertex), diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c index ddf7ba1e412..1246c624941 100644 --- a/source/blender/editors/sculpt_paint/sculpt_detail.c +++ b/source/blender/editors/sculpt_paint/sculpt_detail.c @@ -37,10 +37,17 @@ #include "DEG_depsgraph.h" +#include "GPU_immediate.h" +#include "GPU_immediate_util.h" +#include "GPU_matrix.h" +#include "GPU_state.h" + #include "WM_api.h" #include "WM_types.h" #include "ED_screen.h" +#include "ED_sculpt.h" +#include "ED_space_api.h" #include "ED_view3d.h" #include "sculpt_intern.h" @@ -359,8 +366,12 @@ void SCULPT_OT_sample_detail_size(wmOperatorType *ot) /* Dynamic-topology detail size. * - * This should be improved further, perhaps by showing a triangle - * grid rather than brush alpha. */ + * Currently, there are two operators editing the detail size: + * - SCULPT_OT_set_detail_size uses radial control for all methods + * - SCULPT_OT_dyntopo_detail_size_edit shows a triangle grid representation of the detail + * resolution (for constant detail method, falls back to radial control for the remaining methods). + */ + static void set_brush_rc_props(PointerRNA *ptr, const char *prop) { char *path = BLI_sprintfN("tool_settings.sculpt.brush.%s", prop); @@ -368,7 +379,7 @@ static void set_brush_rc_props(PointerRNA *ptr, const char *prop) MEM_freeN(path); } -static int sculpt_set_detail_size_exec(bContext *C, wmOperator *UNUSED(op)) +static void sculpt_detail_size_set_radial_control(bContext *C) { Sculpt *sd = CTX_data_tool_settings(C)->sculpt; @@ -394,6 +405,11 @@ static int sculpt_set_detail_size_exec(bContext *C, wmOperator *UNUSED(op)) WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &props_ptr); WM_operator_properties_free(&props_ptr); +} + +static int sculpt_set_detail_size_exec(bContext *C, wmOperator *UNUSED(op)) +{ + sculpt_detail_size_set_radial_control(C); return OPERATOR_FINISHED; } @@ -412,3 +428,334 @@ void SCULPT_OT_set_detail_size(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +/* -------------------------------------------------------------------- */ +/** \name Dyntopo Detail Size Edit Operator + * \{ */ + +/* Defines how much the mouse movement will modify the detail size value. */ +#define DETAIL_SIZE_DELTA_SPEED 0.08f +#define DETAIL_SIZE_DELTA_ACCURATE_SPEED 0.004f + +typedef struct DyntopoDetailSizeEditCustomData { + void *draw_handle; + Object *active_object; + + float init_mval[2]; + float accurate_mval[2]; + + float outline_col[4]; + + bool accurate_mode; + bool sample_mode; + + float init_detail_size; + float accurate_detail_size; + float detail_size; + float radius; + + float preview_tri[3][3]; + float gizmo_mat[4][4]; +} DyntopoDetailSizeEditCustomData; + +static void dyntopo_detail_size_parallel_lines_draw(uint pos3d, + DyntopoDetailSizeEditCustomData *cd, + const float start_co[3], + const float end_co[3], + bool flip, + const float angle) +{ + float object_space_constant_detail = 1.0f / + (cd->detail_size * mat4_to_scale(cd->active_object->obmat)); + + /* The constant detail represents the maximum edge length allowed before subdividing it. If the + * triangle grid preview is created with this value it will represent an ideal mesh density where + * all edges have the exact maximum length, which never happens in practice. As the minimum edge + * length for dyntopo is 0.4 * max_edge_length, this adjust the detail size to the average + * between max and min edge length so the preview is more accurate. */ + object_space_constant_detail *= 0.7f; + + const float total_len = len_v3v3(cd->preview_tri[0], cd->preview_tri[1]); + const int tot_lines = (int)(total_len / object_space_constant_detail) + 1; + const float tot_lines_fl = total_len / object_space_constant_detail; + float spacing_disp[3]; + sub_v3_v3v3(spacing_disp, end_co, start_co); + normalize_v3(spacing_disp); + + float line_disp[3]; + rotate_v2_v2fl(line_disp, spacing_disp, DEG2RAD(angle)); + mul_v3_fl(spacing_disp, total_len / tot_lines_fl); + + immBegin(GPU_PRIM_LINES, (uint)tot_lines * 2); + for (int i = 0; i < tot_lines; i++) { + float line_length; + if (flip) { + line_length = total_len * ((float)i / (float)tot_lines_fl); + } + else { + line_length = total_len * (1.0f - ((float)i / (float)tot_lines_fl)); + } + float line_start[3]; + copy_v3_v3(line_start, start_co); + madd_v3_v3v3fl(line_start, line_start, spacing_disp, i); + float line_end[3]; + madd_v3_v3v3fl(line_end, line_start, line_disp, line_length); + immVertex3fv(pos3d, line_start); + immVertex3fv(pos3d, line_end); + } + immEnd(); +} + +static void dyntopo_detail_size_edit_draw(const bContext *UNUSED(C), + ARegion *UNUSED(ar), + void *arg) +{ + DyntopoDetailSizeEditCustomData *cd = arg; + GPU_blend(GPU_BLEND_ALPHA); + GPU_line_smooth(true); + + uint pos3d = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 3, GPU_FETCH_FLOAT); + immBindBuiltinProgram(GPU_SHADER_3D_UNIFORM_COLOR); + GPU_matrix_push(); + GPU_matrix_mul(cd->gizmo_mat); + + /* Draw Cursor */ + immUniformColor4fv(cd->outline_col); + GPU_line_width(3.0f); + + imm_draw_circle_wire_3d(pos3d, 0, 0, cd->radius, 80); + + /* Draw Triangle. */ + immUniformColor4f(0.9f, 0.9f, 0.9f, 0.8f); + immBegin(GPU_PRIM_LINES, 6); + immVertex3fv(pos3d, cd->preview_tri[0]); + immVertex3fv(pos3d, cd->preview_tri[1]); + + immVertex3fv(pos3d, cd->preview_tri[1]); + immVertex3fv(pos3d, cd->preview_tri[2]); + + immVertex3fv(pos3d, cd->preview_tri[2]); + immVertex3fv(pos3d, cd->preview_tri[0]); + immEnd(); + + /* Draw Grid */ + GPU_line_width(1.0f); + dyntopo_detail_size_parallel_lines_draw( + pos3d, cd, cd->preview_tri[0], cd->preview_tri[1], false, 60.0f); + dyntopo_detail_size_parallel_lines_draw( + pos3d, cd, cd->preview_tri[0], cd->preview_tri[1], true, 120.0f); + dyntopo_detail_size_parallel_lines_draw( + pos3d, cd, cd->preview_tri[0], cd->preview_tri[2], false, -60.0f); + + immUnbindProgram(); + GPU_matrix_pop(); + GPU_blend(GPU_BLEND_NONE); + GPU_line_smooth(false); +} + +static void dyntopo_detail_size_edit_cancel(bContext *C, wmOperator *op) +{ + Object *active_object = CTX_data_active_object(C); + SculptSession *ss = active_object->sculpt; + ARegion *region = CTX_wm_region(C); + DyntopoDetailSizeEditCustomData *cd = op->customdata; + ED_region_draw_cb_exit(region->type, cd->draw_handle); + ss->draw_faded_cursor = false; + MEM_freeN(op->customdata); + ED_workspace_status_text(C, NULL); +} + +static void dyntopo_detail_size_sample_from_surface(Object *ob, + DyntopoDetailSizeEditCustomData *cd) +{ + SculptSession *ss = ob->sculpt; + const int active_vertex = SCULPT_active_vertex_get(ss); + + float len_accum = 0; + int num_neighbors = 0; + SculptVertexNeighborIter ni; + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, active_vertex, ni) { + len_accum += len_v3v3(SCULPT_vertex_co_get(ss, active_vertex), + SCULPT_vertex_co_get(ss, ni.index)); + num_neighbors++; + } + SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); + + if (num_neighbors > 0) { + const float avg_edge_len = len_accum / num_neighbors; + /* Use 0.7 as the average of min and max dyntopo edge length. */ + const float detail_size = 0.7f / (avg_edge_len * mat4_to_scale(cd->active_object->obmat)); + cd->detail_size = clamp_f(detail_size, 1.0f, 500.0f); + } +} + +static void dyntopo_detail_size_update_from_mouse_delta(DyntopoDetailSizeEditCustomData *cd, + const wmEvent *event) +{ + const float mval[2] = {event->mval[0], event->mval[1]}; + + float detail_size_delta; + if (cd->accurate_mode) { + detail_size_delta = mval[0] - cd->accurate_mval[0]; + cd->detail_size = cd->accurate_detail_size + + detail_size_delta * DETAIL_SIZE_DELTA_ACCURATE_SPEED; + } + else { + detail_size_delta = mval[0] - cd->init_mval[0]; + cd->detail_size = cd->init_detail_size + detail_size_delta * DETAIL_SIZE_DELTA_SPEED; + } + + if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_PRESS) { + cd->accurate_mode = true; + copy_v2_v2(cd->accurate_mval, mval); + cd->accurate_detail_size = cd->detail_size; + } + if (event->type == EVT_LEFTSHIFTKEY && event->val == KM_RELEASE) { + cd->accurate_mode = false; + cd->accurate_detail_size = 0.0f; + } + + cd->detail_size = clamp_f(cd->detail_size, 1.0f, 500.0f); +} + +static int dyntopo_detail_size_edit_modal(bContext *C, wmOperator *op, const wmEvent *event) +{ + Object *active_object = CTX_data_active_object(C); + SculptSession *ss = active_object->sculpt; + ARegion *region = CTX_wm_region(C); + DyntopoDetailSizeEditCustomData *cd = op->customdata; + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + + /* Cancel modal operator */ + if ((event->type == EVT_ESCKEY && event->val == KM_PRESS) || + (event->type == RIGHTMOUSE && event->val == KM_PRESS)) { + dyntopo_detail_size_edit_cancel(C, op); + ED_region_tag_redraw(region); + return OPERATOR_FINISHED; + } + + /* Finish modal operator */ + if ((event->type == LEFTMOUSE && event->val == KM_RELEASE) || + (event->type == EVT_RETKEY && event->val == KM_PRESS) || + (event->type == EVT_PADENTER && event->val == KM_PRESS)) { + ED_region_draw_cb_exit(region->type, cd->draw_handle); + sd->constant_detail = cd->detail_size; + ss->draw_faded_cursor = false; + MEM_freeN(op->customdata); + ED_region_tag_redraw(region); + ED_workspace_status_text(C, NULL); + return OPERATOR_FINISHED; + } + + ED_region_tag_redraw(region); + + if (event->type == EVT_LEFTCTRLKEY && event->val == KM_PRESS) { + cd->sample_mode = true; + } + if (event->type == EVT_LEFTCTRLKEY && event->val == KM_RELEASE) { + cd->sample_mode = false; + } + + /* Sample mode sets the detail size sampling the average edge length under the surface. */ + if (cd->sample_mode) { + dyntopo_detail_size_sample_from_surface(active_object, cd); + return OPERATOR_RUNNING_MODAL; + } + /* Regular mode, changes the detail size by moving the cursor. */ + dyntopo_detail_size_update_from_mouse_delta(cd, event); + + return OPERATOR_RUNNING_MODAL; +} + +static int dyntopo_detail_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + + /* Fallback to radial control for modes other than SCULPT_DYNTOPO_DETAIL_CONSTANT [same as in + * SCULPT_OT_set_detail_size]. */ + if (!(sd->flags & (SCULPT_DYNTOPO_DETAIL_CONSTANT | SCULPT_DYNTOPO_DETAIL_MANUAL))) { + sculpt_detail_size_set_radial_control(C); + + return OPERATOR_FINISHED; + } + + /* Special method for SCULPT_DYNTOPO_DETAIL_CONSTANT. */ + ARegion *region = CTX_wm_region(C); + Object *active_object = CTX_data_active_object(C); + Brush *brush = BKE_paint_brush(&sd->paint); + + DyntopoDetailSizeEditCustomData *cd = MEM_callocN(sizeof(DyntopoDetailSizeEditCustomData), + "Dyntopo Detail Size Edit OP Custom Data"); + + /* Initial operator Custom Data setup. */ + cd->draw_handle = ED_region_draw_cb_activate( + region->type, dyntopo_detail_size_edit_draw, cd, REGION_DRAW_POST_VIEW); + cd->active_object = active_object; + cd->init_mval[0] = event->mval[0]; + cd->init_mval[1] = event->mval[1]; + cd->detail_size = sd->constant_detail; + cd->init_detail_size = sd->constant_detail; + copy_v4_v4(cd->outline_col, brush->add_col); + op->customdata = cd; + + SculptSession *ss = active_object->sculpt; + cd->radius = ss->cursor_radius; + + /* Generates the matrix to position the gizmo in the surface of the mesh using the same location + * and orientation as the brush cursor. */ + float cursor_trans[4][4], cursor_rot[4][4]; + const float z_axis[4] = {0.0f, 0.0f, 1.0f, 0.0f}; + float quat[4]; + copy_m4_m4(cursor_trans, active_object->obmat); + translate_m4( + cursor_trans, ss->cursor_location[0], ss->cursor_location[1], ss->cursor_location[2]); + + float cursor_normal[3]; + if (!is_zero_v3(ss->cursor_sampled_normal)) { + copy_v3_v3(cursor_normal, ss->cursor_sampled_normal); + } + else { + copy_v3_v3(cursor_normal, ss->cursor_normal); + } + + rotation_between_vecs_to_quat(quat, z_axis, cursor_normal); + quat_to_mat4(cursor_rot, quat); + copy_m4_m4(cd->gizmo_mat, cursor_trans); + mul_m4_m4_post(cd->gizmo_mat, cursor_rot); + + /* Initize the position of the triangle vertices. */ + const float y_axis[3] = {0.0f, cd->radius, 0.0f}; + for (int i = 0; i < 3; i++) { + zero_v3(cd->preview_tri[i]); + rotate_v2_v2fl(cd->preview_tri[i], y_axis, DEG2RAD(120.0f * i)); + } + + SCULPT_vertex_random_access_ensure(ss); + + WM_event_add_modal_handler(C, op); + ED_region_tag_redraw(region); + + ss->draw_faded_cursor = true; + + const char *status_str = TIP_( + "Move the mouse to change the dyntopo detail size. LMB: confirm size, ESC/RMB: cancel"); + ED_workspace_status_text(C, status_str); + + return OPERATOR_RUNNING_MODAL; +} + +void SCULPT_OT_dyntopo_detail_size_edit(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Edit Dyntopo Detail Size"; + ot->description = "Modify the detail size of dyntopo interactively"; + ot->idname = "SCULPT_OT_dyntopo_detail_size_edit"; + + /* api callbacks */ + ot->poll = sculpt_and_dynamic_topology_poll; + ot->invoke = dyntopo_detail_size_edit_invoke; + ot->modal = dyntopo_detail_size_edit_modal; + ot->cancel = dyntopo_detail_size_edit_cancel; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} diff --git a/source/blender/editors/sculpt_paint/sculpt_face_set.c b/source/blender/editors/sculpt_paint/sculpt_face_set.c index df03d2adeaf..332e551c577 100644 --- a/source/blender/editors/sculpt_paint/sculpt_face_set.c +++ b/source/blender/editors/sculpt_paint/sculpt_face_set.c @@ -447,6 +447,7 @@ typedef enum eSculptFaceSetsInitMode { SCULPT_FACE_SETS_FROM_SHARP_EDGES = 5, SCULPT_FACE_SETS_FROM_BEVEL_WEIGHT = 6, SCULPT_FACE_SETS_FROM_FACE_MAPS = 7, + SCULPT_FACE_SETS_FROM_FACE_SET_BOUNDARIES = 8, } eSculptFaceSetsInitMode; static EnumPropertyItem prop_sculpt_face_sets_init_types[] = { @@ -506,6 +507,14 @@ static EnumPropertyItem prop_sculpt_face_sets_init_types[] = { "Face Sets from Face Maps", "Create a Face Set per Face Map", }, + { + SCULPT_FACE_SETS_FROM_FACE_SET_BOUNDARIES, + "FACE_SET_BOUNDARIES", + 0, + "Face Sets from Face Set Boundaries", + "Create a Face Set per isolated Face Set", + }, + {0, NULL, 0, NULL, NULL}, }; @@ -557,6 +566,14 @@ static bool sculpt_face_sets_init_sharp_edges_test(BMesh *UNUSED(bm), return BM_elem_flag_test(from_e, BM_ELEM_SMOOTH); } +static bool sculpt_face_sets_init_face_set_boundary_test( + BMesh *bm, BMFace *from_f, BMEdge *UNUSED(from_e), BMFace *to_f, const float UNUSED(threshold)) +{ + const int cd_face_sets_offset = CustomData_get_offset(&bm->pdata, CD_SCULPT_FACE_SETS); + return BM_ELEM_CD_GET_INT(from_f, cd_face_sets_offset) == + BM_ELEM_CD_GET_INT(to_f, cd_face_sets_offset); +} + static void sculpt_face_sets_init_flood_fill(Object *ob, face_sets_flood_fill_test test, const float threshold) @@ -725,6 +742,10 @@ static int sculpt_face_set_init_exec(bContext *C, wmOperator *op) case SCULPT_FACE_SETS_FROM_BEVEL_WEIGHT: sculpt_face_sets_init_flood_fill(ob, sculpt_face_sets_init_bevel_weight_test, threshold); break; + case SCULPT_FACE_SETS_FROM_FACE_SET_BOUNDARIES: + sculpt_face_sets_init_flood_fill( + ob, sculpt_face_sets_init_face_set_boundary_test, threshold); + break; case SCULPT_FACE_SETS_FROM_FACE_MAPS: sculpt_face_sets_init_loop(ob, SCULPT_FACE_SETS_FROM_FACE_MAPS); break; diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 19c4eda7593..16c2996e392 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -1360,6 +1360,7 @@ void SCULPT_OT_mask_expand(struct wmOperatorType *ot); void SCULPT_OT_detail_flood_fill(struct wmOperatorType *ot); void SCULPT_OT_sample_detail_size(struct wmOperatorType *ot); void SCULPT_OT_set_detail_size(struct wmOperatorType *ot); +void SCULPT_OT_dyntopo_detail_size_edit(struct wmOperatorType *ot); /* Dyntopo. */ void SCULPT_OT_dynamic_topology_toggle(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_api/CMakeLists.txt b/source/blender/editors/space_api/CMakeLists.txt index 4b77b4da668..8af28baa5c2 100644 --- a/source/blender/editors/space_api/CMakeLists.txt +++ b/source/blender/editors/space_api/CMakeLists.txt @@ -50,6 +50,7 @@ set(LIB bf_editor_space_outliner bf_editor_space_script bf_editor_space_sequencer + bf_editor_space_spreadsheet bf_editor_space_statusbar bf_editor_space_text bf_editor_space_topbar diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c index 54320a02f2f..48e4c4ce575 100644 --- a/source/blender/editors/space_api/spacetypes.c +++ b/source/blender/editors/space_api/spacetypes.c @@ -99,6 +99,7 @@ void ED_spacetypes_init(void) ED_spacetype_clip(); ED_spacetype_statusbar(); ED_spacetype_topbar(); + ED_spacetype_spreadsheet(); /* Register operator types for screen and all spaces. */ ED_operatortypes_userpref(); @@ -270,7 +271,7 @@ void ED_region_draw_cb_exit(ARegionType *art, void *handle) void ED_region_draw_cb_draw(const bContext *C, ARegion *region, int type) { - LISTBASE_FOREACH (RegionDrawCB *, rdc, ®ion->type->drawcalls) { + LISTBASE_FOREACH_MUTABLE (RegionDrawCB *, rdc, ®ion->type->drawcalls) { if (rdc->type == type) { rdc->draw(C, region, rdc->customdata); diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index 56fb588776e..309b280177c 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -75,6 +75,7 @@ void FILE_OT_rename(struct wmOperatorType *ot); void FILE_OT_smoothscroll(struct wmOperatorType *ot); void FILE_OT_filepath_drop(struct wmOperatorType *ot); void FILE_OT_start_filter(struct wmOperatorType *ot); +void FILE_OT_view_selected(struct wmOperatorType *ot); void file_directory_enter_handle(bContext *C, void *arg_unused, void *arg_but); void file_filename_enter_handle(bContext *C, void *arg_unused, void *arg_but); @@ -112,6 +113,21 @@ int autocomplete_file(struct bContext *C, char *str, void *arg_v); void file_params_renamefile_activate(struct SpaceFile *sfile, struct FileSelectParams *params); +typedef void *onReloadFnData; +typedef void (*onReloadFn)(struct SpaceFile *space_data, onReloadFnData custom_data); +typedef struct SpaceFile_Runtime { + /* Called once after the file browser has reloaded. Reset to NULL after calling. + * Use file_on_reload_callback_register() to register a callback. */ + onReloadFn on_reload; + onReloadFnData on_reload_custom_data; +} SpaceFile_Runtime; + +/* Register an on-reload callback function. Note that there can only be one such function at a + * time; registering a new one will overwrite the previous one. */ +void file_on_reload_callback_register(struct SpaceFile *sfile, + onReloadFn callback, + onReloadFnData custom_data); + /* file_panels.c */ void file_tool_props_region_panels_register(struct ARegionType *art); void file_execute_region_panels_register(struct ARegionType *art); diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 985c92f19b6..b82290205c7 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -256,6 +256,33 @@ static bool file_is_any_selected(struct FileList *files) return false; } +static FileSelection file_current_selection_range_get(struct FileList *files) +{ + const int numfiles = filelist_files_ensure(files); + FileSelection selection = {-1, -1}; + + /* Iterate over the files once but in two loops, one to find the first selected file, and the + * other to find the last. */ + + int file_index; + for (file_index = 0; file_index < numfiles; file_index++) { + if (filelist_entry_is_selected(files, file_index)) { + /* First selected entry found. */ + selection.first = file_index; + break; + } + } + + for (; file_index < numfiles; file_index++) { + if (filelist_entry_is_selected(files, file_index)) { + selection.last = file_index; + /* Keep looping, we may find more selected files. */ + } + } + + return selection; +} + /** * If \a file is outside viewbounds, this adjusts view to make sure it's inside */ @@ -299,6 +326,24 @@ static void file_ensure_inside_viewbounds(ARegion *region, SpaceFile *sfile, con } } +static void file_ensure_selection_inside_viewbounds(ARegion *region, + SpaceFile *sfile, + FileSelection *sel) +{ + const FileLayout *layout = ED_fileselect_get_layout(sfile, region); + + if (((layout->flag & FILE_LAYOUT_HOR) && region->winx <= (1.2f * layout->tile_w)) && + ((layout->flag & FILE_LAYOUT_VER) && region->winy <= (2.0f * layout->tile_h))) { + return; + } + + /* Adjust view to display selection. Doing iterations for first and last + * selected item makes view showing as much of the selection possible. + * Not really useful if tiles are (almost) bigger than viewbounds though. */ + file_ensure_inside_viewbounds(region, sfile, sel->last); + file_ensure_inside_viewbounds(region, sfile, sel->first); +} + static FileSelect file_select( bContext *C, const rcti *rect, FileSelType select, bool fill, bool do_diropen) { @@ -330,16 +375,7 @@ static FileSelect file_select( } else if (sel.last >= 0) { ARegion *region = CTX_wm_region(C); - const FileLayout *layout = ED_fileselect_get_layout(sfile, region); - - /* Adjust view to display selection. Doing iterations for first and last - * selected item makes view showing as much of the selection possible. - * Not really useful if tiles are (almost) bigger than viewbounds though. */ - if (((layout->flag & FILE_LAYOUT_HOR) && region->winx > (1.2f * layout->tile_w)) || - ((layout->flag & FILE_LAYOUT_VER) && region->winy > (2.0f * layout->tile_h))) { - file_ensure_inside_viewbounds(region, sfile, sel.last); - file_ensure_inside_viewbounds(region, sfile, sel.first); - } + file_ensure_selection_inside_viewbounds(region, sfile, &sel); } /* update operator for name change event */ @@ -926,6 +962,55 @@ void FILE_OT_select_all(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Select All Operator + * \{ */ + +static int file_view_selected_exec(bContext *C, wmOperator *UNUSED(op)) +{ + SpaceFile *sfile = CTX_wm_space_file(C); + FileSelection sel = file_current_selection_range_get(sfile->files); + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + + if (sel.first == -1 && sel.last == -1 && params->active_file == -1) { + /* Nothing was selected. */ + return OPERATOR_CANCELLED; + } + + /* Extend the selection area with the active file, as it may not be selected but still is + * important to have in view. */ + if (sel.first == -1 || params->active_file < sel.first) { + sel.first = params->active_file; + } + if (sel.last == -1 || params->active_file > sel.last) { + sel.last = params->active_file; + } + + ScrArea *area = CTX_wm_area(C); + ARegion *region = CTX_wm_region(C); + file_ensure_selection_inside_viewbounds(region, sfile, &sel); + + file_draw_check(C); + WM_event_add_mousemove(CTX_wm_window(C)); + ED_area_tag_redraw(area); + + return OPERATOR_FINISHED; +} + +void FILE_OT_view_selected(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Frame Selected"; + ot->description = "Scroll the selected files into view"; + ot->idname = "FILE_OT_view_selected"; + + /* api callbacks */ + ot->exec = file_view_selected_exec; + ot->poll = ED_operator_file_active; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Select Bookmark Operator * \{ */ diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index 33c37875372..f5ec9a0e8a1 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -410,14 +410,14 @@ typedef struct FileList { /* Set given path as root directory, * if last bool is true may change given string in place to a valid value. * Returns True if valid dir. */ - bool (*checkdirf)(struct FileList *, char *, const bool); + bool (*check_dir_fn)(struct FileList *, char *, const bool); /* Fill filelist (to be called by read job). */ - void (*read_jobf)( + void (*read_job_fn)( Main *, struct FileList *, const char *, short *, short *, float *, ThreadMutex *); /* Filter an entry of current filelist. */ - bool (*filterf)(struct FileListInternEntry *, const char *, FileListFilter *); + bool (*filter_fn)(struct FileListInternEntry *, const char *, FileListFilter *); short tags; /* FileListTags */ } FileList; @@ -963,7 +963,7 @@ void filelist_filter(FileList *filelist) /* 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) { - if (filelist->filterf(file, filelist->filelist.root, &filelist->filter_data)) { + if (filelist->filter_fn(file, filelist->filelist.root, &filelist->filter_data)) { filtered_tmp[num_filtered++] = file; } } @@ -1742,25 +1742,25 @@ void filelist_settype(FileList *filelist, short type) filelist->tags = 0; switch (filelist->type) { case FILE_MAIN: - filelist->checkdirf = filelist_checkdir_main; - filelist->read_jobf = filelist_readjob_main; - filelist->filterf = is_filtered_main; + filelist->check_dir_fn = filelist_checkdir_main; + filelist->read_job_fn = filelist_readjob_main; + filelist->filter_fn = is_filtered_main; break; case FILE_LOADLIB: - filelist->checkdirf = filelist_checkdir_lib; - filelist->read_jobf = filelist_readjob_lib; - filelist->filterf = is_filtered_lib; + filelist->check_dir_fn = filelist_checkdir_lib; + filelist->read_job_fn = filelist_readjob_lib; + filelist->filter_fn = is_filtered_lib; break; case FILE_MAIN_ASSET: - filelist->checkdirf = filelist_checkdir_main_assets; - filelist->read_jobf = filelist_readjob_main_assets; - filelist->filterf = is_filtered_main_assets; + filelist->check_dir_fn = filelist_checkdir_main_assets; + filelist->read_job_fn = filelist_readjob_main_assets; + filelist->filter_fn = is_filtered_main_assets; filelist->tags |= FILELIST_TAGS_USES_MAIN_DATA | FILELIST_TAGS_NO_THREADS; break; default: - filelist->checkdirf = filelist_checkdir_dir; - filelist->read_jobf = filelist_readjob_dir; - filelist->filterf = is_filtered_file; + filelist->check_dir_fn = filelist_checkdir_dir; + filelist->read_job_fn = filelist_readjob_dir; + filelist->filter_fn = is_filtered_file; break; } @@ -1867,7 +1867,7 @@ const char *filelist_dir(struct FileList *filelist) bool filelist_is_dir(struct FileList *filelist, const char *path) { - return filelist->checkdirf(filelist, (char *)path, false); + return filelist->check_dir_fn(filelist, (char *)path, false); } /** @@ -1879,7 +1879,7 @@ void filelist_setdir(struct FileList *filelist, char *r_dir) BLI_assert(strlen(r_dir) < FILE_MAX_LIBEXTRA); BLI_path_normalize_dir(BKE_main_blendfile_path_from_global(), r_dir); - const bool is_valid_path = filelist->checkdirf(filelist, r_dir, !allow_invalid); + const bool is_valid_path = filelist->check_dir_fn(filelist, r_dir, !allow_invalid); BLI_assert(is_valid_path || allow_invalid); UNUSED_VARS_NDEBUG(is_valid_path); @@ -1990,9 +1990,7 @@ static void filelist_file_release_entry(FileList *filelist, FileDirEntry *entry) filelist_entry_free(entry); } -static FileDirEntry *filelist_file_ex(struct FileList *filelist, - const int index, - const bool use_request) +FileDirEntry *filelist_file_ex(struct FileList *filelist, const int index, const bool use_request) { FileDirEntry *ret = NULL, *old; FileListEntryCache *cache = &filelist->filelist_cache; @@ -2703,6 +2701,19 @@ uint filelist_entry_select_index_get(FileList *filelist, const int index, FileCh return 0; } +bool filelist_entry_is_selected(FileList *filelist, const int index) +{ + BLI_assert(index >= 0 && index < filelist->filelist.nbr_entries_filtered); + FileListInternEntry *intern_entry = filelist->filelist_intern.filtered[index]; + + /* BLI_ghash_lookup returns NULL if not found, which gets mapped to 0, which gets mapped to + * "not selected". */ + const uint selection_state = POINTER_AS_UINT( + BLI_ghash_lookup(filelist->selection_state, intern_entry->uuid)); + + return selection_state != 0; +} + /** * Set selection of the '..' parent entry, but only if it's actually visible. */ @@ -3358,13 +3369,13 @@ static void filelist_readjob_startjob(void *flrjv, short *stop, short *do_update BLI_mutex_unlock(&flrj->lock); - flrj->tmp_filelist->read_jobf(flrj->current_main, - flrj->tmp_filelist, - flrj->main_name, - stop, - do_update, - progress, - &flrj->lock); + flrj->tmp_filelist->read_job_fn(flrj->current_main, + flrj->tmp_filelist, + flrj->main_name, + stop, + do_update, + progress, + &flrj->lock); } static void filelist_readjob_update(void *flrjv) @@ -3464,7 +3475,7 @@ void filelist_readjob_start(FileList *filelist, const bContext *C) filelist_readjob_endjob(flrj); filelist_readjob_free(flrj); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST, NULL); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_FILE_LIST | NA_JOB_FINISHED, NULL); return; } @@ -3476,7 +3487,10 @@ void filelist_readjob_start(FileList *filelist, const bContext *C) WM_JOB_PROGRESS, WM_JOB_TYPE_FILESEL_READDIR); WM_jobs_customdata_set(wm_job, flrj, filelist_readjob_free); - WM_jobs_timer(wm_job, 0.01, NC_SPACE | ND_SPACE_FILE_LIST, NC_SPACE | ND_SPACE_FILE_LIST); + WM_jobs_timer(wm_job, + 0.01, + NC_SPACE | ND_SPACE_FILE_LIST, + NC_SPACE | ND_SPACE_FILE_LIST | NA_JOB_FINISHED); WM_jobs_callbacks( wm_job, filelist_readjob_startjob, NULL, filelist_readjob_update, filelist_readjob_endjob); diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h index 16984bb6e43..9eb70dd8437 100644 --- a/source/blender/editors/space_file/filelist.h +++ b/source/blender/editors/space_file/filelist.h @@ -93,6 +93,8 @@ void filelist_setdir(struct FileList *filelist, char *r_dir); int filelist_files_ensure(struct FileList *filelist); int filelist_needs_reading(struct FileList *filelist); FileDirEntry *filelist_file(struct FileList *filelist, int index); +FileDirEntry *filelist_file_ex(struct FileList *filelist, int index, bool use_request); + int filelist_file_findpath(struct FileList *filelist, const char *file); struct ID *filelist_file_get_id(const struct FileDirEntry *file); FileDirEntry *filelist_entry_find_uuid(struct FileList *filelist, const int uuid[4]); @@ -126,6 +128,7 @@ unsigned int filelist_entry_select_get(struct FileList *filelist, unsigned int filelist_entry_select_index_get(struct FileList *filelist, const int index, FileCheckType check); +bool filelist_entry_is_selected(struct FileList *filelist, const int index); void filelist_entry_parent_select_set(struct FileList *filelist, FileSelType select, unsigned int flag, diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index 6917893ab5f..7015ca970a3 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -454,6 +454,66 @@ bool ED_fileselect_is_asset_browser(const SpaceFile *sfile) return (sfile->browse_mode == FILE_BROWSE_MODE_ASSETS); } +struct ID *ED_fileselect_active_asset_get(const SpaceFile *sfile) +{ + if (!ED_fileselect_is_asset_browser(sfile)) { + return NULL; + } + + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + const FileDirEntry *file = filelist_file(sfile->files, params->active_file); + if (file == NULL) { + return NULL; + } + + return filelist_file_get_id(file); +} + +static void on_reload_activate_by_id(SpaceFile *sfile, onReloadFnData custom_data) +{ + ID *asset_id = (ID *)custom_data; + ED_fileselect_activate_by_id(sfile, asset_id, false); +} + +void ED_fileselect_activate_by_id(SpaceFile *sfile, ID *asset_id, const bool deferred) +{ + if (!ED_fileselect_is_asset_browser(sfile)) { + return; + } + + /* If there are filelist operations running now ("pending" true) or soon ("force reset" true), + * there is a fair chance that the to-be-activated ID will only be present after these operations + * have completed. Defer activation until then. */ + if (deferred || filelist_pending(sfile->files) || filelist_needs_force_reset(sfile->files)) { + /* This should be thread-safe, as this function is likely called from the main thread, and + * notifiers (which cause a call to the on-reload callback function) are handled on the main + * thread as well. */ + file_on_reload_callback_register(sfile, on_reload_activate_by_id, asset_id); + return; + } + + FileSelectParams *params = ED_fileselect_get_active_params(sfile); + struct FileList *files = sfile->files; + + const int num_files_filtered = filelist_files_ensure(files); + for (int file_index = 0; file_index < num_files_filtered; ++file_index) { + const FileDirEntry *file = filelist_file_ex(files, file_index, false); + + if (filelist_file_get_id(file) != asset_id) { + filelist_entry_select_set(files, file, FILE_SEL_REMOVE, FILE_SEL_SELECTED, CHECK_ALL); + continue; + } + + params->active_file = file_index; + filelist_entry_select_set(files, file, FILE_SEL_ADD, FILE_SEL_SELECTED, CHECK_ALL); + + /* Keep looping to deselect the other files. */ + } + + WM_main_add_notifier(NC_ASSET | NA_ACTIVATED, NULL); + WM_main_add_notifier(NC_ASSET | NA_SELECTED, NULL); +} + /* The subset of FileSelectParams.flag items we store into preferences. Note that FILE_SORT_ALPHA * may also be remembered, but only conditionally. */ #define PARAMS_FLAGS_REMEMBERED (FILE_HIDE_DOT) diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index b175844a710..83bb8abf5d8 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -173,6 +173,7 @@ static void file_free(SpaceLink *sl) MEM_SAFE_FREE(sfile->params); MEM_SAFE_FREE(sfile->asset_params); + MEM_SAFE_FREE(sfile->runtime); if (sfile->layout) { MEM_freeN(sfile->layout); @@ -188,6 +189,10 @@ static void file_init(wmWindowManager *UNUSED(wm), ScrArea *area) if (sfile->layout) { sfile->layout->dirty = true; } + + if (sfile->runtime == NULL) { + sfile->runtime = MEM_callocN(sizeof(*sfile->runtime), __func__); + } } static void file_exit(wmWindowManager *wm, ScrArea *area) @@ -209,6 +214,7 @@ static SpaceLink *file_duplicate(SpaceLink *sl) /* clear or remove stuff from old */ sfilen->op = NULL; /* file window doesn't own operators */ + sfilen->runtime = NULL; sfilen->previews_timer = NULL; sfilen->smoothscroll_timer = NULL; @@ -392,6 +398,26 @@ static void file_refresh(const bContext *C, ScrArea *area) ED_area_tag_redraw(area); } +void file_on_reload_callback_register(SpaceFile *sfile, + onReloadFn callback, + onReloadFnData custom_data) +{ + sfile->runtime->on_reload = callback; + sfile->runtime->on_reload_custom_data = custom_data; +} + +static void file_on_reload_callback_call(SpaceFile *sfile) +{ + if (sfile->runtime->on_reload == NULL) { + return; + } + + sfile->runtime->on_reload(sfile, sfile->runtime->on_reload_custom_data); + + sfile->runtime->on_reload = NULL; + sfile->runtime->on_reload_custom_data = NULL; +} + static void file_listener(const wmSpaceTypeListenerParams *params) { ScrArea *area = params->area; @@ -419,12 +445,27 @@ static void file_listener(const wmSpaceTypeListenerParams *params) } break; } + switch (wmn->action) { + case NA_JOB_FINISHED: + file_on_reload_callback_call(sfile); + break; + } break; case NC_ASSET: { - if (sfile->files && filelist_needs_reset_on_main_changes(sfile->files)) { - /* Full refresh of the file list if local asset data was changed. Refreshing this view is - * cheap and users expect this to be updated immediately. */ - file_tag_reset_list(area, sfile); + switch (wmn->action) { + case NA_SELECTED: + case NA_ACTIVATED: + ED_area_tag_refresh(area); + break; + case NA_ADDED: + case NA_REMOVED: + case NA_EDITED: + if (sfile->files && filelist_needs_reset_on_main_changes(sfile->files)) { + /* Full refresh of the file list if local asset data was changed. Refreshing this view + * is cheap and users expect this to be updated immediately. */ + file_tag_reset_list(area, sfile); + } + break; } break; } @@ -464,8 +505,7 @@ static void file_main_region_listener(const wmRegionListenerParams *params) } break; case NC_ID: - if (ELEM(wmn->action, NA_RENAME)) { - /* In case the filelist shows ID names. */ + if (ELEM(wmn->action, NA_SELECTED, NA_ACTIVATED, NA_RENAME)) { ED_region_tag_redraw(region); } break; @@ -620,6 +660,7 @@ static void file_operatortypes(void) WM_operatortype_append(FILE_OT_smoothscroll); WM_operatortype_append(FILE_OT_filepath_drop); WM_operatortype_append(FILE_OT_start_filter); + WM_operatortype_append(FILE_OT_view_selected); } /* NOTE: do not add .blend file reading on this level */ diff --git a/source/blender/editors/space_graph/graph_draw.c b/source/blender/editors/space_graph/graph_draw.c index 4752f62b58c..c5358cdfa5b 100644 --- a/source/blender/editors/space_graph/graph_draw.c +++ b/source/blender/editors/space_graph/graph_draw.c @@ -35,6 +35,7 @@ #include "DNA_userdef_types.h" #include "DNA_windowmanager_types.h" +#include "BKE_action.h" #include "BKE_anim_data.h" #include "BKE_context.h" #include "BKE_curve.h" @@ -579,8 +580,13 @@ static void draw_fcurve_samples(SpaceGraph *sipo, ARegion *region, FCurve *fcu) /* Helper func - just draw the F-Curve by sampling the visible region * (for drawing curves with modifiers). */ -static void draw_fcurve_curve( - bAnimContext *ac, ID *id, FCurve *fcu_, View2D *v2d, uint pos, const bool use_nla_remap) +static void draw_fcurve_curve(bAnimContext *ac, + ID *id, + FCurve *fcu_, + View2D *v2d, + uint pos, + const bool use_nla_remap, + const bool draw_extrapolation) { SpaceGraph *sipo = (SpaceGraph *)ac->sl; short mapping_flag = ANIM_get_normalization_flags(ac); @@ -641,40 +647,90 @@ static void draw_fcurve_curve( /* the start/end times are simply the horizontal extents of the 'cur' rect */ float stime = v2d->cur.xmin; - float etime = v2d->cur.xmax + - samplefreq; /* + samplefreq here so that last item gets included... */ + float etime = v2d->cur.xmax; - /* at each sampling interval, add a new vertex - * - apply the unit correction factor to the calculated values so that - * the displayed values appear correctly in the viewport - */ + AnimData *adt = use_nla_remap ? BKE_animdata_from_id(id) : NULL; + + /* If not drawing extrapolation, then change fcurve drawing bounds to its keyframe bounds clamped + * by graph editor bounds. */ + if (!draw_extrapolation) { + float fcu_start = 0; + float fcu_end = 0; + BKE_fcurve_calc_range(fcu_, &fcu_start, &fcu_end, false, false); - int n = roundf((etime - stime) / samplefreq); + fcu_start = BKE_nla_tweakedit_remap(adt, fcu_start, NLATIME_CONVERT_MAP); + fcu_end = BKE_nla_tweakedit_remap(adt, fcu_end, NLATIME_CONVERT_MAP); - if (n > 0) { - immBegin(GPU_PRIM_LINE_STRIP, (n + 1)); + /* Account for reversed NLA strip effect. */ + if (fcu_end < fcu_start) { + SWAP(float, fcu_start, fcu_end); + } - AnimData *adt = use_nla_remap ? BKE_animdata_from_id(id) : NULL; - /* NLA remapping is linear so we don't have to remap per iteration. */ - const float eval_start = BKE_nla_tweakedit_remap(adt, stime, NLATIME_CONVERT_UNMAP); - const float eval_freq = BKE_nla_tweakedit_remap( - adt, stime + samplefreq, NLATIME_CONVERT_UNMAP) - - eval_start; + /* Clamp to graph editor rendering bounds. */ + stime = max_ff(stime, fcu_start); + etime = min_ff(etime, fcu_end); + } + + const int total_samples = roundf((etime - stime) / samplefreq); + if (total_samples <= 0) { + return; + } - for (int i = 0; i <= n; i++) { - float ctime = stime + i * samplefreq; - const float eval_time = eval_start + i * eval_freq; - immVertex2f(pos, ctime, (evaluate_fcurve(&fcurve_for_draw, eval_time) + offset) * unitFac); + /* NLA remapping is linear so we don't have to remap per iteration. */ + const float eval_start = BKE_nla_tweakedit_remap(adt, stime, NLATIME_CONVERT_UNMAP); + const float eval_freq = BKE_nla_tweakedit_remap(adt, stime + samplefreq, NLATIME_CONVERT_UNMAP) - + eval_start; + const float eval_end = BKE_nla_tweakedit_remap(adt, etime, NLATIME_CONVERT_UNMAP); + + immBegin(GPU_PRIM_LINE_STRIP, (total_samples + 1)); + + /* At each sampling interval, add a new vertex. + * + * Apply the unit correction factor to the calculated values so that the displayed values appear + * correctly in the viewport. + */ + for (int i = 0; i < total_samples; i++) { + const float ctime = stime + i * samplefreq; + float eval_time = eval_start + i * eval_freq; + + /* Prevent drawing past bounds, due to floating point problems. + * User-wise, prevent visual flickering. + * + * This is to cover the case where: + * eval_start + total_samples * eval_freq > eval_end + * due to floating point problems. + */ + if (eval_time > eval_end) { + eval_time = eval_end; } - immEnd(); + immVertex2f(pos, ctime, (evaluate_fcurve(&fcurve_for_draw, eval_time) + offset) * unitFac); } + + /* Ensure we include end boundary point. + * User-wise, prevent visual flickering. + * + * This is to cover the case where: + * eval_start + total_samples * eval_freq < eval_end + * due to floating point problems. + */ + immVertex2f(pos, etime, (evaluate_fcurve(&fcurve_for_draw, eval_end) + offset) * unitFac); + + immEnd(); } /* helper func - draw a samples-based F-Curve */ -static void draw_fcurve_curve_samples( - bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d, const uint shdr_pos) +static void draw_fcurve_curve_samples(bAnimContext *ac, + ID *id, + FCurve *fcu, + View2D *v2d, + const uint shdr_pos, + const bool draw_extrapolation) { + if (!draw_extrapolation && fcu->totvert == 1) { + return; + } + FPoint *prevfpt = fcu->fpt; FPoint *fpt = prevfpt + 1; float fac, v[2]; @@ -683,11 +739,13 @@ static void draw_fcurve_curve_samples( short mapping_flag = ANIM_get_normalization_flags(ac); int count = fcu->totvert; - if (prevfpt->vec[0] > v2d->cur.xmin) { + const bool extrap_left = draw_extrapolation && prevfpt->vec[0] > v2d->cur.xmin; + if (extrap_left) { count++; } - if ((prevfpt + b - 1)->vec[0] < v2d->cur.xmax) { + const bool extrap_right = draw_extrapolation && (prevfpt + b - 1)->vec[0] < v2d->cur.xmax; + if (extrap_right) { count++; } @@ -700,7 +758,7 @@ static void draw_fcurve_curve_samples( immBegin(GPU_PRIM_LINE_STRIP, count); /* extrapolate to left? - left-side of view comes before first keyframe? */ - if (prevfpt->vec[0] > v2d->cur.xmin) { + if (extrap_left) { v[0] = v2d->cur.xmin; /* y-value depends on the interpolation */ @@ -734,7 +792,7 @@ static void draw_fcurve_curve_samples( } /* extrapolate to right? (see code for left-extrapolation above too) */ - if (prevfpt->vec[0] < v2d->cur.xmax) { + if (extrap_right) { v[0] = v2d->cur.xmax; /* y-value depends on the interpolation */ @@ -779,8 +837,13 @@ static bool fcurve_can_use_simple_bezt_drawing(FCurve *fcu) } /* helper func - draw one repeat of an F-Curve (using Bezier curve approximations) */ -static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d, uint pos) +static void draw_fcurve_curve_bezts( + bAnimContext *ac, ID *id, FCurve *fcu, View2D *v2d, uint pos, const bool draw_extrapolation) { + if (!draw_extrapolation && fcu->totvert == 1) { + return; + } + BezTriple *prevbezt = fcu->bezt; BezTriple *bezt = prevbezt + 1; float v1[2], v2[2], v3[2], v4[2]; @@ -803,7 +866,7 @@ static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2 immBeginAtMost(GPU_PRIM_LINE_STRIP, (b * 32 + 3)); /* extrapolate to left? */ - if (prevbezt->vec[1][0] > v2d->cur.xmin) { + if (draw_extrapolation && prevbezt->vec[1][0] > v2d->cur.xmin) { /* left-side of view comes before first keyframe, so need to extend as not cyclic */ v1[0] = v2d->cur.xmin; @@ -923,7 +986,7 @@ static void draw_fcurve_curve_bezts(bAnimContext *ac, ID *id, FCurve *fcu, View2 } /* extrapolate to right? (see code for left-extrapolation above too) */ - if (prevbezt->vec[1][0] < v2d->cur.xmax) { + if (draw_extrapolation && prevbezt->vec[1][0] < v2d->cur.xmax) { v1[0] = v2d->cur.xmax; /* y-value depends on the interpolation */ @@ -1026,6 +1089,7 @@ static void draw_fcurve(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, bAn immUniformColor3fvAlpha(fcu->color, fcurve_display_alpha(fcu)); } + const bool draw_extrapolation = (sipo->flag & SIPO_NO_DRAW_EXTRAPOLATION) == 0; /* draw F-Curve */ if ((fcu->modifiers.first) || (fcu->flag & FCURVE_INT_VALUES)) { /* draw a curve affected by modifiers or only allowed to have integer values @@ -1039,25 +1103,25 @@ static void draw_fcurve(bAnimContext *ac, SpaceGraph *sipo, ARegion *region, bAn * curve itself. Afterward, we go back and redo the keyframe remapping so the controls are * drawn properly. */ ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, true, false); - draw_fcurve_curve(ac, ale->id, fcu, ®ion->v2d, shdr_pos, true); + draw_fcurve_curve(ac, ale->id, fcu, ®ion->v2d, shdr_pos, true, draw_extrapolation); ANIM_nla_mapping_apply_fcurve(adt, ale->key_data, false, false); } else { - draw_fcurve_curve(ac, ale->id, fcu, ®ion->v2d, shdr_pos, false); + draw_fcurve_curve(ac, ale->id, fcu, ®ion->v2d, shdr_pos, false, draw_extrapolation); } } else if (((fcu->bezt) || (fcu->fpt)) && (fcu->totvert)) { /* just draw curve based on defined data (i.e. no modifiers) */ if (fcu->bezt) { if (fcurve_can_use_simple_bezt_drawing(fcu)) { - draw_fcurve_curve_bezts(ac, ale->id, fcu, ®ion->v2d, shdr_pos); + draw_fcurve_curve_bezts(ac, ale->id, fcu, ®ion->v2d, shdr_pos, draw_extrapolation); } else { - draw_fcurve_curve(ac, ale->id, fcu, ®ion->v2d, shdr_pos, false); + draw_fcurve_curve(ac, ale->id, fcu, ®ion->v2d, shdr_pos, false, draw_extrapolation); } } else if (fcu->fpt) { - draw_fcurve_curve_samples(ac, ale->id, fcu, ®ion->v2d, shdr_pos); + draw_fcurve_curve_samples(ac, ale->id, fcu, ®ion->v2d, shdr_pos, draw_extrapolation); } } @@ -1278,6 +1342,7 @@ void graph_draw_ghost_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region immUniform1f("dash_width", 20.0f); immUniform1f("dash_factor", 0.5f); + const bool draw_extrapolation = (sipo->flag & SIPO_NO_DRAW_EXTRAPOLATION) == 0; /* the ghost curves are simply sampled F-Curves stored in sipo->runtime.ghost_curves */ for (fcu = sipo->runtime.ghost_curves.first; fcu; fcu = fcu->next) { /* set whatever color the curve has set @@ -1287,7 +1352,7 @@ void graph_draw_ghost_curves(bAnimContext *ac, SpaceGraph *sipo, ARegion *region immUniformColor3fvAlpha(fcu->color, 0.5f); /* simply draw the stored samples */ - draw_fcurve_curve_samples(ac, NULL, fcu, ®ion->v2d, shdr_pos); + draw_fcurve_curve_samples(ac, NULL, fcu, ®ion->v2d, shdr_pos, draw_extrapolation); } immUnbindProgram(); diff --git a/source/blender/editors/space_graph/graph_slider_ops.c b/source/blender/editors/space_graph/graph_slider_ops.c index 3e52dc7377b..4174e1c63ae 100644 --- a/source/blender/editors/space_graph/graph_slider_ops.c +++ b/source/blender/editors/space_graph/graph_slider_ops.c @@ -187,11 +187,11 @@ static void decimate_draw_status_header(wmOperator *op, tDecimateGraphOp *dgo) strcpy(mode_str, TIP_("Decimate Keyframes")); if (hasNumInput(&dgo->num)) { - char str_offs[NUM_STR_REP_LEN]; + char str_ofs[NUM_STR_REP_LEN]; - outputNumInput(&dgo->num, str_offs, &dgo->scene->unit); + outputNumInput(&dgo->num, str_ofs, &dgo->scene->unit); - BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_offs); + BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs); } else { float percentage = RNA_property_float_get(op->ptr, dgo->percentage_prop); diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 977c2053187..a9a7ef5a0a2 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -3385,7 +3385,12 @@ static void std_node_socket_draw( } } break; - case SOCK_RGBA: + case SOCK_RGBA: { + uiLayout *row = uiLayoutSplit(layout, 0.5f, false); + uiItemL(row, text, 0); + uiItemR(row, ptr, "default_value", DEFAULT_FLAGS, "", 0); + break; + } case SOCK_STRING: { uiLayout *row = uiLayoutSplit(layout, 0.5f, false); uiItemL(row, text, 0); diff --git a/source/blender/editors/space_node/node_geometry_attribute_search.cc b/source/blender/editors/space_node/node_geometry_attribute_search.cc index 982c57eb3ec..b03346577a8 100644 --- a/source/blender/editors/space_node/node_geometry_attribute_search.cc +++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc @@ -75,15 +75,9 @@ static void attribute_search_update_fn( UI_search_item_add(items, str, (void *)str, ICON_X, 0, 0); } - /* Skip the filter when the menu is first opened, so all of the items are visible. */ - if (is_first) { - for (const std::string &attribute_name : attribute_name_hints) { - /* Just use the pointer to the name string as the search data, - * since it's not used anyway but we need a pointer. */ - UI_search_item_add(items, attribute_name.c_str(), (void *)&attribute_name, ICON_NONE, 0, 0); - } - return; - } + /* Don't filter when the menu is first opened, but still run the search + * so the items are in the same order they will appear in while searching. */ + const char *string = is_first ? "" : str; StringSearch *search = BLI_string_search_new(); for (const std::string &attribute_name : attribute_name_hints) { @@ -91,7 +85,7 @@ static void attribute_search_update_fn( } std::string **filtered_items; - const int filtered_amount = BLI_string_search_query(search, str, (void ***)&filtered_items); + const int filtered_amount = BLI_string_search_query(search, string, (void ***)&filtered_items); for (const int i : IndexRange(filtered_amount)) { std::string *item = filtered_items[i]; diff --git a/source/blender/editors/space_node/node_templates.c b/source/blender/editors/space_node/node_templates.c index f0e3f5442cc..b0c0f660717 100644 --- a/source/blender/editors/space_node/node_templates.c +++ b/source/blender/editors/space_node/node_templates.c @@ -826,11 +826,22 @@ static void ui_node_draw_input( case SOCK_INT: case SOCK_BOOLEAN: case SOCK_RGBA: - case SOCK_STRING: uiItemR(sub, &inputptr, "default_value", 0, "", ICON_NONE); uiItemDecoratorR( split_wrapper.decorate_column, &inputptr, "default_value", RNA_NO_INDEX); break; + case SOCK_STRING: { + const bNodeTree *node_tree = (const bNodeTree *)nodeptr.owner_id; + if (node_tree->type == NTREE_GEOMETRY) { + node_geometry_add_attribute_search_button(node_tree, node, &inputptr, row); + } + else { + uiItemR(sub, &inputptr, "default_value", 0, "", ICON_NONE); + } + uiItemDecoratorR( + split_wrapper.decorate_column, &inputptr, "default_value", RNA_NO_INDEX); + break; + } default: add_dummy_decorator = true; } diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt index d54265aa292..eb3371e989a 100644 --- a/source/blender/editors/space_outliner/CMakeLists.txt +++ b/source/blender/editors/space_outliner/CMakeLists.txt @@ -56,8 +56,15 @@ set(SRC tree/tree_display_view_layer.cc tree/tree_element.cc tree/tree_element_anim_data.cc - tree/tree_element_driver_base.cc + tree/tree_element_collection.cc + tree/tree_element_driver.cc + tree/tree_element_gpencil_layer.cc + tree/tree_element_id.cc + tree/tree_element_id_library.cc + tree/tree_element_id_scene.cc tree/tree_element_nla.cc + tree/tree_element_scene_objects.cc + tree/tree_element_view_layer.cc outliner_intern.h tree/tree_display.h @@ -65,8 +72,15 @@ set(SRC tree/tree_element.h tree/tree_element.hh tree/tree_element_anim_data.hh - tree/tree_element_driver_base.hh + tree/tree_element_collection.hh + tree/tree_element_driver.hh + tree/tree_element_gpencil_layer.hh + tree/tree_element_id.hh + tree/tree_element_id_library.hh + tree/tree_element_id_scene.hh tree/tree_element_nla.hh + tree/tree_element_scene_objects.hh + tree/tree_element_view_layer.hh ) set(LIB diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index ef5733fe375..d54e35f659c 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -71,7 +71,7 @@ bool outliner_is_collection_tree_element(const TreeElement *te) TSE_VIEW_COLLECTION_BASE)) { return true; } - if (tselem->type == 0 && te->idcode == ID_GR) { + if ((tselem->type == TSE_SOME_ID) && te->idcode == ID_GR) { return true; } @@ -94,7 +94,7 @@ Collection *outliner_collection_from_tree_element(const TreeElement *te) Scene *scene = (Scene *)tselem->id; return scene->master_collection; } - if (tselem->type == 0 && te->idcode == ID_GR) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_GR)) { return (Collection *)tselem->id; } @@ -111,7 +111,7 @@ TreeTraversalAction outliner_find_selected_collections(TreeElement *te, void *cu return TRAVERSE_CONTINUE; } - if (tselem->type || (tselem->id && GS(tselem->id->name) != ID_GR)) { + if ((tselem->type != TSE_SOME_ID) || (tselem->id && GS(tselem->id->name) != ID_GR)) { return TRAVERSE_SKIP_CHILDS; } @@ -127,7 +127,7 @@ TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *custom return TRAVERSE_CONTINUE; } - if (tselem->type || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) { + if ((tselem->type != TSE_SOME_ID) || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) { return TRAVERSE_SKIP_CHILDS; } @@ -1458,7 +1458,7 @@ static TreeTraversalAction outliner_hide_find_data_to_edit(TreeElement *te, void BLI_gset_add(data->collections_to_edit, lc); } } - else if (tselem->type == 0 && te->idcode == ID_OB) { + else if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { Object *ob = (Object *)tselem->id; Base *base = BKE_view_layer_base_find(data->view_layer, ob); BLI_gset_add(data->bases_to_edit, base); diff --git a/source/blender/editors/space_outliner/outliner_context.c b/source/blender/editors/space_outliner/outliner_context.c index e2b3b79e027..4293d8da73e 100644 --- a/source/blender/editors/space_outliner/outliner_context.c +++ b/source/blender/editors/space_outliner/outliner_context.c @@ -34,7 +34,7 @@ static void outliner_context_selected_ids_recursive(const ListBase *subtree, { LISTBASE_FOREACH (const TreeElement *, te, subtree) { const TreeStoreElem *tse = TREESTORE(te); - if ((tse->flag & TSE_SELECTED) && (ELEM(tse->type, 0, TSE_LAYER_COLLECTION))) { + if ((tse->flag & TSE_SELECTED) && (ELEM(tse->type, TSE_SOME_ID, TSE_LAYER_COLLECTION))) { CTX_data_id_list_add(result, tse->id); } outliner_context_selected_ids_recursive(&te->subtree, result); diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.c index 3090cab75ae..01fb0fc6f78 100644 --- a/source/blender/editors/space_outliner/outliner_dragdrop.c +++ b/source/blender/editors/space_outliner/outliner_dragdrop.c @@ -124,7 +124,7 @@ static ID *outliner_ID_drop_find(bContext *C, const wmEvent *event, short idcode TreeElement *te = outliner_drop_find(C, event); TreeStoreElem *tselem = (te) ? TREESTORE(te) : NULL; - if (te && te->idcode == idcode && tselem->type == 0) { + if (te && (te->idcode == idcode) && (tselem->type == TSE_SOME_ID)) { return tselem->id; } return NULL; @@ -215,7 +215,7 @@ static bool is_collection_element(TreeElement *te) static bool is_object_element(TreeElement *te) { TreeStoreElem *tselem = TREESTORE(te); - return tselem->type == 0 && te->idcode == ID_OB; + return (tselem->type == TSE_SOME_ID) && te->idcode == ID_OB; } static bool is_pchan_element(TreeElement *te) @@ -281,7 +281,7 @@ static int outliner_get_insert_index(TreeElement *drag_te, static bool parent_drop_allowed(TreeElement *te, Object *potential_child) { TreeStoreElem *tselem = TREESTORE(te); - if (te->idcode != ID_OB || tselem->type != 0) { + if ((te->idcode != ID_OB) || (tselem->type != TSE_SOME_ID)) { return false; } @@ -421,7 +421,7 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) TreeElement *te = outliner_drop_find(C, event); TreeStoreElem *tselem = te ? TREESTORE(te) : NULL; - if (!(te && te->idcode == ID_OB && tselem->type == 0)) { + if (!(te && (te->idcode == ID_OB) && (tselem->type == TSE_SOME_ID))) { return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 008ae727947..690adb09570 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -675,7 +675,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) if (ts && tselem) { TreeElement *te = outliner_find_tree_element(&space_outliner->tree, tselem); - if (tselem->type == 0) { + if (tselem->type == TSE_SOME_ID) { BLI_libblock_ensure_unique_name(bmain, tselem->id->name); switch (GS(tselem->id->name)) { @@ -1100,11 +1100,11 @@ static void outliner_draw_restrictbuts(uiBlock *block, UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); } } - else if ((tselem->type == 0 && te->idcode == ID_OB) && + else if (((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) && (te->flag & TE_CHILD_NOT_IN_COLLECTION)) { /* Don't show restrict columns for children that are not directly inside the collection. */ } - else if (tselem->type == 0 && te->idcode == ID_OB) { + else if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { PointerRNA ptr; Object *ob = (Object *)tselem->id; RNA_id_pointer_create(&ob->id, &ptr); @@ -1699,7 +1699,7 @@ static void outliner_draw_userbuts(uiBlock *block, LISTBASE_FOREACH (TreeElement *, te, lb) { TreeStoreElem *tselem = TREESTORE(te); if (te->ys + 2 * UI_UNIT_Y >= region->v2d.cur.ymin && te->ys <= region->v2d.cur.ymax) { - if (tselem->type == 0) { + if (tselem->type == TSE_SOME_ID) { uiBut *bt; ID *id = tselem->id; const char *tip = NULL; @@ -1949,7 +1949,7 @@ static void outliner_draw_mode_column_toggle(uiBlock *block, TreeStoreElem *tselem, const bool lock_object_modes) { - if (tselem->type != 0 || te->idcode != ID_OB) { + if ((tselem->type != TSE_SOME_ID) || (te->idcode != ID_OB)) { return; } @@ -2046,7 +2046,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) { TreeElementIcon data = {0}; - if (tselem->type) { + if (tselem->type != TSE_SOME_ID) { switch (tselem->type) { case TSE_ANIM_DATA: data.icon = ICON_ANIM_DATA; /* XXX */ @@ -2825,7 +2825,8 @@ int tree_element_id_type_to_index(TreeElement *te) { TreeStoreElem *tselem = TREESTORE(te); - const int id_index = tselem->type == 0 ? BKE_idtype_idcode_to_index(te->idcode) : INDEX_ID_GR; + const int id_index = (tselem->type == TSE_SOME_ID) ? BKE_idtype_idcode_to_index(te->idcode) : + INDEX_ID_GR; if (id_index < INDEX_ID_OB) { return id_index; } @@ -2862,9 +2863,9 @@ static void outliner_draw_iconrow(bContext *C, te->flag &= ~(TE_ICONROW | TE_ICONROW_MERGED); /* object hierarchy always, further constrained on level */ - if (level < 1 || (tselem->type == 0 && te->idcode == ID_OB)) { + if ((level < 1) || ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB))) { /* active blocks get white circle */ - if (tselem->type == 0) { + if (tselem->type == TSE_SOME_ID) { if (te->idcode == ID_OB) { active = (tvc->obact == (Object *)tselem->id) ? OL_DRAWSEL_NORMAL : OL_DRAWSEL_NONE; } @@ -2879,7 +2880,7 @@ static void outliner_draw_iconrow(bContext *C, active = tree_element_type_active_state_get(C, tvc, te, tselem); } - if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION, TSE_R_LAYER, TSE_GP_LAYER)) { + if (!ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION, TSE_R_LAYER, TSE_GP_LAYER)) { outliner_draw_iconrow_doit(block, te, fstyle, xmax, offsx, ys, alpha_fac, active, 1); } else { @@ -2954,7 +2955,7 @@ static bool element_should_draw_faded(const TreeViewContext *tvc, const TreeElement *te, const TreeStoreElem *tselem) { - if (tselem->type == 0) { + if (tselem->type == TSE_SOME_ID) { switch (te->idcode) { case ID_OB: { const Object *ob = (const Object *)tselem->id; @@ -3023,7 +3024,7 @@ static void outliner_draw_tree_element(bContext *C, GPU_blend(GPU_BLEND_ALPHA); /* Colors for active/selected data. */ - if (tselem->type == 0) { + if (tselem->type == TSE_SOME_ID) { if (te->idcode == ID_OB) { Object *ob = (Object *)tselem->id; Base *base = (te->directdata) ? (Base *)te->directdata : @@ -3080,7 +3081,7 @@ static void outliner_draw_tree_element(bContext *C, if (tselem->type == TSE_VIEW_COLLECTION_BASE) { /* Scene collection in view layer can't expand/collapse. */ } - else if (te->subtree.first || (tselem->type == 0 && te->idcode == ID_SCE) || + else if (te->subtree.first || ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_SCE)) || (te->flag & TE_LAZY_CLOSED)) { /* Open/close icon, only when sub-levels, except for scene. */ int icon_x = startx; @@ -3117,7 +3118,7 @@ static void outliner_draw_tree_element(bContext *C, offsx += 2 * ufac; } - if (ELEM(tselem->type, 0, TSE_LAYER_COLLECTION) || + if (ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION) || ((tselem->type == TSE_RNA_STRUCT) && RNA_struct_is_ID(te->rnaptr.type))) { const BIFIconID lib_icon = UI_icon_from_library(tselem->id); if (lib_icon != ICON_NONE) { @@ -3143,7 +3144,7 @@ static void outliner_draw_tree_element(bContext *C, /* Closed item, we draw the icons, not when it's a scene, or master-server list though. */ if (!TSELEM_OPEN(tselem, space_outliner)) { if (te->subtree.first) { - if (tselem->type == 0 && te->idcode == ID_SCE) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_SCE)) { /* Pass. */ } /* this tree element always has same amount of branches, so don't draw */ @@ -3210,7 +3211,7 @@ static bool subtree_contains_object(ListBase *lb) { LISTBASE_FOREACH (TreeElement *, te, lb) { TreeStoreElem *tselem = TREESTORE(te); - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { return true; } } @@ -3265,7 +3266,7 @@ static void outliner_draw_hierarchy_lines_recursive(uint pos, y = *starty; } - else if (tselem->type == 0 && te->idcode == ID_OB) { + else if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { if (subtree_contains_object(&te->subtree)) { draw_hierarchy_line = true; is_object_line = true; diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 09aa268d856..18abe17d515 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -464,7 +464,8 @@ static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeSto ID *id = tselem->id; BLI_assert(id != NULL); - BLI_assert(ELEM(tselem->type, 0 && te->idcode != 0, TSE_LAYER_COLLECTION)); + BLI_assert(((tselem->type == TSE_SOME_ID) && (te->idcode != 0)) || + (tselem->type == TSE_LAYER_COLLECTION)); UNUSED_VARS_NDEBUG(te); if (te->idcode == ID_LI && ((Library *)id)->parent != NULL) { @@ -638,7 +639,7 @@ static bool outliner_id_remap_find_tree_element(bContext *C, if (y > te->ys && y < te->ys + UI_UNIT_Y) { TreeStoreElem *tselem = TREESTORE(te); - if (tselem->type == 0 && tselem->id) { + if ((tselem->type == TSE_SOME_ID) && tselem->id) { printf("found id %s (%p)!\n", tselem->id->name, tselem->id); RNA_enum_set(op->ptr, "id_type", GS(tselem->id->name)); @@ -763,7 +764,7 @@ static int outliner_id_copy_tag(SpaceOutliner *space_outliner, ListBase *tree) TreeStoreElem *tselem = TREESTORE(te); /* if item is selected and is an ID, tag it as needing to be copied. */ - if (tselem->flag & TSE_SELECTED && ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) { + if (tselem->flag & TSE_SELECTED && ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION)) { ID *id = tselem->id; if (!(id->tag & LIB_TAG_DOIT)) { BKE_copybuffer_tag_ID(tselem->id); @@ -1640,7 +1641,7 @@ static int subtree_has_objects(ListBase *lb) { LISTBASE_FOREACH (TreeElement *, te, lb) { TreeStoreElem *tselem = TREESTORE(te); - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { return 1; } if (subtree_has_objects(&te->subtree)) { @@ -1658,7 +1659,7 @@ static void tree_element_show_hierarchy(Scene *scene, SpaceOutliner *space_outli TreeStoreElem *tselem = TREESTORE(te); if (ELEM(tselem->type, - 0, + TSE_SOME_ID, TSE_SCENE_OBJECTS_BASE, TSE_VIEW_COLLECTION_BASE, TSE_LAYER_COLLECTION)) { diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index e31af48ab7e..d53a37fa60e 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -198,7 +198,7 @@ void outliner_item_mode_toggle(bContext *C, { TreeStoreElem *tselem = TREESTORE(te); - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { Object *ob = (Object *)tselem->id; Base *base = BKE_view_layer_base_find(tvc->view_layer, ob); @@ -301,7 +301,7 @@ static void tree_element_object_activate(bContext *C, Object *ob = NULL; /* if id is not object, we search back */ - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { ob = (Object *)tselem->id; } else { @@ -443,7 +443,7 @@ static void tree_element_world_activate(bContext *C, Scene *scene, TreeElement * TreeElement *tep = te->parent; if (tep) { TreeStoreElem *tselem = TREESTORE(tep); - if (tselem->type == 0) { + if (tselem->type == TSE_SOME_ID) { sce = (Scene *)tselem->id; } } @@ -1165,7 +1165,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE int context = 0; /* ID Types */ - if (tselem->type == 0) { + if (tselem->type == TSE_SOME_ID) { RNA_id_pointer_create(tselem->id, &ptr); switch (te->idcode) { @@ -1374,12 +1374,12 @@ static void do_outliner_item_activate_tree_element(bContext *C, tvc->scene, tvc->view_layer, te, - (extend && tselem->type == 0) ? OL_SETSEL_EXTEND : - OL_SETSEL_NORMAL, - recursive && tselem->type == 0); + (extend && tselem->type == TSE_SOME_ID) ? OL_SETSEL_EXTEND : + OL_SETSEL_NORMAL, + recursive && tselem->type == TSE_SOME_ID); } - if (tselem->type == 0) { /* The lib blocks. */ + if (tselem->type == TSE_SOME_ID) { /* The lib blocks. */ if (do_activate_data == false) { /* Only select in outliner. */ } diff --git a/source/blender/editors/space_outliner/outliner_sync.c b/source/blender/editors/space_outliner/outliner_sync.c index 8bd5e3a130a..6543a909a41 100644 --- a/source/blender/editors/space_outliner/outliner_sync.c +++ b/source/blender/editors/space_outliner/outliner_sync.c @@ -326,7 +326,7 @@ static void outliner_sync_selection_from_outliner(Scene *scene, LISTBASE_FOREACH (TreeElement *, te, tree) { TreeStoreElem *tselem = TREESTORE(te); - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { if (sync_types->object) { outliner_select_sync_to_object(view_layer, te, tselem, selected_items->objects); } @@ -503,7 +503,7 @@ static void outliner_sync_selection_to_outliner(ViewLayer *view_layer, LISTBASE_FOREACH (TreeElement *, te, tree) { TreeStoreElem *tselem = TREESTORE(te); - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && te->idcode == ID_OB) { if (sync_types->object) { outliner_select_sync_from_object(view_layer, active_data->object, te, tselem); } diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index b735064cfef..9af2ba6a82b 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -106,7 +106,7 @@ static void get_element_operation_type( TreeStoreElem *tselem = TREESTORE(te); if (tselem->flag & TSE_SELECTED) { /* Layer collection points to collection ID. */ - if (!ELEM(tselem->type, 0, TSE_LAYER_COLLECTION)) { + if (!ELEM(tselem->type, TSE_SOME_ID, TSE_LAYER_COLLECTION)) { if (*datalevel == 0) { *datalevel = tselem->type; } @@ -402,7 +402,8 @@ static void outliner_do_libdata_operation(bContext *C, LISTBASE_FOREACH (TreeElement *, te, lb) { TreeStoreElem *tselem = TREESTORE(te); if (tselem->flag & TSE_SELECTED) { - if ((tselem->type == 0 && te->idcode != 0) || tselem->type == TSE_LAYER_COLLECTION) { + if (((tselem->type == TSE_SOME_ID) && (te->idcode != 0)) || + tselem->type == TSE_LAYER_COLLECTION) { TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL; operation_fn(C, reports, scene, te, tsep, tselem, user_data); } @@ -1044,7 +1045,7 @@ void outliner_do_object_operation_ex(bContext *C, TreeStoreElem *tselem = TREESTORE(te); bool select_handled = false; if (tselem->flag & TSE_SELECTED) { - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { /* When objects selected in other scenes... dunno if that should be allowed. */ Scene *scene_owner = (Scene *)outliner_search_back(te, ID_SCE); if (scene_owner && scene_act != scene_owner) { @@ -1601,7 +1602,7 @@ static TreeTraversalAction outliner_find_objects_to_delete(TreeElement *te, void return TRAVERSE_CONTINUE; } - if (tselem->type || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) { + if ((tselem->type != TSE_SOME_ID) || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) { return TRAVERSE_SKIP_CHILDS; } diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index f94f19246fa..6319b890b3b 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -1,4 +1,4 @@ -/* +/* * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 @@ -92,9 +92,6 @@ #endif /* prototypes */ -static TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner, - Collection *collection, - TreeElement *ten); static int outliner_exclude_filter_get(const SpaceOutliner *space_outliner); /* ********************************************************* */ @@ -274,7 +271,7 @@ static void outliner_add_bone(SpaceOutliner *space_outliner, } } -static bool outliner_animdata_test(AnimData *adt) +bool outliner_animdata_test(const AnimData *adt) { if (adt) { return (adt->action || adt->drivers.first || adt->nla_tracks.first); @@ -307,53 +304,13 @@ static void outliner_add_line_styles(SpaceOutliner *space_outliner, continue; } linestyle->id.tag &= ~LIB_TAG_DOIT; - outliner_add_element(space_outliner, lb, linestyle, te, 0, 0); + outliner_add_element(space_outliner, lb, linestyle, te, TSE_SOME_ID, 0); } } } } #endif -static void outliner_add_scene_contents(SpaceOutliner *space_outliner, - ListBase *lb, - Scene *sce, - TreeElement *te) -{ - /* View layers */ - TreeElement *ten = outliner_add_element(space_outliner, lb, sce, te, TSE_R_LAYER_BASE, 0); - ten->name = IFACE_("View Layers"); - - ViewLayer *view_layer; - for (view_layer = sce->view_layers.first; view_layer; view_layer = view_layer->next) { - TreeElement *tenlay = outliner_add_element( - space_outliner, &ten->subtree, sce, ten, TSE_R_LAYER, 0); - tenlay->name = view_layer->name; - tenlay->directdata = view_layer; - } - - /* World */ - outliner_add_element(space_outliner, lb, sce->world, te, 0, 0); - - /* Collections */ - ten = outliner_add_element(space_outliner, lb, &sce->id, te, TSE_SCENE_COLLECTION_BASE, 0); - ten->name = IFACE_("Scene Collection"); - outliner_add_collection_recursive(space_outliner, sce->master_collection, ten); - - /* Objects */ - ten = outliner_add_element(space_outliner, lb, sce, te, TSE_SCENE_OBJECTS_BASE, 0); - ten->name = IFACE_("Objects"); - FOREACH_SCENE_OBJECT_BEGIN (sce, ob) { - outliner_add_element(space_outliner, &ten->subtree, ob, ten, 0, 0); - } - FOREACH_SCENE_OBJECT_END; - outliner_make_object_parent_hierarchy(&ten->subtree); - - /* Animation Data */ - if (outliner_animdata_test(sce->adt)) { - outliner_add_element(space_outliner, lb, sce, te, TSE_ANIM_DATA, 0); - } -} - /* Can be inlined if necessary. */ static void outliner_add_object_contents(SpaceOutliner *space_outliner, TreeElement *te, @@ -368,14 +325,14 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner, &te->subtree, ob->poselib, te, - 0, + TSE_SOME_ID, 0); /* XXX FIXME.. add a special type for this. */ if (ob->proxy && !ID_IS_LINKED(ob)) { outliner_add_element(space_outliner, &te->subtree, ob->proxy, te, TSE_PROXY, 0); } - outliner_add_element(space_outliner, &te->subtree, ob->data, te, 0, 0); + outliner_add_element(space_outliner, &te->subtree, ob->data, te, TSE_SOME_ID, 0); if (ob->pose) { bArmature *arm = ob->data; @@ -458,7 +415,7 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner, } for (int a = 0; a < ob->totcol; a++) { - outliner_add_element(space_outliner, &te->subtree, ob->mat[a], te, 0, a); + outliner_add_element(space_outliner, &te->subtree, ob->mat[a], te, TSE_SOME_ID, a); } if (!BLI_listbase_is_empty(&ob->constraints)) { @@ -624,33 +581,8 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner, /* duplicated group */ if (ob->instance_collection && (ob->transflag & OB_DUPLICOLLECTION)) { - outliner_add_element(space_outliner, &te->subtree, ob->instance_collection, te, 0, 0); - } -} - -static void outliner_add_library_override_contents(SpaceOutliner *soops, TreeElement *te, ID *id) -{ - if (!id->override_library) { - return; - } - - PointerRNA idpoin; - RNA_id_pointer_create(id, &idpoin); - - PointerRNA override_ptr; - PropertyRNA *override_prop; - int index = 0; - LISTBASE_FOREACH (IDOverrideLibraryProperty *, op, &id->override_library->properties) { - if (!BKE_lib_override_rna_property_find(&idpoin, op, &override_ptr, &override_prop)) { - /* This is fine, override properties list is not always fully up-to-date with current - * RNA/IDProps etc., this gets cleaned up when re-generating the overrides rules, - * no error here. */ - continue; - } - - TreeElement *ten = outliner_add_element( - soops, &te->subtree, id, te, TSE_LIBRARY_OVERRIDE, index++); - ten->name = RNA_property_ui_name(override_prop); + outliner_add_element( + space_outliner, &te->subtree, ob->instance_collection, te, TSE_SOME_ID, 0); } } @@ -667,14 +599,10 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, /* expand specific data always */ switch (GS(id->name)) { - case ID_LI: { - te->name = ((Library *)id)->filepath; - break; - } - case ID_SCE: { - outliner_add_scene_contents(space_outliner, &te->subtree, (Scene *)id, te); + case ID_LI: + case ID_SCE: + BLI_assert(!"ID type expected to be expanded through new tree-element design"); break; - } case ID_OB: { outliner_add_object_contents(space_outliner, te, tselem, (Object *)id); break; @@ -686,9 +614,9 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, outliner_add_element(space_outliner, &te->subtree, me, te, TSE_ANIM_DATA, 0); } - outliner_add_element(space_outliner, &te->subtree, me->key, te, 0, 0); + outliner_add_element(space_outliner, &te->subtree, me->key, te, TSE_SOME_ID, 0); for (int a = 0; a < me->totcol; a++) { - outliner_add_element(space_outliner, &te->subtree, me->mat[a], te, 0, a); + outliner_add_element(space_outliner, &te->subtree, me->mat[a], te, TSE_SOME_ID, a); } /* could do tfaces with image links, but the images are not grouped nicely. * would require going over all tfaces, sort images in use. etc... */ @@ -702,7 +630,7 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, } for (int a = 0; a < cu->totcol; a++) { - outliner_add_element(space_outliner, &te->subtree, cu->mat[a], te, 0, a); + outliner_add_element(space_outliner, &te->subtree, cu->mat[a], te, TSE_SOME_ID, a); } break; } @@ -714,7 +642,7 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, } for (int a = 0; a < mb->totcol; a++) { - outliner_add_element(space_outliner, &te->subtree, mb->mat[a], te, 0, a); + outliner_add_element(space_outliner, &te->subtree, mb->mat[a], te, TSE_SOME_ID, a); } break; } @@ -730,7 +658,7 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, if (outliner_animdata_test(tex->adt)) { outliner_add_element(space_outliner, &te->subtree, tex, te, TSE_ANIM_DATA, 0); } - outliner_add_element(space_outliner, &te->subtree, tex->ima, te, 0, 0); + outliner_add_element(space_outliner, &te->subtree, tex->ima, te, TSE_SOME_ID, 0); break; } case ID_CA: { @@ -901,17 +829,6 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, default: break; } - - const bool lib_overrides_visible = !SUPPORT_FILTER_OUTLINER(space_outliner) || - ((space_outliner->filter & SO_FILTER_NO_LIB_OVERRIDE) == 0); - - if (lib_overrides_visible && ID_IS_OVERRIDE_LIBRARY(id)) { - TreeElement *ten = outliner_add_element( - space_outliner, &te->subtree, id, te, TSE_LIBRARY_OVERRIDE_BASE, 0); - - ten->name = IFACE_("Library Overrides"); - outliner_add_library_override_contents(space_outliner, ten, id); - } } /** @@ -991,41 +908,43 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, else if (type == TSE_ID_BASE) { /* pass */ } + else if (type == TSE_SOME_ID) { + if (!te->type) { + BLI_assert(!"Expected this ID type to be ported to new Outliner tree-element design"); + } + } else { /* Other cases must be caught above. */ BLI_assert(TSE_IS_REAL_ID(tselem)); - /* do here too, for blend file viewer, own ID_LI then shows file name */ - if (GS(id->name) == ID_LI) { - te->name = ((Library *)id)->filepath; - } - else { + /* The new type design sets the name already, don't override that here. We need to figure out + * how to deal with the idcode for non-TSE_SOME_ID types still. Some rely on it... */ + if (!te->type) { te->name = id->name + 2; /* Default, can be overridden by Library or non-ID data. */ } te->idcode = GS(id->name); } - if (te->type) { + if (te->type && outliner_tree_element_type_is_expand_valid(te->type)) { outliner_tree_element_type_expand(te->type, space_outliner); } - else if (type == 0) { - TreeStoreElem *tsepar = parent ? TREESTORE(parent) : NULL; - - /* ID data-block. */ - if (tsepar == NULL || tsepar->type != TSE_ID_BASE || space_outliner->filter_id_type) { + else if (type == TSE_SOME_ID) { + /* ID types not (fully) ported to new design yet. */ + if (outliner_tree_element_type_expand_poll(te->type, space_outliner)) { outliner_add_id_contents(space_outliner, te, tselem, id); + outliner_tree_element_type_post_expand(te->type, space_outliner); } } - else if (ELEM(type, TSE_ANIM_DATA, TSE_DRIVER_BASE, TSE_NLA, TSE_NLA_ACTION, TSE_NLA_TRACK)) { + else if (ELEM(type, + TSE_ANIM_DATA, + TSE_DRIVER_BASE, + TSE_NLA, + TSE_NLA_ACTION, + TSE_NLA_TRACK, + TSE_GP_LAYER)) { /* Should already use new AbstractTreeElement design. */ BLI_assert(0); } - else if (type == TSE_GP_LAYER) { - bGPDlayer *gpl = (bGPDlayer *)idv; - - te->name = gpl->info; - te->directdata = gpl; - } else if (type == TSE_SEQUENCE) { Sequence *seq = (Sequence *)idv; @@ -1229,18 +1148,19 @@ BLI_INLINE void outliner_add_collection_objects(SpaceOutliner *space_outliner, TreeElement *parent) { LISTBASE_FOREACH (CollectionObject *, cob, &collection->gobject) { - outliner_add_element(space_outliner, tree, cob->ob, parent, 0, 0); + outliner_add_element(space_outliner, tree, cob->ob, parent, TSE_SOME_ID, 0); } } -static TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner, - Collection *collection, - TreeElement *ten) +TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner, + Collection *collection, + TreeElement *ten) { outliner_add_collection_init(ten, collection); LISTBASE_FOREACH (CollectionChild *, child, &collection->children) { - outliner_add_element(space_outliner, &ten->subtree, &child->collection->id, ten, 0, 0); + outliner_add_element( + space_outliner, &ten->subtree, &child->collection->id, ten, TSE_SOME_ID, 0); } if (space_outliner->outlinevis != SO_SCENES) { @@ -1265,7 +1185,7 @@ void outliner_make_object_parent_hierarchy(ListBase *lb) TreeElement *ten = te->next; TreeStoreElem *tselem = TREESTORE(te); - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && te->idcode == ID_OB) { Object *ob = (Object *)tselem->id; if (ob->parent && ob->parent->id.newid) { BLI_remlink(lb, te); @@ -1406,7 +1326,7 @@ static void outliner_sort(ListBase *lb) /* sorting rules; only object lists, ID lists, or deformgroups */ if (ELEM(tselem->type, TSE_DEFGROUP, TSE_ID_BASE) || - (tselem->type == 0 && te->idcode == ID_OB)) { + ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB))) { int totelem = BLI_listbase_count(lb); if (totelem > 1) { @@ -1420,7 +1340,7 @@ static void outliner_sort(ListBase *lb) tp->name = te->name; tp->idcode = te->idcode; - if (tselem->type && tselem->type != TSE_DEFGROUP) { + if ((tselem->type != TSE_SOME_ID) && tselem->type != TSE_DEFGROUP) { tp->idcode = 0; /* Don't sort this. */ } if (tselem->type == TSE_ID_BASE) { @@ -1471,7 +1391,7 @@ static void outliner_collections_children_sort(ListBase *lb) TreeStoreElem *tselem = TREESTORE(te); /* Sorting rules: only object lists. */ - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { int totelem = BLI_listbase_count(lb); if (totelem > 1) { @@ -1546,7 +1466,7 @@ static bool test_collection_callback(TreeElement *te) static bool test_object_callback(TreeElement *te) { TreeStoreElem *tselem = TREESTORE(te); - return ((tselem->type == 0) && (te->idcode == ID_OB)); + return ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)); } /** @@ -1707,7 +1627,7 @@ static bool outliner_element_visible_get(ViewLayer *view_layer, } TreeStoreElem *tselem = TREESTORE(te); - if ((tselem->type == 0) && (te->idcode == ID_OB)) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { if ((exclude_filter & SO_FILTER_OB_TYPE) == SO_FILTER_OB_TYPE) { return false; } @@ -1790,14 +1710,15 @@ static bool outliner_element_visible_get(ViewLayer *view_layer, return is_visible; } - if ((te->parent != NULL) && (TREESTORE(te->parent)->type == 0) && + if ((te->parent != NULL) && (TREESTORE(te->parent)->type == TSE_SOME_ID) && (te->parent->idcode == ID_OB)) { if (exclude_filter & SO_FILTER_NO_CHILDREN) { return false; } } } - else if (te->parent != NULL && TREESTORE(te->parent)->type == 0 && te->parent->idcode == ID_OB) { + else if ((te->parent != NULL) && (TREESTORE(te->parent)->type == TSE_SOME_ID) && + (te->parent->idcode == ID_OB)) { if (exclude_filter & SO_FILTER_NO_OB_CONTENT) { return false; } @@ -1821,7 +1742,7 @@ static bool outliner_element_is_collection_or_object(TreeElement *te) { TreeStoreElem *tselem = TREESTORE(te); - if ((tselem->type == 0) && (te->idcode == ID_OB)) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { return true; } diff --git a/source/blender/editors/space_outliner/outliner_utils.c b/source/blender/editors/space_outliner/outliner_utils.c index 92178cfdfc9..562457c62e9 100644 --- a/source/blender/editors/space_outliner/outliner_utils.c +++ b/source/blender/editors/space_outliner/outliner_utils.c @@ -226,7 +226,7 @@ TreeElement *outliner_find_id(SpaceOutliner *space_outliner, ListBase *lb, const { LISTBASE_FOREACH (TreeElement *, te, lb) { TreeStoreElem *tselem = TREESTORE(te); - if (tselem->type == 0) { + if (tselem->type == TSE_SOME_ID) { if (tselem->id == id) { return te; } @@ -266,7 +266,7 @@ TreeElement *outliner_find_editbone(ListBase *lb, const EditBone *ebone) } TreeStoreElem *tselem = TREESTORE(te); - if (ELEM(tselem->type, 0, TSE_EBONE)) { + if (ELEM(tselem->type, TSE_SOME_ID, TSE_EBONE)) { TreeElement *tes = outliner_find_editbone(&te->subtree, ebone); if (tes) { return tes; @@ -283,7 +283,7 @@ TreeElement *outliner_search_back_te(TreeElement *te, short idcode) while (te) { tselem = TREESTORE(te); - if (tselem->type == 0 && te->idcode == idcode) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == idcode)) { return te; } te = te->parent; @@ -510,7 +510,7 @@ Base *ED_outliner_give_base_under_cursor(bContext *C, const int mval[2]) te = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]); if (te) { TreeStoreElem *tselem = TREESTORE(te); - if ((tselem->type == 0) && (te->idcode == ID_OB)) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { Object *ob = (Object *)tselem->id; base = (te->directdata) ? (Base *)te->directdata : BKE_view_layer_base_find(view_layer, ob); } diff --git a/source/blender/editors/space_outliner/tree/tree_display.h b/source/blender/editors/space_outliner/tree/tree_display.h index 4ef71ded133..c0a751f2cd5 100644 --- a/source/blender/editors/space_outliner/tree/tree_display.h +++ b/source/blender/editors/space_outliner/tree/tree_display.h @@ -56,6 +56,10 @@ struct TreeElement *outliner_add_element(SpaceOutliner *space_outliner, short type, short index); void outliner_make_object_parent_hierarchy(ListBase *lb); +bool outliner_animdata_test(const struct AnimData *adt); +TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner, + struct Collection *collection, + TreeElement *ten); const char *outliner_idcode_to_plural(short idcode); diff --git a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc index a81ce11498a..91b690d35fa 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc @@ -144,7 +144,7 @@ TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar, if (!tenlib) { /* Create library tree element on demand, depending if there are any data-blocks. */ if (lib) { - tenlib = outliner_add_element(&space_outliner_, &lb, lib, nullptr, 0, 0); + tenlib = outliner_add_element(&space_outliner_, &lb, lib, nullptr, TSE_SOME_ID, 0); } else { tenlib = outliner_add_element(&space_outliner_, &lb, &mainvar, nullptr, TSE_ID_BASE, 0); @@ -168,7 +168,7 @@ TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar, for (ID *id : List<ID>(lbarray[a])) { if (library_id_filter_poll(lib, id)) { - outliner_add_element(&space_outliner_, &ten->subtree, id, ten, 0, 0); + outliner_add_element(&space_outliner_, &ten->subtree, id, ten, TSE_SOME_ID, 0); } } } diff --git a/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc index 559cb289f3f..69ccf014642 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc @@ -76,7 +76,8 @@ ListBase TreeDisplayIDOrphans::buildTree(const TreeSourceData &source_data) /* Add the orphaned data-blocks - these will not be added with any subtrees attached. */ for (ID *id : List<ID>(lbarray[a])) { if (ID_REAL_USERS(id) <= 0) { - outliner_add_element(&space_outliner_, (te) ? &te->subtree : &tree, id, te, 0, 0); + outliner_add_element( + &space_outliner_, (te) ? &te->subtree : &tree, id, te, TSE_SOME_ID, 0); } } } diff --git a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc index f377512d81e..390f81cfcd1 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc @@ -46,7 +46,8 @@ ListBase TreeDisplayScenes::buildTree(const TreeSourceData &source_data) for (ID *id : List<ID>(source_data.bmain->scenes)) { Scene *scene = reinterpret_cast<Scene *>(id); - TreeElement *te = outliner_add_element(&space_outliner_, &tree, scene, nullptr, 0, 0); + TreeElement *te = outliner_add_element( + &space_outliner_, &tree, scene, nullptr, TSE_SOME_ID, 0); TreeStoreElem *tselem = TREESTORE(te); /* New scene elements open by default */ diff --git a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc index a0ebac5f451..89c9960a24f 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_view_layer.cc @@ -80,7 +80,7 @@ ListBase TreeDisplayViewLayer::buildTree(const TreeSourceData &source_data) /* Show objects in the view layer. */ for (Base *base : List<Base>(view_layer_->object_bases)) { TreeElement *te_object = outliner_add_element( - &space_outliner_, &tree, base->object, nullptr, 0, 0); + &space_outliner_, &tree, base->object, nullptr, TSE_SOME_ID, 0); te_object->directdata = base; } @@ -158,7 +158,7 @@ void TreeDisplayViewLayer::add_layer_collection_objects(ListBase &tree, for (CollectionObject *cob : List<CollectionObject>(lc.collection->gobject)) { Base *base = BKE_view_layer_base_find(view_layer_, cob->ob); TreeElement *te_object = outliner_add_element( - &space_outliner_, &tree, base->object, &ten, 0, 0); + &space_outliner_, &tree, base->object, &ten, TSE_SOME_ID, 0); te_object->directdata = base; } } @@ -203,7 +203,7 @@ void ObjectsChildrenBuilder::object_tree_elements_lookup_create_recursive(TreeEl continue; } - if (tselem->type == 0 && te->idcode == ID_OB) { + if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { Object *ob = (Object *)tselem->id; /* Lookup children or add new, empty children vector. */ Vector<TreeElement *> &tree_elements = object_tree_elements_map_.lookup_or_add(ob, {}); @@ -261,8 +261,12 @@ void ObjectsChildrenBuilder::make_object_parent_hierarchy_collections() if (!found) { /* We add the child in the tree even if it is not in the collection. * We deliberately clear its sub-tree though, to make it less prominent. */ - TreeElement *child_ob_tree_element = outliner_add_element( - &outliner_, &parent_ob_tree_element->subtree, child, parent_ob_tree_element, 0, 0); + TreeElement *child_ob_tree_element = outliner_add_element(&outliner_, + &parent_ob_tree_element->subtree, + child, + parent_ob_tree_element, + TSE_SOME_ID, + 0); outliner_free_tree(&child_ob_tree_element->subtree); child_ob_tree_element->flag |= TE_CHILD_NOT_IN_COLLECTION; child_ob_tree_elements.append(child_ob_tree_element); diff --git a/source/blender/editors/space_outliner/tree/tree_element.cc b/source/blender/editors/space_outliner/tree/tree_element.cc index 27846614994..25bd9a53cf8 100644 --- a/source/blender/editors/space_outliner/tree/tree_element.cc +++ b/source/blender/editors/space_outliner/tree/tree_element.cc @@ -21,8 +21,13 @@ #include "DNA_listBase.h" #include "tree_element_anim_data.hh" -#include "tree_element_driver_base.hh" +#include "tree_element_collection.hh" +#include "tree_element_driver.hh" +#include "tree_element_gpencil_layer.hh" +#include "tree_element_id.hh" #include "tree_element_nla.hh" +#include "tree_element_scene_objects.hh" +#include "tree_element_view_layer.hh" #include "tree_element.h" #include "tree_element.hh" @@ -36,6 +41,8 @@ static AbstractTreeElement *tree_element_create(int type, TreeElement &legacy_te ID &id = *static_cast<ID *>(idv); switch (type) { + case TSE_SOME_ID: + return TreeElementID::createFromID(legacy_te, id); case TSE_ANIM_DATA: return new TreeElementAnimData(legacy_te, id); case TSE_DRIVER_BASE: @@ -46,6 +53,14 @@ static AbstractTreeElement *tree_element_create(int type, TreeElement &legacy_te return new TreeElementNLATrack(legacy_te, *static_cast<NlaTrack *>(idv)); case TSE_NLA_ACTION: return new TreeElementNLAAction(legacy_te); + case TSE_GP_LAYER: + return new TreeElementGPencilLayer(legacy_te, *static_cast<bGPDlayer *>(idv)); + case TSE_R_LAYER_BASE: + return new TreeElementViewLayerBase(legacy_te, *static_cast<Scene *>(idv)); + case TSE_SCENE_COLLECTION_BASE: + return new TreeElementCollectionBase(legacy_te, *static_cast<Scene *>(idv)); + case TSE_SCENE_OBJECTS_BASE: + return new TreeElementSceneObjectsBase(legacy_te, *static_cast<Scene *>(idv)); default: break; } @@ -61,7 +76,33 @@ static void tree_element_free(AbstractTreeElement **tree_element) static void tree_element_expand(AbstractTreeElement &tree_element, SpaceOutliner &space_outliner) { + /* Most types can just expand. IDs optionally expand (hence the poll) and do additional, common + * expanding. Could be done nicer, we could request a small "expander" helper object from the + * element type, that the IDs have a more advanced implementation for. */ + if (!tree_element.expandPoll(space_outliner)) { + return; + } tree_element.expand(space_outliner); + tree_element.postExpand(space_outliner); +} + +/** + * Needed for types that still expand in C, but need to execute the same post-expand logic. Can be + * removed once all ID types expand entirely using the new design. + */ +static void tree_element_post_expand_only(AbstractTreeElement &tree_element, + SpaceOutliner &space_outliner) +{ + tree_element.postExpand(space_outliner); +} +/** + * Needed for types that still expand in C, to poll if they should expand in current context. Can + * be removed once all ID types expand entirely using the new design. + */ +static bool tree_element_expand_poll(AbstractTreeElement &tree_element, + SpaceOutliner &space_outliner) +{ + return tree_element.expandPoll(space_outliner); } } // namespace blender::ed::outliner @@ -79,6 +120,22 @@ void outliner_tree_element_type_expand(TreeElementType *type, SpaceOutliner *spa outliner::tree_element_expand(reinterpret_cast<outliner::AbstractTreeElement &>(*type), *space_outliner); } +bool outliner_tree_element_type_is_expand_valid(TreeElementType *type) +{ + outliner::AbstractTreeElement &element = reinterpret_cast<outliner::AbstractTreeElement &>( + *type); + return element.isExpandValid(); +} +bool outliner_tree_element_type_expand_poll(TreeElementType *type, SpaceOutliner *space_outliner) +{ + return outliner::tree_element_expand_poll( + reinterpret_cast<outliner::AbstractTreeElement &>(*type), *space_outliner); +} +void outliner_tree_element_type_post_expand(TreeElementType *type, SpaceOutliner *space_outliner) +{ + outliner::tree_element_post_expand_only(reinterpret_cast<outliner::AbstractTreeElement &>(*type), + *space_outliner); +} void outliner_tree_element_type_free(TreeElementType **type) { diff --git a/source/blender/editors/space_outliner/tree/tree_element.h b/source/blender/editors/space_outliner/tree/tree_element.h index d88c37180b3..8e5b02278cc 100644 --- a/source/blender/editors/space_outliner/tree/tree_element.h +++ b/source/blender/editors/space_outliner/tree/tree_element.h @@ -39,6 +39,9 @@ TreeElementType *outliner_tree_element_type_create(int type, TreeElement *legacy void outliner_tree_element_type_free(TreeElementType **type); void outliner_tree_element_type_expand(TreeElementType *type, SpaceOutliner *space_outliner); +bool outliner_tree_element_type_is_expand_valid(TreeElementType *type); +bool outliner_tree_element_type_expand_poll(TreeElementType *type, SpaceOutliner *space_outliner); +void outliner_tree_element_type_post_expand(TreeElementType *type, SpaceOutliner *space_outliner); #ifdef __cplusplus } diff --git a/source/blender/editors/space_outliner/tree/tree_element.hh b/source/blender/editors/space_outliner/tree/tree_element.hh index 8a1ebb51eae..4a7e95556db 100644 --- a/source/blender/editors/space_outliner/tree/tree_element.hh +++ b/source/blender/editors/space_outliner/tree/tree_element.hh @@ -37,17 +37,39 @@ class AbstractTreeElement { TreeElement &legacy_te_; public: - AbstractTreeElement(TreeElement &legacy_te) : legacy_te_(legacy_te) - { - } virtual ~AbstractTreeElement() = default; /** + * Check if the type is expandible in current context. + */ + virtual bool expandPoll(const SpaceOutliner &) const + { + return true; + } + /** * Let the type add its own children. */ virtual void expand(SpaceOutliner &) const { } + virtual void postExpand(SpaceOutliner &) const + { + } + + /** + * Just while transitioning to the new tree-element design: Some types are only partially ported, + * and the expanding isn't done yet. + */ + virtual bool isExpandValid() const + { + return true; + } + + protected: + /* Pseudo-abstract: Only allow creation through derived types. */ + AbstractTreeElement(TreeElement &legacy_te) : legacy_te_(legacy_te) + { + } }; } // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc b/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc index 13a25800800..5a9568ea906 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_anim_data.cc @@ -44,7 +44,8 @@ TreeElementAnimData::TreeElementAnimData(TreeElement &legacy_te, ID &id) void TreeElementAnimData::expand(SpaceOutliner &space_outliner) const { /* Animation data-block itself. */ - outliner_add_element(&space_outliner, &legacy_te_.subtree, anim_data_.action, &legacy_te_, 0, 0); + outliner_add_element( + &space_outliner, &legacy_te_.subtree, anim_data_.action, &legacy_te_, TSE_SOME_ID, 0); expand_drivers(space_outliner); expand_NLA_tracks(space_outliner); diff --git a/source/blender/editors/space_outliner/tree/tree_element_collection.cc b/source/blender/editors/space_outliner/tree/tree_element_collection.cc new file mode 100644 index 00000000000..1add61db7f1 --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_collection.cc @@ -0,0 +1,44 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "DNA_listBase.h" + +#include "BLT_translation.h" + +#include "../outliner_intern.h" +#include "tree_display.h" + +#include "tree_element_collection.hh" + +namespace blender::ed::outliner { + +TreeElementCollectionBase::TreeElementCollectionBase(TreeElement &legacy_te, Scene &scene) + : AbstractTreeElement(legacy_te), scene_(scene) +{ + BLI_assert(legacy_te.store_elem->type == TSE_SCENE_COLLECTION_BASE); + legacy_te.name = IFACE_("Scene Collection"); +} + +void TreeElementCollectionBase::expand(SpaceOutliner &space_outliner) const +{ + outliner_add_collection_recursive(&space_outliner, scene_.master_collection, &legacy_te_); +} + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_collection.hh b/source/blender/editors/space_outliner/tree/tree_element_collection.hh new file mode 100644 index 00000000000..e9584d37dfe --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_collection.hh @@ -0,0 +1,36 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup spoutliner + */ + +#pragma once + +#include "tree_element.hh" + +namespace blender::ed::outliner { + +class TreeElementCollectionBase final : public AbstractTreeElement { + Scene &scene_; + + public: + TreeElementCollectionBase(TreeElement &legacy_te, Scene &scene); + + void expand(SpaceOutliner &) const override; +}; + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_driver_base.cc b/source/blender/editors/space_outliner/tree/tree_element_driver.cc index a01a3c42531..42f51908eaa 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_driver_base.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_driver.cc @@ -30,7 +30,7 @@ #include "../outliner_intern.h" #include "tree_display.h" -#include "tree_element_driver_base.hh" +#include "tree_element_driver.hh" namespace blender::ed::outliner { diff --git a/source/blender/editors/space_outliner/tree/tree_element_driver_base.hh b/source/blender/editors/space_outliner/tree/tree_element_driver.hh index 1925e3570be..1925e3570be 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_driver_base.hh +++ b/source/blender/editors/space_outliner/tree/tree_element_driver.hh diff --git a/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc new file mode 100644 index 00000000000..91e6fdcde4b --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc @@ -0,0 +1,40 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "BLI_utildefines.h" + +#include "DNA_gpencil_types.h" + +#include "../outliner_intern.h" + +#include "tree_element_gpencil_layer.hh" + +namespace blender::ed::outliner { + +TreeElementGPencilLayer::TreeElementGPencilLayer(TreeElement &legacy_te, bGPDlayer &gplayer) + : AbstractTreeElement(legacy_te) +{ + BLI_assert(legacy_te.store_elem->type == TSE_GP_LAYER); + /* this element's info */ + legacy_te.name = gplayer.info; + legacy_te.directdata = &gplayer; +} + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.hh b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.hh new file mode 100644 index 00000000000..da57ef63f1f --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.hh @@ -0,0 +1,34 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup spoutliner + */ + +#pragma once + +#include "tree_element.hh" + +struct bGPDlayer; + +namespace blender::ed::outliner { + +class TreeElementGPencilLayer final : public AbstractTreeElement { + public: + TreeElementGPencilLayer(TreeElement &legacy_te, bGPDlayer &gplayer); +}; + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.cc b/source/blender/editors/space_outliner/tree/tree_element_id.cc new file mode 100644 index 00000000000..823a7644f38 --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_id.cc @@ -0,0 +1,167 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "DNA_ID.h" + +#include "BLI_listbase_wrapper.hh" +#include "BLI_utildefines.h" + +#include "BKE_lib_override.h" + +#include "BLT_translation.h" + +#include "RNA_access.h" + +#include "../outliner_intern.h" +#include "tree_display.h" +#include "tree_element_id_library.hh" +#include "tree_element_id_scene.hh" + +#include "tree_element_id.hh" + +namespace blender::ed::outliner { + +TreeElementID *TreeElementID::createFromID(TreeElement &legacy_te, ID &id) +{ + switch (ID_Type type = GS(id.name); type) { + case ID_LI: + return new TreeElementIDLibrary(legacy_te, (Library &)id); + case ID_SCE: + return new TreeElementIDScene(legacy_te, (Scene &)id); + case ID_OB: + case ID_ME: + case ID_CU: + case ID_MB: + case ID_MA: + case ID_TE: + case ID_LT: + case ID_LA: + case ID_CA: + case ID_KE: + case ID_SCR: + case ID_WO: + case ID_SPK: + case ID_GR: + case ID_NT: + case ID_BR: + case ID_PA: + case ID_MC: + case ID_MSK: + case ID_LS: + case ID_LP: + case ID_GD: + case ID_WS: + case ID_HA: + case ID_PT: + case ID_VO: + case ID_SIM: + case ID_WM: + case ID_IM: + case ID_VF: + case ID_TXT: + case ID_SO: + case ID_AR: + case ID_AC: + case ID_PAL: + case ID_PC: + case ID_CF: + return new TreeElementID(legacy_te, id); + /* Deprecated */ + case ID_IP: + BLI_assert(!"Outliner trying to build tree-element for deprecated ID type"); + return nullptr; + } + + return nullptr; +} + +/* -------------------------------------------------------------------- */ +/* ID Tree-Element Base Class (common/default logic) */ + +TreeElementID::TreeElementID(TreeElement &legacy_te, ID &id) + : AbstractTreeElement(legacy_te), id_(id) +{ + BLI_assert(legacy_te_.store_elem->type == TSE_SOME_ID); + BLI_assert(TSE_IS_REAL_ID(legacy_te_.store_elem)); + + /* Default, some specific types override this. */ + legacy_te_.name = id.name + 2; + legacy_te_.idcode = GS(id.name); +} + +void TreeElementID::expand_library_overrides(SpaceOutliner &space_outliner) const +{ + if (!id_.override_library) { + return; + } + + PointerRNA idpoin; + RNA_id_pointer_create(&id_, &idpoin); + + PointerRNA override_rna_ptr; + PropertyRNA *override_rna_prop; + int index = 0; + + for (auto *override_prop : + ListBaseWrapper<IDOverrideLibraryProperty>(id_.override_library->properties)) { + if (!BKE_lib_override_rna_property_find( + &idpoin, override_prop, &override_rna_ptr, &override_rna_prop)) { + /* This is fine, override properties list is not always fully up-to-date with current + * RNA/IDProps etc., this gets cleaned up when re-generating the overrides rules, + * no error here. */ + continue; + } + + TreeElement *ten = outliner_add_element( + &space_outliner, &legacy_te_.subtree, &id_, &legacy_te_, TSE_LIBRARY_OVERRIDE, index++); + ten->name = RNA_property_ui_name(override_rna_prop); + } +} + +void TreeElementID::postExpand(SpaceOutliner &space_outliner) const +{ + const bool lib_overrides_visible = !SUPPORT_FILTER_OUTLINER(&space_outliner) || + ((space_outliner.filter & SO_FILTER_NO_LIB_OVERRIDE) == 0); + + if (lib_overrides_visible && ID_IS_OVERRIDE_LIBRARY(&id_)) { + TreeElement *ten = outliner_add_element( + &space_outliner, &legacy_te_.subtree, &id_, &legacy_te_, TSE_LIBRARY_OVERRIDE_BASE, 0); + + ten->name = IFACE_("Library Overrides"); + expand_library_overrides(space_outliner); + } +} + +bool TreeElementID::expandPoll(const SpaceOutliner &space_outliner) const +{ + const TreeStoreElem *tsepar = legacy_te_.parent ? TREESTORE(legacy_te_.parent) : nullptr; + return (tsepar == nullptr || tsepar->type != TSE_ID_BASE || space_outliner.filter_id_type); +} + +void TreeElementID::expand_animation_data(SpaceOutliner &space_outliner, + const AnimData *anim_data) const +{ + if (outliner_animdata_test(anim_data)) { + outliner_add_element( + &space_outliner, &legacy_te_.subtree, &id_, &legacy_te_, TSE_ANIM_DATA, 0); + } +} + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.hh b/source/blender/editors/space_outliner/tree/tree_element_id.hh new file mode 100644 index 00000000000..2d077464b6d --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_id.hh @@ -0,0 +1,58 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup spoutliner + * + * Tree element classes for the tree elements directly representing an ID (#TSE_SOME_ID). + */ + +#pragma once + +#include "tree_element.hh" + +namespace blender::ed::outliner { + +class TreeElementID : public AbstractTreeElement { + protected: + ID &id_; + + public: + TreeElementID(TreeElement &legacy_te, ID &id); + + static TreeElementID *createFromID(TreeElement &legacy_te, ID &id); + + void postExpand(SpaceOutliner &) const override; + bool expandPoll(const SpaceOutliner &) const override; + + /** + * Expanding not implemented for all types yet. Once it is, this can be set to true or + * `AbstractTreeElement::expandValid()` can be removed altogether. + */ + bool isExpandValid() const override + { + return false; + } + + protected: + /* ID types with animation data can use this. */ + void expand_animation_data(SpaceOutliner &, const AnimData *) const; + + private: + void expand_library_overrides(SpaceOutliner &) const; +}; + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_id_library.cc b/source/blender/editors/space_outliner/tree/tree_element_id_library.cc new file mode 100644 index 00000000000..36f536c9845 --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_id_library.cc @@ -0,0 +1,40 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "DNA_listBase.h" + +#include "../outliner_intern.h" + +#include "tree_element_id_library.hh" + +namespace blender::ed::outliner { + +TreeElementIDLibrary::TreeElementIDLibrary(TreeElement &legacy_te, Library &library) + : TreeElementID(legacy_te, library.id) +{ + legacy_te.name = library.filepath; +} + +bool TreeElementIDLibrary::isExpandValid() const +{ + return true; +} + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_id_library.hh b/source/blender/editors/space_outliner/tree/tree_element_id_library.hh new file mode 100644 index 00000000000..88660cd8aa9 --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_id_library.hh @@ -0,0 +1,34 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup spoutliner + */ + +#pragma once + +#include "tree_element_id.hh" + +namespace blender::ed::outliner { + +class TreeElementIDLibrary final : public TreeElementID { + public: + TreeElementIDLibrary(TreeElement &legacy_te, Library &library); + + bool isExpandValid() const override; +}; + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_id_scene.cc b/source/blender/editors/space_outliner/tree/tree_element_id_scene.cc new file mode 100644 index 00000000000..ae81b44a1e4 --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_id_scene.cc @@ -0,0 +1,74 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "DNA_listBase.h" + +#include "../outliner_intern.h" +#include "tree_display.h" + +#include "tree_element_id_scene.hh" + +namespace blender::ed::outliner { + +TreeElementIDScene::TreeElementIDScene(TreeElement &legacy_te, Scene &scene) + : TreeElementID(legacy_te, scene.id), scene_(scene) +{ +} + +bool TreeElementIDScene::isExpandValid() const +{ + return true; +} + +void TreeElementIDScene::expand(SpaceOutliner &space_outliner) const +{ + expandViewLayers(space_outliner); + expandWorld(space_outliner); + expandCollections(space_outliner); + expandObjects(space_outliner); + + expand_animation_data(space_outliner, scene_.adt); +} + +void TreeElementIDScene::expandViewLayers(SpaceOutliner &space_outliner) const +{ + outliner_add_element( + &space_outliner, &legacy_te_.subtree, &scene_, &legacy_te_, TSE_R_LAYER_BASE, 0); +} + +void TreeElementIDScene::expandWorld(SpaceOutliner &space_outliner) const +{ + outliner_add_element( + &space_outliner, &legacy_te_.subtree, scene_.world, &legacy_te_, TSE_SOME_ID, 0); +} + +void TreeElementIDScene::expandCollections(SpaceOutliner &space_outliner) const +{ + outliner_add_element( + &space_outliner, &legacy_te_.subtree, &scene_, &legacy_te_, TSE_SCENE_COLLECTION_BASE, 0); +} + +void TreeElementIDScene::expandObjects(SpaceOutliner &space_outliner) const +{ + outliner_add_element( + &space_outliner, &legacy_te_.subtree, &scene_, &legacy_te_, TSE_SCENE_OBJECTS_BASE, 0); +} + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_id_scene.hh b/source/blender/editors/space_outliner/tree/tree_element_id_scene.hh new file mode 100644 index 00000000000..3340bacd307 --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_id_scene.hh @@ -0,0 +1,43 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup spoutliner + */ + +#pragma once + +#include "tree_element_id.hh" + +namespace blender::ed::outliner { + +class TreeElementIDScene final : public TreeElementID { + Scene &scene_; + + public: + TreeElementIDScene(TreeElement &legacy_te, Scene &scene); + + void expand(SpaceOutliner &) const override; + bool isExpandValid() const override; + + private: + void expandViewLayers(SpaceOutliner &) const; + void expandWorld(SpaceOutliner &) const; + void expandCollections(SpaceOutliner &) const; + void expandObjects(SpaceOutliner &) const; +}; + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc new file mode 100644 index 00000000000..a46e8de1bdd --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc @@ -0,0 +1,50 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "BKE_collection.h" + +#include "BLI_utildefines.h" + +#include "BLT_translation.h" + +#include "../outliner_intern.h" +#include "tree_display.h" + +#include "tree_element_scene_objects.hh" + +namespace blender::ed::outliner { + +TreeElementSceneObjectsBase::TreeElementSceneObjectsBase(TreeElement &legacy_te, Scene &scene) + : AbstractTreeElement(legacy_te), scene_(scene) +{ + BLI_assert(legacy_te.store_elem->type == TSE_SCENE_OBJECTS_BASE); + legacy_te.name = IFACE_("Objects"); +} + +void TreeElementSceneObjectsBase::expand(SpaceOutliner &space_outliner) const +{ + FOREACH_SCENE_OBJECT_BEGIN (&scene_, ob) { + outliner_add_element(&space_outliner, &legacy_te_.subtree, ob, &legacy_te_, TSE_SOME_ID, 0); + } + FOREACH_SCENE_OBJECT_END; + outliner_make_object_parent_hierarchy(&legacy_te_.subtree); +} + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh new file mode 100644 index 00000000000..a2aa29c4a33 --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh @@ -0,0 +1,36 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup spoutliner + */ + +#pragma once + +#include "tree_element.hh" + +namespace blender::ed::outliner { + +class TreeElementSceneObjectsBase final : public AbstractTreeElement { + Scene &scene_; + + public: + TreeElementSceneObjectsBase(TreeElement &legacy_te, Scene &scene); + + void expand(SpaceOutliner &) const override; +}; + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc b/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc new file mode 100644 index 00000000000..7bb9405147e --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc @@ -0,0 +1,51 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup spoutliner + */ + +#include "DNA_layer_types.h" + +#include "BLI_listbase_wrapper.hh" + +#include "BLT_translation.h" + +#include "../outliner_intern.h" +#include "tree_display.h" + +#include "tree_element_view_layer.hh" + +namespace blender::ed::outliner { + +TreeElementViewLayerBase::TreeElementViewLayerBase(TreeElement &legacy_te, Scene &scene) + : AbstractTreeElement(legacy_te), scene_(scene) +{ + BLI_assert(legacy_te.store_elem->type == TSE_R_LAYER_BASE); + legacy_te_.name = IFACE_("View Layers"); +} + +void TreeElementViewLayerBase::expand(SpaceOutliner &space_outliner) const +{ + for (auto *view_layer : ListBaseWrapper<ViewLayer>(scene_.view_layers)) { + TreeElement *tenlay = outliner_add_element( + &space_outliner, &legacy_te_.subtree, &scene_, &legacy_te_, TSE_R_LAYER, 0); + tenlay->name = view_layer->name; + tenlay->directdata = view_layer; + } +} + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_view_layer.hh b/source/blender/editors/space_outliner/tree/tree_element_view_layer.hh new file mode 100644 index 00000000000..24e03b265dc --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_view_layer.hh @@ -0,0 +1,36 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup spoutliner + */ + +#pragma once + +#include "tree_element.hh" + +namespace blender::ed::outliner { + +class TreeElementViewLayerBase final : public AbstractTreeElement { + Scene &scene_; + + public: + TreeElementViewLayerBase(TreeElement &legacy_te, Scene &scene); + + void expand(SpaceOutliner &) const override; +}; + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 9828368ccf7..31d3d0bc1bc 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -2112,7 +2112,7 @@ static void seq_draw_sfra_efra(Scene *scene, View2D *v2d) typedef struct CacheDrawData { struct View2D *v2d; - float stripe_offs; + float stripe_ofs_y; float stripe_ht; int cache_flag; GPUVertBuf *raw_vbo; @@ -2151,7 +2151,7 @@ static bool draw_cache_view_iter_fn(void *userdata, { CacheDrawData *drawdata = userdata; struct View2D *v2d = drawdata->v2d; - float stripe_bot, stripe_top, stripe_offs, stripe_ht; + float stripe_bot, stripe_top, stripe_ofs_y, stripe_ht; GPUVertBuf *vbo; size_t *vert_count; @@ -2164,27 +2164,27 @@ static bool draw_cache_view_iter_fn(void *userdata, vert_count = &drawdata->final_out_vert_count; } else if ((cache_type & SEQ_CACHE_STORE_RAW) && (drawdata->cache_flag & SEQ_CACHE_VIEW_RAW)) { - stripe_offs = drawdata->stripe_offs; + stripe_ofs_y = drawdata->stripe_ofs_y; stripe_ht = drawdata->stripe_ht; - stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + stripe_offs; + stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + stripe_ofs_y; stripe_top = stripe_bot + stripe_ht; vbo = drawdata->raw_vbo; vert_count = &drawdata->raw_vert_count; } else if ((cache_type & SEQ_CACHE_STORE_PREPROCESSED) && (drawdata->cache_flag & SEQ_CACHE_VIEW_PREPROCESSED)) { - stripe_offs = drawdata->stripe_offs; + stripe_ofs_y = drawdata->stripe_ofs_y; stripe_ht = drawdata->stripe_ht; - stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + (stripe_offs + stripe_ht) + stripe_offs; + stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + (stripe_ofs_y + stripe_ht) + stripe_ofs_y; stripe_top = stripe_bot + stripe_ht; vbo = drawdata->preprocessed_vbo; vert_count = &drawdata->preprocessed_vert_count; } else if ((cache_type & SEQ_CACHE_STORE_COMPOSITE) && (drawdata->cache_flag & SEQ_CACHE_VIEW_COMPOSITE)) { - stripe_offs = drawdata->stripe_offs; + stripe_ofs_y = drawdata->stripe_ofs_y; stripe_ht = drawdata->stripe_ht; - stripe_top = seq->machine + SEQ_STRIP_OFSTOP - stripe_offs; + stripe_top = seq->machine + SEQ_STRIP_OFSTOP - stripe_ofs_y; stripe_bot = stripe_top - stripe_ht; vbo = drawdata->composite_vbo; vert_count = &drawdata->composite_vert_count; @@ -2237,12 +2237,12 @@ static void draw_cache_view(const bContext *C) immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); float stripe_bot, stripe_top; - float stripe_offs = UI_view2d_region_to_view_y(v2d, 1.0f) - v2d->cur.ymin; + float stripe_ofs_y = UI_view2d_region_to_view_y(v2d, 1.0f) - v2d->cur.ymin; float stripe_ht = UI_view2d_region_to_view_y(v2d, 4.0f * UI_DPI_FAC * U.pixelsize) - v2d->cur.ymin; CLAMP_MAX(stripe_ht, 0.2f); - CLAMP_MIN(stripe_offs, stripe_ht / 2); + CLAMP_MIN(stripe_ofs_y, stripe_ht / 2); if (scene->ed->cache_flag & SEQ_CACHE_VIEW_FINAL_OUT) { stripe_bot = UI_view2d_region_to_view_y(v2d, V2D_SCROLL_HANDLE_HEIGHT); @@ -2262,7 +2262,7 @@ static void draw_cache_view(const bContext *C) continue; } - stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + stripe_offs; + stripe_bot = seq->machine + SEQ_STRIP_OFSBOTTOM + stripe_ofs_y; stripe_top = stripe_bot + stripe_ht; if (scene->ed->cache_flag & SEQ_CACHE_VIEW_RAW) { @@ -2271,7 +2271,7 @@ static void draw_cache_view(const bContext *C) immRectf(pos, seq->startdisp, stripe_bot, seq->enddisp, stripe_top); } - stripe_bot += stripe_ht + stripe_offs; + stripe_bot += stripe_ht + stripe_ofs_y; stripe_top = stripe_bot + stripe_ht; if (scene->ed->cache_flag & SEQ_CACHE_VIEW_PREPROCESSED) { @@ -2280,7 +2280,7 @@ static void draw_cache_view(const bContext *C) immRectf(pos, seq->startdisp, stripe_bot, seq->enddisp, stripe_top); } - stripe_top = seq->machine + SEQ_STRIP_OFSTOP - stripe_offs; + stripe_top = seq->machine + SEQ_STRIP_OFSTOP - stripe_ofs_y; stripe_bot = stripe_top - stripe_ht; if (scene->ed->cache_flag & SEQ_CACHE_VIEW_COMPOSITE) { @@ -2297,7 +2297,7 @@ static void draw_cache_view(const bContext *C) CacheDrawData userdata; userdata.v2d = v2d; - userdata.stripe_offs = stripe_offs; + userdata.stripe_ofs_y = stripe_ofs_y; userdata.stripe_ht = stripe_ht; userdata.cache_flag = scene->ed->cache_flag; userdata.raw_vert_count = 0; diff --git a/source/blender/editors/space_spreadsheet/CMakeLists.txt b/source/blender/editors/space_spreadsheet/CMakeLists.txt new file mode 100644 index 00000000000..8be5f506dd7 --- /dev/null +++ b/source/blender/editors/space_spreadsheet/CMakeLists.txt @@ -0,0 +1,39 @@ +# ***** BEGIN GPL LICENSE BLOCK ***** +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software Foundation, +# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. +# ***** END GPL LICENSE BLOCK ***** + +set(INC + ../include + ../../blenkernel + ../../blenlib + ../../makesdna + ../../makesrna + ../../windowmanager + ../../../../intern/glew-mx + ../../../../intern/guardedalloc +) + +set(SRC + space_spreadsheet.cc + spreadsheet_ops.cc + + spreadsheet_intern.hh +) + +set(LIB +) + +blender_add_lib(bf_editor_space_spreadsheet "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc new file mode 100644 index 00000000000..27276b4bedc --- /dev/null +++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc @@ -0,0 +1,221 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include <cstring> + +#include "BLI_listbase.h" + +#include "BKE_screen.h" + +#include "ED_screen.h" +#include "ED_space_api.h" + +#include "DNA_scene_types.h" +#include "DNA_screen_types.h" +#include "DNA_space_types.h" + +#include "MEM_guardedalloc.h" + +#include "UI_resources.h" +#include "UI_view2d.h" + +#include "RNA_access.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "spreadsheet_intern.hh" + +static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *UNUSED(scene)) +{ + SpaceSpreadsheet *spreadsheet_space = (SpaceSpreadsheet *)MEM_callocN(sizeof(SpaceSpreadsheet), + "spreadsheet space"); + spreadsheet_space->spacetype = SPACE_SPREADSHEET; + + { + /* header */ + ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet header"); + BLI_addtail(&spreadsheet_space->regionbase, region); + region->regiontype = RGN_TYPE_HEADER; + region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP; + } + + { + /* main window */ + ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet main region"); + BLI_addtail(&spreadsheet_space->regionbase, region); + region->regiontype = RGN_TYPE_WINDOW; + } + + return (SpaceLink *)spreadsheet_space; +} + +static void spreadsheet_free(SpaceLink *UNUSED(sl)) +{ +} + +static void spreadsheet_init(wmWindowManager *UNUSED(wm), ScrArea *UNUSED(area)) +{ +} + +static SpaceLink *spreadsheet_duplicate(SpaceLink *sl) +{ + return (SpaceLink *)MEM_dupallocN(sl); +} + +static void spreadsheet_keymap(wmKeyConfig *UNUSED(keyconf)) +{ +} + +static void spreadsheet_main_region_init(wmWindowManager *wm, ARegion *region) +{ + region->v2d.scroll = V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM; + region->v2d.align = V2D_ALIGN_NO_NEG_X | V2D_ALIGN_NO_POS_Y; + region->v2d.keepzoom = V2D_LOCKZOOM_X | V2D_LOCKZOOM_Y | V2D_LIMITZOOM | V2D_KEEPASPECT; + region->v2d.keeptot = V2D_KEEPTOT_STRICT; + region->v2d.minzoom = region->v2d.maxzoom = 1.0f; + + UI_view2d_region_reinit(®ion->v2d, V2D_COMMONVIEW_LIST, region->winx, region->winy); + + wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "View2D Buttons List", 0, 0); + WM_event_add_keymap_handler(®ion->handlers, keymap); +} + +static void spreadsheet_main_region_draw(const bContext *UNUSED(C), ARegion *UNUSED(region)) +{ + UI_ThemeClearColor(TH_BACK); +} + +static void spreadsheet_main_region_listener(const wmRegionListenerParams *params) +{ + ARegion *region = params->region; + wmNotifier *wmn = params->notifier; + + switch (wmn->category) { + case NC_SCENE: { + switch (wmn->data) { + case ND_MODE: + case ND_OB_ACTIVE: { + ED_region_tag_redraw(region); + break; + } + } + break; + } + case NC_OBJECT: { + ED_region_tag_redraw(region); + break; + } + case NC_SPACE: { + if (wmn->data == ND_SPACE_SPREADSHEET) { + ED_region_tag_redraw(region); + } + break; + } + case NC_GEOM: { + ED_region_tag_redraw(region); + break; + } + } +} + +static void spreadsheet_header_region_init(wmWindowManager *UNUSED(wm), ARegion *region) +{ + ED_region_header_init(region); +} + +static void spreadsheet_header_region_draw(const bContext *C, ARegion *region) +{ + ED_region_header(C, region); +} + +static void spreadsheet_header_region_free(ARegion *UNUSED(region)) +{ +} + +static void spreadsheet_header_region_listener(const wmRegionListenerParams *params) +{ + ARegion *region = params->region; + wmNotifier *wmn = params->notifier; + + switch (wmn->category) { + case NC_SCENE: { + switch (wmn->data) { + case ND_MODE: + case ND_OB_ACTIVE: { + ED_region_tag_redraw(region); + break; + } + } + break; + } + case NC_OBJECT: { + ED_region_tag_redraw(region); + break; + } + case NC_SPACE: { + if (wmn->data == ND_SPACE_SPREADSHEET) { + ED_region_tag_redraw(region); + } + break; + } + case NC_GEOM: { + ED_region_tag_redraw(region); + break; + } + } +} + +void ED_spacetype_spreadsheet(void) +{ + SpaceType *st = (SpaceType *)MEM_callocN(sizeof(SpaceType), "spacetype spreadsheet"); + ARegionType *art; + + st->spaceid = SPACE_SPREADSHEET; + strncpy(st->name, "Spreadsheet", BKE_ST_MAXNAME); + + st->create = spreadsheet_create; + st->free = spreadsheet_free; + st->init = spreadsheet_init; + st->duplicate = spreadsheet_duplicate; + st->operatortypes = spreadsheet_operatortypes; + st->keymap = spreadsheet_keymap; + + /* regions: main window */ + art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet region"); + art->regionid = RGN_TYPE_WINDOW; + art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D; + + art->init = spreadsheet_main_region_init; + art->draw = spreadsheet_main_region_draw; + art->listener = spreadsheet_main_region_listener; + BLI_addhead(&st->regiontypes, art); + + /* regions: header */ + art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet header region"); + art->regionid = RGN_TYPE_HEADER; + art->prefsizey = HEADERY; + art->keymapflag = 0; + art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER; + + art->init = spreadsheet_header_region_init; + art->draw = spreadsheet_header_region_draw; + art->free = spreadsheet_header_region_free; + art->listener = spreadsheet_header_region_listener; + BLI_addhead(&st->regiontypes, art); + + BKE_spacetype_register(st); +} diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh b/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh new file mode 100644 index 00000000000..10a875e2c14 --- /dev/null +++ b/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh @@ -0,0 +1,19 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#pragma once + +void spreadsheet_operatortypes(void); diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc b/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc new file mode 100644 index 00000000000..770bd207e8d --- /dev/null +++ b/source/blender/editors/space_spreadsheet/spreadsheet_ops.cc @@ -0,0 +1,21 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "spreadsheet_intern.hh" + +void spreadsheet_operatortypes() +{ +} diff --git a/source/blender/editors/space_view3d/view3d_placement.c b/source/blender/editors/space_view3d/view3d_placement.c index c75d9796265..48f274ca71b 100644 --- a/source/blender/editors/space_view3d/view3d_placement.c +++ b/source/blender/editors/space_view3d/view3d_placement.c @@ -1438,6 +1438,8 @@ static int view3d_interactive_add_modal(bContext *C, wmOperator *op, const wmEve const int cube_verts[3] = {3, 1, 4}; for (int i = 0; i < 3; i++) { scale[i] = len_v3v3(bounds.vec[0], bounds.vec[cube_verts[i]]); + /* Primitives have size 2 by default, compensate for this here. */ + scale[i] /= 2.0f; } wmOperatorType *ot = NULL; diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 0605ea30806..7dc4a72e510 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -1673,8 +1673,8 @@ static int selectbuffer_ret_hits_15(uint *UNUSED(buffer), const int hits15) static int selectbuffer_ret_hits_9(uint *buffer, const int hits15, const int hits9) { - const int offs = 4 * hits15; - memcpy(buffer, buffer + offs, 4 * hits9 * sizeof(uint)); + const int ofs = 4 * hits15; + memcpy(buffer, buffer + ofs, 4 * hits9 * sizeof(uint)); return hits9; } @@ -1683,8 +1683,8 @@ static int selectbuffer_ret_hits_5(uint *buffer, const int hits9, const int hits5) { - const int offs = 4 * hits15 + 4 * hits9; - memcpy(buffer, buffer + offs, 4 * hits5 * sizeof(uint)); + const int ofs = 4 * hits15 + 4 * hits9; + memcpy(buffer, buffer + ofs, 4 * hits5 * sizeof(uint)); return hits5; } @@ -1726,30 +1726,30 @@ static int mixed_bones_object_selectbuffer(ViewContext *vc, goto finally; } else if (hits15 > 0) { - int offs; + int ofs; has_bones15 = selectbuffer_has_bones(buffer, hits15); - offs = 4 * hits15; + ofs = 4 * hits15; BLI_rcti_init_pt_radius(&rect, mval, 9); hits9 = view3d_opengl_select( - vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode, select_filter); + vc, buffer + ofs, MAXPICKBUF - ofs, &rect, select_mode, select_filter); if (hits9 == 1) { hits = selectbuffer_ret_hits_9(buffer, hits15, hits9); goto finally; } else if (hits9 > 0) { - has_bones9 = selectbuffer_has_bones(buffer + offs, hits9); + has_bones9 = selectbuffer_has_bones(buffer + ofs, hits9); - offs += 4 * hits9; + ofs += 4 * hits9; BLI_rcti_init_pt_radius(&rect, mval, 5); hits5 = view3d_opengl_select( - vc, buffer + offs, MAXPICKBUF - offs, &rect, select_mode, select_filter); + vc, buffer + ofs, MAXPICKBUF - ofs, &rect, select_mode, select_filter); if (hits5 == 1) { hits = selectbuffer_ret_hits_5(buffer, hits15, hits9, hits5); goto finally; } else if (hits5 > 0) { - has_bones5 = selectbuffer_has_bones(buffer + offs, hits5); + has_bones5 = selectbuffer_has_bones(buffer + ofs, hits5); } } diff --git a/source/blender/editors/util/ed_util_ops.cc b/source/blender/editors/util/ed_util_ops.cc index 5b2e1a16bc2..06f1b999d58 100644 --- a/source/blender/editors/util/ed_util_ops.cc +++ b/source/blender/editors/util/ed_util_ops.cc @@ -92,7 +92,7 @@ static int lib_id_load_custom_preview_exec(bContext *C, wmOperator *op) BKE_previewimg_id_custom_set(id, path); - WM_event_add_notifier(C, NC_ASSET, nullptr); + WM_event_add_notifier(C, NC_ASSET | NA_EDITED, nullptr); return OPERATOR_FINISHED; } @@ -133,7 +133,7 @@ static int lib_id_generate_preview_exec(bContext *C, wmOperator *UNUSED(op)) } UI_icon_render_id(C, nullptr, id, ICON_SIZE_PREVIEW, true); - WM_event_add_notifier(C, NC_ASSET, nullptr); + WM_event_add_notifier(C, NC_ASSET | NA_EDITED, nullptr); return OPERATOR_FINISHED; } diff --git a/source/blender/functions/CMakeLists.txt b/source/blender/functions/CMakeLists.txt index 429959f9c33..e4a0b154a07 100644 --- a/source/blender/functions/CMakeLists.txt +++ b/source/blender/functions/CMakeLists.txt @@ -27,7 +27,6 @@ set(INC_SYS ) set(SRC - intern/attributes_ref.cc intern/cpp_types.cc intern/multi_function.cc intern/multi_function_builder.cc @@ -36,7 +35,6 @@ set(SRC intern/multi_function_network_optimization.cc FN_array_spans.hh - FN_attributes_ref.hh FN_cpp_type.hh FN_generic_pointer.hh FN_generic_value_map.hh @@ -63,7 +61,6 @@ blender_add_lib(bf_functions "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") if(WITH_GTESTS) set(TEST_SRC tests/FN_array_spans_test.cc - tests/FN_attributes_ref_test.cc tests/FN_cpp_type_test.cc tests/FN_generic_vector_array_test.cc tests/FN_multi_function_network_test.cc diff --git a/source/blender/functions/FN_attributes_ref.hh b/source/blender/functions/FN_attributes_ref.hh deleted file mode 100644 index a9236f73549..00000000000 --- a/source/blender/functions/FN_attributes_ref.hh +++ /dev/null @@ -1,341 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#pragma once - -/** \file - * \ingroup fn - * - * An AttributesRef references multiple arrays of equal length. Each array has a corresponding name - * and index. - */ - -#include <optional> - -#include "FN_spans.hh" - -#include "BLI_linear_allocator.hh" -#include "BLI_map.hh" -#include "BLI_utility_mixins.hh" -#include "BLI_vector_set.hh" - -namespace blender::fn { - -class AttributesInfo; - -class AttributesInfoBuilder : NonCopyable, NonMovable { - private: - LinearAllocator<> allocator_; - VectorSet<std::string> names_; - Vector<const CPPType *> types_; - Vector<void *> defaults_; - - friend AttributesInfo; - - public: - AttributesInfoBuilder() = default; - ~AttributesInfoBuilder(); - - template<typename T> bool add(StringRef name, const T &default_value) - { - return this->add(name, CPPType::get<T>(), static_cast<const void *>(&default_value)); - } - - bool add(StringRef name, const CPPType &type, const void *default_value = nullptr); -}; - -/** - * Stores which attributes are in an AttributesRef. Every attribute has a unique index, a unique - * name, a type and a default value. - */ -class AttributesInfo : NonCopyable, NonMovable { - private: - LinearAllocator<> allocator_; - Map<StringRefNull, int> index_by_name_; - Vector<StringRefNull> name_by_index_; - Vector<const CPPType *> type_by_index_; - Vector<void *> defaults_; - - public: - AttributesInfo() = default; - AttributesInfo(const AttributesInfoBuilder &builder); - ~AttributesInfo(); - - int size() const - { - return name_by_index_.size(); - } - - IndexRange index_range() const - { - return name_by_index_.index_range(); - } - - StringRefNull name_of(int index) const - { - return name_by_index_[index]; - } - - int index_of(StringRef name) const - { - return index_by_name_.lookup_as(name); - } - - const void *default_of(int index) const - { - return defaults_[index]; - } - - const void *default_of(StringRef name) const - { - return this->default_of(this->index_of(name)); - } - - template<typename T> const T &default_of(int index) const - { - BLI_assert(type_by_index_[index]->is<T>()); - return *static_cast<T *>(defaults_[index]); - } - - template<typename T> const T &default_of(StringRef name) const - { - return this->default_of<T>(this->index_of(name)); - } - - const CPPType &type_of(int index) const - { - return *type_by_index_[index]; - } - - const CPPType &type_of(StringRef name) const - { - return this->type_of(this->index_of(name)); - } - - bool has_attribute(StringRef name, const CPPType &type) const - { - return this->try_index_of(name, type) >= 0; - } - - int try_index_of(StringRef name) const - { - return index_by_name_.lookup_default_as(name, -1); - } - - int try_index_of(StringRef name, const CPPType &type) const - { - int index = this->try_index_of(name); - if (index == -1) { - return -1; - } - else if (this->type_of(index) == type) { - return index; - } - else { - return -1; - } - } -}; - -/** - * References multiple arrays that match the description of an AttributesInfo instance. This class - * is supposed to be relatively cheap to copy. It does not own any of the arrays itself. - */ -class MutableAttributesRef { - private: - const AttributesInfo *info_; - Span<void *> buffers_; - IndexRange range_; - - friend class AttributesRef; - - public: - MutableAttributesRef(const AttributesInfo &info, Span<void *> buffers, int64_t size) - : MutableAttributesRef(info, buffers, IndexRange(size)) - { - } - - MutableAttributesRef(const AttributesInfo &info, Span<void *> buffers, IndexRange range) - : info_(&info), buffers_(buffers), range_(range) - { - } - - int64_t size() const - { - return range_.size(); - } - - IndexRange index_range() const - { - return IndexRange(this->size()); - } - - const AttributesInfo &info() const - { - return *info_; - } - - GMutableSpan get(int index) const - { - const CPPType &type = info_->type_of(index); - void *ptr = POINTER_OFFSET(buffers_[index], type.size() * range_.start()); - return GMutableSpan(type, ptr, range_.size()); - } - - GMutableSpan get(StringRef name) const - { - return this->get(info_->index_of(name)); - } - - template<typename T> MutableSpan<T> get(int index) const - { - BLI_assert(info_->type_of(index).is<T>()); - return MutableSpan<T>(static_cast<T *>(buffers_[index]) + range_.start(), range_.size()); - } - - template<typename T> MutableSpan<T> get(StringRef name) const - { - return this->get<T>(info_->index_of(name)); - } - - std::optional<GMutableSpan> try_get(StringRef name, const CPPType &type) const - { - int index = info_->try_index_of(name, type); - if (index == -1) { - return {}; - } - else { - return this->get(index); - } - } - - template<typename T> std::optional<MutableSpan<T>> try_get(StringRef name) const - { - int index = info_->try_index_of(name); - if (index == -1) { - return {}; - } - else if (info_->type_of(index).is<T>()) { - return this->get<T>(index); - } - else { - return {}; - } - } - - MutableAttributesRef slice(IndexRange range) const - { - return this->slice(range.start(), range.size()); - } - - MutableAttributesRef slice(int64_t start, int64_t size) const - { - return MutableAttributesRef(*info_, buffers_, range_.slice(start, size)); - } -}; - -class AttributesRef { - private: - const AttributesInfo *info_; - Span<const void *> buffers_; - IndexRange range_; - - public: - AttributesRef(const AttributesInfo &info, Span<const void *> buffers, int64_t size) - : AttributesRef(info, buffers, IndexRange(size)) - { - } - - AttributesRef(const AttributesInfo &info, Span<const void *> buffers, IndexRange range) - : info_(&info), buffers_(buffers), range_(range) - { - } - - AttributesRef(MutableAttributesRef attributes) - : info_(attributes.info_), buffers_(attributes.buffers_), range_(attributes.range_) - { - } - - int64_t size() const - { - return range_.size(); - } - - const AttributesInfo &info() const - { - return *info_; - } - - GSpan get(int index) const - { - const CPPType &type = info_->type_of(index); - const void *ptr = POINTER_OFFSET(buffers_[index], type.size() * range_.start()); - return GSpan(type, ptr, range_.size()); - } - - GSpan get(StringRef name) const - { - return this->get(info_->index_of(name)); - } - - template<typename T> Span<T> get(int index) const - { - BLI_assert(info_->type_of(index).is<T>()); - return Span<T>(static_cast<T *>(buffers_[index]) + range_.start(), range_.size()); - } - - template<typename T> Span<T> get(StringRef name) const - { - return this->get<T>(info_->index_of(name)); - } - - std::optional<GSpan> try_get(StringRef name, const CPPType &type) const - { - int64_t index = info_->try_index_of(name, type); - if (index == -1) { - return {}; - } - else { - return this->get(index); - } - } - - template<typename T> std::optional<Span<T>> try_get(StringRef name) const - { - int index = info_->try_index_of(name); - if (index == -1) { - return {}; - } - else if (info_->type_of(index).is<T>()) { - return this->get<T>(index); - } - else { - return {}; - } - } - - AttributesRef slice(IndexRange range) const - { - return this->slice(range.start(), range.size()); - } - - AttributesRef slice(int64_t start, int64_t size) const - { - return AttributesRef(*info_, buffers_, range_.slice(start, size)); - } -}; - -} // namespace blender::fn diff --git a/source/blender/functions/FN_cpp_type.hh b/source/blender/functions/FN_cpp_type.hh index a854e63288d..b8ac97d6dbd 100644 --- a/source/blender/functions/FN_cpp_type.hh +++ b/source/blender/functions/FN_cpp_type.hh @@ -935,3 +935,9 @@ inline std::unique_ptr<const CPPType> create_cpp_type(StringRef name, const T &d { \ return blender::fn::CPPType::get<TYPE_NAME>(); \ } + +/* Utility for allocating an uninitialized buffer for a single value of the given #CPPType. */ +#define BUFFER_FOR_CPP_TYPE_VALUE(type, variable_name) \ + blender::DynamicStackBuffer<64, 64> stack_buffer_for_##variable_name(type.size(), \ + type.alignment()); \ + void *variable_name = stack_buffer_for_##variable_name.buffer(); diff --git a/source/blender/functions/FN_multi_function_builder.hh b/source/blender/functions/FN_multi_function_builder.hh index 6d5ca7f64ad..0cd1bc262be 100644 --- a/source/blender/functions/FN_multi_function_builder.hh +++ b/source/blender/functions/FN_multi_function_builder.hh @@ -170,6 +170,63 @@ class CustomMF_SI_SI_SI_SO : public MultiFunction { /** * Generates a multi-function with the following parameters: + * 1. single input (SI) of type In1 + * 2. single input (SI) of type In2 + * 3. single input (SI) of type In3 + * 4. single input (SI) of type In4 + * 5. single output (SO) of type Out1 + */ +template<typename In1, typename In2, typename In3, typename In4, typename Out1> +class CustomMF_SI_SI_SI_SI_SO : public MultiFunction { + private: + using FunctionT = std::function<void( + IndexMask, VSpan<In1>, VSpan<In2>, VSpan<In3>, VSpan<In4>, MutableSpan<Out1>)>; + FunctionT function_; + + public: + CustomMF_SI_SI_SI_SI_SO(StringRef name, FunctionT function) : function_(std::move(function)) + { + MFSignatureBuilder signature = this->get_builder(name); + signature.single_input<In1>("In1"); + signature.single_input<In2>("In2"); + signature.single_input<In3>("In3"); + signature.single_input<In4>("In4"); + signature.single_output<Out1>("Out1"); + } + + template<typename ElementFuncT> + CustomMF_SI_SI_SI_SI_SO(StringRef name, ElementFuncT element_fn) + : CustomMF_SI_SI_SI_SI_SO(name, CustomMF_SI_SI_SI_SI_SO::create_function(element_fn)) + { + } + + template<typename ElementFuncT> static FunctionT create_function(ElementFuncT element_fn) + { + return [=](IndexMask mask, + VSpan<In1> in1, + VSpan<In2> in2, + VSpan<In3> in3, + VSpan<In4> in4, + MutableSpan<Out1> out1) { + mask.foreach_index([&](int i) { + new (static_cast<void *>(&out1[i])) Out1(element_fn(in1[i], in2[i], in3[i], in4[i])); + }); + }; + } + + void call(IndexMask mask, MFParams params, MFContext UNUSED(context)) const override + { + VSpan<In1> in1 = params.readonly_single_input<In1>(0); + VSpan<In2> in2 = params.readonly_single_input<In2>(1); + VSpan<In3> in3 = params.readonly_single_input<In3>(2); + VSpan<In4> in4 = params.readonly_single_input<In4>(3); + MutableSpan<Out1> out1 = params.uninitialized_single_output<Out1>(4); + function_(mask, in1, in2, in3, in4, out1); + } +}; + +/** + * Generates a multi-function with the following parameters: * 1. single mutable (SM) of type Mut1 */ template<typename Mut1> class CustomMF_SM : public MultiFunction { diff --git a/source/blender/functions/intern/attributes_ref.cc b/source/blender/functions/intern/attributes_ref.cc deleted file mode 100644 index 9f1e7fa65e5..00000000000 --- a/source/blender/functions/intern/attributes_ref.cc +++ /dev/null @@ -1,78 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "FN_attributes_ref.hh" - -namespace blender::fn { - -AttributesInfoBuilder::~AttributesInfoBuilder() -{ - for (int i : defaults_.index_range()) { - types_[i]->destruct(defaults_[i]); - } -} - -bool AttributesInfoBuilder::add(StringRef name, const CPPType &type, const void *default_value) -{ - if (name.size() == 0) { - std::cout << "Warning: Tried to add an attribute with empty name.\n"; - return false; - } - if (names_.add_as(name)) { - types_.append(&type); - - if (default_value == nullptr) { - default_value = type.default_value(); - } - void *dst = allocator_.allocate(type.size(), type.alignment()); - type.copy_to_uninitialized(default_value, dst); - defaults_.append(dst); - return true; - } - - const CPPType &stored_type = *types_[names_.index_of_as(name)]; - if (stored_type != type) { - std::cout << "Warning: Tried to add an attribute twice with different types (" << name << ": " - << stored_type.name() << ", " << type.name() << ").\n"; - } - return false; -} - -AttributesInfo::AttributesInfo(const AttributesInfoBuilder &builder) -{ - for (int i : builder.types_.index_range()) { - StringRefNull name = allocator_.copy_string(builder.names_[i]); - const CPPType &type = *builder.types_[i]; - const void *default_value = builder.defaults_[i]; - - index_by_name_.add_new(name, i); - name_by_index_.append(name); - type_by_index_.append(&type); - - void *dst = allocator_.allocate(type.size(), type.alignment()); - type.copy_to_uninitialized(default_value, dst); - defaults_.append(dst); - } -} - -AttributesInfo::~AttributesInfo() -{ - for (int i : defaults_.index_range()) { - type_by_index_[i]->destruct(defaults_[i]); - } -} - -} // namespace blender::fn diff --git a/source/blender/functions/intern/multi_function_network.cc b/source/blender/functions/intern/multi_function_network.cc index 77c8ba6373f..b5c2c09a35a 100644 --- a/source/blender/functions/intern/multi_function_network.cc +++ b/source/blender/functions/intern/multi_function_network.cc @@ -70,7 +70,7 @@ MFFunctionNode &MFNetwork::add_function(const MultiFunction &function) } } - MFFunctionNode &node = *allocator_.construct<MFFunctionNode>(); + MFFunctionNode &node = *allocator_.construct<MFFunctionNode>().release(); function_nodes_.add_new(&node); node.network_ = this; @@ -129,7 +129,7 @@ MFDummyNode &MFNetwork::add_dummy(StringRef name, assert_same_size(input_types, input_names); assert_same_size(output_types, output_names); - MFDummyNode &node = *allocator_.construct<MFDummyNode>(); + MFDummyNode &node = *allocator_.construct<MFDummyNode>().release(); dummy_nodes_.add_new(&node); node.network_ = this; diff --git a/source/blender/functions/intern/multi_function_network_evaluation.cc b/source/blender/functions/intern/multi_function_network_evaluation.cc index c543d86ad34..5a37a45908f 100644 --- a/source/blender/functions/intern/multi_function_network_evaluation.cc +++ b/source/blender/functions/intern/multi_function_network_evaluation.cc @@ -663,7 +663,7 @@ void MFNetworkEvaluationStorage::add_single_input_from_caller(const MFOutputSock BLI_assert(value_per_output_id_[socket.id()] == nullptr); BLI_assert(virtual_span.size() >= min_array_size_); - auto *value = allocator_.construct<InputSingleValue>(virtual_span); + auto *value = allocator_.construct<InputSingleValue>(virtual_span).release(); value_per_output_id_[socket.id()] = value; } @@ -673,7 +673,7 @@ void MFNetworkEvaluationStorage::add_vector_input_from_caller(const MFOutputSock BLI_assert(value_per_output_id_[socket.id()] == nullptr); BLI_assert(virtual_array_span.size() >= min_array_size_); - auto *value = allocator_.construct<InputVectorValue>(virtual_array_span); + auto *value = allocator_.construct<InputVectorValue>(virtual_array_span).release(); value_per_output_id_[socket.id()] = value; } @@ -683,7 +683,7 @@ void MFNetworkEvaluationStorage::add_single_output_from_caller(const MFOutputSoc BLI_assert(value_per_output_id_[socket.id()] == nullptr); BLI_assert(span.size() >= min_array_size_); - auto *value = allocator_.construct<OutputSingleValue>(span); + auto *value = allocator_.construct<OutputSingleValue>(span).release(); value_per_output_id_[socket.id()] = value; } @@ -693,7 +693,7 @@ void MFNetworkEvaluationStorage::add_vector_output_from_caller(const MFOutputSoc BLI_assert(value_per_output_id_[socket.id()] == nullptr); BLI_assert(vector_array.size() >= min_array_size_); - auto *value = allocator_.construct<OutputVectorValue>(vector_array); + auto *value = allocator_.construct<OutputVectorValue>(vector_array).release(); value_per_output_id_[socket.id()] = value; } @@ -705,7 +705,8 @@ GMutableSpan MFNetworkEvaluationStorage::get_single_output__full(const MFOutputS void *buffer = MEM_mallocN_aligned(min_array_size_ * type.size(), type.alignment(), AT); GMutableSpan span(type, buffer, min_array_size_); - auto *value = allocator_.construct<OwnSingleValue>(span, socket.targets().size(), false); + auto *value = + allocator_.construct<OwnSingleValue>(span, socket.targets().size(), false).release(); value_per_output_id_[socket.id()] = value; return span; @@ -723,7 +724,8 @@ GMutableSpan MFNetworkEvaluationStorage::get_single_output__single(const MFOutpu void *buffer = allocator_.allocate(type.size(), type.alignment()); GMutableSpan span(type, buffer, 1); - auto *value = allocator_.construct<OwnSingleValue>(span, socket.targets().size(), true); + auto *value = + allocator_.construct<OwnSingleValue>(span, socket.targets().size(), true).release(); value_per_output_id_[socket.id()] = value; return value->span; @@ -742,7 +744,8 @@ GVectorArray &MFNetworkEvaluationStorage::get_vector_output__full(const MFOutput const CPPType &type = socket.data_type().vector_base_type(); GVectorArray *vector_array = new GVectorArray(type, min_array_size_); - auto *value = allocator_.construct<OwnVectorValue>(*vector_array, socket.targets().size()); + auto *value = + allocator_.construct<OwnVectorValue>(*vector_array, socket.targets().size()).release(); value_per_output_id_[socket.id()] = value; return *value->vector_array; @@ -759,7 +762,8 @@ GVectorArray &MFNetworkEvaluationStorage::get_vector_output__single(const MFOutp const CPPType &type = socket.data_type().vector_base_type(); GVectorArray *vector_array = new GVectorArray(type, 1); - auto *value = allocator_.construct<OwnVectorValue>(*vector_array, socket.targets().size()); + auto *value = + allocator_.construct<OwnVectorValue>(*vector_array, socket.targets().size()).release(); value_per_output_id_[socket.id()] = value; return *value->vector_array; @@ -806,8 +810,8 @@ GMutableSpan MFNetworkEvaluationStorage::get_mutable_single__full(const MFInputS GMutableSpan new_array_ref(type, new_buffer, min_array_size_); virtual_span.materialize_to_uninitialized(mask_, new_array_ref.data()); - OwnSingleValue *new_value = allocator_.construct<OwnSingleValue>( - new_array_ref, to.targets().size(), false); + OwnSingleValue *new_value = + allocator_.construct<OwnSingleValue>(new_array_ref, to.targets().size(), false).release(); value_per_output_id_[to.id()] = new_value; return new_array_ref; } @@ -850,8 +854,8 @@ GMutableSpan MFNetworkEvaluationStorage::get_mutable_single__single(const MFInpu type.copy_to_uninitialized(virtual_span.as_single_element(), new_buffer); GMutableSpan new_array_ref(type, new_buffer, 1); - OwnSingleValue *new_value = allocator_.construct<OwnSingleValue>( - new_array_ref, to.targets().size(), true); + OwnSingleValue *new_value = + allocator_.construct<OwnSingleValue>(new_array_ref, to.targets().size(), true).release(); value_per_output_id_[to.id()] = new_value; return new_array_ref; } @@ -891,8 +895,8 @@ GVectorArray &MFNetworkEvaluationStorage::get_mutable_vector__full(const MFInput GVectorArray *new_vector_array = new GVectorArray(base_type, min_array_size_); new_vector_array->extend(mask_, virtual_array_span); - OwnVectorValue *new_value = allocator_.construct<OwnVectorValue>(*new_vector_array, - to.targets().size()); + OwnVectorValue *new_value = + allocator_.construct<OwnVectorValue>(*new_vector_array, to.targets().size()).release(); value_per_output_id_[to.id()] = new_value; return *new_vector_array; @@ -934,8 +938,8 @@ GVectorArray &MFNetworkEvaluationStorage::get_mutable_vector__single(const MFInp GVectorArray *new_vector_array = new GVectorArray(base_type, 1); new_vector_array->extend(0, virtual_array_span[0]); - OwnVectorValue *new_value = allocator_.construct<OwnVectorValue>(*new_vector_array, - to.targets().size()); + OwnVectorValue *new_value = + allocator_.construct<OwnVectorValue>(*new_vector_array, to.targets().size()).release(); value_per_output_id_[to.id()] = new_value; return *new_vector_array; } diff --git a/source/blender/functions/tests/FN_attributes_ref_test.cc b/source/blender/functions/tests/FN_attributes_ref_test.cc deleted file mode 100644 index 3a5e4743c1e..00000000000 --- a/source/blender/functions/tests/FN_attributes_ref_test.cc +++ /dev/null @@ -1,97 +0,0 @@ -/* Apache License, Version 2.0 */ - -#include "BLI_float3.hh" -#include "FN_attributes_ref.hh" - -#include "testing/testing.h" - -namespace blender::fn::tests { - -TEST(attributes_info, BuildEmpty) -{ - AttributesInfoBuilder info_builder; - AttributesInfo info{info_builder}; - - EXPECT_EQ(info.size(), 0); -} - -TEST(attributes_info, AddSameNameTwice) -{ - AttributesInfoBuilder info_builder; - info_builder.add<int>("A", 4); - info_builder.add<int>("A", 5); - AttributesInfo info{info_builder}; - EXPECT_EQ(info.size(), 1); - EXPECT_TRUE(info.has_attribute("A", CPPType::get<int>())); - EXPECT_FALSE(info.has_attribute("B", CPPType::get<int>())); - EXPECT_FALSE(info.has_attribute("A", CPPType::get<float>())); - EXPECT_EQ(info.default_of<int>("A"), 4); - EXPECT_EQ(info.name_of(0), "A"); - EXPECT_EQ(info.index_range().start(), 0); - EXPECT_EQ(info.index_range().one_after_last(), 1); -} - -TEST(attributes_info, BuildWithDefaultString) -{ - AttributesInfoBuilder info_builder; - info_builder.add("A", CPPType::get<std::string>()); - AttributesInfo info{info_builder}; - EXPECT_EQ(info.default_of<std::string>("A"), ""); -} - -TEST(attributes_info, BuildWithGivenDefault) -{ - AttributesInfoBuilder info_builder; - info_builder.add<std::string>("A", "hello world"); - AttributesInfo info{info_builder}; - const void *default_value = info.default_of("A"); - EXPECT_EQ(*(const std::string *)default_value, "hello world"); - EXPECT_EQ(info.type_of("A"), CPPType::get<std::string>()); -} - -TEST(mutable_attributes_ref, ComplexTest) -{ - AttributesInfoBuilder info_builder; - info_builder.add<float3>("Position", {0, 0, 10}); - info_builder.add<uint>("ID", 0); - info_builder.add<float>("Size", 0.5f); - info_builder.add<std::string>("Name", "<no name>"); - AttributesInfo info{info_builder}; - - int amount = 5; - Array<float3> positions(amount); - Array<uint> ids(amount, 0); - Array<float> sizes(amount); - Array<std::string> names(amount); - - Array<void *> buffers = {positions.data(), ids.data(), sizes.data(), names.data()}; - MutableAttributesRef attributes{info, buffers, IndexRange(1, 3)}; - EXPECT_EQ(attributes.size(), 3); - EXPECT_EQ(attributes.info().size(), 4); - EXPECT_EQ(attributes.get("Position").data(), positions.data() + 1); - EXPECT_EQ(attributes.get("ID").data(), ids.data() + 1); - EXPECT_EQ(attributes.get("Size").data(), sizes.data() + 1); - EXPECT_EQ(attributes.get("Name").data(), names.data() + 1); - - EXPECT_EQ(attributes.get("ID").size(), 3); - EXPECT_EQ(attributes.get<uint>("ID").size(), 3); - - EXPECT_EQ(ids[2], 0); - MutableSpan<uint> ids_span = attributes.get<uint>("ID"); - ids_span[1] = 42; - EXPECT_EQ(ids[2], 42); - - EXPECT_FALSE(attributes.try_get<int>("not existant").has_value()); - EXPECT_FALSE(attributes.try_get<int>("Position").has_value()); - EXPECT_TRUE(attributes.try_get<float3>("Position").has_value()); - EXPECT_FALSE(attributes.try_get("not existant", CPPType::get<int>()).has_value()); - EXPECT_FALSE(attributes.try_get("Position", CPPType::get<int>()).has_value()); - EXPECT_TRUE(attributes.try_get("Position", CPPType::get<float3>()).has_value()); - - MutableAttributesRef sliced = attributes.slice(IndexRange(1, 2)); - EXPECT_EQ(sliced.size(), 2); - sliced.get<uint>("ID")[0] = 100; - EXPECT_EQ(ids[2], 100); -} - -} // namespace blender::fn::tests diff --git a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c index 05e7a23bc82..10383a9417d 100644 --- a/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c +++ b/source/blender/gpencil_modifiers/intern/MOD_gpencil_ui_common.c @@ -371,14 +371,9 @@ PanelType *gpencil_modifier_panel_register(ARegionType *region_type, GpencilModifierType type, PanelDrawFn draw) { + PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__); - /* Get the name for the modifier's panel. */ - char panel_idname[BKE_ST_MAXNAME]; - BKE_gpencil_modifierType_panel_id(type, panel_idname); - - PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname); - - BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME); + BKE_gpencil_modifierType_panel_id(type, panel_type->idname); BLI_strncpy(panel_type->label, "", BKE_ST_MAXNAME); BLI_strncpy(panel_type->context, "modifier", BKE_ST_MAXNAME); BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME); @@ -412,13 +407,9 @@ PanelType *gpencil_modifier_subpanel_register(ARegionType *region_type, PanelDrawFn draw, PanelType *parent) { - /* Create the subpanel's ID name. */ - char panel_idname[BKE_ST_MAXNAME]; - BLI_snprintf(panel_idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name); - - PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname); + PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__); - BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME); + BLI_snprintf(panel_type->idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name); BLI_strncpy(panel_type->label, label, BKE_ST_MAXNAME); BLI_strncpy(panel_type->context, "modifier", BKE_ST_MAXNAME); BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME); diff --git a/source/blender/gpu/intern/gpu_matrix.cc b/source/blender/gpu/intern/gpu_matrix.cc index 24cdea74347..2ae50d913da 100644 --- a/source/blender/gpu/intern/gpu_matrix.cc +++ b/source/blender/gpu/intern/gpu_matrix.cc @@ -736,7 +736,7 @@ float GPU_polygon_offset_calc(const float (*winmat)[4], float viewdist, float di int depthbits = 24; depth_fac = 1.0f / (float)((1 << depthbits) - 1); } - offs = (-1.0 / winmat[2][2]) * dist * depth_fac; + ofs = (-1.0 / winmat[2][2]) * dist * depth_fac; UNUSED_VARS(viewdist); #endif @@ -765,10 +765,10 @@ void GPU_polygon_offset(float viewdist, float dist) /* dist is from camera to center point */ - float offs = GPU_polygon_offset_calc(winmat, viewdist, dist); + float ofs = GPU_polygon_offset_calc(winmat, viewdist, dist); - winmat[3][2] -= offs; - offset += offs; + winmat[3][2] -= ofs; + offset += ofs; } else { winmat[3][2] += offset; diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl index 0231aeca04b..edf2c93c9a0 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_ambient_occlusion.glsl @@ -3,12 +3,13 @@ void node_ambient_occlusion(vec4 color, float dist, vec3 normal, const float inverted, + const float sample_count, out vec4 result_color, out float result_ao) { vec3 bent_normal; vec4 rand = texelfetch_noise_tex(gl_FragCoord.xy); - OcclusionData data = occlusion_search(viewPosition, maxzBuffer, dist, inverted, 8.0); + OcclusionData data = occlusion_search(viewPosition, maxzBuffer, dist, inverted, sample_count); vec3 V = cameraVec(worldPosition); vec3 N = normalize(normal); diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 14f0fef5270..c708219cfe8 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -566,6 +566,12 @@ enum { /* RESET_AFTER_USE Used by undo system to tag unchanged IDs re-used from old Main (instead of * read from memfile). */ LIB_TAG_UNDO_OLD_ID_REUSED = 1 << 19, + + /* This ID is part of a temporary #Main which is expected to be freed in a short time-frame. + * Don't allow assigning this to non-temporary members (since it's likely to cause errors). + * When set #ID.session_uuid isn't initialized, since the data isn't part of the session. */ + LIB_TAG_TEMP_MAIN = 1 << 20, + }; /* Tag given ID for an update in all the dependency graphs. */ diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index dbcb6ce45ea..368b1f93e4a 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -904,6 +904,7 @@ enum { eBooleanModifierFlag_Self = (1 << 0), eBooleanModifierFlag_Object = (1 << 1), eBooleanModifierFlag_Collection = (1 << 2), + eBooleanModifierFlag_HoleTolerant = (1 << 3), }; /* bm_flag only used when G_DEBUG. */ diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 8b0bc235861..82509599931 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1070,7 +1070,8 @@ typedef struct CryptomatteEntry { typedef struct NodeCryptomatte { float add[3]; float remove[3]; - char *matte_id DNA_DEPRECATED; + /* Stores `entries` as a string for opening in 2.80-2.91. */ + char *matte_id; /* Contains `CryptomatteEntry`. */ ListBase entries; int num_inputs; diff --git a/source/blender/makesdna/DNA_outliner_types.h b/source/blender/makesdna/DNA_outliner_types.h index 16129768b60..7a39e0caef3 100644 --- a/source/blender/makesdna/DNA_outliner_types.h +++ b/source/blender/makesdna/DNA_outliner_types.h @@ -73,6 +73,16 @@ enum { /** #TreeStoreElem.types */ typedef enum eTreeStoreElemType { + /** + * If an element is of this type, `TreeStoreElem.id` points to a valid ID and the ID-type can be + * received through `TreeElement.idcode` (or `GS(TreeStoreElem.id->name)`). Note however that the + * types below may also have a valid ID pointer (see #TSE_IS_REAL_ID()). + * + * In cases where the type is still checked against "0" (even implicitly), please replace it with + * an explicit check against `TSE_SOME_ID`. + */ + TSE_SOME_ID = 0, + TSE_NLA = 1, /* NO ID */ TSE_NLA_ACTION = 2, TSE_DEFGROUP_BASE = 3, diff --git a/source/blender/makesdna/DNA_space_types.h b/source/blender/makesdna/DNA_space_types.h index 8c0660522e0..8fa2951e3d7 100644 --- a/source/blender/makesdna/DNA_space_types.h +++ b/source/blender/makesdna/DNA_space_types.h @@ -66,6 +66,9 @@ typedef struct SpaceProperties_Runtime SpaceProperties_Runtime; /* Defined in `node_intern.h`. */ typedef struct SpaceNode_Runtime SpaceNode_Runtime; +/* Defined in `file_intern.h`. */ +typedef struct SpaceFile_Runtime SpaceFile_Runtime; + /* -------------------------------------------------------------------- */ /** \name SpaceLink (Base) * \{ */ @@ -490,6 +493,7 @@ typedef enum eGraphEdit_Flag { SIPO_NORMALIZE_FREEZE = (1 << 15), /* show markers region */ SIPO_SHOW_MARKERS = (1 << 16), + SIPO_NO_DRAW_EXTRAPOLATION = (1 << 17), } eGraphEdit_Flag; /* SpaceGraph.mode (Graph Editor Mode) */ @@ -847,6 +851,8 @@ typedef struct SpaceFile { short recentnr, bookmarknr; short systemnr, system_bookmarknr; + + SpaceFile_Runtime *runtime; } SpaceFile; /* SpaceFile.browse_mode (File Space Browsing Mode) */ @@ -1836,6 +1842,22 @@ typedef struct SpaceStatusBar { /** \} */ /* -------------------------------------------------------------------- */ +/** \name Spreadsheet + * \{ */ + +typedef struct SpaceSpreadsheet { + SpaceLink *next, *prev; + /** Storage of regions for inactive spaces. */ + ListBase regionbase; + char spacetype; + char link_flag; + char _pad0[6]; + /* End 'SpaceLink' header. */ +} SpaceSpreadsheet; + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Space Defines (eSpace_Type) * \{ */ @@ -1872,8 +1894,9 @@ typedef enum eSpace_Type { SPACE_CLIP = 20, SPACE_TOPBAR = 21, SPACE_STATUSBAR = 22, + SPACE_SPREADSHEET = 23 -#define SPACE_TYPE_LAST SPACE_STATUSBAR +#define SPACE_TYPE_LAST SPACE_SPREADSHEET } eSpace_Type; /* use for function args */ diff --git a/source/blender/makesdna/DNA_userdef_types.h b/source/blender/makesdna/DNA_userdef_types.h index d304641e112..bd8f3cd95a7 100644 --- a/source/blender/makesdna/DNA_userdef_types.h +++ b/source/blender/makesdna/DNA_userdef_types.h @@ -492,6 +492,7 @@ typedef struct bTheme { ThemeSpace space_clip; ThemeSpace space_topbar; ThemeSpace space_statusbar; + ThemeSpace space_spreadsheet; /* 20 sets of bone colors for this theme */ ThemeWireColor tarm[20]; @@ -507,7 +508,7 @@ typedef struct bTheme { #define UI_THEMESPACE_START(btheme) \ (CHECK_TYPE_INLINE(btheme, bTheme *), &((btheme)->space_properties)) #define UI_THEMESPACE_END(btheme) \ - (CHECK_TYPE_INLINE(btheme, bTheme *), (&((btheme)->space_statusbar) + 1)) + (CHECK_TYPE_INLINE(btheme, bTheme *), (&((btheme)->space_spreadsheet) + 1)) typedef struct bAddon { struct bAddon *next, *prev; diff --git a/source/blender/makesrna/RNA_access.h b/source/blender/makesrna/RNA_access.h index fc9ad7918a4..8e3c94a3ff9 100644 --- a/source/blender/makesrna/RNA_access.h +++ b/source/blender/makesrna/RNA_access.h @@ -603,6 +603,7 @@ extern StructRNA RNA_SpaceOutliner; extern StructRNA RNA_SpacePreferences; extern StructRNA RNA_SpaceProperties; extern StructRNA RNA_SpaceSequenceEditor; +extern StructRNA RNA_SpaceSpreadsheet; extern StructRNA RNA_SpaceTextEditor; extern StructRNA RNA_SpaceUVEditor; extern StructRNA RNA_SpaceView3D; diff --git a/source/blender/makesrna/RNA_define.h b/source/blender/makesrna/RNA_define.h index c12426ffcd0..c49a52ceed7 100644 --- a/source/blender/makesrna/RNA_define.h +++ b/source/blender/makesrna/RNA_define.h @@ -421,7 +421,7 @@ void RNA_def_property_string_funcs(PropertyRNA *prop, const char *length, const char *set); void RNA_def_property_pointer_funcs( - PropertyRNA *prop, const char *get, const char *set, const char *typef, const char *poll); + PropertyRNA *prop, const char *get, const char *set, const char *type_fn, const char *poll); void RNA_def_property_collection_funcs(PropertyRNA *prop, const char *begin, const char *next, diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index bec3db10905..1f887c2eec3 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -3671,7 +3671,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr } } else { - if (!defaultfound && !(eprop->itemf && eprop->item == DummyRNA_NULL_items)) { + if (!defaultfound && !(eprop->item_fn && eprop->item == DummyRNA_NULL_items)) { CLOG_ERROR(&LOG, "%s%s.%s, enum default is not in items.", srna->identifier, @@ -3992,7 +3992,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr "\t%s, %s, %s, %s, %s, NULL, ", rna_function_string(eprop->get), rna_function_string(eprop->set), - rna_function_string(eprop->itemf), + rna_function_string(eprop->item_fn), rna_function_string(eprop->get_ex), rna_function_string(eprop->set_ex)); if (eprop->item) { @@ -4010,7 +4010,7 @@ static void rna_generate_property(FILE *f, StructRNA *srna, const char *nest, Pr "\t%s, %s, %s, %s,", rna_function_string(pprop->get), rna_function_string(pprop->set), - rna_function_string(pprop->typef), + rna_function_string(pprop->type_fn), rna_function_string(pprop->poll)); if (pprop->type) { fprintf(f, "&RNA_%s\n", (const char *)pprop->type); diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index c5dd516d16e..8e5e70642cc 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -1571,8 +1571,8 @@ StructRNA *RNA_property_pointer_type(PointerRNA *ptr, PropertyRNA *prop) if (prop->type == PROP_POINTER) { PointerPropertyRNA *pprop = (PointerPropertyRNA *)prop; - if (pprop->typef) { - return pprop->typef(ptr); + if (pprop->type_fn) { + return pprop->type_fn(ptr); } if (pprop->type) { return pprop->type; @@ -1623,14 +1623,14 @@ void RNA_property_enum_items_ex(bContext *C, *r_free = false; - if (!use_static && eprop->itemf && (C != NULL || (prop->flag & PROP_ENUM_NO_CONTEXT))) { + if (!use_static && eprop->item_fn && (C != NULL || (prop->flag & PROP_ENUM_NO_CONTEXT))) { const EnumPropertyItem *item; if (prop->flag & PROP_ENUM_NO_CONTEXT) { - item = eprop->itemf(NULL, ptr, prop, r_free); + item = eprop->item_fn(NULL, ptr, prop, r_free); } else { - item = eprop->itemf(C, ptr, prop, r_free); + item = eprop->item_fn(C, ptr, prop, r_free); } /* any callbacks returning NULL should be fixed */ @@ -1753,16 +1753,16 @@ void RNA_property_enum_items_gettexted_all(bContext *C, *r_totitem = eprop->totitem; } - if (eprop->itemf && (C != NULL || (prop->flag & PROP_ENUM_NO_CONTEXT))) { + if (eprop->item_fn && (C != NULL || (prop->flag & PROP_ENUM_NO_CONTEXT))) { const EnumPropertyItem *item; int i; bool free = false; if (prop->flag & PROP_ENUM_NO_CONTEXT) { - item = eprop->itemf(NULL, ptr, prop, &free); + item = eprop->item_fn(NULL, ptr, prop, &free); } else { - item = eprop->itemf(C, ptr, prop, &free); + item = eprop->item_fn(C, ptr, prop, &free); } /* any callbacks returning NULL should be fixed */ @@ -3662,8 +3662,8 @@ PointerRNA RNA_property_pointer_get(PointerRNA *ptr, PropertyRNA *prop) } /* for groups, data is idprop itself */ - if (pprop->typef) { - return rna_pointer_inherit_refine(ptr, pprop->typef(ptr), idprop); + if (pprop->type_fn) { + return rna_pointer_inherit_refine(ptr, pprop->type_fn(ptr), idprop); } return rna_pointer_inherit_refine(ptr, pprop->type, idprop); } diff --git a/source/blender/makesrna/intern/rna_access_compare_override.c b/source/blender/makesrna/intern/rna_access_compare_override.c index d6305388cf9..0f3b0a895db 100644 --- a/source/blender/makesrna/intern/rna_access_compare_override.c +++ b/source/blender/makesrna/intern/rna_access_compare_override.c @@ -20,6 +20,8 @@ #include <string.h> +#include <CLG_log.h> + #include "MEM_guardedalloc.h" #include "DNA_ID.h" @@ -53,6 +55,8 @@ #include "rna_access_internal.h" #include "rna_internal.h" +static CLG_LogRef LOG = {"rna.access_compare_override"}; + /** * Find the actual ID owner of the given \a ptr #PointerRNA, in override sense, and generate the * full rna path from it to given \a prop #PropertyRNA if \a rna_path is given. @@ -411,12 +415,11 @@ static int rna_property_override_diff(Main *bmain, } if (override_diff == NULL) { -#ifndef NDEBUG - printf("'%s' gives unmatching or NULL RNA diff callbacks, should not happen (%d vs. %d).\n", - rna_path ? rna_path : prop_a->identifier, - !prop_a->is_idprop, - !prop_b->is_idprop); -#endif + CLOG_ERROR(&LOG, + "'%s' gives unmatching or NULL RNA diff callbacks, should not happen (%d vs. %d)", + rna_path ? rna_path : prop_a->identifier, + !prop_a->is_idprop, + !prop_b->is_idprop); BLI_assert(0); return 1; } @@ -501,12 +504,11 @@ static bool rna_property_override_operation_store(Main *bmain, } if (override_store == NULL) { -#ifndef NDEBUG - printf("'%s' gives unmatching or NULL RNA store callbacks, should not happen (%d vs. %d).\n", - op->rna_path, - prop_local->magic == RNA_MAGIC, - prop_reference->magic == RNA_MAGIC); -#endif + CLOG_ERROR(&LOG, + "'%s' gives unmatching or NULL RNA store callbacks, should not happen (%d vs. %d)", + op->rna_path, + prop_local->magic == RNA_MAGIC, + prop_reference->magic == RNA_MAGIC); BLI_assert(0); return changed; } @@ -590,12 +592,12 @@ static bool rna_property_override_operation_apply(Main *bmain, } if (override_apply == NULL) { -#ifndef NDEBUG - printf("'%s' gives unmatching or NULL RNA copy callbacks, should not happen (%d vs. %d).\n", - prop_dst->magic != RNA_MAGIC ? ((IDProperty *)prop_dst)->name : prop_dst->identifier, - prop_dst->magic == RNA_MAGIC, - prop_src->magic == RNA_MAGIC); -#endif + CLOG_ERROR(&LOG, + "'%s' gives unmatching or NULL RNA apply callbacks, should not happen (%d vs. %d)", + prop_dst->magic != RNA_MAGIC ? ((IDProperty *)prop_dst)->name : + prop_dst->identifier, + prop_dst->magic == RNA_MAGIC, + prop_src->magic == RNA_MAGIC); BLI_assert(0); return false; } @@ -788,7 +790,7 @@ bool RNA_struct_override_matches(Main *bmain, continue; } - // printf("Override Checking %s\n", rna_path); + CLOG_INFO(&LOG, 5, "Override Checking %s\n", rna_path); IDOverrideLibraryProperty *op = BKE_lib_override_library_property_find(override, rna_path); if (ignore_overridden && op != NULL) { @@ -990,11 +992,9 @@ static void rna_property_override_apply_ex(Main *bmain, if (!do_insert != !ELEM(opop->operation, IDOVERRIDE_LIBRARY_OP_INSERT_AFTER, IDOVERRIDE_LIBRARY_OP_INSERT_BEFORE)) { -#ifndef NDEBUG if (!do_insert) { - printf("Skipping insert override operations in first pass (%s)!\n", op->rna_path); + CLOG_INFO(&LOG, 5, "Skipping insert override operations in first pass (%s)", op->rna_path); } -#endif continue; } @@ -1078,22 +1078,25 @@ static void rna_property_override_apply_ex(Main *bmain, ptr_item_src = &private_ptr_item_src; ptr_item_storage = &private_ptr_item_storage; -#ifndef NDEBUG if (ptr_item_dst->type == NULL) { - printf("Failed to find destination sub-item '%s' (%d) of '%s' in new override data '%s'\n", - opop->subitem_reference_name, - opop->subitem_reference_index, - op->rna_path, - ptr_dst->owner_id->name); + CLOG_INFO( + &LOG, + 2, + "Failed to find destination sub-item '%s' (%d) of '%s' in new override data '%s'", + opop->subitem_reference_name, + opop->subitem_reference_index, + op->rna_path, + ptr_dst->owner_id->name); } if (ptr_item_src->type == NULL) { - printf("Failed to find source sub-item '%s' (%d) of '%s' in old override data '%s'\n", - opop->subitem_local_name, - opop->subitem_local_index, - op->rna_path, - ptr_src->owner_id->name); + CLOG_INFO(&LOG, + 2, + "Failed to find source sub-item '%s' (%d) of '%s' in old override data '%s'", + opop->subitem_local_name, + opop->subitem_local_index, + op->rna_path, + ptr_src->owner_id->name); } -#endif } if (!rna_property_override_operation_apply(bmain, @@ -1107,9 +1110,11 @@ static void rna_property_override_apply_ex(Main *bmain, ptr_item_src, ptr_item_storage, opop)) { - printf("Failed to apply '%s' override operation on %s\n", - op->rna_path, - ptr_src->owner_id->name); + CLOG_INFO(&LOG, + 2, + "Failed to apply '%s' override operation on %s\n", + op->rna_path, + ptr_src->owner_id->name); } } } @@ -1166,17 +1171,16 @@ void RNA_struct_override_apply(Main *bmain, op, do_insert); } -#ifndef NDEBUG else { - printf( - "Failed to apply library override operation to '%s.%s' " - "(could not resolve some properties, local: %d, override: %d)\n", - ((ID *)ptr_src->owner_id)->name, - op->rna_path, - RNA_path_resolve_property(ptr_dst, op->rna_path, &data_dst, &prop_dst), - RNA_path_resolve_property(ptr_src, op->rna_path, &data_src, &prop_src)); + CLOG_INFO(&LOG, + 2, + "Failed to apply library override operation to '%s.%s' " + "(could not resolve some properties, local: %d, override: %d)", + ((ID *)ptr_src->owner_id)->name, + op->rna_path, + RNA_path_resolve_property(ptr_dst, op->rna_path, &data_dst, &prop_dst), + RNA_path_resolve_property(ptr_src, op->rna_path, &data_src, &prop_src)); } -#endif } } diff --git a/source/blender/makesrna/intern/rna_define.c b/source/blender/makesrna/intern/rna_define.c index df3bd0cca29..5e188285e39 100644 --- a/source/blender/makesrna/intern/rna_define.c +++ b/source/blender/makesrna/intern/rna_define.c @@ -3267,7 +3267,7 @@ void RNA_def_property_enum_funcs(PropertyRNA *prop, eprop->set = (PropEnumSetFunc)set; } if (item) { - eprop->itemf = (PropEnumItemFunc)item; + eprop->item_fn = (PropEnumItemFunc)item; } break; } @@ -3292,7 +3292,7 @@ void RNA_def_property_enum_funcs_runtime(PropertyRNA *prop, eprop->set_ex = setfunc; } if (itemfunc) { - eprop->itemf = itemfunc; + eprop->item_fn = itemfunc; } if (getfunc || setfunc) { @@ -3373,7 +3373,7 @@ void RNA_def_property_string_funcs_runtime(PropertyRNA *prop, } void RNA_def_property_pointer_funcs( - PropertyRNA *prop, const char *get, const char *set, const char *typef, const char *poll) + PropertyRNA *prop, const char *get, const char *set, const char *type_fn, const char *poll) { StructRNA *srna = DefRNA.laststruct; @@ -3392,8 +3392,8 @@ void RNA_def_property_pointer_funcs( if (set) { pprop->set = (PropPointerSetFunc)set; } - if (typef) { - pprop->typef = (PropPointerTypeFunc)typef; + if (type_fn) { + pprop->type_fn = (PropPointerTypeFunc)type_fn; } if (poll) { pprop->poll = (PropPointerPollFunc)poll; @@ -3821,7 +3821,7 @@ PropertyRNA *RNA_def_enum_flag(StructOrFunctionRNA *cont_, void RNA_def_enum_funcs(PropertyRNA *prop, EnumPropertyItemFunc itemfunc) { EnumPropertyRNA *eprop = (EnumPropertyRNA *)prop; - eprop->itemf = itemfunc; + eprop->item_fn = itemfunc; } PropertyRNA *RNA_def_float(StructOrFunctionRNA *cont_, diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h index bfcb0039ca8..95972dd444f 100644 --- a/source/blender/makesrna/intern/rna_internal.h +++ b/source/blender/makesrna/intern/rna_internal.h @@ -424,6 +424,7 @@ void RNA_api_window(struct StructRNA *srna); void RNA_api_wm(struct StructRNA *srna); void RNA_api_space_node(struct StructRNA *srna); void RNA_api_space_text(struct StructRNA *srna); +void RNA_api_space_filebrowser(struct StructRNA *srna); void RNA_api_region_view3d(struct StructRNA *srna); void RNA_api_texture(struct StructRNA *srna); void RNA_api_sequences(BlenderRNA *brna, PropertyRNA *cprop, const bool metastrip); diff --git a/source/blender/makesrna/intern/rna_internal_types.h b/source/blender/makesrna/intern/rna_internal_types.h index e6ed0f69300..1dd08bb1074 100644 --- a/source/blender/makesrna/intern/rna_internal_types.h +++ b/source/blender/makesrna/intern/rna_internal_types.h @@ -453,7 +453,7 @@ typedef struct EnumPropertyRNA { PropEnumGetFunc get; PropEnumSetFunc set; - PropEnumItemFunc itemf; + PropEnumItemFunc item_fn; PropEnumGetFuncEx get_ex; PropEnumSetFuncEx set_ex; @@ -471,7 +471,7 @@ typedef struct PointerPropertyRNA { PropPointerGetFunc get; PropPointerSetFunc set; - PropPointerTypeFunc typef; + PropPointerTypeFunc type_fn; /** unlike operators, 'set' can still run if poll fails, used for filtering display. */ PropPointerPollFunc poll; diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 5008240ea33..98a2b683f18 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -2789,6 +2789,11 @@ static void rna_def_modifier_boolean(BlenderRNA *brna) RNA_def_property_ui_text(prop, "Self", "Allow self-intersection in operands"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "use_hole_tolerant", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "flag", eBooleanModifierFlag_HoleTolerant); + RNA_def_property_ui_text(prop, "Hole Tolerant", "Better results when there are holes (slower)"); + RNA_def_property_update(prop, 0, "rna_Modifier_update"); + /* BMesh debugging options, only used when G_DEBUG is set */ /* BMesh intersection options */ @@ -3134,7 +3139,8 @@ static void rna_def_modifier_uvproject(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_PROPORTIONAL); RNA_def_property_range(prop, 1, FLT_MAX); RNA_def_property_ui_range(prop, 1, 1000, 1, 3); - RNA_def_property_ui_text(prop, "Horizontal Aspect Ratio", ""); + RNA_def_property_ui_text( + prop, "Aspect X", "Horizontal aspect ratio (only used for camera projectors)"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "aspect_y", PROP_FLOAT, PROP_NONE); @@ -3142,7 +3148,8 @@ static void rna_def_modifier_uvproject(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_PROPORTIONAL); RNA_def_property_range(prop, 1, FLT_MAX); RNA_def_property_ui_range(prop, 1, 1000, 1, 3); - RNA_def_property_ui_text(prop, "Vertical Aspect Ratio", ""); + RNA_def_property_ui_text( + prop, "Aspect Y", "Vertical aspect ratio (only used for camera projectors)"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "scale_x", PROP_FLOAT, PROP_NONE); @@ -3150,7 +3157,7 @@ static void rna_def_modifier_uvproject(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_PROPORTIONAL); RNA_def_property_range(prop, 0, FLT_MAX); RNA_def_property_ui_range(prop, 0, 1000, 1, 3); - RNA_def_property_ui_text(prop, "Horizontal Scale", ""); + RNA_def_property_ui_text(prop, "Scale X", "Horizontal scale (only used for camera projectors)"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); prop = RNA_def_property(srna, "scale_y", PROP_FLOAT, PROP_NONE); @@ -3158,7 +3165,7 @@ static void rna_def_modifier_uvproject(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_PROPORTIONAL); RNA_def_property_range(prop, 0, FLT_MAX); RNA_def_property_ui_range(prop, 0, 1000, 1, 3); - RNA_def_property_ui_text(prop, "Vertical Scale", ""); + RNA_def_property_ui_text(prop, "Scale Y", "Vertical scale (only used for camera projectors)"); RNA_def_property_update(prop, 0, "rna_Modifier_update"); srna = RNA_def_struct(brna, "UVProjector", NULL); diff --git a/source/blender/makesrna/intern/rna_pose_api.c b/source/blender/makesrna/intern/rna_pose_api.c index 59704b00391..29516830058 100644 --- a/source/blender/makesrna/intern/rna_pose_api.c +++ b/source/blender/makesrna/intern/rna_pose_api.c @@ -38,9 +38,14 @@ #ifdef RNA_RUNTIME -/* #include "DNA_anim_types.h" */ +# include "BKE_animsys.h" # include "BKE_armature.h" -# include "DNA_action_types.h" /* bPose */ +# include "BKE_context.h" + +# include "DNA_action_types.h" +# include "DNA_anim_types.h" + +# include "BLI_ghash.h" static float rna_PoseBone_do_envelope(bPoseChannel *chan, float *vec) { @@ -102,12 +107,49 @@ static void rna_PoseBone_compute_bbone_handles(bPoseChannel *pchan, BKE_pchan_bbone_handles_compute( ¶ms, ret_h1, ret_roll1, ret_h2, ret_roll2, ease || offsets, offsets); } + +static void rna_Pose_apply_pose_from_action(ID *pose_owner, + bContext *C, + bAction *action, + const float evaluation_time) +{ + BLI_assert(GS(pose_owner->name) == ID_OB); + Object *pose_owner_ob = (Object *)pose_owner; + + AnimationEvalContext anim_eval_context = {CTX_data_depsgraph_pointer(C), evaluation_time}; + BKE_pose_apply_action(pose_owner_ob, action, &anim_eval_context); + + /* Do NOT tag with ID_RECALC_ANIMATION, as that would overwrite the just-applied pose. */ + DEG_id_tag_update(pose_owner, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, pose_owner); +} + #else -void RNA_api_pose(StructRNA *UNUSED(srna)) +void RNA_api_pose(StructRNA *srna) { - /* FunctionRNA *func; */ - /* PropertyRNA *parm; */ + FunctionRNA *func; + PropertyRNA *parm; + + func = RNA_def_function(srna, "apply_pose_from_action", "rna_Pose_apply_pose_from_action"); + RNA_def_function_flag(func, FUNC_USE_SELF_ID | FUNC_NO_SELF | FUNC_USE_CONTEXT); + RNA_def_function_ui_description( + func, + "Apply the given action to this pose by evaluating it at a specific time. Only updates the " + "pose of selected bones, or all bones if none are selected."); + + parm = RNA_def_pointer(func, "action", "Action", "Action", "The Action containing the pose"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + + parm = RNA_def_float(func, + "evaluation_time", + 0.0f, + -FLT_MAX, + FLT_MAX, + "Evaluation Time", + "Time at which the given action is evaluated to obtain the pose", + -FLT_MAX, + FLT_MAX); } void RNA_api_pose_channel(StructRNA *srna) diff --git a/source/blender/makesrna/intern/rna_rna.c b/source/blender/makesrna/intern/rna_rna.c index b0a942cd39e..d553ead1e45 100644 --- a/source/blender/makesrna/intern/rna_rna.c +++ b/source/blender/makesrna/intern/rna_rna.c @@ -910,14 +910,14 @@ static const EnumPropertyItem *rna_EnumProperty_default_itemf(bContext *C, return DummyRNA_NULL_items; } - if ((eprop->itemf == NULL) || (eprop->itemf == rna_EnumProperty_default_itemf) || + if ((eprop->item_fn == NULL) || (eprop->item_fn == rna_EnumProperty_default_itemf) || (ptr->type == &RNA_EnumProperty) || (C == NULL)) { if (eprop->item) { return eprop->item; } } - return eprop->itemf(C, ptr, prop, r_free); + return eprop->item_fn(C, ptr, prop, r_free); } /* XXX - not sure this is needed? */ diff --git a/source/blender/makesrna/intern/rna_screen.c b/source/blender/makesrna/intern/rna_screen.c index 6cf1d7a923b..58e446381ad 100644 --- a/source/blender/makesrna/intern/rna_screen.c +++ b/source/blender/makesrna/intern/rna_screen.c @@ -201,6 +201,10 @@ static const EnumPropertyItem *rna_Area_ui_type_itemf(bContext *C, if (ELEM(item_from->value, SPACE_TOPBAR, SPACE_STATUSBAR)) { continue; } + /* Hide spreadsheet editor until we want to expose it in the ui. */ + if (item_from->value == SPACE_SPREADSHEET) { + continue; + } SpaceType *st = item_from->identifier[0] ? BKE_spacetype_from_id(item_from->value) : NULL; int totitem_prev = totitem; diff --git a/source/blender/makesrna/intern/rna_space.c b/source/blender/makesrna/intern/rna_space.c index 89402c3170d..447e11594a7 100644 --- a/source/blender/makesrna/intern/rna_space.c +++ b/source/blender/makesrna/intern/rna_space.c @@ -145,6 +145,11 @@ const EnumPropertyItem rna_enum_space_type_items[] = { "Properties", "Edit properties of active object and related data-blocks"}, {SPACE_FILE, "FILE_BROWSER", ICON_FILEBROWSER, "File Browser", "Browse for files and assets"}, + {SPACE_SPREADSHEET, + "SPREADSHEET", + ICON_SPREADSHEET, + "Spreadsheet", + "Explore geometry data in a table"}, {SPACE_USERPREF, "PREFERENCES", ICON_PREFERENCES, @@ -572,6 +577,8 @@ static StructRNA *rna_Space_refine(struct PointerRNA *ptr) return &RNA_SpacePreferences; case SPACE_CLIP: return &RNA_SpaceClipEditor; + case SPACE_SPREADSHEET: + return &RNA_SpaceSpreadsheet; /* Currently no type info. */ case SPACE_SCRIPT: @@ -5675,6 +5682,11 @@ static void rna_def_space_graph(BlenderRNA *brna) "If any exists, show markers in a separate row at the bottom of the editor"); RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL); + prop = RNA_def_property(srna, "show_extrapolation", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SIPO_NO_DRAW_EXTRAPOLATION); + RNA_def_property_ui_text(prop, "Show Extrapolation", ""); + RNA_def_property_update(prop, NC_SPACE | ND_SPACE_GRAPH, NULL); + /* editing */ prop = RNA_def_property(srna, "use_auto_merge_keyframes", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_negative_sdna(prop, NULL, "flag", SIPO_NOTRANSKEYCULL); @@ -6570,6 +6582,8 @@ static void rna_def_space_filebrowser(BlenderRNA *brna) RNA_def_property_flag(prop, PROP_CONTEXT_UPDATE); RNA_def_property_update( prop, NC_SPACE | ND_SPACE_FILE_PARAMS, "rna_FileBrowser_FSMenu_active_update"); + + RNA_api_space_filebrowser(srna); } static void rna_def_space_info(BlenderRNA *brna) @@ -7170,6 +7184,14 @@ static void rna_def_space_clip(BlenderRNA *brna) RNA_def_property_update(prop, NC_SPACE | ND_SPACE_CLIP, NULL); } +static void rna_def_space_spreadsheet(BlenderRNA *brna) +{ + StructRNA *srna; + + srna = RNA_def_struct(brna, "SpaceSpreadsheet", "Space"); + RNA_def_struct_ui_text(srna, "Space Spreadsheet", "Spreadsheet space data"); +} + void RNA_def_space(BlenderRNA *brna) { rna_def_space(brna); @@ -7195,6 +7217,7 @@ void RNA_def_space(BlenderRNA *brna) rna_def_node_tree_path(brna); rna_def_space_node(brna); rna_def_space_clip(brna); + rna_def_space_spreadsheet(brna); } #endif diff --git a/source/blender/makesrna/intern/rna_space_api.c b/source/blender/makesrna/intern/rna_space_api.c index e4c0ade1533..205a88edf84 100644 --- a/source/blender/makesrna/intern/rna_space_api.c +++ b/source/blender/makesrna/intern/rna_space_api.c @@ -27,6 +27,7 @@ # include "BKE_global.h" +# include "ED_fileselect.h" # include "ED_screen.h" # include "ED_text.h" @@ -115,4 +116,24 @@ void RNA_api_space_text(StructRNA *srna) RNA_def_function_output(func, parm); } +void RNA_api_space_filebrowser(StructRNA *srna) +{ + FunctionRNA *func; + PropertyRNA *parm; + + func = RNA_def_function(srna, "activate_asset_by_id", "ED_fileselect_activate_by_id"); + RNA_def_function_ui_description(func, "Activate the asset entry that represents the given ID"); + + parm = RNA_def_property(func, "id_to_activate", PROP_POINTER, PROP_NONE); + RNA_def_property_struct_type(parm, "ID"); + RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); + + parm = RNA_def_boolean( + func, + "deferred", + 0, + "", + "Whether to activate the ID immediately (false) or after the file browser refreshes (true)"); +} + #endif diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index b06ec674e81..4097e2dddea 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -3847,6 +3847,26 @@ static void rna_def_userdef_theme_space_statusbar(BlenderRNA *brna) rna_def_userdef_theme_spaces_main(srna); } +static void rna_def_userdef_theme_space_spreadsheet(BlenderRNA *brna) +{ + StructRNA *srna; + PropertyRNA *prop; + + /* space_spreadsheet */ + + srna = RNA_def_struct(brna, "ThemeSpreadsheet", NULL); + RNA_def_struct_sdna(srna, "ThemeSpace"); + RNA_def_struct_clear_flag(srna, STRUCT_UNDO); + RNA_def_struct_ui_text(srna, "Theme Spreadsheet", "Theme settings for the Spreadsheet"); + + prop = RNA_def_property(srna, "row_alternate", PROP_FLOAT, PROP_COLOR_GAMMA); + RNA_def_property_array(prop, 4); + RNA_def_property_ui_text(prop, "Alternate Rows", "Overlay color on every other row"); + RNA_def_property_update(prop, 0, "rna_userdef_theme_update"); + + rna_def_userdef_theme_spaces_main(srna); +} + static void rna_def_userdef_themes(BlenderRNA *brna) { StructRNA *srna; @@ -3873,6 +3893,7 @@ static void rna_def_userdef_themes(BlenderRNA *brna) {20, "CLIP_EDITOR", ICON_TRACKER, "Movie Clip Editor", ""}, {21, "TOPBAR", ICON_TOPBAR, "Top Bar", ""}, {22, "STATUSBAR", ICON_STATUSBAR, "Status Bar", ""}, + {23, "SPREADSHEET", ICON_SPREADSHEET, "Spreadsheet"}, {0, NULL, 0, NULL, NULL}, }; @@ -4001,6 +4022,12 @@ static void rna_def_userdef_themes(BlenderRNA *brna) RNA_def_property_pointer_sdna(prop, NULL, "space_statusbar"); RNA_def_property_struct_type(prop, "ThemeStatusBar"); RNA_def_property_ui_text(prop, "Status Bar", ""); + + prop = RNA_def_property(srna, "spreadsheet", PROP_POINTER, PROP_NONE); + RNA_def_property_flag(prop, PROP_NEVER_NULL); + RNA_def_property_pointer_sdna(prop, NULL, "space_spreadsheet"); + RNA_def_property_struct_type(prop, "ThemeSpreadsheet"); + RNA_def_property_ui_text(prop, "Spreadsheet", ""); /* end space types */ prop = RNA_def_property(srna, "bone_color_sets", PROP_COLLECTION, PROP_NONE); @@ -4254,6 +4281,7 @@ static void rna_def_userdef_dothemes(BlenderRNA *brna) rna_def_userdef_theme_space_clip(brna); rna_def_userdef_theme_space_topbar(brna); rna_def_userdef_theme_space_statusbar(brna); + rna_def_userdef_theme_space_spreadsheet(brna); rna_def_userdef_theme_colorset(brna); rna_def_userdef_theme_collection_color(brna); rna_def_userdef_themes(brna); diff --git a/source/blender/makesrna/intern/rna_wm_api.c b/source/blender/makesrna/intern/rna_wm_api.c index cb20b480ee5..e7ca41bb5be 100644 --- a/source/blender/makesrna/intern/rna_wm_api.c +++ b/source/blender/makesrna/intern/rna_wm_api.c @@ -1216,6 +1216,11 @@ void RNA_api_keymaps(StructRNA *srna) func = RNA_def_function(srna, "new", "rna_keymap_new"); /* add_keymap */ RNA_def_function_flag(func, FUNC_USE_REPORTS); + RNA_def_function_ui_description( + func, + "Ensure the keymap exists. This will return the one with the given name/space type/region " + "type, or create a new one if it does not exist yet."); + parm = RNA_def_string(func, "name", NULL, 0, "Name", ""); RNA_def_parameter_flags(parm, 0, PARM_REQUIRED); RNA_def_enum(func, "space_type", rna_enum_space_type_items, SPACE_EMPTY, "Space Type", ""); diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c index 070ba3a1bcf..6ffbf518dd1 100644 --- a/source/blender/modifiers/intern/MOD_boolean.c +++ b/source/blender/modifiers/intern/MOD_boolean.c @@ -21,7 +21,7 @@ * \ingroup modifiers */ -// #ifdef DEBUG_TIME +// #define DEBUG_TIME #include <stdio.h> @@ -422,7 +422,7 @@ static void BMD_mesh_intersection(BMesh *bm, if (use_exact) { BM_mesh_boolean( - bm, looptris, tottri, bm_face_isect_pair, NULL, 2, use_self, false, bmd->operation); + bm, looptris, tottri, bm_face_isect_pair, NULL, 2, use_self, false, false, bmd->operation); } else { BM_mesh_intersect(bm, @@ -587,8 +587,16 @@ static Mesh *collection_boolean_exact(BooleanModifierData *bmd, } BM_mesh_elem_index_ensure(bm, BM_FACE); - BM_mesh_boolean( - bm, looptris, tottri, bm_face_isect_nary, shape, num_shapes, true, false, bmd->operation); + BM_mesh_boolean(bm, + looptris, + tottri, + bm_face_isect_nary, + shape, + num_shapes, + true, + false, + false, + bmd->operation); result = BKE_mesh_from_bmesh_for_eval_nomain(bm, NULL, mesh); BM_mesh_free(bm); @@ -651,10 +659,12 @@ static Mesh *exact_boolean_mesh(BooleanModifierData *bmd, } const bool use_self = (bmd->flag & eBooleanModifierFlag_Self) != 0; + const bool hole_tolerant = (bmd->flag & eBooleanModifierFlag_HoleTolerant) != 0; result = BKE_mesh_boolean((const Mesh **)meshes, (const float(**)[4][4])obmats, BLI_array_len(meshes), use_self, + hole_tolerant, bmd->operation); BLI_array_free(meshes); @@ -846,31 +856,44 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel) uiItemR(layout, ptr, "collection", 0, NULL, ICON_NONE); } + uiItemR(layout, ptr, "solver", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + + modifier_panel_end(layout, ptr); +} + +static void solver_options_panel_draw(const bContext *UNUSED(C), Panel *panel) +{ + uiLayout *layout = panel->layout; + + PointerRNA *ptr = modifier_panel_get_property_pointers(panel, NULL); + const bool use_exact = RNA_enum_get(ptr, "solver") == eBooleanModifierSolver_Exact; + const bool operand_object = RNA_enum_get(ptr, "operand_type") == eBooleanModifierFlag_Object; - uiItemR(layout, ptr, "solver", UI_ITEM_R_EXPAND, NULL, ICON_NONE); + uiLayoutSetPropSep(layout, true); + uiLayout *col = uiLayoutColumn(layout, true); if (use_exact) { /* When operand is collection, we always use_self. */ if (operand_object) { - uiItemR(layout, ptr, "use_self", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "use_self", 0, NULL, ICON_NONE); } + uiItemR(col, ptr, "use_hole_tolerant", 0, NULL, ICON_NONE); } else { - uiItemR(layout, ptr, "double_threshold", 0, NULL, ICON_NONE); + uiItemR(col, ptr, "double_threshold", 0, NULL, ICON_NONE); } if (G.debug) { - uiLayout *col = uiLayoutColumn(layout, true); uiItemR(col, ptr, "debug_options", 0, NULL, ICON_NONE); } - - modifier_panel_end(layout, ptr); } static void panelRegister(ARegionType *region_type) { - modifier_panel_register(region_type, eModifierType_Boolean, panel_draw); + PanelType *panel = modifier_panel_register(region_type, eModifierType_Boolean, panel_draw); + modifier_subpanel_register( + region_type, "solver_options", "Solver Options", NULL, solver_options_panel_draw, panel); } ModifierTypeInfo modifierType_Boolean = { diff --git a/source/blender/modifiers/intern/MOD_nodes.cc b/source/blender/modifiers/intern/MOD_nodes.cc index b47f5806c9c..34730292133 100644 --- a/source/blender/modifiers/intern/MOD_nodes.cc +++ b/source/blender/modifiers/intern/MOD_nodes.cc @@ -77,6 +77,7 @@ #include "NOD_type_callbacks.hh" using blender::float3; +using blender::FunctionRef; using blender::IndexRange; using blender::Map; using blender::Set; @@ -90,8 +91,8 @@ using blender::bke::PersistentObjectHandle; using blender::fn::GMutablePointer; using blender::fn::GValueMap; using blender::nodes::GeoNodeExecParams; -using namespace blender::nodes::derived_node_tree_types; using namespace blender::fn::multi_function_types; +using namespace blender::nodes::derived_node_tree_types; static void initData(ModifierData *md) { @@ -254,8 +255,8 @@ static bool isDisabled(const struct Scene *UNUSED(scene), class GeometryNodesEvaluator { private: blender::LinearAllocator<> allocator_; - Map<std::pair<const DInputSocket *, const DOutputSocket *>, GMutablePointer> value_by_input_; - Vector<const DInputSocket *> group_outputs_; + Map<std::pair<DInputSocket, DOutputSocket>, GMutablePointer> value_by_input_; + Vector<DInputSocket> group_outputs_; blender::nodes::MultiFunctionByNode &mf_by_node_; const blender::nodes::DataTypeConversions &conversions_; const PersistentDataHandleMap &handle_map_; @@ -264,8 +265,8 @@ class GeometryNodesEvaluator { Depsgraph *depsgraph_; public: - GeometryNodesEvaluator(const Map<const DOutputSocket *, GMutablePointer> &group_input_data, - Vector<const DInputSocket *> group_outputs, + GeometryNodesEvaluator(const Map<DOutputSocket, GMutablePointer> &group_input_data, + Vector<DInputSocket> group_outputs, blender::nodes::MultiFunctionByNode &mf_by_node, const PersistentDataHandleMap &handle_map, const Object *self_object, @@ -280,15 +281,15 @@ class GeometryNodesEvaluator { depsgraph_(depsgraph) { for (auto item : group_input_data.items()) { - this->forward_to_inputs(*item.key, item.value); + this->forward_to_inputs(item.key, item.value); } } Vector<GMutablePointer> execute() { Vector<GMutablePointer> results; - for (const DInputSocket *group_output : group_outputs_) { - Vector<GMutablePointer> result = this->get_input_values(*group_output); + for (const DInputSocket &group_output : group_outputs_) { + Vector<GMutablePointer> result = this->get_input_values(group_output); results.append(result[0]); } for (GMutablePointer value : value_by_input_.values()) { @@ -298,62 +299,63 @@ class GeometryNodesEvaluator { } private: - Vector<GMutablePointer> get_input_values(const DInputSocket &socket_to_compute) + Vector<GMutablePointer> get_input_values(const DInputSocket socket_to_compute) { + Vector<DSocket> from_sockets; + socket_to_compute.foreach_origin_socket([&](DSocket socket) { from_sockets.append(socket); }); - Span<const DOutputSocket *> from_sockets = socket_to_compute.linked_sockets(); - Span<const DGroupInput *> from_group_inputs = socket_to_compute.linked_group_inputs(); - const int total_inputs = from_sockets.size() + from_group_inputs.size(); + /* Multi-input sockets contain a vector of inputs. */ + if (socket_to_compute->is_multi_input_socket()) { + Vector<GMutablePointer> values; + for (const DSocket &from_socket : from_sockets) { + GMutablePointer value = get_input_from_incoming_link(socket_to_compute, from_socket); + values.append(value); + } + return values; + } - if (total_inputs == 0) { + if (from_sockets.is_empty()) { /* The input is not connected, use the value from the socket itself. */ - return {get_unlinked_input_value(socket_to_compute)}; + const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute->typeinfo()); + return {get_unlinked_input_value(socket_to_compute, type)}; } - if (from_group_inputs.size() == 1) { - return {get_unlinked_input_value(socket_to_compute)}; - } + const DSocket from_socket = from_sockets[0]; + GMutablePointer value = this->get_input_from_incoming_link(socket_to_compute, from_socket); + return {value}; + } - /* Multi-input sockets contain a vector of inputs. */ - if (socket_to_compute.is_multi_input_socket()) { - Vector<GMutablePointer> values; - for (const DOutputSocket *from_socket : from_sockets) { - const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair( - &socket_to_compute, from_socket); - std::optional<GMutablePointer> value = value_by_input_.pop_try(key); - if (value.has_value()) { - values.append(*value); - } - else { - this->compute_output_and_forward(*from_socket); - GMutablePointer value = value_by_input_.pop(key); - values.append(value); - } + GMutablePointer get_input_from_incoming_link(const DInputSocket socket_to_compute, + const DSocket from_socket) + { + if (from_socket->is_output()) { + const DOutputSocket from_output_socket{from_socket}; + const std::pair<DInputSocket, DOutputSocket> key = std::make_pair(socket_to_compute, + from_output_socket); + std::optional<GMutablePointer> value = value_by_input_.pop_try(key); + if (value.has_value()) { + /* This input has been computed before, return it directly. */ + return {*value}; } - return values; - } - const DOutputSocket &from_socket = *from_sockets[0]; - const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair( - &socket_to_compute, &from_socket); - std::optional<GMutablePointer> value = value_by_input_.pop_try(key); - if (value.has_value()) { - /* This input has been computed before, return it directly. */ - return {*value}; + /* Compute the socket now. */ + this->compute_output_and_forward(from_output_socket); + return {value_by_input_.pop(key)}; } - /* Compute the socket now. */ - this->compute_output_and_forward(from_socket); - return {value_by_input_.pop(key)}; + /* Get value from an unlinked input socket. */ + const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute->typeinfo()); + const DInputSocket from_input_socket{from_socket}; + return {get_unlinked_input_value(from_input_socket, type)}; } - void compute_output_and_forward(const DOutputSocket &socket_to_compute) + void compute_output_and_forward(const DOutputSocket socket_to_compute) { - const DNode &node = socket_to_compute.node(); + const DNode node{socket_to_compute.context(), &socket_to_compute->node()}; - if (!socket_to_compute.is_available()) { + if (!socket_to_compute->is_available()) { /* If the output is not available, use a default value. */ - const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute.typeinfo()); + const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_to_compute->typeinfo()); void *buffer = allocator_.allocate(type.size(), type.alignment()); type.copy_to_uninitialized(type.default_value(), buffer); this->forward_to_inputs(socket_to_compute, {type, buffer}); @@ -362,9 +364,9 @@ class GeometryNodesEvaluator { /* Prepare inputs required to execute the node. */ GValueMap<StringRef> node_inputs_map{allocator_}; - for (const DInputSocket *input_socket : node.inputs()) { + for (const InputSocketRef *input_socket : node->inputs()) { if (input_socket->is_available()) { - Vector<GMutablePointer> values = this->get_input_values(*input_socket); + Vector<GMutablePointer> values = this->get_input_values({node.context(), input_socket}); for (int i = 0; i < values.size(); ++i) { /* Values from Multi Input Sockets are stored in input map with the format * <identifier>[<index>]. */ @@ -382,15 +384,15 @@ class GeometryNodesEvaluator { this->execute_node(node, params); /* Forward computed outputs to linked input sockets. */ - for (const DOutputSocket *output_socket : node.outputs()) { + for (const OutputSocketRef *output_socket : node->outputs()) { if (output_socket->is_available()) { GMutablePointer value = node_outputs_map.extract(output_socket->identifier()); - this->forward_to_inputs(*output_socket, value); + this->forward_to_inputs({node.context(), output_socket}, value); } } } - void execute_node(const DNode &node, GeoNodeExecParams params) + void execute_node(const DNode node, GeoNodeExecParams params) { const bNode &bnode = params.node(); @@ -403,7 +405,7 @@ class GeometryNodesEvaluator { } /* Use the multi-function implementation if it exists. */ - const MultiFunction *multi_function = mf_by_node_.lookup_default(&node, nullptr); + const MultiFunction *multi_function = mf_by_node_.lookup_default(node, nullptr); if (multi_function != nullptr) { this->execute_multi_function_node(node, params, *multi_function); return; @@ -413,51 +415,56 @@ class GeometryNodesEvaluator { this->execute_unknown_node(node, params); } - void store_ui_hints(const DNode &node, GeoNodeExecParams params) const + void store_ui_hints(const DNode node, GeoNodeExecParams params) const { - for (const DInputSocket *dsocket : node.inputs()) { - if (!dsocket->is_available()) { + for (const InputSocketRef *socket_ref : node->inputs()) { + if (!socket_ref->is_available()) { continue; } - if (dsocket->bsocket()->type != SOCK_GEOMETRY) { + if (socket_ref->bsocket()->type != SOCK_GEOMETRY) { + continue; + } + if (socket_ref->is_multi_input_socket()) { + /* Not needed currently. */ continue; } - bNodeTree *btree_cow = node.node_ref().tree().btree(); + bNodeTree *btree_cow = node->btree(); bNodeTree *btree_original = (bNodeTree *)DEG_get_original_id((ID *)btree_cow); const NodeTreeEvaluationContext context(*self_object_, *modifier_); - const GeometrySet &geometry_set = params.get_input<GeometrySet>(dsocket->identifier()); + const GeometrySet &geometry_set = params.get_input<GeometrySet>(socket_ref->identifier()); const Vector<const GeometryComponent *> components = geometry_set.get_components_for_read(); for (const GeometryComponent *component : components) { - component->attribute_foreach([&](StringRefNull attribute_name, - const AttributeMetaData &UNUSED(meta_data)) { - BKE_nodetree_attribute_hint_add(*btree_original, context, *node.bnode(), attribute_name); - return true; - }); + component->attribute_foreach( + [&](StringRefNull attribute_name, const AttributeMetaData &UNUSED(meta_data)) { + BKE_nodetree_attribute_hint_add( + *btree_original, context, *node->bnode(), attribute_name); + return true; + }); } } } - void execute_multi_function_node(const DNode &node, + void execute_multi_function_node(const DNode node, GeoNodeExecParams params, const MultiFunction &fn) { MFContextBuilder fn_context; MFParamsBuilder fn_params{fn, 1}; Vector<GMutablePointer> input_data; - for (const DInputSocket *dsocket : node.inputs()) { - if (dsocket->is_available()) { - GMutablePointer data = params.extract_input(dsocket->identifier()); + for (const InputSocketRef *socket_ref : node->inputs()) { + if (socket_ref->is_available()) { + GMutablePointer data = params.extract_input(socket_ref->identifier()); fn_params.add_readonly_single_input(GSpan(*data.type(), data.get(), 1)); input_data.append(data); } } Vector<GMutablePointer> output_data; - for (const DOutputSocket *dsocket : node.outputs()) { - if (dsocket->is_available()) { - const CPPType &type = *blender::nodes::socket_cpp_type_get(*dsocket->typeinfo()); + for (const OutputSocketRef *socket_ref : node->outputs()) { + if (socket_ref->is_available()) { + const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket_ref->typeinfo()); void *buffer = allocator_.allocate(type.size(), type.alignment()); fn_params.add_uninitialized_single_output(GMutableSpan(type, buffer, 1)); output_data.append(GMutablePointer(type, buffer)); @@ -468,19 +475,19 @@ class GeometryNodesEvaluator { value.destruct(); } int output_index = 0; - for (const int i : node.outputs().index_range()) { - if (node.output(i).is_available()) { + for (const int i : node->outputs().index_range()) { + if (node->output(i).is_available()) { GMutablePointer value = output_data[output_index]; - params.set_output_by_move(node.output(i).identifier(), value); + params.set_output_by_move(node->output(i).identifier(), value); value.destruct(); output_index++; } } } - void execute_unknown_node(const DNode &node, GeoNodeExecParams params) + void execute_unknown_node(const DNode node, GeoNodeExecParams params) { - for (const DOutputSocket *socket : node.outputs()) { + for (const OutputSocketRef *socket : node->outputs()) { if (socket->is_available()) { const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket->typeinfo()); params.set_output_by_copy(socket->identifier(), {type, type.default_value()}); @@ -488,17 +495,18 @@ class GeometryNodesEvaluator { } } - void forward_to_inputs(const DOutputSocket &from_socket, GMutablePointer value_to_forward) + void forward_to_inputs(const DOutputSocket from_socket, GMutablePointer value_to_forward) { /* For all sockets that are linked with the from_socket push the value to their node. */ - Span<const DInputSocket *> to_sockets_all = from_socket.linked_sockets(); + Vector<DInputSocket> to_sockets_all; + from_socket.foreach_target_socket( + [&](DInputSocket to_socket) { to_sockets_all.append(to_socket); }); const CPPType &from_type = *value_to_forward.type(); - Vector<const DInputSocket *> to_sockets_same_type; - for (const DInputSocket *to_socket : to_sockets_all) { + Vector<DInputSocket> to_sockets_same_type; + for (const DInputSocket &to_socket : to_sockets_all) { const CPPType &to_type = *blender::nodes::socket_cpp_type_get(*to_socket->typeinfo()); - const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair( - to_socket, &from_socket); + const std::pair<DInputSocket, DOutputSocket> key = std::make_pair(to_socket, from_socket); if (from_type == to_type) { to_sockets_same_type.append(to_socket); } @@ -520,23 +528,21 @@ class GeometryNodesEvaluator { } else if (to_sockets_same_type.size() == 1) { /* This value is only used on one input socket, no need to copy it. */ - const DInputSocket *to_socket = to_sockets_same_type[0]; - const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair( - to_socket, &from_socket); + const DInputSocket to_socket = to_sockets_same_type[0]; + const std::pair<DInputSocket, DOutputSocket> key = std::make_pair(to_socket, from_socket); add_value_to_input_socket(key, value_to_forward); } else { /* Multiple inputs use the value, make a copy for every input except for one. */ - const DInputSocket *first_to_socket = to_sockets_same_type[0]; - Span<const DInputSocket *> other_to_sockets = to_sockets_same_type.as_span().drop_front(1); + const DInputSocket first_to_socket = to_sockets_same_type[0]; + Span<DInputSocket> other_to_sockets = to_sockets_same_type.as_span().drop_front(1); const CPPType &type = *value_to_forward.type(); - const std::pair<const DInputSocket *, const DOutputSocket *> first_key = std::make_pair( - first_to_socket, &from_socket); + const std::pair<DInputSocket, DOutputSocket> first_key = std::make_pair(first_to_socket, + from_socket); add_value_to_input_socket(first_key, value_to_forward); - for (const DInputSocket *to_socket : other_to_sockets) { - const std::pair<const DInputSocket *, const DOutputSocket *> key = std::make_pair( - to_socket, &from_socket); + for (const DInputSocket &to_socket : other_to_sockets) { + const std::pair<DInputSocket, DOutputSocket> key = std::make_pair(to_socket, from_socket); void *buffer = allocator_.allocate(type.size(), type.alignment()); type.copy_to_uninitialized(value_to_forward.get(), buffer); add_value_to_input_socket(key, GMutablePointer{type, buffer}); @@ -544,22 +550,17 @@ class GeometryNodesEvaluator { } } - void add_value_to_input_socket(const std::pair<const DInputSocket *, const DOutputSocket *> key, + void add_value_to_input_socket(const std::pair<DInputSocket, DOutputSocket> key, GMutablePointer value) { value_by_input_.add_new(key, value); } - GMutablePointer get_unlinked_input_value(const DInputSocket &socket) + GMutablePointer get_unlinked_input_value(const DInputSocket &socket, + const CPPType &required_type) { - bNodeSocket *bsocket; - if (socket.linked_group_inputs().size() == 0) { - bsocket = socket.bsocket(); - } - else { - bsocket = socket.linked_group_inputs()[0]->bsocket(); - } - const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket.typeinfo()); + bNodeSocket *bsocket = socket->bsocket(); + const CPPType &type = *blender::nodes::socket_cpp_type_get(*socket->typeinfo()); void *buffer = allocator_.allocate(type.size(), type.alignment()); if (bsocket->type == SOCK_OBJECT) { @@ -576,7 +577,19 @@ class GeometryNodesEvaluator { blender::nodes::socket_cpp_value_get(*bsocket, buffer); } - return {type, buffer}; + if (type == required_type) { + return {type, buffer}; + } + if (conversions_.is_convertible(type, required_type)) { + void *converted_buffer = allocator_.allocate(required_type.size(), + required_type.alignment()); + conversions_.convert(type, required_type, buffer, converted_buffer); + type.destruct(buffer); + return {required_type, converted_buffer}; + } + void *default_buffer = allocator_.allocate(required_type.size(), required_type.alignment()); + type.copy_to_uninitialized(type.default_value(), default_buffer); + return {required_type, default_buffer}; } }; @@ -985,7 +998,7 @@ static void fill_data_handle_map(const NodesModifierSettings &settings, { Set<ID *> used_ids; find_used_ids_from_settings(settings, used_ids); - find_used_ids_from_nodes(*tree.btree(), used_ids); + find_used_ids_from_nodes(*tree.root_context().tree().btree(), used_ids); int current_handle = 0; for (ID *id : used_ids) { @@ -1013,8 +1026,8 @@ static void reset_tree_ui_storage(Span<const blender::nodes::NodeTreeRef *> tree * often than necessary. It's going to be replaced soon. */ static GeometrySet compute_geometry(const DerivedNodeTree &tree, - Span<const DOutputSocket *> group_input_sockets, - const DInputSocket &socket_to_compute, + Span<const OutputSocketRef *> group_input_sockets, + const InputSocketRef &socket_to_compute, GeometrySet input_geometry_set, NodesModifierData *nmd, const ModifierEvalContext *ctx) @@ -1026,32 +1039,33 @@ static GeometrySet compute_geometry(const DerivedNodeTree &tree, PersistentDataHandleMap handle_map; fill_data_handle_map(nmd->settings, tree, handle_map); - Map<const DOutputSocket *, GMutablePointer> group_inputs; + Map<DOutputSocket, GMutablePointer> group_inputs; + const DTreeContext *root_context = &tree.root_context(); if (group_input_sockets.size() > 0) { - Span<const DOutputSocket *> remaining_input_sockets = group_input_sockets; + Span<const OutputSocketRef *> remaining_input_sockets = group_input_sockets; /* If the group expects a geometry as first input, use the geometry that has been passed to * modifier. */ - const DOutputSocket *first_input_socket = group_input_sockets[0]; + const OutputSocketRef *first_input_socket = group_input_sockets[0]; if (first_input_socket->bsocket()->type == SOCK_GEOMETRY) { - GeometrySet *geometry_set_in = allocator.construct<GeometrySet>( - std::move(input_geometry_set)); - group_inputs.add_new(first_input_socket, geometry_set_in); + GeometrySet *geometry_set_in = + allocator.construct<GeometrySet>(std::move(input_geometry_set)).release(); + group_inputs.add_new({root_context, first_input_socket}, geometry_set_in); remaining_input_sockets = remaining_input_sockets.drop_front(1); } /* Initialize remaining group inputs. */ - for (const DOutputSocket *socket : remaining_input_sockets) { + for (const OutputSocketRef *socket : remaining_input_sockets) { const CPPType &cpp_type = *blender::nodes::socket_cpp_type_get(*socket->typeinfo()); void *value_in = allocator.allocate(cpp_type.size(), cpp_type.alignment()); initialize_group_input(*nmd, handle_map, *socket->bsocket(), cpp_type, value_in); - group_inputs.add_new(socket, {cpp_type, value_in}); + group_inputs.add_new({root_context, socket}, {cpp_type, value_in}); } } - Vector<const DInputSocket *> group_outputs; - group_outputs.append(&socket_to_compute); + Vector<DInputSocket> group_outputs; + group_outputs.append({root_context, &socket_to_compute}); GeometryNodesEvaluator evaluator{group_inputs, group_outputs, @@ -1126,16 +1140,17 @@ static void modifyGeometry(ModifierData *md, check_property_socket_sync(ctx->object, md); - blender::nodes::NodeTreeRefMap tree_refs; - DerivedNodeTree tree{nmd->node_group, tree_refs}; + NodeTreeRefMap tree_refs; + DerivedNodeTree tree{*nmd->node_group, tree_refs}; if (tree.has_link_cycles()) { BKE_modifier_set_error(ctx->object, md, "Node group has cycles"); return; } - Span<const DNode *> input_nodes = tree.nodes_by_type("NodeGroupInput"); - Span<const DNode *> output_nodes = tree.nodes_by_type("NodeGroupOutput"); + const NodeTreeRef &root_tree_ref = tree.root_context().tree(); + Span<const NodeRef *> input_nodes = root_tree_ref.nodes_by_type("NodeGroupInput"); + Span<const NodeRef *> output_nodes = root_tree_ref.nodes_by_type("NodeGroupOutput"); if (input_nodes.size() > 1) { return; @@ -1144,16 +1159,18 @@ static void modifyGeometry(ModifierData *md, return; } - Span<const DOutputSocket *> group_inputs = (input_nodes.size() == 1) ? - input_nodes[0]->outputs().drop_back(1) : - Span<const DOutputSocket *>{}; - Span<const DInputSocket *> group_outputs = output_nodes[0]->inputs().drop_back(1); + Span<const OutputSocketRef *> group_inputs; + if (input_nodes.size() == 1) { + group_inputs = input_nodes[0]->outputs().drop_back(1); + } + + Span<const InputSocketRef *> group_outputs = output_nodes[0]->inputs().drop_back(1); if (group_outputs.size() == 0) { return; } - const DInputSocket *group_output = group_outputs[0]; + const InputSocketRef *group_output = group_outputs[0]; if (group_output->idname() != "NodeSocketGeometry") { return; } diff --git a/source/blender/modifiers/intern/MOD_ui_common.c b/source/blender/modifiers/intern/MOD_ui_common.c index 821c74496f2..6b2facc16a2 100644 --- a/source/blender/modifiers/intern/MOD_ui_common.c +++ b/source/blender/modifiers/intern/MOD_ui_common.c @@ -409,13 +409,9 @@ static void modifier_panel_header(const bContext *C, Panel *panel) */ PanelType *modifier_panel_register(ARegionType *region_type, ModifierType type, PanelDrawFn draw) { - /* Get the name for the modifier's panel. */ - char panel_idname[BKE_ST_MAXNAME]; - BKE_modifier_type_panel_id(type, panel_idname); + PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__); - PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname); - - BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME); + BKE_modifier_type_panel_id(type, panel_type->idname); BLI_strncpy(panel_type->label, "", BKE_ST_MAXNAME); BLI_strncpy(panel_type->context, "modifier", BKE_ST_MAXNAME); BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME); @@ -450,13 +446,9 @@ PanelType *modifier_subpanel_register(ARegionType *region_type, PanelDrawFn draw, PanelType *parent) { - /* Create the subpanel's ID name. */ - char panel_idname[BKE_ST_MAXNAME]; - BLI_snprintf(panel_idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name); - - PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname); + PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__); - BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME); + BLI_snprintf(panel_type->idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name); BLI_strncpy(panel_type->label, label, BKE_ST_MAXNAME); BLI_strncpy(panel_type->context, "modifier", BKE_ST_MAXNAME); BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME); diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c index a6b83ed60ea..487250eb4e3 100644 --- a/source/blender/modifiers/intern/MOD_uvproject.c +++ b/source/blender/modifiers/intern/MOD_uvproject.c @@ -331,12 +331,24 @@ static void panel_draw(const bContext *UNUSED(C), Panel *panel) uiItemPointerR(layout, ptr, "uv_layer", &obj_data_ptr, "uv_layers", NULL, ICON_NONE); + /* Aspect and Scale are only used for camera projectors. */ + bool has_camera = false; + RNA_BEGIN (ptr, projector_ptr, "projectors") { + PointerRNA ob_projector = RNA_pointer_get(&projector_ptr, "object"); + if (!RNA_pointer_is_null(&ob_projector) && RNA_enum_get(&ob_projector, "type") == OB_CAMERA) { + has_camera = true; + } + } + RNA_END; + sub = uiLayoutColumn(layout, true); - uiItemR(sub, ptr, "aspect_x", 0, IFACE_("Aspect X"), ICON_NONE); + uiLayoutSetActive(sub, has_camera); + uiItemR(sub, ptr, "aspect_x", 0, NULL, ICON_NONE); uiItemR(sub, ptr, "aspect_y", 0, IFACE_("Y"), ICON_NONE); sub = uiLayoutColumn(layout, true); - uiItemR(sub, ptr, "scale_x", 0, IFACE_("Scale X"), ICON_NONE); + uiLayoutSetActive(sub, has_camera); + uiItemR(sub, ptr, "scale_x", 0, NULL, ICON_NONE); uiItemR(sub, ptr, "scale_y", 0, IFACE_("Y"), ICON_NONE); uiItemR(layout, ptr, "projector_count", 0, IFACE_("Projectors"), ICON_NONE); diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index 50e29d4a447..d89cf2ecefa 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -168,8 +168,8 @@ set(SRC geometry/nodes/node_geo_point_separate.cc geometry/nodes/node_geo_point_translate.cc geometry/nodes/node_geo_points_to_volume.cc - geometry/nodes/node_geo_subdivision_surface.cc - geometry/nodes/node_geo_subdivision_surface_simple.cc + geometry/nodes/node_geo_subdivide_smooth.cc + geometry/nodes/node_geo_subdivide.cc geometry/nodes/node_geo_transform.cc geometry/nodes/node_geo_triangulate.cc geometry/nodes/node_geo_volume_to_mesh.cc @@ -259,7 +259,7 @@ set(SRC shader/nodes/node_shader_vectTransform.c shader/nodes/node_shader_vector_displacement.c shader/nodes/node_shader_vector_math.cc - shader/nodes/node_shader_vector_rotate.c + shader/nodes/node_shader_vector_rotate.cc shader/nodes/node_shader_vertex_color.c shader/nodes/node_shader_volume_absorption.c shader/nodes/node_shader_volume_info.c @@ -302,7 +302,6 @@ set(SRC intern/node_exec.c intern/node_geometry_exec.cc intern/node_socket.cc - intern/node_tree_dependencies.cc intern/node_tree_multi_function.cc intern/node_tree_ref.cc intern/node_util.c @@ -321,7 +320,6 @@ set(SRC NOD_geometry.h NOD_geometry_exec.hh NOD_math_functions.hh - NOD_node_tree_dependencies.hh NOD_node_tree_multi_function.hh NOD_node_tree_ref.hh NOD_shader.h diff --git a/source/blender/nodes/NOD_derived_node_tree.hh b/source/blender/nodes/NOD_derived_node_tree.hh index ea67f23eade..3529336baf6 100644 --- a/source/blender/nodes/NOD_derived_node_tree.hh +++ b/source/blender/nodes/NOD_derived_node_tree.hh @@ -19,544 +19,361 @@ /** \file * \ingroup nodes * - * DerivedNodeTree provides a flattened view on a bNodeTree, i.e. node groups are inlined. It - * builds on top of NodeTreeRef and supports similar queries efficiently. - * - * Every inlined node remembers its path to the parent ("call stack"). - * - * Unlinked group node inputs are handled separately from other sockets. - * - * There is a dot graph exporter for debugging purposes. + * DerivedNodeTree builds on top of NodeTreeRef and makes working with (nested) node groups more + * convenient and safe. It does so by pairing nodes and sockets with a context. The context + * contains information about the current "instance" of the node or socket. A node might be + * "instanced" multiple times when it is in a node group that is used multiple times. */ -#include "NOD_node_tree_ref.hh" - +#include "BLI_function_ref.hh" #include "BLI_vector_set.hh" +#include "NOD_node_tree_ref.hh" + namespace blender::nodes { +class DTreeContext; +class DerivedNodeTree; + +class DNode; class DSocket; class DInputSocket; class DOutputSocket; -class DNode; -class DParentNode; -class DGroupInput; -class DerivedNodeTree; -class DSocket : NonCopyable, NonMovable { - protected: - DNode *node_; - const SocketRef *socket_ref_; - int id_; +/** + * The context attached to every node or socket in a derived node tree. It can be used to determine + * the place of a node in a hierarchy of node groups. + * + * Contexts are organized in a tree data structure to avoid having to store the entire path to the + * root node group for every node/socket. + */ +class DTreeContext { + private: + /* Null when this context is for the root node group. Otherwise it points to the context one + * level up. */ + DTreeContext *parent_context_; + /* Null when this context is for the root node group. Otherwise it points to the group node in + * the parent node group that contains this context. */ + const NodeRef *parent_node_; + /* The current node tree. */ + const NodeTreeRef *tree_; + /* All the children contexts of this context. */ + Map<const NodeRef *, DTreeContext *> children_; friend DerivedNodeTree; public: - const DNode &node() const; - - int id() const; - int index() const; - - bool is_input() const; - bool is_output() const; - - const DSocket &as_base() const; - const DInputSocket &as_input() const; - const DOutputSocket &as_output() const; - - PointerRNA *rna() const; - StringRefNull idname() const; - StringRefNull name() const; - StringRefNull identifier() const; - bNodeSocketType *typeinfo() const; - - const SocketRef &socket_ref() const; - bNodeSocket *bsocket() const; - - bool is_available() const; + const NodeTreeRef &tree() const; + const DTreeContext *parent_context() const; + const NodeRef *parent_node() const; + const DTreeContext *child_context(const NodeRef &node) const; + bool is_root() const; }; -class DInputSocket : public DSocket { +/* A (nullable) reference to a node and the context it is in. It is unique within an entire nested + * node group hierarchy. This type is small and can be passed around by value. */ +class DNode { private: - Vector<DOutputSocket *> linked_sockets_; - Vector<DGroupInput *> linked_group_inputs_; - bool is_multi_input_socket_; - - friend DerivedNodeTree; + const DTreeContext *context_ = nullptr; + const NodeRef *node_ref_ = nullptr; public: - const InputSocketRef &socket_ref() const; - - Span<const DOutputSocket *> linked_sockets() const; - Span<const DGroupInput *> linked_group_inputs() const; - - bool is_linked() const; - bool is_multi_input_socket() const; -}; + DNode() = default; + DNode(const DTreeContext *context, const NodeRef *node); -class DOutputSocket : public DSocket { - private: - Vector<DInputSocket *> linked_sockets_; + const DTreeContext *context() const; + const NodeRef *node_ref() const; + const NodeRef *operator->() const; - friend DerivedNodeTree; + friend bool operator==(const DNode &a, const DNode &b); + friend bool operator!=(const DNode &a, const DNode &b); + operator bool() const; - public: - const OutputSocketRef &socket_ref() const; - Span<const DInputSocket *> linked_sockets() const; + uint64_t hash() const; }; -class DGroupInput : NonCopyable, NonMovable { - private: - const InputSocketRef *socket_ref_; - DParentNode *parent_; - Vector<DInputSocket *> linked_sockets_; - int id_; - - friend DerivedNodeTree; +/* A (nullable) reference to a socket and the context it is in. It is unique within an entire + * nested node group hierarchy. This type is small and can be passed around by value. + * + * A #DSocket can represent an input or an output socket. If the type of a socket is known at + * compile time is is preferable to use #DInputSocket or #DOutputSocket instead. */ +class DSocket { + protected: + const DTreeContext *context_ = nullptr; + const SocketRef *socket_ref_ = nullptr; public: - const InputSocketRef &socket_ref() const; - bNodeSocket *bsocket() const; - const DParentNode *parent() const; - Span<const DInputSocket *> linked_sockets() const; - int id() const; - StringRefNull name() const; -}; - -class DNode : NonCopyable, NonMovable { - private: - const NodeRef *node_ref_; - DParentNode *parent_; + DSocket() = default; + DSocket(const DTreeContext *context, const SocketRef *socket); + DSocket(const DInputSocket &input_socket); + DSocket(const DOutputSocket &output_socket); - Span<DInputSocket *> inputs_; - Span<DOutputSocket *> outputs_; + const DTreeContext *context() const; + const SocketRef *socket_ref() const; + const SocketRef *operator->() const; - int id_; + friend bool operator==(const DSocket &a, const DSocket &b); + friend bool operator!=(const DSocket &a, const DSocket &b); + operator bool() const; - friend DerivedNodeTree; + uint64_t hash() const; +}; +/* A (nullable) reference to an input socket and the context it is in. */ +class DInputSocket : public DSocket { public: - const NodeRef &node_ref() const; - const DParentNode *parent() const; - - Span<const DInputSocket *> inputs() const; - Span<const DOutputSocket *> outputs() const; - - const DInputSocket &input(int index) const; - const DOutputSocket &output(int index) const; - - const DInputSocket &input(int index, StringRef expected_name) const; - const DOutputSocket &output(int index, StringRef expected_name) const; + DInputSocket() = default; + DInputSocket(const DTreeContext *context, const InputSocketRef *socket); + explicit DInputSocket(const DSocket &base_socket); - int id() const; + const InputSocketRef *socket_ref() const; + const InputSocketRef *operator->() const; - PointerRNA *rna() const; - StringRefNull idname() const; - StringRefNull name() const; - bNode *bnode() const; - bNodeType *typeinfo() const; + DOutputSocket get_corresponding_group_node_output() const; + Vector<DOutputSocket, 4> get_corresponding_group_input_sockets() const; - private: - void destruct_with_sockets(); + void foreach_origin_socket(FunctionRef<void(DSocket)> callback, + const bool follow_only_first_incoming_link = false) const; }; -class DParentNode : NonCopyable, NonMovable { - private: - const NodeRef *node_ref_; - DParentNode *parent_; - int id_; +/* A (nullable) reference to an output socket and the context it is in. */ +class DOutputSocket : public DSocket { + public: + DOutputSocket() = default; + DOutputSocket(const DTreeContext *context, const OutputSocketRef *socket); + explicit DOutputSocket(const DSocket &base_socket); - friend DerivedNodeTree; + const OutputSocketRef *socket_ref() const; + const OutputSocketRef *operator->() const; - public: - const DParentNode *parent() const; - const NodeRef &node_ref() const; - int id() const; + DInputSocket get_corresponding_group_node_input() const; + DInputSocket get_active_corresponding_group_output_socket() const; + + void foreach_target_socket(FunctionRef<void(DInputSocket)> callback) const; }; -class DerivedNodeTree : NonCopyable, NonMovable { +class DerivedNodeTree { private: LinearAllocator<> allocator_; - Vector<DNode *> nodes_by_id_; - Vector<DGroupInput *> group_inputs_; - Vector<DParentNode *> parent_nodes_; - - Vector<DSocket *> sockets_by_id_; - Vector<DInputSocket *> input_sockets_; - Vector<DOutputSocket *> output_sockets_; - - MultiValueMap<const bNodeType *, DNode *> nodes_by_type_; + DTreeContext *root_context_; VectorSet<const NodeTreeRef *> used_node_tree_refs_; - bNodeTree *btree_; public: - DerivedNodeTree(bNodeTree *btree, NodeTreeRefMap &node_tree_refs); + DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs); ~DerivedNodeTree(); - bNodeTree *btree() const; - - Span<const DNode *> nodes() const; - Span<const DNode *> nodes_by_type(StringRefNull idname) const; - Span<const DNode *> nodes_by_type(const bNodeType *nodetype) const; - - Span<const DSocket *> sockets() const; - Span<const DInputSocket *> input_sockets() const; - Span<const DOutputSocket *> output_sockets() const; - - Span<const DGroupInput *> group_inputs() const; - + const DTreeContext &root_context() const; Span<const NodeTreeRef *> used_node_tree_refs() const; bool has_link_cycles() const; - - std::string to_dot() const; + void foreach_node(FunctionRef<void(DNode)> callback) const; private: - /* Utility functions used during construction. */ - void insert_nodes_and_links_in_id_order(const NodeTreeRef &tree_ref, - DParentNode *parent, - Vector<DNode *> &all_nodes); - DNode &create_node(const NodeRef &node_ref, - DParentNode *parent, - MutableSpan<DSocket *> r_sockets_map); - void expand_groups(Vector<DNode *> &all_nodes, - Vector<DGroupInput *> &all_group_inputs, - Vector<DParentNode *> &all_parent_nodes, - NodeTreeRefMap &node_tree_refs); - void expand_group_node(DNode &group_node, - Vector<DNode *> &all_nodes, - Vector<DGroupInput *> &all_group_inputs, - Vector<DParentNode *> &all_parent_nodes, - NodeTreeRefMap &node_tree_refs); - void create_group_inputs_for_unlinked_inputs(DNode &node, - Vector<DGroupInput *> &all_group_inputs); - void relink_group_inputs(const NodeTreeRef &group_ref, - Span<DNode *> nodes_by_id, - DNode &group_node); - void relink_group_outputs(const NodeTreeRef &group_ref, - Span<DNode *> nodes_by_id, - DNode &group_node); - void remove_expanded_group_interfaces(Vector<DNode *> &all_nodes); - void remove_unused_group_inputs(Vector<DGroupInput *> &all_group_inputs); - void relink_and_remove_muted_nodes(Vector<DNode *> &all_nodes); - void relink_muted_node(DNode &muted_node); - void store_in_this_and_init_ids(Vector<DNode *> &&all_nodes, - Vector<DGroupInput *> &&all_group_inputs, - Vector<DParentNode *> &&all_parent_nodes); + DTreeContext &construct_context_recursively(DTreeContext *parent_context, + const NodeRef *parent_node, + bNodeTree &btree, + NodeTreeRefMap &node_tree_refs); + void destruct_context_recursively(DTreeContext *context); + + void foreach_node_in_context_recursive(const DTreeContext &context, + FunctionRef<void(DNode)> callback) const; }; namespace derived_node_tree_types { +using namespace node_tree_ref_types; using nodes::DerivedNodeTree; -using nodes::DGroupInput; using nodes::DInputSocket; using nodes::DNode; using nodes::DOutputSocket; -using nodes::DParentNode; -}; // namespace derived_node_tree_types +using nodes::DSocket; +using nodes::DTreeContext; +} // namespace derived_node_tree_types /* -------------------------------------------------------------------- - * DSocket inline methods. + * DTreeContext inline methods. */ -inline const DNode &DSocket::node() const -{ - return *node_; -} - -inline int DSocket::id() const +inline const NodeTreeRef &DTreeContext::tree() const { - return id_; + return *tree_; } -inline int DSocket::index() const +inline const DTreeContext *DTreeContext::parent_context() const { - return socket_ref_->index(); + return parent_context_; } -inline bool DSocket::is_input() const +inline const NodeRef *DTreeContext::parent_node() const { - return socket_ref_->is_input(); + return parent_node_; } -inline bool DSocket::is_output() const +inline const DTreeContext *DTreeContext::child_context(const NodeRef &node) const { - return socket_ref_->is_output(); + return children_.lookup_default(&node, nullptr); } -inline const DSocket &DSocket::as_base() const +inline bool DTreeContext::is_root() const { - return *this; + return parent_context_ == nullptr; } -inline const DInputSocket &DSocket::as_input() const -{ - return static_cast<const DInputSocket &>(*this); -} - -inline const DOutputSocket &DSocket::as_output() const -{ - return static_cast<const DOutputSocket &>(*this); -} +/* -------------------------------------------------------------------- + * DNode inline methods. + */ -inline PointerRNA *DSocket::rna() const +inline DNode::DNode(const DTreeContext *context, const NodeRef *node_ref) + : context_(context), node_ref_(node_ref) { - return socket_ref_->rna(); + BLI_assert(node_ref == nullptr || &node_ref->tree() == &context->tree()); } -inline StringRefNull DSocket::idname() const +inline const DTreeContext *DNode::context() const { - return socket_ref_->idname(); + return context_; } -inline StringRefNull DSocket::name() const +inline const NodeRef *DNode::node_ref() const { - return socket_ref_->name(); + return node_ref_; } -inline StringRefNull DSocket::identifier() const +inline bool operator==(const DNode &a, const DNode &b) { - return socket_ref_->identifier(); + return a.context_ == b.context_ && a.node_ref_ == b.node_ref_; } -inline bNodeSocketType *DSocket::typeinfo() const +inline bool operator!=(const DNode &a, const DNode &b) { - return socket_ref_->bsocket()->typeinfo; + return !(a == b); } -inline const SocketRef &DSocket::socket_ref() const +inline DNode::operator bool() const { - return *socket_ref_; + return node_ref_ != nullptr; } -inline bNodeSocket *DSocket::bsocket() const +inline const NodeRef *DNode::operator->() const { - return socket_ref_->bsocket(); + return node_ref_; } -inline bool DSocket::is_available() const +inline uint64_t DNode::hash() const { - return (socket_ref_->bsocket()->flag & SOCK_UNAVAIL) == 0; + return DefaultHash<const DTreeContext *>{}(context_) ^ DefaultHash<const NodeRef *>{}(node_ref_); } /* -------------------------------------------------------------------- - * DInputSocket inline methods. + * DSocket inline methods. */ -inline const InputSocketRef &DInputSocket::socket_ref() const -{ - return socket_ref_->as_input(); -} - -inline Span<const DOutputSocket *> DInputSocket::linked_sockets() const -{ - return linked_sockets_; -} - -inline Span<const DGroupInput *> DInputSocket::linked_group_inputs() const -{ - return linked_group_inputs_; -} - -inline bool DInputSocket::is_linked() const +inline DSocket::DSocket(const DTreeContext *context, const SocketRef *socket_ref) + : context_(context), socket_ref_(socket_ref) { - return linked_sockets_.size() > 0 || linked_group_inputs_.size() > 0; + BLI_assert(socket_ref == nullptr || &socket_ref->tree() == &context->tree()); } -inline bool DInputSocket::is_multi_input_socket() const +inline DSocket::DSocket(const DInputSocket &input_socket) + : DSocket(input_socket.context_, input_socket.socket_ref_) { - return is_multi_input_socket_; } -/* -------------------------------------------------------------------- - * DOutputSocket inline methods. - */ - -inline const OutputSocketRef &DOutputSocket::socket_ref() const +inline DSocket::DSocket(const DOutputSocket &output_socket) + : DSocket(output_socket.context_, output_socket.socket_ref_) { - return socket_ref_->as_output(); } -inline Span<const DInputSocket *> DOutputSocket::linked_sockets() const +inline const DTreeContext *DSocket::context() const { - return linked_sockets_; + return context_; } -/* -------------------------------------------------------------------- - * DGroupInput inline methods. - */ - -inline const InputSocketRef &DGroupInput::socket_ref() const +inline const SocketRef *DSocket::socket_ref() const { - return *socket_ref_; + return socket_ref_; } -inline bNodeSocket *DGroupInput::bsocket() const +inline bool operator==(const DSocket &a, const DSocket &b) { - return socket_ref_->bsocket(); + return a.context_ == b.context_ && a.socket_ref_ == b.socket_ref_; } -inline const DParentNode *DGroupInput::parent() const +inline bool operator!=(const DSocket &a, const DSocket &b) { - return parent_; + return !(a == b); } -inline Span<const DInputSocket *> DGroupInput::linked_sockets() const +inline DSocket::operator bool() const { - return linked_sockets_; + return socket_ref_ != nullptr; } -inline int DGroupInput::id() const +inline const SocketRef *DSocket::operator->() const { - return id_; + return socket_ref_; } -inline StringRefNull DGroupInput::name() const +inline uint64_t DSocket::hash() const { - return socket_ref_->name(); + return DefaultHash<const DTreeContext *>{}(context_) ^ + DefaultHash<const SocketRef *>{}(socket_ref_); } /* -------------------------------------------------------------------- - * DNode inline methods. + * DInputSocket inline methods. */ -inline const NodeRef &DNode::node_ref() const -{ - return *node_ref_; -} - -inline const DParentNode *DNode::parent() const -{ - return parent_; -} - -inline Span<const DInputSocket *> DNode::inputs() const -{ - return inputs_; -} - -inline Span<const DOutputSocket *> DNode::outputs() const -{ - return outputs_; -} - -inline const DInputSocket &DNode::input(int index) const -{ - return *inputs_[index]; -} - -inline const DOutputSocket &DNode::output(int index) const -{ - return *outputs_[index]; -} - -inline const DInputSocket &DNode::input(int index, StringRef expected_name) const +inline DInputSocket::DInputSocket(const DTreeContext *context, const InputSocketRef *socket_ref) + : DSocket(context, socket_ref) { - const DInputSocket &socket = *inputs_[index]; - BLI_assert(socket.name() == expected_name); - UNUSED_VARS_NDEBUG(expected_name); - return socket; } -inline const DOutputSocket &DNode::output(int index, StringRef expected_name) const +inline DInputSocket::DInputSocket(const DSocket &base_socket) : DSocket(base_socket) { - const DOutputSocket &socket = *outputs_[index]; - BLI_assert(socket.name() == expected_name); - UNUSED_VARS_NDEBUG(expected_name); - return socket; + BLI_assert(base_socket->is_input()); } -inline int DNode::id() const +inline const InputSocketRef *DInputSocket::socket_ref() const { - return id_; + return (const InputSocketRef *)socket_ref_; } -inline PointerRNA *DNode::rna() const +inline const InputSocketRef *DInputSocket::operator->() const { - return node_ref_->rna(); + return (const InputSocketRef *)socket_ref_; } -inline StringRefNull DNode::idname() const -{ - return node_ref_->idname(); -} - -inline StringRefNull DNode::name() const -{ - return node_ref_->name(); -} - -inline bNode *DNode::bnode() const -{ - return node_ref_->bnode(); -} +/* -------------------------------------------------------------------- + * DOutputSocket inline methods. + */ -inline bNodeType *DNode::typeinfo() const +inline DOutputSocket::DOutputSocket(const DTreeContext *context, const OutputSocketRef *socket_ref) + : DSocket(context, socket_ref) { - return node_ref_->bnode()->typeinfo; } -/* -------------------------------------------------------------------- - * DParentNode inline methods. - */ - -inline const DParentNode *DParentNode::parent() const +inline DOutputSocket::DOutputSocket(const DSocket &base_socket) : DSocket(base_socket) { - return parent_; + BLI_assert(base_socket->is_output()); } -inline const NodeRef &DParentNode::node_ref() const +inline const OutputSocketRef *DOutputSocket::socket_ref() const { - return *node_ref_; + return (const OutputSocketRef *)socket_ref_; } -inline int DParentNode::id() const +inline const OutputSocketRef *DOutputSocket::operator->() const { - return id_; + return (const OutputSocketRef *)socket_ref_; } /* -------------------------------------------------------------------- * DerivedNodeTree inline methods. */ -inline bNodeTree *DerivedNodeTree::btree() const -{ - return btree_; -} - -inline Span<const DNode *> DerivedNodeTree::nodes() const -{ - return nodes_by_id_; -} - -inline Span<const DNode *> DerivedNodeTree::nodes_by_type(StringRefNull idname) const -{ - const bNodeType *nodetype = nodeTypeFind(idname.c_str()); - return this->nodes_by_type(nodetype); -} - -inline Span<const DNode *> DerivedNodeTree::nodes_by_type(const bNodeType *nodetype) const -{ - return nodes_by_type_.lookup(nodetype); -} - -inline Span<const DSocket *> DerivedNodeTree::sockets() const -{ - return sockets_by_id_; -} - -inline Span<const DInputSocket *> DerivedNodeTree::input_sockets() const -{ - return input_sockets_; -} - -inline Span<const DOutputSocket *> DerivedNodeTree::output_sockets() const -{ - return output_sockets_; -} - -inline Span<const DGroupInput *> DerivedNodeTree::group_inputs() const +inline const DTreeContext &DerivedNodeTree::root_context() const { - return group_inputs_; + return *root_context_; } inline Span<const NodeTreeRef *> DerivedNodeTree::used_node_tree_refs() const diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index 3ee8067e81a..b094256190c 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -51,8 +51,8 @@ void register_node_type_geo_point_separate(void); void register_node_type_geo_point_translate(void); void register_node_type_geo_points_to_volume(void); void register_node_type_geo_sample_texture(void); -void register_node_type_geo_subdivision_surface(void); -void register_node_type_geo_subdivision_surface_simple(void); +void register_node_type_geo_subdivide_smooth(void); +void register_node_type_geo_subdivide(void); void register_node_type_geo_transform(void); void register_node_type_geo_triangulate(void); void register_node_type_geo_volume_to_mesh(void); diff --git a/source/blender/nodes/NOD_geometry_exec.hh b/source/blender/nodes/NOD_geometry_exec.hh index e648d77337b..5b123e68fe2 100644 --- a/source/blender/nodes/NOD_geometry_exec.hh +++ b/source/blender/nodes/NOD_geometry_exec.hh @@ -59,7 +59,7 @@ using fn::GValueMap; class GeoNodeExecParams { private: - const DNode &node_; + const DNode node_; GValueMap<StringRef> &input_values_; GValueMap<StringRef> &output_values_; const PersistentDataHandleMap &handle_map_; @@ -68,7 +68,7 @@ class GeoNodeExecParams { Depsgraph *depsgraph_; public: - GeoNodeExecParams(const DNode &node, + GeoNodeExecParams(const DNode node, GValueMap<StringRef> &input_values, GValueMap<StringRef> &output_values, const PersistentDataHandleMap &handle_map, @@ -120,13 +120,17 @@ class GeoNodeExecParams { template<typename T> Vector<T> extract_multi_input(StringRef identifier) { Vector<T> values; - values.append(input_values_.extract<T>(identifier)); - int i = 1; - std::string sub_identifier = identifier + "[1]"; - while (input_values_.contains(sub_identifier)) { + int index = 0; + while (true) { + std::string sub_identifier = identifier; + if (index > 0) { + sub_identifier += "[" + std::to_string(index) + "]"; + } + if (!input_values_.contains(sub_identifier)) { + break; + } values.append(input_values_.extract<T>(sub_identifier)); - i++; - sub_identifier = identifier + "[" + std::to_string(i) + "]"; + index++; } return values; } @@ -182,7 +186,7 @@ class GeoNodeExecParams { */ const bNode &node() const { - return *node_.bnode(); + return *node_->bnode(); } const PersistentDataHandleMap &handle_map() const diff --git a/source/blender/nodes/NOD_node_tree_dependencies.hh b/source/blender/nodes/NOD_node_tree_dependencies.hh deleted file mode 100644 index 13bb2bde2f3..00000000000 --- a/source/blender/nodes/NOD_node_tree_dependencies.hh +++ /dev/null @@ -1,76 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#pragma once - -#include "BLI_vector_set.hh" - -#include "DNA_ID.h" -#include "DNA_object_types.h" - -struct bNodeTree; - -namespace blender::nodes { - -class NodeTreeDependencies { - private: - VectorSet<Object *> transform_deps_; - VectorSet<Object *> geometry_deps_; - VectorSet<ID *> id_deps_; - - public: - void add_transform_dependency(Object *object) - { - if (object == nullptr) { - return; - } - transform_deps_.add(object); - id_deps_.add(&object->id); - } - - void add_geometry_dependency(Object *object) - { - if (object == nullptr) { - return; - } - geometry_deps_.add(object); - id_deps_.add(&object->id); - } - - bool depends_on(ID *id) const - { - return id_deps_.contains(id); - } - - Span<Object *> transform_dependencies() - { - return transform_deps_; - } - - Span<Object *> geometry_dependencies() - { - return geometry_deps_; - } - - Span<ID *> id_dependencies() - { - return id_deps_; - } -}; - -NodeTreeDependencies find_node_tree_dependencies(bNodeTree &ntree); - -} // namespace blender::nodes diff --git a/source/blender/nodes/NOD_node_tree_multi_function.hh b/source/blender/nodes/NOD_node_tree_multi_function.hh index 552ef5509fa..df31ee18369 100644 --- a/source/blender/nodes/NOD_node_tree_multi_function.hh +++ b/source/blender/nodes/NOD_node_tree_multi_function.hh @@ -28,14 +28,15 @@ #include "NOD_derived_node_tree.hh" #include "NOD_type_callbacks.hh" +#include "BLI_multi_value_map.hh" #include "BLI_resource_collector.hh" namespace blender::nodes { /** - * A MFNetworkTreeMap maps various components of a DerivedNodeTree to components of a - * fn::MFNetwork. This is necessary for further processing of a multi-function network that has - * been generated from a node tree. + * A MFNetworkTreeMap maps various components of a node tree to components of a fn::MFNetwork. This + * is necessary for further processing of a multi-function network that has been generated from a + * node tree. */ class MFNetworkTreeMap { private: @@ -47,15 +48,11 @@ class MFNetworkTreeMap { */ const DerivedNodeTree &tree_; fn::MFNetwork &network_; - Array<Vector<fn::MFSocket *, 1>> sockets_by_dsocket_id_; - Array<fn::MFOutputSocket *> socket_by_group_input_id_; + MultiValueMap<DSocket, fn::MFSocket *> sockets_by_dsocket_; public: MFNetworkTreeMap(const DerivedNodeTree &tree, fn::MFNetwork &network) - : tree_(tree), - network_(network), - sockets_by_dsocket_id_(tree.sockets().size()), - socket_by_group_input_id_(tree.group_inputs().size(), nullptr) + : tree_(tree), network_(network) { } @@ -76,96 +73,95 @@ class MFNetworkTreeMap { void add(const DSocket &dsocket, fn::MFSocket &socket) { - BLI_assert(dsocket.is_input() == socket.is_input()); - BLI_assert(dsocket.is_input() || sockets_by_dsocket_id_[dsocket.id()].size() == 0); - sockets_by_dsocket_id_[dsocket.id()].append(&socket); + BLI_assert(dsocket->is_input() == socket.is_input()); + BLI_assert(dsocket->is_input() || sockets_by_dsocket_.lookup(dsocket).is_empty()); + sockets_by_dsocket_.add(dsocket, &socket); } void add(const DInputSocket &dsocket, fn::MFInputSocket &socket) { - sockets_by_dsocket_id_[dsocket.id()].append(&socket); + sockets_by_dsocket_.add(dsocket, &socket); } void add(const DOutputSocket &dsocket, fn::MFOutputSocket &socket) { /* There can be at most one matching output socket. */ - BLI_assert(sockets_by_dsocket_id_[dsocket.id()].size() == 0); - sockets_by_dsocket_id_[dsocket.id()].append(&socket); + BLI_assert(sockets_by_dsocket_.lookup(dsocket).is_empty()); + sockets_by_dsocket_.add(dsocket, &socket); } - void add(Span<const DInputSocket *> dsockets, Span<fn::MFInputSocket *> sockets) + void add(const DTreeContext &context, + Span<const InputSocketRef *> dsockets, + Span<fn::MFInputSocket *> sockets) { assert_same_size(dsockets, sockets); for (int i : dsockets.index_range()) { - this->add(*dsockets[i], *sockets[i]); + this->add(DInputSocket(&context, dsockets[i]), *sockets[i]); } } - void add(Span<const DOutputSocket *> dsockets, Span<fn::MFOutputSocket *> sockets) + void add(const DTreeContext &context, + Span<const OutputSocketRef *> dsockets, + Span<fn::MFOutputSocket *> sockets) { assert_same_size(dsockets, sockets); for (int i : dsockets.index_range()) { - this->add(*dsockets[i], *sockets[i]); + this->add(DOutputSocket(&context, dsockets[i]), *sockets[i]); } } - void add(const DGroupInput &group_input, fn::MFOutputSocket &socket) - { - BLI_assert(socket_by_group_input_id_[group_input.id()] == nullptr); - socket_by_group_input_id_[group_input.id()] = &socket; - } - void add_try_match(const DNode &dnode, fn::MFNode &node) { - this->add_try_match(dnode.inputs().cast<const DSocket *>(), + this->add_try_match(*dnode.context(), + dnode->inputs().cast<const SocketRef *>(), node.inputs().cast<fn::MFSocket *>()); - this->add_try_match(dnode.outputs().cast<const DSocket *>(), + this->add_try_match(*dnode.context(), + dnode->outputs().cast<const SocketRef *>(), node.outputs().cast<fn::MFSocket *>()); } - void add_try_match(Span<const DInputSocket *> dsockets, Span<fn::MFInputSocket *> sockets) + void add_try_match(const DTreeContext &context, + Span<const InputSocketRef *> dsockets, + Span<fn::MFInputSocket *> sockets) { - this->add_try_match(dsockets.cast<const DSocket *>(), sockets.cast<fn::MFSocket *>()); + this->add_try_match( + context, dsockets.cast<const SocketRef *>(), sockets.cast<fn::MFSocket *>()); } - void add_try_match(Span<const DOutputSocket *> dsockets, Span<fn::MFOutputSocket *> sockets) + void add_try_match(const DTreeContext &context, + Span<const OutputSocketRef *> dsockets, + Span<fn::MFOutputSocket *> sockets) { - this->add_try_match(dsockets.cast<const DSocket *>(), sockets.cast<fn::MFSocket *>()); + this->add_try_match( + context, dsockets.cast<const SocketRef *>(), sockets.cast<fn::MFSocket *>()); } - void add_try_match(Span<const DSocket *> dsockets, Span<fn::MFSocket *> sockets) + void add_try_match(const DTreeContext &context, + Span<const SocketRef *> dsockets, + Span<fn::MFSocket *> sockets) { int used_sockets = 0; - for (const DSocket *dsocket : dsockets) { + for (const SocketRef *dsocket : dsockets) { if (!dsocket->is_available()) { continue; } - if (!socket_is_mf_data_socket(*dsocket->bsocket()->typeinfo)) { + if (!socket_is_mf_data_socket(*dsocket->typeinfo())) { continue; } fn::MFSocket *socket = sockets[used_sockets]; - this->add(*dsocket, *socket); + this->add(DSocket(&context, dsocket), *socket); used_sockets++; } } - fn::MFOutputSocket &lookup(const DGroupInput &group_input) - { - fn::MFOutputSocket *socket = socket_by_group_input_id_[group_input.id()]; - BLI_assert(socket != nullptr); - return *socket; - } - fn::MFOutputSocket &lookup(const DOutputSocket &dsocket) { - auto &sockets = sockets_by_dsocket_id_[dsocket.id()]; - BLI_assert(sockets.size() == 1); - return sockets[0]->as_output(); + return sockets_by_dsocket_.lookup(dsocket)[0]->as_output(); } Span<fn::MFInputSocket *> lookup(const DInputSocket &dsocket) { - return sockets_by_dsocket_id_[dsocket.id()].as_span().cast<fn::MFInputSocket *>(); + return sockets_by_dsocket_.lookup(dsocket).cast<fn::MFInputSocket *>(); } fn::MFInputSocket &lookup_dummy(const DInputSocket &dsocket) @@ -186,7 +182,7 @@ class MFNetworkTreeMap { bool is_mapped(const DSocket &dsocket) const { - return sockets_by_dsocket_id_[dsocket.id()].size() >= 1; + return !sockets_by_dsocket_.lookup(dsocket).is_empty(); } }; @@ -258,12 +254,7 @@ class SocketMFNetworkBuilder : public MFNetworkBuilderBase { public: SocketMFNetworkBuilder(CommonMFNetworkBuilderData &common, const DSocket &dsocket) - : MFNetworkBuilderBase(common), bsocket_(dsocket.bsocket()) - { - } - - SocketMFNetworkBuilder(CommonMFNetworkBuilderData &common, const DGroupInput &group_input) - : MFNetworkBuilderBase(common), bsocket_(group_input.bsocket()) + : MFNetworkBuilderBase(common), bsocket_(dsocket->bsocket()) { } @@ -331,10 +322,10 @@ class SocketMFNetworkBuilder : public MFNetworkBuilderBase { */ class NodeMFNetworkBuilder : public MFNetworkBuilderBase { private: - const DNode &dnode_; + DNode dnode_; public: - NodeMFNetworkBuilder(CommonMFNetworkBuilderData &common, const DNode &dnode) + NodeMFNetworkBuilder(CommonMFNetworkBuilderData &common, DNode dnode) : MFNetworkBuilderBase(common), dnode_(dnode) { } @@ -352,7 +343,7 @@ class NodeMFNetworkBuilder : public MFNetworkBuilderBase { const fn::MultiFunction &get_not_implemented_fn() { - return this->get_default_fn("Not Implemented (" + dnode_.name() + ")"); + return this->get_default_fn("Not Implemented (" + dnode_->name() + ")"); } const fn::MultiFunction &get_default_fn(StringRef name); @@ -377,7 +368,7 @@ class NodeMFNetworkBuilder : public MFNetworkBuilderBase { */ bNode &bnode() { - return *dnode_.node_ref().bnode(); + return *dnode_->bnode(); } /** @@ -393,7 +384,7 @@ MFNetworkTreeMap insert_node_tree_into_mf_network(fn::MFNetwork &network, const DerivedNodeTree &tree, ResourceCollector &resources); -using MultiFunctionByNode = Map<const DNode *, const fn::MultiFunction *>; +using MultiFunctionByNode = Map<DNode, const fn::MultiFunction *>; MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree, ResourceCollector &resources); diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 35550bdec48..22204d7204e 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -272,7 +272,7 @@ DefNode(FunctionNode, FN_NODE_INPUT_STRING, def_fn_input_string, "INPUT_STRING", DefNode(GeometryNode, GEO_NODE_TRIANGULATE, def_geo_triangulate, "TRIANGULATE", Triangulate, "Triangulate", "") DefNode(GeometryNode, GEO_NODE_EDGE_SPLIT, 0, "EDGE_SPLIT", EdgeSplit, "Edge Split", "") DefNode(GeometryNode, GEO_NODE_TRANSFORM, 0, "TRANSFORM", Transform, "Transform", "") -DefNode(GeometryNode, GEO_NODE_SUBDIVISION_SURFACE, 0, "SUBDIVISION_SURFACE", SubdivisionSurface, "Subdivision Surface", "") +DefNode(GeometryNode, GEO_NODE_SUBDIVIDE_SMOOTH, 0, "SUBDIVIDE_SMOOTH", SubdivideSmooth, "Subdivide Smooth", "") DefNode(GeometryNode, GEO_NODE_BOOLEAN, def_geo_boolean, "BOOLEAN", Boolean, "Boolean", "") DefNode(GeometryNode, GEO_NODE_POINT_DISTRIBUTE, def_geo_point_distribute, "POINT_DISTRIBUTE", PointDistribute, "Point Distribute", "") DefNode(GeometryNode, GEO_NODE_POINT_INSTANCE, def_geo_point_instance, "POINT_INSTANCE", PointInstance, "Point Instance", "") @@ -298,7 +298,7 @@ DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_PROXIMITY, def_geo_attribute_proximity, DefNode(GeometryNode, GEO_NODE_VOLUME_TO_MESH, def_geo_volume_to_mesh, "VOLUME_TO_MESH", VolumeToMesh, "Volume to Mesh", "") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_COMBINE_XYZ, def_geo_attribute_combine_xyz, "ATTRIBUTE_COMBINE_XYZ", AttributeCombineXYZ, "Attribute Combine XYZ", "") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_SEPARATE_XYZ, def_geo_attribute_separate_xyz, "ATTRIBUTE_SEPARATE_XYZ", AttributeSeparateXYZ, "Attribute Separate XYZ", "") -DefNode(GeometryNode, GEO_NODE_SUBDIVISION_SURFACE_SIMPLE, 0, "SUBDIVISION_SURFACE_SIMPLE", SubdivisionSurfaceSimple, "Simple Subdivision Surface", "") +DefNode(GeometryNode, GEO_NODE_SUBDIVIDE, 0, "SUBDIVIDE", Subdivide, "Subdivide", "") /* undefine macros */ #undef DefNode diff --git a/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc b/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc index 1e22cde721d..3d0ea201239 100644 --- a/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc +++ b/source/blender/nodes/function/nodes/node_fn_group_instance_id.cc @@ -26,9 +26,10 @@ static void fn_node_group_instance_id_expand_in_mf_network( { const blender::nodes::DNode &node = builder.dnode(); std::string id = "/"; - for (const blender::nodes::DParentNode *parent = node.parent(); parent; - parent = parent->parent()) { - id = "/" + parent->node_ref().name() + id; + for (const blender::nodes::DTreeContext *context = node.context(); + context->parent_node() != nullptr; + context = context->parent_context()) { + id = "/" + context->parent_node()->name() + id; } builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<std::string>>( std::move(id)); diff --git a/source/blender/nodes/function/nodes/node_fn_random_float.cc b/source/blender/nodes/function/nodes/node_fn_random_float.cc index f3401a2c00d..d0ecb5592da 100644 --- a/source/blender/nodes/function/nodes/node_fn_random_float.cc +++ b/source/blender/nodes/function/nodes/node_fn_random_float.cc @@ -67,12 +67,13 @@ static void fn_node_random_float_expand_in_mf_network( blender::nodes::NodeMFNetworkBuilder &builder) { uint32_t function_seed = 1746872341u; - const blender::nodes::DNode &node = builder.dnode(); + blender::nodes::DNode node = builder.dnode(); const blender::DefaultHash<blender::StringRefNull> hasher; - function_seed = 33 * function_seed + hasher(node.name()); - for (const blender::nodes::DParentNode *parent = node.parent(); parent != nullptr; - parent = parent->parent()) { - function_seed = 33 * function_seed + hasher(parent->node_ref().name()); + function_seed = 33 * function_seed + hasher(node->name()); + for (const blender::nodes::DTreeContext *context = node.context(); + context->parent_node() != nullptr; + context = context->parent_context()) { + function_seed = 33 * function_seed + hasher(context->parent_node()->name()); } builder.construct_and_set_matching_fn<RandomFloatFunction>(function_seed); diff --git a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc index 38215b54640..9f331190420 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_boolean.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_boolean.cc @@ -100,7 +100,7 @@ static Mesh *mesh_boolean_calc(const Mesh *mesh_a, const Mesh *mesh_b, int boole } BM_mesh_boolean( - bm, looptris, tottri, bm_face_isect_pair, nullptr, 2, false, false, boolean_mode); + bm, looptris, tottri, bm_face_isect_pair, nullptr, 2, false, false, false, boolean_mode); Mesh *result = BKE_mesh_from_bmesh_for_eval_nomain(bm, nullptr, mesh_a); BM_mesh_free(bm); diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc index 4e15f232934..45aaf81d63f 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc @@ -222,8 +222,9 @@ static void join_components(Span<const MeshComponent *> src_components, Geometry dst_component.replace(new_mesh); /* Don't copy attributes that are stored directly in the mesh data structs. */ - join_attributes( - to_base_components(src_components), dst_component, {"position", "material_index"}); + join_attributes(to_base_components(src_components), + dst_component, + {"position", "material_index", "vertex_normal", "shade_smooth"}); } static void join_components(Span<const PointCloudComponent *> src_components, GeometrySet &result) diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc index c40cb2bb0ae..742383f5b46 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_distribute.cc @@ -29,6 +29,7 @@ #include "BKE_attribute_math.hh" #include "BKE_bvhutils.h" #include "BKE_deform.h" +#include "BKE_geometry_set_instances.hh" #include "BKE_mesh.h" #include "BKE_mesh_runtime.h" #include "BKE_pointcloud.h" @@ -38,6 +39,9 @@ #include "node_geometry_util.hh" +using blender::bke::AttributeKind; +using blender::bke::GeometryInstanceGroup; + static bNodeSocketTemplate geo_node_point_distribute_in[] = { {SOCK_GEOMETRY, N_("Geometry")}, {SOCK_FLOAT, N_("Distance Min"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 100000.0f, PROP_NONE}, @@ -89,6 +93,7 @@ static Span<MLoopTri> get_mesh_looptris(const Mesh &mesh) } static void sample_mesh_surface(const Mesh &mesh, + const float4x4 &transform, const float base_density, const FloatReadAttribute *density_factors, const int seed, @@ -106,9 +111,9 @@ static void sample_mesh_surface(const Mesh &mesh, const int v0_index = mesh.mloop[v0_loop].v; const int v1_index = mesh.mloop[v1_loop].v; const int v2_index = mesh.mloop[v2_loop].v; - const float3 v0_pos = mesh.mvert[v0_index].co; - const float3 v1_pos = mesh.mvert[v1_index].co; - const float3 v2_pos = mesh.mvert[v2_index].co; + const float3 v0_pos = transform * float3(mesh.mvert[v0_index].co); + const float3 v1_pos = transform * float3(mesh.mvert[v1_index].co); + const float3 v2_pos = transform * float3(mesh.mvert[v2_index].co); float looptri_density_factor = 1.0f; if (density_factors != nullptr) { @@ -138,47 +143,64 @@ static void sample_mesh_surface(const Mesh &mesh, } } -BLI_NOINLINE static KDTree_3d *build_kdtree(Span<float3> positions) +BLI_NOINLINE static KDTree_3d *build_kdtree(Span<Vector<float3>> positions_all, + const int initial_points_len) { - KDTree_3d *kdtree = BLI_kdtree_3d_new(positions.size()); - for (const int i : positions.index_range()) { - BLI_kdtree_3d_insert(kdtree, i, positions[i]); + KDTree_3d *kdtree = BLI_kdtree_3d_new(initial_points_len); + + int i_point = 0; + for (const Vector<float3> &positions : positions_all) { + for (const float3 position : positions) { + BLI_kdtree_3d_insert(kdtree, i_point, position); + i_point++; + } } BLI_kdtree_3d_balance(kdtree); return kdtree; } BLI_NOINLINE static void update_elimination_mask_for_close_points( - Span<float3> positions, const float minimum_distance, MutableSpan<bool> elimination_mask) + Span<Vector<float3>> positions_all, + Span<int> instance_start_offsets, + const float minimum_distance, + MutableSpan<bool> elimination_mask, + const int initial_points_len) { if (minimum_distance <= 0.0f) { return; } - KDTree_3d *kdtree = build_kdtree(positions); + KDTree_3d *kdtree = build_kdtree(positions_all, initial_points_len); - for (const int i : positions.index_range()) { - if (elimination_mask[i]) { - continue; - } + /* The elimination mask is a flattened array for every point, + * so keep track of the index to it separately. */ + for (const int i_instance : positions_all.index_range()) { + Span<float3> positions = positions_all[i_instance]; + const int offset = instance_start_offsets[i_instance]; + + for (const int i : positions.index_range()) { + if (elimination_mask[offset + i]) { + continue; + } - struct CallbackData { - int index; - MutableSpan<bool> elimination_mask; - } callback_data = {i, elimination_mask}; - - BLI_kdtree_3d_range_search_cb( - kdtree, - positions[i], - minimum_distance, - [](void *user_data, int index, const float *UNUSED(co), float UNUSED(dist_sq)) { - CallbackData &callback_data = *static_cast<CallbackData *>(user_data); - if (index != callback_data.index) { - callback_data.elimination_mask[index] = true; - } - return true; - }, - &callback_data); + struct CallbackData { + int index; + MutableSpan<bool> elimination_mask; + } callback_data = {offset + i, elimination_mask}; + + BLI_kdtree_3d_range_search_cb( + kdtree, + positions[i], + minimum_distance, + [](void *user_data, int index, const float *UNUSED(co), float UNUSED(dist_sq)) { + CallbackData &callback_data = *static_cast<CallbackData *>(user_data); + if (index != callback_data.index) { + callback_data.elimination_mask[index] = true; + } + return true; + }, + &callback_data); + } } BLI_kdtree_3d_free(kdtree); } @@ -287,73 +309,106 @@ BLI_NOINLINE static void interpolate_attribute_corner(const Mesh &mesh, } } +template<typename T> BLI_NOINLINE static void interpolate_attribute(const Mesh &mesh, Span<float3> bary_coords, Span<int> looptri_indices, - const StringRef attribute_name, - const ReadAttribute &attribute_in, - GeometryComponent &component) + const AttributeDomain source_domain, + Span<T> source_span, + MutableSpan<T> output_span) { - const CustomDataType data_type = attribute_in.custom_data_type(); - const AttributeDomain domain = attribute_in.domain(); - if (!ELEM(domain, ATTR_DOMAIN_POINT, ATTR_DOMAIN_CORNER)) { - /* Not supported currently. */ - return; - } - - OutputAttributePtr attribute_out = component.attribute_try_get_for_output( - attribute_name, ATTR_DOMAIN_POINT, data_type); - if (!attribute_out) { - return; - } - - attribute_math::convert_to_static_type(data_type, [&](auto dummy) { - using T = decltype(dummy); - - Span data_in = attribute_in.get_span<T>(); - MutableSpan data_out = attribute_out->get_span_for_write_only<T>(); - - switch (domain) { - case ATTR_DOMAIN_POINT: { - interpolate_attribute_point<T>(mesh, bary_coords, looptri_indices, data_in, data_out); - break; - } - case ATTR_DOMAIN_CORNER: { - interpolate_attribute_corner<T>(mesh, bary_coords, looptri_indices, data_in, data_out); - break; - } - default: { - BLI_assert(false); - break; - } + switch (source_domain) { + case ATTR_DOMAIN_POINT: { + interpolate_attribute_point<T>(mesh, bary_coords, looptri_indices, source_span, output_span); + break; + } + case ATTR_DOMAIN_CORNER: { + interpolate_attribute_corner<T>( + mesh, bary_coords, looptri_indices, source_span, output_span); + break; } - }); - attribute_out.apply_span_and_save(); + default: { + /* Not supported currently. */ + return; + } + } } -BLI_NOINLINE static void interpolate_existing_attributes(const MeshComponent &mesh_component, - GeometryComponent &component, - Span<float3> bary_coords, - Span<int> looptri_indices) +BLI_NOINLINE static void interpolate_existing_attributes( + Span<GeometryInstanceGroup> set_groups, + Span<int> instance_start_offsets, + const Map<std::string, AttributeKind> &attributes, + GeometryComponent &component, + Span<Vector<float3>> bary_coords_array, + Span<Vector<int>> looptri_indices_array) { - const Mesh &mesh = *mesh_component.get_for_read(); - - Set<std::string> attribute_names = mesh_component.attribute_names(); - for (StringRefNull attribute_name : attribute_names) { - if (ELEM(attribute_name, "position", "normal", "id")) { + for (Map<std::string, AttributeKind>::Item entry : attributes.items()) { + StringRef attribute_name = entry.key; + const CustomDataType output_data_type = entry.value.data_type; + /* The output domain is always #ATTR_DOMAIN_POINT, since we are creating a point cloud. */ + OutputAttributePtr attribute_out = component.attribute_try_get_for_output( + attribute_name, ATTR_DOMAIN_POINT, output_data_type); + if (!attribute_out) { continue; } - ReadAttributePtr attribute_in = mesh_component.attribute_try_get_for_read(attribute_name); - interpolate_attribute( - mesh, bary_coords, looptri_indices, attribute_name, *attribute_in, component); + fn::GMutableSpan out_span = attribute_out->get_span_for_write_only(); + + int i_instance = 0; + for (const GeometryInstanceGroup &set_group : set_groups) { + const GeometrySet &set = set_group.geometry_set; + const MeshComponent &source_component = *set.get_component_for_read<MeshComponent>(); + const Mesh &mesh = *source_component.get_for_read(); + + /* Use a dummy read without specifying a domain or data type in order to + * get the existing attribute's domain. Interpolation is done manually based + * on the bary coords in #interpolate_attribute. */ + ReadAttributePtr dummy_attribute = source_component.attribute_try_get_for_read( + attribute_name); + if (!dummy_attribute) { + i_instance += set_group.transforms.size(); + continue; + } + + const AttributeDomain source_domain = dummy_attribute->domain(); + ReadAttributePtr source_attribute = source_component.attribute_get_for_read( + attribute_name, source_domain, output_data_type, nullptr); + if (!source_attribute) { + i_instance += set_group.transforms.size(); + continue; + } + fn::GSpan source_span = source_attribute->get_span(); + + attribute_math::convert_to_static_type(output_data_type, [&](auto dummy) { + using T = decltype(dummy); + + for (const int UNUSED(i_set_instance) : set_group.transforms.index_range()) { + const int offset = instance_start_offsets[i_instance]; + Span<float3> bary_coords = bary_coords_array[i_instance]; + Span<int> looptri_indices = looptri_indices_array[i_instance]; + + MutableSpan<T> instance_span = out_span.typed<T>().slice(offset, bary_coords.size()); + interpolate_attribute<T>(mesh, + bary_coords, + looptri_indices, + source_domain, + source_span.typed<T>(), + instance_span); + + i_instance++; + } + }); + } + + attribute_out.apply_span_and_save(); } } -BLI_NOINLINE static void compute_special_attributes(const Mesh &mesh, +BLI_NOINLINE static void compute_special_attributes(Span<GeometryInstanceGroup> sets, + Span<int> instance_start_offsets, GeometryComponent &component, - Span<float3> bary_coords, - Span<int> looptri_indices) + Span<Vector<float3>> bary_coords_array, + Span<Vector<int>> looptri_indices_array) { OutputAttributePtr id_attribute = component.attribute_try_get_for_output( "id", ATTR_DOMAIN_POINT, CD_PROP_INT32); @@ -362,26 +417,50 @@ BLI_NOINLINE static void compute_special_attributes(const Mesh &mesh, OutputAttributePtr rotation_attribute = component.attribute_try_get_for_output( "rotation", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3); - MutableSpan<int> ids = id_attribute->get_span_for_write_only<int>(); - MutableSpan<float3> normals = normal_attribute->get_span_for_write_only<float3>(); - MutableSpan<float3> rotations = rotation_attribute->get_span_for_write_only<float3>(); - - Span<MLoopTri> looptris = get_mesh_looptris(mesh); - for (const int i : bary_coords.index_range()) { - const int looptri_index = looptri_indices[i]; - const MLoopTri &looptri = looptris[looptri_index]; - const float3 &bary_coord = bary_coords[i]; - - const int v0_index = mesh.mloop[looptri.tri[0]].v; - const int v1_index = mesh.mloop[looptri.tri[1]].v; - const int v2_index = mesh.mloop[looptri.tri[2]].v; - const float3 v0_pos = mesh.mvert[v0_index].co; - const float3 v1_pos = mesh.mvert[v1_index].co; - const float3 v2_pos = mesh.mvert[v2_index].co; + MutableSpan<int> result_ids = id_attribute->get_span_for_write_only<int>(); + MutableSpan<float3> result_normals = normal_attribute->get_span_for_write_only<float3>(); + MutableSpan<float3> result_rotations = rotation_attribute->get_span_for_write_only<float3>(); + + int i_instance = 0; + for (const GeometryInstanceGroup &set_group : sets) { + const GeometrySet &set = set_group.geometry_set; + const MeshComponent &component = *set.get_component_for_read<MeshComponent>(); + const Mesh &mesh = *component.get_for_read(); + Span<MLoopTri> looptris = get_mesh_looptris(mesh); + + for (const float4x4 &transform : set_group.transforms) { + const int offset = instance_start_offsets[i_instance]; + + Span<float3> bary_coords = bary_coords_array[i_instance]; + Span<int> looptri_indices = looptri_indices_array[i_instance]; + MutableSpan<int> ids = result_ids.slice(offset, bary_coords.size()); + MutableSpan<float3> normals = result_normals.slice(offset, bary_coords.size()); + MutableSpan<float3> rotations = result_rotations.slice(offset, bary_coords.size()); + + /* Use one matrix multiplication per point instead of three (for each triangle corner). */ + float rotation_matrix[3][3]; + mat4_to_rot(rotation_matrix, transform.values); + + for (const int i : bary_coords.index_range()) { + const int looptri_index = looptri_indices[i]; + const MLoopTri &looptri = looptris[looptri_index]; + const float3 &bary_coord = bary_coords[i]; + + const int v0_index = mesh.mloop[looptri.tri[0]].v; + const int v1_index = mesh.mloop[looptri.tri[1]].v; + const int v2_index = mesh.mloop[looptri.tri[2]].v; + const float3 v0_pos = float3(mesh.mvert[v0_index].co); + const float3 v1_pos = float3(mesh.mvert[v1_index].co); + const float3 v2_pos = float3(mesh.mvert[v2_index].co); + + ids[i] = (int)(bary_coord.hash() + (uint64_t)looptri_index); + normal_tri_v3(normals[i], v0_pos, v1_pos, v2_pos); + mul_m3_v3(rotation_matrix, normals[i]); + rotations[i] = normal_to_euler_rotation(normals[i]); + } - ids[i] = (int)(bary_coord.hash() + (uint64_t)looptri_index); - normal_tri_v3(normals[i], v0_pos, v1_pos, v2_pos); - rotations[i] = normal_to_euler_rotation(normals[i]); + i_instance++; + } } id_attribute.apply_span_and_save(); @@ -389,109 +468,244 @@ BLI_NOINLINE static void compute_special_attributes(const Mesh &mesh, rotation_attribute.apply_span_and_save(); } -BLI_NOINLINE static void add_remaining_point_attributes(const MeshComponent &mesh_component, - GeometryComponent &component, - Span<float3> bary_coords, - Span<int> looptri_indices) +BLI_NOINLINE static void add_remaining_point_attributes( + Span<GeometryInstanceGroup> set_groups, + Span<int> instance_start_offsets, + const Map<std::string, AttributeKind> &attributes, + GeometryComponent &component, + Span<Vector<float3>> bary_coords_array, + Span<Vector<int>> looptri_indices_array) { - interpolate_existing_attributes(mesh_component, component, bary_coords, looptri_indices); + interpolate_existing_attributes(set_groups, + instance_start_offsets, + attributes, + component, + bary_coords_array, + looptri_indices_array); compute_special_attributes( - *mesh_component.get_for_read(), component, bary_coords, looptri_indices); + set_groups, instance_start_offsets, component, bary_coords_array, looptri_indices_array); } -static void sample_mesh_surface_with_minimum_distance(const Mesh &mesh, - const float max_density, - const float minimum_distance, - const FloatReadAttribute &density_factors, - const int seed, - Vector<float3> &r_positions, - Vector<float3> &r_bary_coords, - Vector<int> &r_looptri_indices) +static void distribute_points_random(Span<GeometryInstanceGroup> set_groups, + const StringRef density_attribute_name, + const float density, + const int seed, + MutableSpan<Vector<float3>> positions_all, + MutableSpan<Vector<float3>> bary_coords_all, + MutableSpan<Vector<int>> looptri_indices_all) { - sample_mesh_surface( - mesh, max_density, nullptr, seed, r_positions, r_bary_coords, r_looptri_indices); - Array<bool> elimination_mask(r_positions.size(), false); - update_elimination_mask_for_close_points(r_positions, minimum_distance, elimination_mask); - update_elimination_mask_based_on_density_factors( - mesh, density_factors, r_bary_coords, r_looptri_indices, elimination_mask); - eliminate_points_based_on_mask(elimination_mask, r_positions, r_bary_coords, r_looptri_indices); + /* If there is an attribute name, the default value for the densities should be zero so that + * points are only scattered where the attribute exists. Otherwise, just "ignore" the density + * factors. */ + const bool use_one_default = density_attribute_name.is_empty(); + + int i_instance = 0; + for (const GeometryInstanceGroup &set_group : set_groups) { + const GeometrySet &set = set_group.geometry_set; + const MeshComponent &component = *set.get_component_for_read<MeshComponent>(); + const FloatReadAttribute density_factors = component.attribute_get_for_read<float>( + density_attribute_name, ATTR_DOMAIN_CORNER, use_one_default ? 1.0f : 0.0f); + const Mesh &mesh = *component.get_for_read(); + for (const float4x4 &transform : set_group.transforms) { + Vector<float3> &positions = positions_all[i_instance]; + Vector<float3> &bary_coords = bary_coords_all[i_instance]; + Vector<int> &looptri_indices = looptri_indices_all[i_instance]; + sample_mesh_surface(mesh, + transform, + density, + &density_factors, + seed, + positions, + bary_coords, + looptri_indices); + i_instance++; + } + } +} + +static void distribute_points_poisson_disk(Span<GeometryInstanceGroup> set_groups, + const StringRef density_attribute_name, + const float density, + const int seed, + const float minimum_distance, + MutableSpan<Vector<float3>> positions_all, + MutableSpan<Vector<float3>> bary_coords_all, + MutableSpan<Vector<int>> looptri_indices_all) +{ + Array<int> instance_start_offsets(positions_all.size()); + int initial_points_len = 0; + int i_instance = 0; + for (const GeometryInstanceGroup &set_group : set_groups) { + const GeometrySet &set = set_group.geometry_set; + const MeshComponent &component = *set.get_component_for_read<MeshComponent>(); + const Mesh &mesh = *component.get_for_read(); + for (const float4x4 &transform : set_group.transforms) { + Vector<float3> &positions = positions_all[i_instance]; + Vector<float3> &bary_coords = bary_coords_all[i_instance]; + Vector<int> &looptri_indices = looptri_indices_all[i_instance]; + sample_mesh_surface( + mesh, transform, density, nullptr, seed, positions, bary_coords, looptri_indices); + + instance_start_offsets[i_instance] = initial_points_len; + initial_points_len += positions.size(); + i_instance++; + } + } + + /* If there is an attribute name, the default value for the densities should be zero so that + * points are only scattered where the attribute exists. Otherwise, just "ignore" the density + * factors. */ + const bool use_one_default = density_attribute_name.is_empty(); + + /* Unlike the other result arrays, the elimination mask in stored as a flat array for every + * point, in order to simplify culling points from the KDTree (which needs to know about all + * points at once). */ + Array<bool> elimination_mask(initial_points_len, false); + update_elimination_mask_for_close_points(positions_all, + instance_start_offsets, + minimum_distance, + elimination_mask, + initial_points_len); + + i_instance = 0; + for (const GeometryInstanceGroup &set_group : set_groups) { + const GeometrySet &set = set_group.geometry_set; + const MeshComponent &component = *set.get_component_for_read<MeshComponent>(); + const Mesh &mesh = *component.get_for_read(); + const FloatReadAttribute density_factors = component.attribute_get_for_read<float>( + density_attribute_name, ATTR_DOMAIN_CORNER, use_one_default ? 1.0f : 0.0f); + + for (const int UNUSED(i_set_instance) : set_group.transforms.index_range()) { + Vector<float3> &positions = positions_all[i_instance]; + Vector<float3> &bary_coords = bary_coords_all[i_instance]; + Vector<int> &looptri_indices = looptri_indices_all[i_instance]; + + const int offset = instance_start_offsets[i_instance]; + update_elimination_mask_based_on_density_factors( + mesh, + density_factors, + bary_coords, + looptri_indices, + elimination_mask.as_mutable_span().slice(offset, positions.size())); + + eliminate_points_based_on_mask(elimination_mask.as_span().slice(offset, positions.size()), + positions, + bary_coords, + looptri_indices); + + i_instance++; + } + } } static void geo_node_point_distribute_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); - GeometrySet geometry_set_out; - /* TODO: This node only needs read-only access to input instances. */ - geometry_set = geometry_set_realize_instances(geometry_set); + const GeometryNodePointDistributeMode distribute_method = + static_cast<GeometryNodePointDistributeMode>(params.node().custom1); - GeometryNodePointDistributeMode distribute_method = static_cast<GeometryNodePointDistributeMode>( - params.node().custom1); + const int seed = params.get_input<int>("Seed"); + const float density = params.extract_input<float>("Density Max"); + const std::string density_attribute_name = params.extract_input<std::string>( + "Density Attribute"); - if (!geometry_set.has_mesh()) { - params.error_message_add(NodeWarningType::Error, TIP_("Geometry must contain a mesh")); - params.set_output("Geometry", std::move(geometry_set_out)); + if (density <= 0.0f) { + params.set_output("Geometry", GeometrySet()); return; } - const float density = params.extract_input<float>("Density Max"); - const std::string density_attribute = params.extract_input<std::string>("Density Attribute"); - - if (density <= 0.0f) { - params.set_output("Geometry", std::move(geometry_set_out)); + Vector<GeometryInstanceGroup> set_groups = bke::geometry_set_gather_instances(geometry_set); + if (set_groups.is_empty()) { + params.set_output("Geometry", GeometrySet()); return; } - const MeshComponent &mesh_component = *geometry_set.get_component_for_read<MeshComponent>(); - const Mesh *mesh_in = mesh_component.get_for_read(); + /* Remove any set inputs that don't contain a mesh, to avoid checking later on. */ + for (int i = set_groups.size() - 1; i >= 0; i--) { + const GeometrySet &set = set_groups[i].geometry_set; + if (!set.has_mesh()) { + set_groups.remove_and_reorder(i); + } + } - if (mesh_in->mpoly == nullptr) { - params.error_message_add(NodeWarningType::Error, TIP_("Mesh has no faces")); - params.set_output("Geometry", std::move(geometry_set_out)); + if (set_groups.is_empty()) { + params.error_message_add(NodeWarningType::Error, TIP_("Input geometry must contain a mesh")); + params.set_output("Geometry", GeometrySet()); return; } - const FloatReadAttribute density_factors = mesh_component.attribute_get_for_read<float>( - density_attribute, ATTR_DOMAIN_CORNER, 1.0f); - const int seed = params.get_input<int>("Seed"); + int instances_len = 0; + for (GeometryInstanceGroup &set_group : set_groups) { + instances_len += set_group.transforms.size(); + } + + /* Store data per-instance in order to simplify attribute access after the scattering, + * and to make the point elimination simpler for the poisson disk mode. Note that some + * vectors will be empty if any instances don't contain mesh data. */ + Array<Vector<float3>> positions_all(instances_len); + Array<Vector<float3>> bary_coords_all(instances_len); + Array<Vector<int>> looptri_indices_all(instances_len); - Vector<float3> positions; - Vector<float3> bary_coords; - Vector<int> looptri_indices; switch (distribute_method) { - case GEO_NODE_POINT_DISTRIBUTE_RANDOM: - sample_mesh_surface( - *mesh_in, density, &density_factors, seed, positions, bary_coords, looptri_indices); + case GEO_NODE_POINT_DISTRIBUTE_RANDOM: { + distribute_points_random(set_groups, + density_attribute_name, + density, + seed, + positions_all, + bary_coords_all, + looptri_indices_all); break; - case GEO_NODE_POINT_DISTRIBUTE_POISSON: + } + case GEO_NODE_POINT_DISTRIBUTE_POISSON: { const float minimum_distance = params.extract_input<float>("Distance Min"); - sample_mesh_surface_with_minimum_distance(*mesh_in, - density, - minimum_distance, - density_factors, - seed, - positions, - bary_coords, - looptri_indices); + distribute_points_poisson_disk(set_groups, + density_attribute_name, + density, + seed, + minimum_distance, + positions_all, + bary_coords_all, + looptri_indices_all); break; + } } - const int tot_points = positions.size(); - PointCloud *pointcloud = BKE_pointcloud_new_nomain(tot_points); - memcpy(pointcloud->co, positions.data(), sizeof(float3) * tot_points); - for (const int i : positions.index_range()) { - *(float3 *)(pointcloud->co + i) = positions[i]; - pointcloud->radius[i] = 0.05f; + int final_points_len = 0; + Array<int> instance_start_offsets(set_groups.size()); + for (const int i : positions_all.index_range()) { + Vector<float3> &positions = positions_all[i]; + instance_start_offsets[i] = final_points_len; + final_points_len += positions.size(); } + PointCloud *pointcloud = BKE_pointcloud_new_nomain(final_points_len); + for (const int instance_index : positions_all.index_range()) { + const int offset = instance_start_offsets[instance_index]; + Span<float3> positions = positions_all[instance_index]; + memcpy(pointcloud->co + offset, positions.data(), sizeof(float3) * positions.size()); + } + + uninitialized_fill_n(pointcloud->radius, pointcloud->totpoint, 0.05f); + + GeometrySet geometry_set_out = GeometrySet::create_with_pointcloud(pointcloud); PointCloudComponent &point_component = geometry_set_out.get_component_for_write<PointCloudComponent>(); - point_component.replace(pointcloud); - add_remaining_point_attributes(mesh_component, point_component, bary_coords, looptri_indices); + Map<std::string, AttributeKind> attributes; + bke::gather_attribute_info( + attributes, {GeometryComponentType::Mesh}, set_groups, {"position", "normal", "id"}); + add_remaining_point_attributes(set_groups, + instance_start_offsets, + attributes, + point_component, + bary_coords_all, + looptri_indices_all); params.set_output("Geometry", std::move(geometry_set_out)); } + } // namespace blender::nodes void register_node_type_geo_point_distribute() diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc b/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc index cb3cd012c77..015f4cd38e7 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_translate.cc @@ -46,6 +46,9 @@ static void execute_on_component(GeoNodeExecParams params, GeometryComponent &co { OutputAttributePtr position_attribute = component.attribute_try_get_for_output( "position", ATTR_DOMAIN_POINT, CD_PROP_FLOAT3); + if (!position_attribute) { + return; + } ReadAttributePtr attribute = params.get_input_attribute( "Translation", component, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3, nullptr); if (!attribute) { diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface_simple.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivide.cc index 38560d277e3..b5731851229 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface_simple.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_subdivide.cc @@ -25,20 +25,20 @@ #include "node_geometry_util.hh" -static bNodeSocketTemplate geo_node_subdivision_surface_simple_in[] = { +static bNodeSocketTemplate geo_node_subdivide_in[] = { {SOCK_GEOMETRY, N_("Geometry")}, {SOCK_INT, N_("Level"), 1, 0, 0, 0, 0, 6}, {-1, ""}, }; -static bNodeSocketTemplate geo_node_subdivision_surface_simple_out[] = { +static bNodeSocketTemplate geo_node_subdivide_out[] = { {SOCK_GEOMETRY, N_("Geometry")}, {-1, ""}, }; namespace blender::nodes { -static void geo_node_subdivision_surface_simple_exec(GeoNodeExecParams params) +static void geo_node_subdivide_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -99,17 +99,12 @@ static void geo_node_subdivision_surface_simple_exec(GeoNodeExecParams params) } } // namespace blender::nodes -void register_node_type_geo_subdivision_surface_simple() +void register_node_type_geo_subdivide() { static bNodeType ntype; - geo_node_type_base(&ntype, - GEO_NODE_SUBDIVISION_SURFACE_SIMPLE, - "Simple Subdivision Surface", - NODE_CLASS_GEOMETRY, - 0); - node_type_socket_templates( - &ntype, geo_node_subdivision_surface_simple_in, geo_node_subdivision_surface_simple_out); - ntype.geometry_node_execute = blender::nodes::geo_node_subdivision_surface_simple_exec; + geo_node_type_base(&ntype, GEO_NODE_SUBDIVIDE, "Subdivide", NODE_CLASS_GEOMETRY, 0); + node_type_socket_templates(&ntype, geo_node_subdivide_in, geo_node_subdivide_out); + ntype.geometry_node_execute = blender::nodes::geo_node_subdivide_exec; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc b/source/blender/nodes/geometry/nodes/node_geo_subdivide_smooth.cc index 47304a0de68..4d9b8110d65 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_subdivision_surface.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_subdivide_smooth.cc @@ -25,7 +25,7 @@ #include "node_geometry_util.hh" -static bNodeSocketTemplate geo_node_subdivision_surface_in[] = { +static bNodeSocketTemplate geo_node_subdivide_smooth_in[] = { {SOCK_GEOMETRY, N_("Geometry")}, {SOCK_INT, N_("Level"), 1, 0, 0, 0, 0, 6}, {SOCK_BOOLEAN, N_("Use Creases")}, @@ -34,14 +34,14 @@ static bNodeSocketTemplate geo_node_subdivision_surface_in[] = { {-1, ""}, }; -static bNodeSocketTemplate geo_node_subdivision_surface_out[] = { +static bNodeSocketTemplate geo_node_subdivide_smooth_out[] = { {SOCK_GEOMETRY, N_("Geometry")}, {-1, ""}, }; -static void geo_node_subdivision_surface_layout(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *UNUSED(ptr)) +static void geo_node_subdivide_smooth_layout(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *UNUSED(ptr)) { #ifndef WITH_OPENSUBDIV uiItemL(layout, IFACE_("Disabled, built without OpenSubdiv"), ICON_ERROR); @@ -51,7 +51,7 @@ static void geo_node_subdivision_surface_layout(uiLayout *layout, } namespace blender::nodes { -static void geo_node_subdivision_surface_exec(GeoNodeExecParams params) +static void geo_node_subdivide_smooth_exec(GeoNodeExecParams params) { GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry"); @@ -120,15 +120,14 @@ static void geo_node_subdivision_surface_exec(GeoNodeExecParams params) } } // namespace blender::nodes -void register_node_type_geo_subdivision_surface() +void register_node_type_geo_subdivide_smooth() { static bNodeType ntype; geo_node_type_base( - &ntype, GEO_NODE_SUBDIVISION_SURFACE, "Subdivision Surface", NODE_CLASS_GEOMETRY, 0); - node_type_socket_templates( - &ntype, geo_node_subdivision_surface_in, geo_node_subdivision_surface_out); - ntype.geometry_node_execute = blender::nodes::geo_node_subdivision_surface_exec; - ntype.draw_buttons = geo_node_subdivision_surface_layout; + &ntype, GEO_NODE_SUBDIVIDE_SMOOTH, "Subdivide Smooth", NODE_CLASS_GEOMETRY, 0); + node_type_socket_templates(&ntype, geo_node_subdivide_smooth_in, geo_node_subdivide_smooth_out); + ntype.geometry_node_execute = blender::nodes::geo_node_subdivide_smooth_exec; + ntype.draw_buttons = geo_node_subdivide_smooth_layout; nodeRegisterType(&ntype); } diff --git a/source/blender/nodes/intern/derived_node_tree.cc b/source/blender/nodes/intern/derived_node_tree.cc index a65641bca2a..36c64b00f47 100644 --- a/source/blender/nodes/intern/derived_node_tree.cc +++ b/source/blender/nodes/intern/derived_node_tree.cc @@ -16,518 +16,261 @@ #include "NOD_derived_node_tree.hh" -#include "BLI_dot_export.hh" - -#define UNINITIALIZED_ID UINT32_MAX - namespace blender::nodes { -DerivedNodeTree::DerivedNodeTree(bNodeTree *btree, NodeTreeRefMap &node_tree_refs) : btree_(btree) +/* Construct a new derived node tree for a given root node tree. The generated derived node tree + * does not own the used node tree refs (so that those can be used by others as well). The caller + * has to make sure that the node tree refs added to #node_tree_refs live at least as long as the + * derived node tree. */ +DerivedNodeTree::DerivedNodeTree(bNodeTree &btree, NodeTreeRefMap &node_tree_refs) { - BLI_assert(btree != nullptr); - - const NodeTreeRef &main_tree_ref = get_tree_ref_from_map(node_tree_refs, *btree); - used_node_tree_refs_.add_new(&main_tree_ref); - - Vector<DNode *> all_nodes; - Vector<DGroupInput *> all_group_inputs; - Vector<DParentNode *> all_parent_nodes; - - this->insert_nodes_and_links_in_id_order(main_tree_ref, nullptr, all_nodes); - this->expand_groups(all_nodes, all_group_inputs, all_parent_nodes, node_tree_refs); - this->relink_and_remove_muted_nodes(all_nodes); - this->remove_expanded_group_interfaces(all_nodes); - this->remove_unused_group_inputs(all_group_inputs); - this->store_in_this_and_init_ids( - std::move(all_nodes), std::move(all_group_inputs), std::move(all_parent_nodes)); + /* Construct all possible contexts immediately. This is significantly cheaper than inlining all + * node groups. If it still becomes a performance issue in the future, contexts could be + * constructed lazily when they are needed. */ + root_context_ = &this->construct_context_recursively(nullptr, nullptr, btree, node_tree_refs); } -BLI_NOINLINE void DerivedNodeTree::insert_nodes_and_links_in_id_order(const NodeTreeRef &tree_ref, - DParentNode *parent, - Vector<DNode *> &all_nodes) +DTreeContext &DerivedNodeTree::construct_context_recursively(DTreeContext *parent_context, + const NodeRef *parent_node, + bNodeTree &btree, + NodeTreeRefMap &node_tree_refs) { - Array<DSocket *, 64> sockets_map(tree_ref.sockets().size()); - - /* Insert nodes. */ - for (const NodeRef *node_ref : tree_ref.nodes()) { - DNode &node = this->create_node(*node_ref, parent, sockets_map); - all_nodes.append(&node); - } - - /* Insert links. */ - for (const NodeRef *node_ref : tree_ref.nodes()) { - for (const InputSocketRef *to_socket_ref : node_ref->inputs()) { - DInputSocket *to_socket = static_cast<DInputSocket *>(sockets_map[to_socket_ref->id()]); - for (const OutputSocketRef *from_socket_ref : to_socket_ref->linked_sockets()) { - DOutputSocket *from_socket = static_cast<DOutputSocket *>( - sockets_map[from_socket_ref->id()]); - to_socket->linked_sockets_.append(from_socket); - from_socket->linked_sockets_.append(to_socket); + DTreeContext &context = *allocator_.construct<DTreeContext>().release(); + context.parent_context_ = parent_context; + context.parent_node_ = parent_node; + context.tree_ = &get_tree_ref_from_map(node_tree_refs, btree); + used_node_tree_refs_.add(context.tree_); + + for (const NodeRef *node : context.tree_->nodes()) { + if (node->is_group_node()) { + bNode *bnode = node->bnode(); + bNodeTree *child_btree = reinterpret_cast<bNodeTree *>(bnode->id); + if (child_btree != nullptr) { + DTreeContext &child = this->construct_context_recursively( + &context, node, *child_btree, node_tree_refs); + context.children_.add_new(node, &child); } } } + + return context; } -DNode &DerivedNodeTree::create_node(const NodeRef &node_ref, - DParentNode *parent, - MutableSpan<DSocket *> r_sockets_map) +DerivedNodeTree::~DerivedNodeTree() { - DNode &node = *allocator_.construct<DNode>(); - node.node_ref_ = &node_ref; - node.parent_ = parent; - node.id_ = UNINITIALIZED_ID; - - node.inputs_ = allocator_.construct_elements_and_pointer_array<DInputSocket>( - node_ref.inputs().size()); - node.outputs_ = allocator_.construct_elements_and_pointer_array<DOutputSocket>( - node_ref.outputs().size()); - - for (int i : node.inputs_.index_range()) { - const InputSocketRef &socket_ref = node_ref.input(i); - DInputSocket &socket = *node.inputs_[i]; - socket.is_multi_input_socket_ = socket_ref.bsocket()->flag & SOCK_MULTI_INPUT; - socket.id_ = UNINITIALIZED_ID; - socket.node_ = &node; - socket.socket_ref_ = &socket_ref; - - r_sockets_map[socket_ref.id()] = &socket; - } - - for (int i : node.outputs_.index_range()) { - const OutputSocketRef &socket_ref = node_ref.output(i); - DOutputSocket &socket = *node.outputs_[i]; - - socket.id_ = UNINITIALIZED_ID; - socket.node_ = &node; - socket.socket_ref_ = &socket_ref; - - r_sockets_map[socket_ref.id()] = &socket; - } - - return node; + /* Has to be destructed manually, because the context info is allocated in a linear allocator. */ + this->destruct_context_recursively(root_context_); } -BLI_NOINLINE void DerivedNodeTree::expand_groups(Vector<DNode *> &all_nodes, - Vector<DGroupInput *> &all_group_inputs, - Vector<DParentNode *> &all_parent_nodes, - NodeTreeRefMap &node_tree_refs) +void DerivedNodeTree::destruct_context_recursively(DTreeContext *context) { - for (int i = 0; i < all_nodes.size(); i++) { - DNode &node = *all_nodes[i]; - if (node.node_ref_->is_group_node()) { - /* Muted nodes are relinked in a separate step. */ - if (!node.node_ref_->is_muted()) { - this->expand_group_node( - node, all_nodes, all_group_inputs, all_parent_nodes, node_tree_refs); - } - } + for (DTreeContext *child : context->children_.values()) { + this->destruct_context_recursively(child); } + context->~DTreeContext(); } -BLI_NOINLINE void DerivedNodeTree::expand_group_node(DNode &group_node, - Vector<DNode *> &all_nodes, - Vector<DGroupInput *> &all_group_inputs, - Vector<DParentNode *> &all_parent_nodes, - NodeTreeRefMap &node_tree_refs) +/* Returns true if there are any cycles in the node tree. */ +bool DerivedNodeTree::has_link_cycles() const { - const NodeRef &group_node_ref = *group_node.node_ref_; - BLI_assert(group_node_ref.is_group_node()); - - bNodeTree *btree = reinterpret_cast<bNodeTree *>(group_node_ref.bnode()->id); - if (btree == nullptr) { - return; + for (const NodeTreeRef *tree_ref : used_node_tree_refs_) { + if (tree_ref->has_link_cycles()) { + return true; + } } - - const NodeTreeRef &group_ref = get_tree_ref_from_map(node_tree_refs, *btree); - used_node_tree_refs_.add(&group_ref); - - DParentNode &parent = *allocator_.construct<DParentNode>(); - parent.id_ = all_parent_nodes.append_and_get_index(&parent); - parent.parent_ = group_node.parent_; - parent.node_ref_ = &group_node_ref; - - this->insert_nodes_and_links_in_id_order(group_ref, &parent, all_nodes); - Span<DNode *> new_nodes_by_id = all_nodes.as_span().take_back(group_ref.nodes().size()); - - this->create_group_inputs_for_unlinked_inputs(group_node, all_group_inputs); - this->relink_group_inputs(group_ref, new_nodes_by_id, group_node); - this->relink_group_outputs(group_ref, new_nodes_by_id, group_node); + return false; } -BLI_NOINLINE void DerivedNodeTree::create_group_inputs_for_unlinked_inputs( - DNode &node, Vector<DGroupInput *> &all_group_inputs) +/* Calls the given callback on all nodes in the (possibly nested) derived node tree. */ +void DerivedNodeTree::foreach_node(FunctionRef<void(DNode)> callback) const { - for (DInputSocket *input_socket : node.inputs_) { - if (input_socket->is_linked()) { - continue; - } - - DGroupInput &group_input = *allocator_.construct<DGroupInput>(); - group_input.id_ = UNINITIALIZED_ID; - group_input.socket_ref_ = &input_socket->socket_ref(); - group_input.parent_ = node.parent_; - - group_input.linked_sockets_.append(input_socket); - input_socket->linked_group_inputs_.append(&group_input); - all_group_inputs.append(&group_input); - } + this->foreach_node_in_context_recursive(*root_context_, callback); } -BLI_NOINLINE void DerivedNodeTree::relink_group_inputs(const NodeTreeRef &group_ref, - Span<DNode *> nodes_by_id, - DNode &group_node) +void DerivedNodeTree::foreach_node_in_context_recursive(const DTreeContext &context, + FunctionRef<void(DNode)> callback) const { - Span<const NodeRef *> node_refs = group_ref.nodes_by_type("NodeGroupInput"); - if (node_refs.size() == 0) { - return; + for (const NodeRef *node_ref : context.tree_->nodes()) { + callback(DNode(&context, node_ref)); } - - int input_amount = group_node.inputs().size(); - - for (int input_index : IndexRange(input_amount)) { - DInputSocket *outside_group = group_node.inputs_[input_index]; - - for (DOutputSocket *outside_connected : outside_group->linked_sockets_) { - outside_connected->linked_sockets_.remove_first_occurrence_and_reorder(outside_group); - } - - for (DGroupInput *outside_connected : outside_group->linked_group_inputs_) { - outside_connected->linked_sockets_.remove_first_occurrence_and_reorder(outside_group); - } - - for (const NodeRef *input_node_ref : node_refs) { - DNode &input_node = *nodes_by_id[input_node_ref->id()]; - DOutputSocket *inside_group = input_node.outputs_[input_index]; - - for (DInputSocket *inside_connected : inside_group->linked_sockets_) { - inside_connected->linked_sockets_.remove_first_occurrence_and_reorder(inside_group); - - for (DOutputSocket *outside_connected : outside_group->linked_sockets_) { - inside_connected->linked_sockets_.append(outside_connected); - outside_connected->linked_sockets_.append(inside_connected); - } - - for (DGroupInput *outside_connected : outside_group->linked_group_inputs_) { - inside_connected->linked_group_inputs_.append(outside_connected); - outside_connected->linked_sockets_.append(inside_connected); - } - } - - inside_group->linked_sockets_.clear(); - } - - outside_group->linked_sockets_.clear(); - outside_group->linked_group_inputs_.clear(); + for (const DTreeContext *child_context : context.children_.values()) { + this->foreach_node_in_context_recursive(*child_context, callback); } } -BLI_NOINLINE void DerivedNodeTree::relink_group_outputs(const NodeTreeRef &group_ref, - Span<DNode *> nodes_by_id, - DNode &group_node) +DOutputSocket DInputSocket::get_corresponding_group_node_output() const { - Span<const NodeRef *> node_refs = group_ref.nodes_by_type("NodeGroupOutput"); - if (node_refs.size() == 0) { - return; - } - /* TODO: Pick correct group output node if there are more than one. */ - const NodeRef &output_node_ref = *node_refs[0]; - DNode &output_node = *nodes_by_id[output_node_ref.id()]; + BLI_assert(*this); + BLI_assert(socket_ref_->node().is_group_output_node()); + BLI_assert(socket_ref_->index() < socket_ref_->node().inputs().size() - 1); - int output_amount = group_node.outputs().size(); - BLI_assert(output_amount == output_node_ref.inputs().size() - 1); + const DTreeContext *parent_context = context_->parent_context(); + const NodeRef *parent_node = context_->parent_node(); + BLI_assert(parent_context != nullptr); + BLI_assert(parent_node != nullptr); - for (int output_index : IndexRange(output_amount)) { - DOutputSocket *outside_group = group_node.outputs_[output_index]; - DInputSocket *inside_group = output_node.inputs_[output_index]; - - for (DInputSocket *outside_connected : outside_group->linked_sockets_) { - outside_connected->linked_sockets_.remove_first_occurrence_and_reorder(outside_group); - } - - for (DOutputSocket *inside_connected : inside_group->linked_sockets_) { - inside_connected->linked_sockets_.remove_first_occurrence_and_reorder(inside_group); - - for (DInputSocket *outside_connected : outside_group->linked_sockets_) { - inside_connected->linked_sockets_.append(outside_connected); - outside_connected->linked_sockets_.append(inside_connected); - } - } - - for (DGroupInput *inside_connected : inside_group->linked_group_inputs_) { - inside_connected->linked_sockets_.remove_first_occurrence_and_reorder(inside_group); - - for (DInputSocket *outside_connected : outside_group->linked_sockets_) { - inside_connected->linked_sockets_.append(outside_connected); - outside_connected->linked_group_inputs_.append(inside_connected); - } - } - - outside_group->linked_sockets_.clear(); - inside_group->linked_sockets_.clear(); - } + const int socket_index = socket_ref_->index(); + return {parent_context, &parent_node->output(socket_index)}; } -BLI_NOINLINE void DerivedNodeTree::remove_expanded_group_interfaces(Vector<DNode *> &all_nodes) +Vector<DOutputSocket> DInputSocket::get_corresponding_group_input_sockets() const { - int index = 0; - while (index < all_nodes.size()) { - DNode &node = *all_nodes[index]; - const NodeRef &node_ref = *node.node_ref_; - if (node_ref.is_group_node() || - (node.parent_ != nullptr && - (node_ref.is_group_input_node() || node_ref.is_group_output_node()))) { - all_nodes.remove_and_reorder(index); - node.destruct_with_sockets(); - } - else { - index++; - } + BLI_assert(*this); + BLI_assert(socket_ref_->node().is_group_node()); + + const DTreeContext *child_context = context_->child_context(socket_ref_->node()); + BLI_assert(child_context != nullptr); + + const NodeTreeRef &child_tree = child_context->tree(); + Span<const NodeRef *> group_input_nodes = child_tree.nodes_by_type("NodeGroupInput"); + const int socket_index = socket_ref_->index(); + Vector<DOutputSocket> sockets; + for (const NodeRef *group_input_node : group_input_nodes) { + sockets.append(DOutputSocket(child_context, &group_input_node->output(socket_index))); } + return sockets; } -BLI_NOINLINE void DerivedNodeTree::remove_unused_group_inputs( - Vector<DGroupInput *> &all_group_inputs) +DInputSocket DOutputSocket::get_corresponding_group_node_input() const { - int index = 0; - while (index < all_group_inputs.size()) { - DGroupInput &group_input = *all_group_inputs[index]; - if (group_input.linked_sockets_.is_empty()) { - all_group_inputs.remove_and_reorder(index); - group_input.~DGroupInput(); - } - else { - index++; - } - } + BLI_assert(*this); + BLI_assert(socket_ref_->node().is_group_input_node()); + BLI_assert(socket_ref_->index() < socket_ref_->node().outputs().size() - 1); + + const DTreeContext *parent_context = context_->parent_context(); + const NodeRef *parent_node = context_->parent_node(); + BLI_assert(parent_context != nullptr); + BLI_assert(parent_node != nullptr); + + const int socket_index = socket_ref_->index(); + return {parent_context, &parent_node->input(socket_index)}; } -BLI_NOINLINE void DerivedNodeTree::relink_and_remove_muted_nodes(Vector<DNode *> &all_nodes) +DInputSocket DOutputSocket::get_active_corresponding_group_output_socket() const { - int index = 0; - while (index < all_nodes.size()) { - DNode &node = *all_nodes[index]; - const NodeRef &node_ref = *node.node_ref_; - if (node_ref.is_muted()) { - this->relink_muted_node(node); - all_nodes.remove_and_reorder(index); - node.destruct_with_sockets(); - } - else { - index++; + BLI_assert(*this); + BLI_assert(socket_ref_->node().is_group_node()); + + const DTreeContext *child_context = context_->child_context(socket_ref_->node()); + BLI_assert(child_context != nullptr); + + const NodeTreeRef &child_tree = child_context->tree(); + Span<const NodeRef *> group_output_nodes = child_tree.nodes_by_type("NodeGroupOutput"); + const int socket_index = socket_ref_->index(); + for (const NodeRef *group_output_node : group_output_nodes) { + if (group_output_node->bnode()->flag & NODE_DO_OUTPUT || group_output_nodes.size() == 1) { + return {child_context, &group_output_node->input(socket_index)}; } } + return {}; } -BLI_NOINLINE void DerivedNodeTree::relink_muted_node(DNode &node) +/* Call the given callback for every "real" origin socket. "Real" means that reroutes, muted nodes + * and node groups are handled by this function. Origin sockets are ones where a node gets its + * inputs from. */ +void DInputSocket::foreach_origin_socket(FunctionRef<void(DSocket)> callback, + const bool follow_only_first_incoming_link) const { - const bNode &bnode = *node.bnode(); - LISTBASE_FOREACH (const bNodeLink *, internal_link, &bnode.internal_links) { - BLI_assert(internal_link->fromnode == &bnode); - BLI_assert(internal_link->tonode == &bnode); - bNodeSocket *input_bsocket = internal_link->fromsock; - bNodeSocket *output_bsocket = internal_link->tosock; - - /* Find internally linked sockets. */ - DInputSocket *input_socket = nullptr; - DOutputSocket *output_socket = nullptr; - for (DInputSocket *socket : node.inputs_) { - if (socket->bsocket() == input_bsocket) { - input_socket = socket; - break; - } - } - for (DOutputSocket *socket : node.outputs_) { - if (socket->bsocket() == output_bsocket) { - output_socket = socket; - break; + BLI_assert(*this); + Span<const OutputSocketRef *> linked_sockets_to_check = socket_ref_->as_input().linked_sockets(); + if (follow_only_first_incoming_link) { + linked_sockets_to_check = linked_sockets_to_check.take_front(1); + } + for (const OutputSocketRef *linked_socket : linked_sockets_to_check) { + const NodeRef &linked_node = linked_socket->node(); + DOutputSocket linked_dsocket{context_, linked_socket}; + + if (linked_node.is_muted()) { + /* If the node is muted, follow the internal links of the node. */ + for (const InternalLinkRef *internal_link : linked_node.internal_links()) { + if (&internal_link->to() == linked_socket) { + DInputSocket input_of_muted_node{context_, &internal_link->from()}; + input_of_muted_node.foreach_origin_socket(callback, true); + } } } - BLI_assert(input_socket != nullptr); - BLI_assert(output_socket != nullptr); - - /* Link sockets connected to the input to sockets that are connected to the internally linked - * output. */ - for (DInputSocket *to_socket : output_socket->linked_sockets_) { - for (DOutputSocket *from_socket : input_socket->linked_sockets_) { - from_socket->linked_sockets_.append_non_duplicates(to_socket); - to_socket->linked_sockets_.append_non_duplicates(from_socket); + else if (linked_node.is_group_input_node()) { + if (context_->is_root()) { + /* This is a group input in the root node group. */ + callback(linked_dsocket); } - for (DGroupInput *group_input : input_socket->linked_group_inputs_) { - group_input->linked_sockets_.append_non_duplicates(to_socket); - to_socket->linked_group_inputs_.append_non_duplicates(group_input); + else { + DInputSocket socket_in_parent_group = linked_dsocket.get_corresponding_group_node_input(); + if (socket_in_parent_group->is_linked()) { + /* Follow the links coming into the corresponding socket on the parent group node. */ + socket_in_parent_group.foreach_origin_socket(callback); + } + else { + /* The corresponding input on the parent group node is not connected. Therefore, we use + * the value of that input socket directly. */ + callback(socket_in_parent_group); + } } } - } - - /* Remove remaining links from muted node. */ - for (DInputSocket *to_socket : node.inputs_) { - for (DOutputSocket *from_socket : to_socket->linked_sockets_) { - from_socket->linked_sockets_.remove_first_occurrence_and_reorder(to_socket); - } - for (DGroupInput *from_group_input : to_socket->linked_group_inputs_) { - from_group_input->linked_sockets_.remove_first_occurrence_and_reorder(to_socket); - } - to_socket->linked_sockets_.clear(); - to_socket->linked_group_inputs_.clear(); - } - for (DOutputSocket *from_socket : node.outputs_) { - for (DInputSocket *to_socket : from_socket->linked_sockets_) { - to_socket->linked_sockets_.remove_first_occurrence_and_reorder(from_socket); - } - from_socket->linked_sockets_.clear(); - } -} - -void DNode::destruct_with_sockets() -{ - for (DInputSocket *socket : inputs_) { - socket->~DInputSocket(); - } - for (DOutputSocket *socket : outputs_) { - socket->~DOutputSocket(); - } - this->~DNode(); -} - -BLI_NOINLINE void DerivedNodeTree::store_in_this_and_init_ids( - Vector<DNode *> &&all_nodes, - Vector<DGroupInput *> &&all_group_inputs, - Vector<DParentNode *> &&all_parent_nodes) -{ - nodes_by_id_ = std::move(all_nodes); - group_inputs_ = std::move(all_group_inputs); - parent_nodes_ = std::move(all_parent_nodes); - - for (int node_index : nodes_by_id_.index_range()) { - DNode *node = nodes_by_id_[node_index]; - node->id_ = node_index; - - const bNodeType *nodetype = node->node_ref_->bnode()->typeinfo; - nodes_by_type_.add(nodetype, node); - - for (DInputSocket *socket : node->inputs_) { - socket->id_ = sockets_by_id_.append_and_get_index(socket); - input_sockets_.append(socket); - } - for (DOutputSocket *socket : node->outputs_) { - socket->id_ = sockets_by_id_.append_and_get_index(socket); - output_sockets_.append(socket); + else if (linked_node.is_group_node()) { + DInputSocket socket_in_group = linked_dsocket.get_active_corresponding_group_output_socket(); + if (socket_in_group) { + if (socket_in_group->is_linked()) { + /* Follow the links coming into the group output node of the child node group. */ + socket_in_group.foreach_origin_socket(callback); + } + else { + /* The output of the child node group is not connected, so we have to get the value from + * that socket. */ + callback(socket_in_group); + } + } } - } - - for (int i : group_inputs_.index_range()) { - group_inputs_[i]->id_ = i; - } -} - -DerivedNodeTree::~DerivedNodeTree() -{ - for (DInputSocket *socket : input_sockets_) { - socket->~DInputSocket(); - } - for (DOutputSocket *socket : output_sockets_) { - socket->~DOutputSocket(); - } - for (DNode *node : nodes_by_id_) { - node->~DNode(); - } - for (DGroupInput *group_input : group_inputs_) { - group_input->~DGroupInput(); - } - for (DParentNode *parent : parent_nodes_) { - parent->~DParentNode(); - } -} - -bool DerivedNodeTree::has_link_cycles() const -{ - for (const NodeTreeRef *tree : used_node_tree_refs_) { - if (tree->has_link_cycles()) { - return true; + else { + /* The normal case: just use the value of a linked output socket. */ + callback(linked_dsocket); } } - return false; -} - -static dot::Cluster *get_cluster_for_parent(dot::DirectedGraph &graph, - Map<const DParentNode *, dot::Cluster *> &clusters, - const DParentNode *parent) -{ - if (parent == nullptr) { - return nullptr; - } - return clusters.lookup_or_add_cb(parent, [&]() { - dot::Cluster *parent_cluster = get_cluster_for_parent(graph, clusters, parent->parent()); - bNodeTree *btree = reinterpret_cast<bNodeTree *>(parent->node_ref().bnode()->id); - dot::Cluster *new_cluster = &graph.new_cluster(parent->node_ref().name() + " / " + - StringRef(btree->id.name + 2)); - new_cluster->set_parent_cluster(parent_cluster); - return new_cluster; - }); } -std::string DerivedNodeTree::to_dot() const +/* Calls the given callback for every "real" target socket. "Real" means that reroutes, muted nodes + * and node groups are handled by this function. Target sockets are on the nodes that use the value + * from this socket. */ +void DOutputSocket::foreach_target_socket(FunctionRef<void(DInputSocket)> callback) const { - dot::DirectedGraph digraph; - digraph.set_rankdir(dot::Attr_rankdir::LeftToRight); - - Map<const DNode *, dot::NodeWithSocketsRef> dot_nodes; - Map<const DGroupInput *, dot::NodeWithSocketsRef> dot_group_inputs; - Map<const DParentNode *, dot::Cluster *> dot_clusters; - - for (const DNode *node : nodes_by_id_) { - dot::Node &dot_node = digraph.new_node(""); - dot_node.set_background_color("white"); - - Vector<std::string> input_names; - for (const DInputSocket *socket : node->inputs()) { - input_names.append(socket->name()); - } - Vector<std::string> output_names; - for (const DOutputSocket *socket : node->outputs()) { - output_names.append(socket->name()); + for (const InputSocketRef *linked_socket : socket_ref_->as_output().linked_sockets()) { + const NodeRef &linked_node = linked_socket->node(); + DInputSocket linked_dsocket{context_, linked_socket}; + + if (linked_node.is_muted()) { + /* If the target node is muted, follow its internal links. */ + for (const InternalLinkRef *internal_link : linked_node.internal_links()) { + if (&internal_link->from() == linked_socket) { + DOutputSocket output_of_muted_node{context_, &internal_link->to()}; + output_of_muted_node.foreach_target_socket(callback); + } + } } - - dot_nodes.add_new(node, - dot::NodeWithSocketsRef(dot_node, node->name(), input_names, output_names)); - - dot::Cluster *cluster = get_cluster_for_parent(digraph, dot_clusters, node->parent()); - dot_node.set_parent_cluster(cluster); - } - - for (const DGroupInput *group_input : group_inputs_) { - dot::Node &dot_node = digraph.new_node(""); - dot_node.set_background_color("white"); - - std::string group_input_name = group_input->name(); - dot_group_inputs.add_new( - group_input, dot::NodeWithSocketsRef(dot_node, "Group Input", {}, {group_input_name})); - - dot::Cluster *cluster = get_cluster_for_parent(digraph, dot_clusters, group_input->parent()); - dot_node.set_parent_cluster(cluster); - } - - for (const DNode *to_node : nodes_by_id_) { - dot::NodeWithSocketsRef &to_dot_node = dot_nodes.lookup(to_node); - - for (const DInputSocket *to_socket : to_node->inputs()) { - for (const DOutputSocket *from_socket : to_socket->linked_sockets()) { - const DNode *from_node = &from_socket->node(); - dot::NodeWithSocketsRef &from_dot_node = dot_nodes.lookup(from_node); - - digraph.new_edge(from_dot_node.output(from_socket->index()), - to_dot_node.input(to_socket->index())); + else if (linked_node.is_group_output_node()) { + if (context_->is_root()) { + /* This is a group output in the root node group. */ + callback(linked_dsocket); } - for (const DGroupInput *group_input : to_socket->linked_group_inputs()) { - dot::NodeWithSocketsRef &from_dot_node = dot_group_inputs.lookup(group_input); - - digraph.new_edge(from_dot_node.output(0), to_dot_node.input(to_socket->index())); + else { + /* Follow the links going out of the group node in the parent node group. */ + DOutputSocket socket_in_parent_group = + linked_dsocket.get_corresponding_group_node_output(); + socket_in_parent_group.foreach_target_socket(callback); } } + else if (linked_node.is_group_node()) { + /* Follow the links within the nested node group. */ + Vector<DOutputSocket> sockets_in_group = + linked_dsocket.get_corresponding_group_input_sockets(); + for (DOutputSocket socket_in_group : sockets_in_group) { + socket_in_group.foreach_target_socket(callback); + } + } + else { + /* The normal case: just use the linked input socket as target. */ + callback(linked_dsocket); + } } - - digraph.set_random_cluster_bgcolors(); - return digraph.to_dot_string(); } } // namespace blender::nodes diff --git a/source/blender/nodes/intern/node_exec.c b/source/blender/nodes/intern/node_exec.c index 0d46119ab60..6207a1bf024 100644 --- a/source/blender/nodes/intern/node_exec.c +++ b/source/blender/nodes/intern/node_exec.c @@ -218,7 +218,7 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context, /* prepare all nodes for execution */ for (n = 0, nodeexec = exec->nodeexec; n < totnodes; n++, nodeexec++) { node = nodeexec->node = nodelist[n]; - nodeexec->freeexecfunc = node->typeinfo->freeexecfunc; + nodeexec->free_exec_fn = node->typeinfo->free_exec_fn; /* tag inputs */ for (sock = node->inputs.first; sock; sock = sock->next) { @@ -242,8 +242,8 @@ bNodeTreeExec *ntree_exec_begin(bNodeExecContext *context, nodeexec->data.preview = context->previews ? BKE_node_instance_hash_lookup(context->previews, nodekey) : NULL; - if (node->typeinfo->initexecfunc) { - nodeexec->data.data = node->typeinfo->initexecfunc(context, node, nodekey); + if (node->typeinfo->init_exec_fn) { + nodeexec->data.data = node->typeinfo->init_exec_fn(context, node, nodekey); } } @@ -264,8 +264,8 @@ void ntree_exec_end(bNodeTreeExec *exec) } for (n = 0, nodeexec = exec->nodeexec; n < exec->totnodes; n++, nodeexec++) { - if (nodeexec->freeexecfunc) { - nodeexec->freeexecfunc(nodeexec->data.data); + if (nodeexec->free_exec_fn) { + nodeexec->free_exec_fn(nodeexec->data.data); } } @@ -323,8 +323,8 @@ bool ntreeExecThreadNodes(bNodeTreeExec *exec, bNodeThreadStack *nts, void *call * If the mute func is not set, assume the node should never be muted, * and hence execute it! */ - if (node->typeinfo->execfunc && !(node->flag & NODE_MUTED)) { - node->typeinfo->execfunc(callerdata, thread, node, &nodeexec->data, nsin, nsout); + if (node->typeinfo->exec_fn && !(node->flag & NODE_MUTED)) { + node->typeinfo->exec_fn(callerdata, thread, node, &nodeexec->data, nsin, nsout); } } } diff --git a/source/blender/nodes/intern/node_exec.h b/source/blender/nodes/intern/node_exec.h index 806dd10d9bf..de7cbb8cedb 100644 --- a/source/blender/nodes/intern/node_exec.h +++ b/source/blender/nodes/intern/node_exec.h @@ -48,7 +48,7 @@ typedef struct bNodeExec { bNodeExecData data; /** Free function, stored in exec itself to avoid dangling node pointer access. */ - NodeFreeExecFunction freeexecfunc; + NodeFreeExecFunction free_exec_fn; } bNodeExec; /* Execution Data for each instance of node tree execution */ diff --git a/source/blender/nodes/intern/node_geometry_exec.cc b/source/blender/nodes/intern/node_geometry_exec.cc index 9e62b7d7312..a4fb99a988e 100644 --- a/source/blender/nodes/intern/node_geometry_exec.cc +++ b/source/blender/nodes/intern/node_geometry_exec.cc @@ -20,7 +20,6 @@ #include "DEG_depsgraph_query.h" -#include "NOD_derived_node_tree.hh" #include "NOD_geometry_exec.hh" #include "NOD_type_callbacks.hh" @@ -30,7 +29,7 @@ namespace blender::nodes { void GeoNodeExecParams::error_message_add(const NodeWarningType type, std::string message) const { - bNodeTree *btree_cow = node_.node_ref().tree().btree(); + bNodeTree *btree_cow = node_->btree(); BLI_assert(btree_cow != nullptr); if (btree_cow == nullptr) { return; @@ -40,12 +39,12 @@ void GeoNodeExecParams::error_message_add(const NodeWarningType type, std::strin const NodeTreeEvaluationContext context(*self_object_, *modifier_); BKE_nodetree_error_message_add( - *btree_original, context, *node_.bnode(), type, std::move(message)); + *btree_original, context, *node_->bnode(), type, std::move(message)); } const bNodeSocket *GeoNodeExecParams::find_available_socket(const StringRef name) const { - for (const DSocket *socket : node_.inputs()) { + for (const InputSocketRef *socket : node_->inputs()) { if (socket->is_available() && socket->name() == name) { return socket->bsocket(); } @@ -176,7 +175,7 @@ void GeoNodeExecParams::check_extract_input(StringRef identifier, const CPPType *requested_type) const { bNodeSocket *found_socket = nullptr; - for (const DSocket *socket : node_.inputs()) { + for (const InputSocketRef *socket : node_->inputs()) { if (socket->identifier() == identifier) { found_socket = socket->bsocket(); break; @@ -186,7 +185,7 @@ void GeoNodeExecParams::check_extract_input(StringRef identifier, if (found_socket == nullptr) { std::cout << "Did not find an input socket with the identifier '" << identifier << "'.\n"; std::cout << "Possible identifiers are: "; - for (const DSocket *socket : node_.inputs()) { + for (const InputSocketRef *socket : node_->inputs()) { if (socket->is_available()) { std::cout << "'" << socket->identifier() << "', "; } @@ -218,7 +217,7 @@ void GeoNodeExecParams::check_extract_input(StringRef identifier, void GeoNodeExecParams::check_set_output(StringRef identifier, const CPPType &value_type) const { bNodeSocket *found_socket = nullptr; - for (const DSocket *socket : node_.outputs()) { + for (const OutputSocketRef *socket : node_->outputs()) { if (socket->identifier() == identifier) { found_socket = socket->bsocket(); break; @@ -228,7 +227,7 @@ void GeoNodeExecParams::check_set_output(StringRef identifier, const CPPType &va if (found_socket == nullptr) { std::cout << "Did not find an output socket with the identifier '" << identifier << "'.\n"; std::cout << "Possible identifiers are: "; - for (const DSocket *socket : node_.outputs()) { + for (const OutputSocketRef *socket : node_->outputs()) { if (socket->is_available()) { std::cout << "'" << socket->identifier() << "', "; } diff --git a/source/blender/nodes/intern/node_tree_dependencies.cc b/source/blender/nodes/intern/node_tree_dependencies.cc deleted file mode 100644 index 9d279dd4d75..00000000000 --- a/source/blender/nodes/intern/node_tree_dependencies.cc +++ /dev/null @@ -1,57 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include "NOD_node_tree_dependencies.hh" - -#include "DNA_node_types.h" - -#include "BKE_node.h" - -namespace blender::nodes { - -static void add_dependencies_of_node_tree(bNodeTree &ntree, NodeTreeDependencies &r_dependencies) -{ - /* TODO: Do a bit more sophisticated parsing to see which dependencies are really required. */ - LISTBASE_FOREACH (bNode *, node, &ntree.nodes) { - LISTBASE_FOREACH (bNodeSocket *, socket, &node->inputs) { - if (socket->type == SOCK_OBJECT) { - Object *object = reinterpret_cast<bNodeSocketValueObject *>(socket->default_value)->value; - if (object != nullptr) { - r_dependencies.add_transform_dependency(object); - if (object->type == OB_MESH) { - r_dependencies.add_geometry_dependency(object); - } - } - } - } - - if (node->type == NODE_GROUP) { - bNodeTree *group = reinterpret_cast<bNodeTree *>(node->id); - if (group != nullptr) { - add_dependencies_of_node_tree(*group, r_dependencies); - } - } - } -} - -NodeTreeDependencies find_node_tree_dependencies(bNodeTree &ntree) -{ - NodeTreeDependencies dependencies; - add_dependencies_of_node_tree(ntree, dependencies); - return dependencies; -} - -} // namespace blender::nodes diff --git a/source/blender/nodes/intern/node_tree_multi_function.cc b/source/blender/nodes/intern/node_tree_multi_function.cc index c2391667e86..bb1367573f8 100644 --- a/source/blender/nodes/intern/node_tree_multi_function.cc +++ b/source/blender/nodes/intern/node_tree_multi_function.cc @@ -29,17 +29,17 @@ const fn::MultiFunction &NodeMFNetworkBuilder::get_default_fn(StringRef name) Vector<fn::MFDataType, 10> input_types; Vector<fn::MFDataType, 10> output_types; - for (const DInputSocket *dsocket : dnode_.inputs()) { + for (const InputSocketRef *dsocket : dnode_->inputs()) { if (dsocket->is_available()) { - std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo); + std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->typeinfo()); if (data_type.has_value()) { input_types.append(*data_type); } } } - for (const DOutputSocket *dsocket : dnode_.outputs()) { + for (const OutputSocketRef *dsocket : dnode_->outputs()) { if (dsocket->is_available()) { - std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo); + std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->typeinfo()); if (data_type.has_value()) { output_types.append(*data_type); } @@ -57,9 +57,9 @@ static void insert_dummy_node(CommonMFNetworkBuilderData &common, const DNode &d Vector<fn::MFDataType, stack_capacity> input_types; Vector<StringRef, stack_capacity> input_names; - Vector<const DInputSocket *, stack_capacity> input_dsockets; + Vector<const InputSocketRef *, stack_capacity> input_dsockets; - for (const DInputSocket *dsocket : dnode.inputs()) { + for (const InputSocketRef *dsocket : dnode->inputs()) { if (dsocket->is_available()) { std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo); if (data_type.has_value()) { @@ -72,9 +72,9 @@ static void insert_dummy_node(CommonMFNetworkBuilderData &common, const DNode &d Vector<fn::MFDataType, stack_capacity> output_types; Vector<StringRef, stack_capacity> output_names; - Vector<const DOutputSocket *, stack_capacity> output_dsockets; + Vector<const OutputSocketRef *, stack_capacity> output_dsockets; - for (const DOutputSocket *dsocket : dnode.outputs()) { + for (const OutputSocketRef *dsocket : dnode->outputs()) { if (dsocket->is_available()) { std::optional<fn::MFDataType> data_type = socket_mf_type_get(*dsocket->bsocket()->typeinfo); if (data_type.has_value()) { @@ -86,20 +86,20 @@ static void insert_dummy_node(CommonMFNetworkBuilderData &common, const DNode &d } fn::MFDummyNode &dummy_node = common.network.add_dummy( - dnode.name(), input_types, output_types, input_names, output_names); + dnode->name(), input_types, output_types, input_names, output_names); - common.network_map.add(input_dsockets, dummy_node.inputs()); - common.network_map.add(output_dsockets, dummy_node.outputs()); + common.network_map.add(*dnode.context(), input_dsockets, dummy_node.inputs()); + common.network_map.add(*dnode.context(), output_dsockets, dummy_node.outputs()); } static bool has_data_sockets(const DNode &dnode) { - for (const DInputSocket *socket : dnode.inputs()) { + for (const InputSocketRef *socket : dnode->inputs()) { if (socket_is_mf_data_socket(*socket->bsocket()->typeinfo)) { return true; } } - for (const DOutputSocket *socket : dnode.outputs()) { + for (const OutputSocketRef *socket : dnode->outputs()) { if (socket_is_mf_data_socket(*socket->bsocket()->typeinfo)) { return true; } @@ -107,70 +107,39 @@ static bool has_data_sockets(const DNode &dnode) return false; } +static void foreach_node_to_insert(CommonMFNetworkBuilderData &common, + FunctionRef<void(DNode)> callback) +{ + common.tree.foreach_node([&](const DNode dnode) { + if (dnode->is_group_node()) { + return; + } + /* Don't insert non-root group input/output nodes, because they will be inlined. */ + if (!dnode.context()->is_root()) { + if (dnode->is_group_input_node() || dnode->is_group_output_node()) { + return; + } + } + callback(dnode); + }); +} + /** * Expands all function nodes in the multi-function network. Nodes that don't have an expand * function, but do have data sockets, will get corresponding dummy nodes. */ static void insert_nodes(CommonMFNetworkBuilderData &common) { - for (const DNode *dnode : common.tree.nodes()) { - const bNodeType *node_type = dnode->node_ref().bnode()->typeinfo; + foreach_node_to_insert(common, [&](const DNode dnode) { + const bNodeType *node_type = dnode->typeinfo(); if (node_type->expand_in_mf_network != nullptr) { - NodeMFNetworkBuilder builder{common, *dnode}; + NodeMFNetworkBuilder builder{common, dnode}; node_type->expand_in_mf_network(builder); } - else if (has_data_sockets(*dnode)) { - insert_dummy_node(common, *dnode); - } - } -} - -static void insert_group_inputs(CommonMFNetworkBuilderData &common) -{ - for (const DGroupInput *group_input : common.tree.group_inputs()) { - bNodeSocket *bsocket = group_input->bsocket(); - if (socket_is_mf_data_socket(*bsocket->typeinfo)) { - bNodeSocketType *socktype = bsocket->typeinfo; - BLI_assert(socktype->expand_in_mf_network != nullptr); - - SocketMFNetworkBuilder builder{common, *group_input}; - socktype->expand_in_mf_network(builder); - - fn::MFOutputSocket *from_socket = builder.built_socket(); - BLI_assert(from_socket != nullptr); - common.network_map.add(*group_input, *from_socket); - } - } -} - -static fn::MFOutputSocket *try_find_origin(CommonMFNetworkBuilderData &common, - const DInputSocket &to_dsocket) -{ - Span<const DOutputSocket *> from_dsockets = to_dsocket.linked_sockets(); - Span<const DGroupInput *> from_group_inputs = to_dsocket.linked_group_inputs(); - int total_linked_amount = from_dsockets.size() + from_group_inputs.size(); - BLI_assert(total_linked_amount <= 1); - - if (total_linked_amount == 0) { - return nullptr; - } - - if (from_dsockets.size() == 1) { - const DOutputSocket &from_dsocket = *from_dsockets[0]; - if (!from_dsocket.is_available()) { - return nullptr; - } - if (socket_is_mf_data_socket(*from_dsocket.bsocket()->typeinfo)) { - return &common.network_map.lookup(from_dsocket); + else if (has_data_sockets(dnode)) { + insert_dummy_node(common, dnode); } - return nullptr; - } - - const DGroupInput &from_group_input = *from_group_inputs[0]; - if (socket_is_mf_data_socket(*from_group_input.bsocket()->typeinfo)) { - return &common.network_map.lookup(from_group_input); - } - return nullptr; + }); } template<typename From, typename To> @@ -286,78 +255,82 @@ static fn::MFOutputSocket &insert_default_value_for_type(CommonMFNetworkBuilderD return node.output(0); } -static void insert_links(CommonMFNetworkBuilderData &common) +static fn::MFOutputSocket *insert_unlinked_input(CommonMFNetworkBuilderData &common, + const DInputSocket &dsocket) { - for (const DInputSocket *to_dsocket : common.tree.input_sockets()) { - if (!to_dsocket->is_available()) { - continue; - } - if (!to_dsocket->is_linked()) { - continue; - } - if (!socket_is_mf_data_socket(*to_dsocket->bsocket()->typeinfo)) { - continue; - } - - Span<fn::MFInputSocket *> to_sockets = common.network_map.lookup(*to_dsocket); - BLI_assert(to_sockets.size() >= 1); - fn::MFDataType to_type = to_sockets[0]->data_type(); + BLI_assert(socket_is_mf_data_socket(*dsocket->typeinfo())); - fn::MFOutputSocket *from_socket = try_find_origin(common, *to_dsocket); - if (from_socket == nullptr) { - from_socket = &insert_default_value_for_type(common, to_type); - } - - fn::MFDataType from_type = from_socket->data_type(); - - if (from_type != to_type) { - const fn::MultiFunction *conversion_fn = get_implicit_type_conversions().get_conversion( - from_type, to_type); - if (conversion_fn != nullptr) { - fn::MFNode &node = common.network.add_function(*conversion_fn); - common.network.add_link(*from_socket, node.input(0)); - from_socket = &node.output(0); - } - else { - from_socket = &insert_default_value_for_type(common, to_type); - } - } + SocketMFNetworkBuilder builder{common, dsocket}; + socket_expand_in_mf_network(builder); - for (fn::MFInputSocket *to_socket : to_sockets) { - common.network.add_link(*from_socket, *to_socket); - } - } + fn::MFOutputSocket *built_socket = builder.built_socket(); + BLI_assert(built_socket != nullptr); + return built_socket; } -static void insert_unlinked_input(CommonMFNetworkBuilderData &common, const DInputSocket &dsocket) +static void insert_links_and_unlinked_inputs(CommonMFNetworkBuilderData &common) { - bNodeSocket *bsocket = dsocket.bsocket(); - bNodeSocketType *socktype = bsocket->typeinfo; - BLI_assert(socktype->expand_in_mf_network != nullptr); - - SocketMFNetworkBuilder builder{common, dsocket}; - socktype->expand_in_mf_network(builder); - - fn::MFOutputSocket *from_socket = builder.built_socket(); - BLI_assert(from_socket != nullptr); + foreach_node_to_insert(common, [&](const DNode dnode) { + for (const InputSocketRef *socket_ref : dnode->inputs()) { + const DInputSocket to_dsocket{dnode.context(), socket_ref}; + if (!to_dsocket->is_available()) { + continue; + } + if (!socket_is_mf_data_socket(*to_dsocket->typeinfo())) { + continue; + } - for (fn::MFInputSocket *to_socket : common.network_map.lookup(dsocket)) { - common.network.add_link(*from_socket, *to_socket); - } -} + Span<fn::MFInputSocket *> to_sockets = common.network_map.lookup(to_dsocket); + BLI_assert(to_sockets.size() >= 1); + const fn::MFDataType to_type = to_sockets[0]->data_type(); -static void insert_unlinked_inputs(CommonMFNetworkBuilderData &common) -{ - Vector<const DInputSocket *> unlinked_data_inputs; - for (const DInputSocket *dsocket : common.tree.input_sockets()) { - if (dsocket->is_available()) { - if (socket_is_mf_data_socket(*dsocket->bsocket()->typeinfo)) { - if (!dsocket->is_linked()) { - insert_unlinked_input(common, *dsocket); + Vector<DSocket> from_dsockets; + to_dsocket.foreach_origin_socket([&](DSocket socket) { from_dsockets.append(socket); }); + if (from_dsockets.size() > 1) { + fn::MFOutputSocket &from_socket = insert_default_value_for_type(common, to_type); + for (fn::MFInputSocket *to_socket : to_sockets) { + common.network.add_link(from_socket, *to_socket); + } + continue; + } + if (from_dsockets.is_empty()) { + /* The socket is not linked. Need to use the value of the socket itself. */ + fn::MFOutputSocket *built_socket = insert_unlinked_input(common, to_dsocket); + for (fn::MFInputSocket *to_socket : to_sockets) { + common.network.add_link(*built_socket, *to_socket); } + continue; + } + if (from_dsockets[0]->is_input()) { + DInputSocket from_dsocket{from_dsockets[0]}; + fn::MFOutputSocket *built_socket = insert_unlinked_input(common, from_dsocket); + for (fn::MFInputSocket *to_socket : to_sockets) { + common.network.add_link(*built_socket, *to_socket); + } + continue; + } + DOutputSocket from_dsocket{from_dsockets[0]}; + fn::MFOutputSocket *from_socket = &common.network_map.lookup(from_dsocket); + const fn::MFDataType from_type = from_socket->data_type(); + + if (from_type != to_type) { + const fn::MultiFunction *conversion_fn = get_implicit_type_conversions().get_conversion( + from_type, to_type); + if (conversion_fn != nullptr) { + fn::MFNode &node = common.network.add_function(*conversion_fn); + common.network.add_link(*from_socket, node.input(0)); + from_socket = &node.output(0); + } + else { + from_socket = &insert_default_value_for_type(common, to_type); + } + } + + for (fn::MFInputSocket *to_socket : to_sockets) { + common.network.add_link(*from_socket, *to_socket); } } - } + }); } /** @@ -376,9 +349,7 @@ MFNetworkTreeMap insert_node_tree_into_mf_network(fn::MFNetwork &network, CommonMFNetworkBuilderData common{resources, network, network_map, tree}; insert_nodes(common); - insert_group_inputs(common); - insert_links(common); - insert_unlinked_inputs(common); + insert_links_and_unlinked_inputs(common); return network_map; } @@ -420,16 +391,17 @@ static NodeExpandType get_node_expand_type(MFNetworkTreeMap &network_map, } }; - for (const DInputSocket *dsocket : dnode.inputs()) { + for (const InputSocketRef *dsocket : dnode->inputs()) { if (dsocket->is_available()) { - for (fn::MFInputSocket *mf_input : network_map.lookup(*dsocket)) { + for (fn::MFInputSocket *mf_input : + network_map.lookup(DInputSocket(dnode.context(), dsocket))) { check_mf_node(mf_input->node()); } } } - for (const DOutputSocket *dsocket : dnode.outputs()) { + for (const OutputSocketRef *dsocket : dnode->outputs()) { if (dsocket->is_available()) { - fn::MFOutputSocket &mf_output = network_map.lookup(*dsocket); + fn::MFOutputSocket &mf_output = network_map.lookup(DOutputSocket(dnode.context(), dsocket)); check_mf_node(mf_output.node()); } } @@ -451,20 +423,21 @@ static const fn::MultiFunction &create_function_for_node_that_expands_into_multi ResourceCollector &resources) { Vector<const fn::MFOutputSocket *> dummy_fn_inputs; - for (const DInputSocket *dsocket : dnode.inputs()) { + for (const InputSocketRef *dsocket : dnode->inputs()) { if (dsocket->is_available()) { MFDataType data_type = *socket_mf_type_get(*dsocket->typeinfo()); fn::MFOutputSocket &fn_input = network.add_input(data_type.to_string(), data_type); - for (fn::MFInputSocket *mf_input : network_map.lookup(*dsocket)) { + for (fn::MFInputSocket *mf_input : + network_map.lookup(DInputSocket(dnode.context(), dsocket))) { network.add_link(fn_input, *mf_input); dummy_fn_inputs.append(&fn_input); } } } Vector<const fn::MFInputSocket *> dummy_fn_outputs; - for (const DOutputSocket *dsocket : dnode.outputs()) { + for (const OutputSocketRef *dsocket : dnode->outputs()) { if (dsocket->is_available()) { - fn::MFOutputSocket &mf_output = network_map.lookup(*dsocket); + fn::MFOutputSocket &mf_output = network_map.lookup(DOutputSocket(dnode.context(), dsocket)); MFDataType data_type = mf_output.data_type(); fn::MFInputSocket &fn_output = network.add_output(data_type.to_string(), data_type); network.add_link(mf_output, fn_output); @@ -492,18 +465,18 @@ MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree, CommonMFNetworkBuilderData common{resources, network, network_map, tree}; - for (const DNode *dnode : tree.nodes()) { + tree.foreach_node([&](DNode dnode) { const bNodeType *node_type = dnode->typeinfo(); if (node_type->expand_in_mf_network == nullptr) { /* This node does not have a multi-function implementation. */ - continue; + return; } - NodeMFNetworkBuilder builder{common, *dnode}; + NodeMFNetworkBuilder builder{common, dnode}; node_type->expand_in_mf_network(builder); const fn::MultiFunction *single_function = nullptr; - const NodeExpandType expand_type = get_node_expand_type(network_map, *dnode, &single_function); + const NodeExpandType expand_type = get_node_expand_type(network_map, dnode, &single_function); switch (expand_type) { case NodeExpandType::HasDummyNodes: { @@ -519,12 +492,12 @@ MultiFunctionByNode get_multi_function_per_node(const DerivedNodeTree &tree, /* If a node expanded into multiple functions, a new function has to be created that * combines those. */ const fn::MultiFunction &fn = create_function_for_node_that_expands_into_multiple( - *dnode, network, network_map, resources); + dnode, network, network_map, resources); functions_by_node.add_new(dnode, &fn); break; } } - } + }); return functions_by_node; } diff --git a/source/blender/nodes/intern/node_tree_ref.cc b/source/blender/nodes/intern/node_tree_ref.cc index 7fe21ec8582..0ea2538d6f1 100644 --- a/source/blender/nodes/intern/node_tree_ref.cc +++ b/source/blender/nodes/intern/node_tree_ref.cc @@ -25,7 +25,7 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree) Map<bNode *, NodeRef *> node_mapping; LISTBASE_FOREACH (bNode *, bnode, &btree->nodes) { - NodeRef &node = *allocator_.construct<NodeRef>(); + NodeRef &node = *allocator_.construct<NodeRef>().release(); node.tree_ = this; node.bnode_ = bnode; @@ -33,7 +33,7 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree) RNA_pointer_create(&btree->id, &RNA_Node, bnode, &node.rna_); LISTBASE_FOREACH (bNodeSocket *, bsocket, &bnode->inputs) { - InputSocketRef &socket = *allocator_.construct<InputSocketRef>(); + InputSocketRef &socket = *allocator_.construct<InputSocketRef>().release(); socket.node_ = &node; socket.index_ = node.inputs_.append_and_get_index(&socket); socket.is_input_ = true; @@ -43,7 +43,7 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree) } LISTBASE_FOREACH (bNodeSocket *, bsocket, &bnode->outputs) { - OutputSocketRef &socket = *allocator_.construct<OutputSocketRef>(); + OutputSocketRef &socket = *allocator_.construct<OutputSocketRef>().release(); socket.node_ = &node; socket.index_ = node.outputs_.append_and_get_index(&socket); socket.is_input_ = false; @@ -53,7 +53,7 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree) } LISTBASE_FOREACH (bNodeLink *, blink, &bnode->internal_links) { - InternalLinkRef &internal_link = *allocator_.construct<InternalLinkRef>(); + InternalLinkRef &internal_link = *allocator_.construct<InternalLinkRef>().release(); internal_link.blink_ = blink; for (InputSocketRef *socket_ref : node.inputs_) { if (socket_ref->bsocket_ == blink->fromsock) { @@ -82,7 +82,7 @@ NodeTreeRef::NodeTreeRef(bNodeTree *btree) : btree_(btree) InputSocketRef &to_socket = this->find_input_socket( node_mapping, blink->tonode, blink->tosock); - LinkRef &link = *allocator_.construct<LinkRef>(); + LinkRef &link = *allocator_.construct<LinkRef>().release(); link.from_ = &from_socket; link.to_ = &to_socket; link.blink_ = blink; diff --git a/source/blender/nodes/shader/node_shader_util.c b/source/blender/nodes/shader/node_shader_util.c index 25d6aef69e5..1a2405e021f 100644 --- a/source/blender/nodes/shader/node_shader_util.c +++ b/source/blender/nodes/shader/node_shader_util.c @@ -257,11 +257,11 @@ void ntreeExecGPUNodes(bNodeTreeExec *exec, GPUMaterial *mat, bNode *output_node } if (do_it) { - if (node->typeinfo->gpufunc) { + if (node->typeinfo->gpu_fn) { node_get_stack(node, stack, nsin, nsout); gpu_stack_from_data_list(gpuin, &node->inputs, nsin); gpu_stack_from_data_list(gpuout, &node->outputs, nsout); - if (node->typeinfo->gpufunc(mat, node, &nodeexec->data, gpuin, gpuout)) { + if (node->typeinfo->gpu_fn(mat, node, &nodeexec->data, gpuin, gpuout)) { data_from_gpu_stack_list(&node->outputs, nsout, gpuout); } } diff --git a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c index 36971d4e799..abe80ebcefb 100644 --- a/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c +++ b/source/blender/nodes/shader/nodes/node_shader_ambient_occlusion.c @@ -47,8 +47,15 @@ static int node_shader_gpu_ambient_occlusion(GPUMaterial *mat, GPU_material_flag_set(mat, GPU_MATFLAG_DIFFUSE); float inverted = node->custom2 ? 1.0f : 0.0f; + float f_samples = divide_ceil_u(node->custom1, 4); - return GPU_stack_link(mat, node, "node_ambient_occlusion", in, out, GPU_constant(&inverted)); + return GPU_stack_link(mat, + node, + "node_ambient_occlusion", + in, + out, + GPU_constant(&inverted), + GPU_constant(&f_samples)); } static void node_shader_init_ambient_occlusion(bNodeTree *UNUSED(ntree), bNode *node) diff --git a/source/blender/nodes/shader/nodes/node_shader_math.cc b/source/blender/nodes/shader/nodes/node_shader_math.cc index f54914ceba9..7a846031456 100644 --- a/source/blender/nodes/shader/nodes/node_shader_math.cc +++ b/source/blender/nodes/shader/nodes/node_shader_math.cc @@ -116,7 +116,7 @@ static void sh_node_math_expand_in_mf_network(blender::nodes::NodeMFNetworkBuild blender::fn::MFNetwork &network = builder.network(); blender::fn::MFFunctionNode &base_node = network.add_function(base_function); - builder.network_map().add_try_match(dnode.inputs(), base_node.inputs()); + builder.network_map().add_try_match(*dnode.context(), dnode->inputs(), base_node.inputs()); const bool clamp_output = builder.bnode().custom2 != 0; if (clamp_output) { @@ -126,10 +126,12 @@ static void sh_node_math_expand_in_mf_network(blender::nodes::NodeMFNetworkBuild }}; blender::fn::MFFunctionNode &clamp_node = network.add_function(clamp_fn); network.add_link(base_node.output(0), clamp_node.input(0)); - builder.network_map().add(dnode.output(0), clamp_node.output(0)); + builder.network_map().add(blender::nodes::DOutputSocket(dnode.context(), &dnode->output(0)), + clamp_node.output(0)); } else { - builder.network_map().add(dnode.output(0), base_node.output(0)); + builder.network_map().add(blender::nodes::DOutputSocket(dnode.context(), &dnode->output(0)), + base_node.output(0)); } } diff --git a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c index 41c978e75ba..26a1db1f3a6 100644 --- a/source/blender/nodes/shader/nodes/node_shader_tex_environment.c +++ b/source/blender/nodes/shader/nodes/node_shader_tex_environment.c @@ -90,7 +90,7 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, sampler &= ~GPU_SAMPLER_REPEAT; } - const char *gpufunc; + const char *gpu_fn; static const char *names[] = { "node_tex_image_linear", "node_tex_image_cubic", @@ -98,19 +98,19 @@ static int node_shader_gpu_tex_environment(GPUMaterial *mat, switch (tex->interpolation) { case SHD_INTERP_LINEAR: - gpufunc = names[0]; + gpu_fn = names[0]; break; case SHD_INTERP_CLOSEST: sampler &= ~(GPU_SAMPLER_FILTER | GPU_SAMPLER_MIPMAP); - gpufunc = names[0]; + gpu_fn = names[0]; break; default: - gpufunc = names[1]; + gpu_fn = names[1]; break; } /* Sample texture with correct interpolation. */ - GPU_link(mat, gpufunc, in[0].link, GPU_image(mat, ima, iuser, sampler), &out[0].link, &outalpha); + GPU_link(mat, gpu_fn, in[0].link, GPU_image(mat, ima, iuser, sampler), &out[0].link, &outalpha); if (out[0].hasoutput) { if (ELEM(ima->alpha_mode, IMA_ALPHA_IGNORE, IMA_ALPHA_CHANNEL_PACKED) || diff --git a/source/blender/nodes/shader/nodes/node_shader_value.cc b/source/blender/nodes/shader/nodes/node_shader_value.cc index 5a8a1b847cc..495c8d12824 100644 --- a/source/blender/nodes/shader/nodes/node_shader_value.cc +++ b/source/blender/nodes/shader/nodes/node_shader_value.cc @@ -41,7 +41,7 @@ static int gpu_shader_value(GPUMaterial *mat, static void sh_node_value_expand_in_mf_network(blender::nodes::NodeMFNetworkBuilder &builder) { - const bNodeSocket *bsocket = builder.dnode().output(0).bsocket(); + const bNodeSocket *bsocket = builder.dnode()->output(0).bsocket(); const bNodeSocketValueFloat *value = (const bNodeSocketValueFloat *)bsocket->default_value; builder.construct_and_set_matching_fn<blender::fn::CustomMF_Constant<float>>(value->value); } diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.c b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.c deleted file mode 100644 index b2132c59cde..00000000000 --- a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.c +++ /dev/null @@ -1,80 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2013 Blender Foundation. - * All rights reserved. - */ - -/** \file - * \ingroup shdnodes - */ - -#include "../node_shader_util.h" - -/* **************** Vector Rotate ******************** */ -static bNodeSocketTemplate sh_node_vector_rotate_in[] = { - {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, - {SOCK_VECTOR, N_("Center"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_NONE}, - {SOCK_VECTOR, N_("Axis"), 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, PROP_NONE, PROP_NONE}, - {SOCK_FLOAT, N_("Angle"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_ANGLE, PROP_NONE}, - {SOCK_VECTOR, N_("Rotation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_EULER}, - {-1, ""}}; - -static bNodeSocketTemplate sh_node_vector_rotate_out[] = {{SOCK_VECTOR, N_("Vector")}, {-1, ""}}; - -static int gpu_shader_vector_rotate(GPUMaterial *mat, - bNode *node, - bNodeExecData *UNUSED(execdata), - GPUNodeStack *in, - GPUNodeStack *out) -{ - - static const char *names[] = { - [NODE_VECTOR_ROTATE_TYPE_AXIS] = "node_vector_rotate_axis_angle", - [NODE_VECTOR_ROTATE_TYPE_AXIS_X] = "node_vector_rotate_axis_x", - [NODE_VECTOR_ROTATE_TYPE_AXIS_Y] = "node_vector_rotate_axis_y", - [NODE_VECTOR_ROTATE_TYPE_AXIS_Z] = "node_vector_rotate_axis_z", - [NODE_VECTOR_ROTATE_TYPE_EULER_XYZ] = "node_vector_rotate_euler_xyz", - }; - - if (node->custom1 < ARRAY_SIZE(names) && names[node->custom1]) { - float invert = (node->custom2) ? -1.0 : 1.0; - return GPU_stack_link(mat, node, names[node->custom1], in, out, GPU_constant(&invert)); - } - - return 0; -} - -static void node_shader_update_vector_rotate(bNodeTree *UNUSED(ntree), bNode *node) -{ - bNodeSocket *sock_rotation = nodeFindSocket(node, SOCK_IN, "Rotation"); - nodeSetSocketAvailability(sock_rotation, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ)); - bNodeSocket *sock_axis = nodeFindSocket(node, SOCK_IN, "Axis"); - nodeSetSocketAvailability(sock_axis, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_AXIS)); - bNodeSocket *sock_angle = nodeFindSocket(node, SOCK_IN, "Angle"); - nodeSetSocketAvailability(sock_angle, !ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ)); -} - -void register_node_type_sh_vector_rotate(void) -{ - static bNodeType ntype; - - sh_node_type_base(&ntype, SH_NODE_VECTOR_ROTATE, "Vector Rotate", NODE_CLASS_OP_VECTOR, 0); - node_type_socket_templates(&ntype, sh_node_vector_rotate_in, sh_node_vector_rotate_out); - node_type_gpu(&ntype, gpu_shader_vector_rotate); - node_type_update(&ntype, node_shader_update_vector_rotate); - - nodeRegisterType(&ntype); -} diff --git a/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc new file mode 100644 index 00000000000..30b043439b8 --- /dev/null +++ b/source/blender/nodes/shader/nodes/node_shader_vector_rotate.cc @@ -0,0 +1,217 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + * The Original Code is Copyright (C) 2013 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup shdnodes + */ + +#include "../node_shader_util.h" + +/* **************** Vector Rotate ******************** */ +static bNodeSocketTemplate sh_node_vector_rotate_in[] = { + {SOCK_VECTOR, N_("Vector"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE, SOCK_HIDE_VALUE}, + {SOCK_VECTOR, N_("Center"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_NONE}, + {SOCK_VECTOR, N_("Axis"), 0.0f, 0.0f, 1.0f, 0.0f, -1.0f, 1.0f, PROP_NONE, PROP_NONE}, + {SOCK_FLOAT, N_("Angle"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_ANGLE, PROP_NONE}, + {SOCK_VECTOR, N_("Rotation"), 0.0f, 0.0f, 0.0f, 1.0f, -FLT_MAX, FLT_MAX, PROP_EULER}, + {-1, ""}}; + +static bNodeSocketTemplate sh_node_vector_rotate_out[] = { + {SOCK_VECTOR, N_("Vector")}, + {-1, ""}, +}; + +static const char *gpu_shader_get_name(int mode) +{ + switch (mode) { + case NODE_VECTOR_ROTATE_TYPE_AXIS: + return "node_vector_rotate_axis_angle"; + case NODE_VECTOR_ROTATE_TYPE_AXIS_X: + return "node_vector_rotate_axis_x"; + case NODE_VECTOR_ROTATE_TYPE_AXIS_Y: + return "node_vector_rotate_axis_y"; + case NODE_VECTOR_ROTATE_TYPE_AXIS_Z: + return "node_vector_rotate_axis_z"; + case NODE_VECTOR_ROTATE_TYPE_EULER_XYZ: + return "node_vector_rotate_euler_xyz"; + } + + return nullptr; +} + +static int gpu_shader_vector_rotate(GPUMaterial *mat, + bNode *node, + bNodeExecData *UNUSED(execdata), + GPUNodeStack *in, + GPUNodeStack *out) +{ + const char *name = gpu_shader_get_name(node->custom1); + + if (name != nullptr) { + float invert = (node->custom2) ? -1.0 : 1.0; + return GPU_stack_link(mat, node, name, in, out, GPU_constant(&invert)); + } + + return 0; +} + +using blender::float3; + +static float3 sh_node_vector_rotate_around_axis(const float3 vector, + const float3 center, + const float3 axis, + const float angle) +{ + float3 result = vector - center; + float mat[3][3]; + axis_angle_to_mat3(mat, axis, angle); + mul_m3_v3(mat, result); + return result + center; +} + +static float3 sh_node_vector_rotate_euler(const float3 vector, + const float3 center, + const float3 rotation, + const bool invert) +{ + float mat[3][3]; + float3 result = vector - center; + eul_to_mat3(mat, rotation); + if (invert) { + invert_m3(mat); + } + mul_m3_v3(mat, result); + return result + center; +} + +static const blender::fn::MultiFunction &get_multi_function( + blender::nodes::NodeMFNetworkBuilder &builder) +{ + bool invert = builder.bnode().custom2; + const int mode = builder.bnode().custom1; + + switch (mode) { + case NODE_VECTOR_ROTATE_TYPE_AXIS: { + if (invert) { + static blender::fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float3, float, float3> fn{ + "Rotate Axis", [](float3 in, float3 center, float3 axis, float angle) { + return sh_node_vector_rotate_around_axis(in, center, axis, -angle); + }}; + return fn; + } + static blender::fn::CustomMF_SI_SI_SI_SI_SO<float3, float3, float3, float, float3> fn{ + "Rotate Axis", [](float3 in, float3 center, float3 axis, float angle) { + return sh_node_vector_rotate_around_axis(in, center, axis, angle); + }}; + return fn; + } + case NODE_VECTOR_ROTATE_TYPE_AXIS_X: { + float3 axis = float3(1.0f, 0.0f, 0.0f); + if (invert) { + static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{ + "Rotate X-Axis", [=](float3 in, float3 center, float angle) { + return sh_node_vector_rotate_around_axis(in, center, axis, -angle); + }}; + return fn; + } + static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{ + "Rotate X-Axis", [=](float3 in, float3 center, float angle) { + return sh_node_vector_rotate_around_axis(in, center, axis, angle); + }}; + return fn; + } + case NODE_VECTOR_ROTATE_TYPE_AXIS_Y: { + float3 axis = float3(0.0f, 1.0f, 0.0f); + if (invert) { + static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{ + "Rotate Y-Axis", [=](float3 in, float3 center, float angle) { + return sh_node_vector_rotate_around_axis(in, center, axis, -angle); + }}; + return fn; + } + static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{ + "Rotate Y-Axis", [=](float3 in, float3 center, float angle) { + return sh_node_vector_rotate_around_axis(in, center, axis, angle); + }}; + return fn; + } + case NODE_VECTOR_ROTATE_TYPE_AXIS_Z: { + float3 axis = float3(0.0f, 0.0f, 1.0f); + if (invert) { + static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{ + "Rotate Z-Axis", [=](float3 in, float3 center, float angle) { + return sh_node_vector_rotate_around_axis(in, center, axis, -angle); + }}; + return fn; + } + static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float, float3> fn{ + "Rotate Z-Axis", [=](float3 in, float3 center, float angle) { + return sh_node_vector_rotate_around_axis(in, center, axis, angle); + }}; + return fn; + } + case NODE_VECTOR_ROTATE_TYPE_EULER_XYZ: { + if (invert) { + static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{ + "Rotate Euler", [](float3 in, float3 center, float3 rotation) { + return sh_node_vector_rotate_euler(in, center, rotation, true); + }}; + return fn; + } + static blender::fn::CustomMF_SI_SI_SI_SO<float3, float3, float3, float3> fn{ + "Rotate Euler", [](float3 in, float3 center, float3 rotation) { + return sh_node_vector_rotate_euler(in, center, rotation, false); + }}; + return fn; + } + default: + BLI_assert(false); + return builder.get_not_implemented_fn(); + } +} + +static void sh_node_vector_rotate_expand_in_mf_network( + blender::nodes::NodeMFNetworkBuilder &builder) +{ + const blender::fn::MultiFunction &fn = get_multi_function(builder); + builder.set_matching_fn(fn); +} + +static void node_shader_update_vector_rotate(bNodeTree *UNUSED(ntree), bNode *node) +{ + bNodeSocket *sock_rotation = nodeFindSocket(node, SOCK_IN, "Rotation"); + nodeSetSocketAvailability(sock_rotation, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ)); + bNodeSocket *sock_axis = nodeFindSocket(node, SOCK_IN, "Axis"); + nodeSetSocketAvailability(sock_axis, ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_AXIS)); + bNodeSocket *sock_angle = nodeFindSocket(node, SOCK_IN, "Angle"); + nodeSetSocketAvailability(sock_angle, !ELEM(node->custom1, NODE_VECTOR_ROTATE_TYPE_EULER_XYZ)); +} + +void register_node_type_sh_vector_rotate(void) +{ + static bNodeType ntype; + + sh_fn_node_type_base(&ntype, SH_NODE_VECTOR_ROTATE, "Vector Rotate", NODE_CLASS_OP_VECTOR, 0); + node_type_socket_templates(&ntype, sh_node_vector_rotate_in, sh_node_vector_rotate_out); + node_type_gpu(&ntype, gpu_shader_vector_rotate); + node_type_update(&ntype, node_shader_update_vector_rotate); + ntype.expand_in_mf_network = sh_node_vector_rotate_expand_in_mf_network; + + nodeRegisterType(&ntype); +} diff --git a/source/blender/python/gpu/gpu_py_offscreen.c b/source/blender/python/gpu/gpu_py_offscreen.c index dff4b169f9a..4a2b359bf39 100644 --- a/source/blender/python/gpu/gpu_py_offscreen.c +++ b/source/blender/python/gpu/gpu_py_offscreen.c @@ -96,20 +96,20 @@ static int pygpu_offscreen_valid_check(BPyGPUOffScreen *py_ofs) typedef struct { PyObject_HEAD /* required python macro */ - BPyGPUOffScreen *py_offs; + BPyGPUOffScreen *py_offscreen; int level; bool is_explicitly_bound; /* Bound by "bind" method. */ } OffScreenStackContext; static void pygpu_offscreen_stack_context__tp_dealloc(OffScreenStackContext *self) { - Py_DECREF(self->py_offs); + Py_DECREF(self->py_offscreen); PyObject_DEL(self); } static PyObject *pygpu_offscreen_stack_context_enter(OffScreenStackContext *self) { - BPY_GPU_OFFSCREEN_CHECK_OBJ(self->py_offs); + BPY_GPU_OFFSCREEN_CHECK_OBJ(self->py_offscreen); if (!self->is_explicitly_bound) { if (self->level != -1) { @@ -117,7 +117,7 @@ static PyObject *pygpu_offscreen_stack_context_enter(OffScreenStackContext *self return NULL; } - GPU_offscreen_bind(self->py_offs->ofs, true); + GPU_offscreen_bind(self->py_offscreen->ofs, true); self->level = GPU_framebuffer_stack_level_get(); } @@ -127,7 +127,7 @@ static PyObject *pygpu_offscreen_stack_context_enter(OffScreenStackContext *self static PyObject *pygpu_offscreen_stack_context_exit(OffScreenStackContext *self, PyObject *UNUSED(args)) { - BPY_GPU_OFFSCREEN_CHECK_OBJ(self->py_offs); + BPY_GPU_OFFSCREEN_CHECK_OBJ(self->py_offscreen); if (self->level == -1) { PyErr_SetString(PyExc_RuntimeError, "Not yet in use\n"); @@ -140,7 +140,7 @@ static PyObject *pygpu_offscreen_stack_context_exit(OffScreenStackContext *self, PyExc_RuntimeError, "Level of bind mismatch, expected %d, got %d\n", self->level, level); } - GPU_offscreen_unbind(self->py_offs->ofs, true); + GPU_offscreen_unbind(self->py_offscreen->ofs, true); Py_RETURN_NONE; } @@ -166,7 +166,7 @@ static PyObject *pygpu_offscreen_bind(BPyGPUOffScreen *self) { OffScreenStackContext *ret = PyObject_New(OffScreenStackContext, &PyGPUOffscreenStackContext_Type); - ret->py_offs = self; + ret->py_offscreen = self; ret->level = -1; ret->is_explicitly_bound = false; Py_INCREF(self); diff --git a/source/blender/python/intern/CMakeLists.txt b/source/blender/python/intern/CMakeLists.txt index 352787b4fdb..822ab0bd969 100644 --- a/source/blender/python/intern/CMakeLists.txt +++ b/source/blender/python/intern/CMakeLists.txt @@ -75,6 +75,7 @@ set(SRC bpy_rna_anim.c bpy_rna_array.c bpy_rna_callback.c + bpy_rna_data.c bpy_rna_driver.c bpy_rna_gizmo.c bpy_rna_id_collection.c @@ -113,6 +114,7 @@ set(SRC bpy_rna.h bpy_rna_anim.h bpy_rna_callback.h + bpy_rna_data.h bpy_rna_driver.h bpy_rna_gizmo.h bpy_rna_id_collection.h diff --git a/source/blender/python/intern/bpy.c b/source/blender/python/intern/bpy.c index 74fc8bcfec9..547cf2ad38f 100644 --- a/source/blender/python/intern/bpy.c +++ b/source/blender/python/intern/bpy.c @@ -44,6 +44,7 @@ #include "bpy_operator.h" #include "bpy_props.h" #include "bpy_rna.h" +#include "bpy_rna_data.h" #include "bpy_rna_gizmo.h" #include "bpy_rna_id_collection.h" #include "bpy_rna_types_capi.h" @@ -425,6 +426,8 @@ void BPy_init_modules(struct bContext *C) /* needs to be first so bpy_types can run */ BPY_library_load_type_ready(); + BPY_rna_data_context_type_ready(); + BPY_rna_gizmo_module(mod); bpy_import_test("bpy_types"); diff --git a/source/blender/python/intern/bpy_library_load.c b/source/blender/python/intern/bpy_library_load.c index 03771a8c294..1ee14df24cf 100644 --- a/source/blender/python/intern/bpy_library_load.c +++ b/source/blender/python/intern/bpy_library_load.c @@ -34,6 +34,7 @@ #include "BLI_string.h" #include "BLI_utildefines.h" +#include "BKE_context.h" #include "BKE_idtype.h" #include "BKE_lib_id.h" #include "BKE_main.h" @@ -67,8 +68,10 @@ typedef struct { BlendHandle *blo_handle; int flag; PyObject *dict; - /* Borrowed reference to the `bmain`, taken from the RNA instance of #RNA_BlendDataLibraries. */ + /* Borrowed reference to the `bmain`, taken from the RNA instance of #RNA_BlendDataLibraries. + * Defaults to #G.main, Otherwise use a temporary #Main when `bmain_is_temp` is true. */ Main *bmain; + bool bmain_is_temp; } BPy_Library; static PyObject *bpy_lib_load(BPy_PropertyRNA *self, PyObject *args, PyObject *kwds); @@ -185,6 +188,7 @@ PyDoc_STRVAR( " :type assets_only: bool\n"); static PyObject *bpy_lib_load(BPy_PropertyRNA *self, PyObject *args, PyObject *kw) { + Main *bmain_base = CTX_data_main(BPY_context_get()); Main *bmain = self->ptr.data; /* Typically #G_MAIN */ BPy_Library *ret; const char *filename = NULL; @@ -212,6 +216,7 @@ static PyObject *bpy_lib_load(BPy_PropertyRNA *self, PyObject *args, PyObject *k BLI_path_abs(ret->abspath, BKE_main_blendfile_path(bmain)); ret->bmain = bmain; + ret->bmain_is_temp = (bmain != bmain_base); ret->blo_handle = NULL; ret->flag = ((is_link ? FILE_LINK : 0) | (is_rel ? FILE_RELPATH : 0) | @@ -344,8 +349,9 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) BKE_main_id_tag_all(bmain, LIB_TAG_PRE_EXISTING, true); /* here appending/linking starts */ + const int id_tag_extra = self->bmain_is_temp ? LIB_TAG_TEMP_MAIN : 0; struct LibraryLink_Params liblink_params; - BLO_library_link_params_init(&liblink_params, bmain, self->flag); + BLO_library_link_params_init(&liblink_params, bmain, self->flag, id_tag_extra); mainl = BLO_library_link_begin(&(self->blo_handle), self->relpath, &liblink_params); @@ -372,6 +378,12 @@ static PyObject *bpy_lib_exit(BPy_Library *self, PyObject *UNUSED(args)) ID *id = BLO_library_link_named_part( mainl, &(self->blo_handle), idcode, item_idname, &liblink_params); if (id) { + + if (self->bmain_is_temp) { + /* If this fails, #LibraryLink_Params.id_tag_extra is not being applied. */ + BLI_assert(id->tag & LIB_TAG_TEMP_MAIN); + } + #ifdef USE_RNA_DATABLOCKS /* swap name for pointer to the id */ item_dst = PyCapsule_New((void *)id, NULL, NULL); diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index cdf121a6864..7a43c9cb997 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -2061,6 +2061,19 @@ static int pyrna_py_to_prop( Py_XDECREF(value_new); return -1; } + + if (value_owner_id->tag & LIB_TAG_TEMP_MAIN) { + /* Allow passing temporary ID's to functions, but not attribute assignment. */ + if (ptr->type != &RNA_Function) { + PyErr_Format(PyExc_TypeError, + "%.200s %.200s.%.200s ID type assignment is temporary, can't assign", + error_prefix, + RNA_struct_identifier(ptr->type), + RNA_property_identifier(prop)); + Py_XDECREF(value_new); + return -1; + } + } } } @@ -4598,13 +4611,12 @@ static PyObject *pyrna_prop_collection_getattro(BPy_PropertyRNA *self, PyObject #else { /* Could just do this except for 1 awkward case. - * PyObject_GenericGetAttr((PyObject *)self, pyname); - * so as to support 'bpy.data.library.load()' - * note, this _only_ supports static methods */ + * `PyObject_GenericGetAttr((PyObject *)self, pyname);` + * so as to support `bpy.data.library.load()` */ PyObject *ret = PyObject_GenericGetAttr((PyObject *)self, pyname); - if (ret == NULL && name[0] != '_') { /* Avoid inheriting __call__ and similar. */ + if (ret == NULL && name[0] != '_') { /* Avoid inheriting `__call__` and similar. */ /* Since this is least common case, handle it last. */ PointerRNA r_ptr; if (RNA_property_collection_type_get(&self->ptr, self->prop, &r_ptr)) { diff --git a/source/blender/python/intern/bpy_rna_data.c b/source/blender/python/intern/bpy_rna_data.c new file mode 100644 index 00000000000..3771cc05490 --- /dev/null +++ b/source/blender/python/intern/bpy_rna_data.c @@ -0,0 +1,219 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup pythonintern + * + * This file defines the API to support temporarily creating #Main data. + * The only use case for this is currently to support temporarily loading data-blocks + * which can be freed, without them polluting the current #G_MAIN. + * + * This is exposed via a context manager `bpy.types.BlendData.temp_data(...)` + * which returns a new `bpy.types.BlendData` that is freed once the context manager exits. + */ + +#include <Python.h> +#include <stddef.h> + +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "BKE_global.h" +#include "BKE_main.h" + +#include "RNA_access.h" + +#include "bpy_rna.h" +#include "bpy_rna_data.h" + +typedef struct { + PyObject_HEAD /* required python macro */ + BPy_StructRNA *data_rna; + char filepath[1024]; +} BPy_DataContext; + +static PyObject *bpy_rna_data_temp_data(PyObject *self, PyObject *args, PyObject *kwds); +static PyObject *bpy_rna_data_context_enter(BPy_DataContext *self); +static PyObject *bpy_rna_data_context_exit(BPy_DataContext *self, PyObject *args); + +static PyMethodDef bpy_rna_data_context_methods[] = { + {"__enter__", (PyCFunction)bpy_rna_data_context_enter, METH_NOARGS}, + {"__exit__", (PyCFunction)bpy_rna_data_context_exit, METH_VARARGS}, + {NULL} /* sentinel */ +}; + +static int bpy_rna_data_context_traverse(BPy_DataContext *self, visitproc visit, void *arg) +{ + Py_VISIT(self->data_rna); + return 0; +} + +static int bpy_rna_data_context_clear(BPy_DataContext *self) +{ + Py_CLEAR(self->data_rna); + return 0; +} + +static void bpy_rna_data_context_dealloc(BPy_DataContext *self) +{ + PyObject_GC_UnTrack(self); + Py_CLEAR(self->data_rna); + PyObject_GC_Del(self); +} + +static PyTypeObject bpy_rna_data_context_Type = { + PyVarObject_HEAD_INIT(NULL, 0) "bpy_rna_data_context", /* tp_name */ + sizeof(BPy_DataContext), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)bpy_rna_data_context_dealloc, /* tp_dealloc */ + 0, /* tp_vectorcall_offset */ + NULL, /* getattrfunc tp_getattr; */ + NULL, /* setattrfunc tp_setattr; */ + NULL, + /* tp_compare */ /* DEPRECATED in python 3.0! */ + NULL, /* tp_repr */ + + /* Method suites for standard classes */ + + NULL, /* PyNumberMethods *tp_as_number; */ + NULL, /* PySequenceMethods *tp_as_sequence; */ + NULL, /* PyMappingMethods *tp_as_mapping; */ + + /* More standard operations (here for binary compatibility) */ + + NULL, /* hashfunc tp_hash; */ + NULL, /* ternaryfunc tp_call; */ + NULL, /* reprfunc tp_str; */ + + /* will only use these if this is a subtype of a py class */ + NULL /*PyObject_GenericGetAttr is assigned later */, /* getattrofunc tp_getattro; */ + NULL, /* setattrofunc tp_setattro; */ + + /* Functions to access object as input/output buffer */ + NULL, /* PyBufferProcs *tp_as_buffer; */ + + /*** Flags to define presence of optional/expanded features ***/ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* long tp_flags; */ + + NULL, /* char *tp_doc; Documentation string */ + /*** Assigned meaning in release 2.0 ***/ + /* call function for all accessible objects */ + (traverseproc)bpy_rna_data_context_traverse, /* traverseproc tp_traverse; */ + + /* delete references to contained objects */ + (inquiry)bpy_rna_data_context_clear, /* inquiry tp_clear; */ + + /*** Assigned meaning in release 2.1 ***/ + /*** rich comparisons (subclassed) ***/ + NULL, /* richcmpfunc tp_richcompare; */ + + /*** weak reference enabler ***/ + 0, + /*** Added in release 2.2 ***/ + /* Iterators */ + NULL, /* getiterfunc tp_iter; */ + NULL, /* iternextfunc tp_iternext; */ + + /*** Attribute descriptor and subclassing stuff ***/ + bpy_rna_data_context_methods, /* struct PyMethodDef *tp_methods; */ + NULL, /* struct PyMemberDef *tp_members; */ + NULL, /* struct PyGetSetDef *tp_getset; */ + NULL, /* struct _typeobject *tp_base; */ + NULL, /* PyObject *tp_dict; */ + NULL, /* descrgetfunc tp_descr_get; */ + NULL, /* descrsetfunc tp_descr_set; */ + 0, /* long tp_dictoffset; */ + NULL, /* initproc tp_init; */ + NULL, /* allocfunc tp_alloc; */ + NULL, /* newfunc tp_new; */ + /* Low-level free-memory routine */ + NULL, /* freefunc tp_free; */ + /* For PyObject_IS_GC */ + NULL, /* inquiry tp_is_gc; */ + NULL, /* PyObject *tp_bases; */ + /* method resolution order */ + NULL, /* PyObject *tp_mro; */ + NULL, /* PyObject *tp_cache; */ + NULL, /* PyObject *tp_subclasses; */ + NULL, /* PyObject *tp_weaklist; */ + NULL, +}; + +PyDoc_STRVAR(bpy_rna_data_context_load_doc, + ".. method:: temp_data(filepath=None)\n" + "\n" + " A context manager that temporarily creates blender file data.\n" + "\n" + " :arg filepath: The file path for the newly temporary data. " + "When None, the path of the currently open file is used.\n" + " :type filepath: str or NoneType\n" + "\n" + " :return: Blend file data which is freed once the context exists.\n" + " :rtype: :class:`bpy.types.BlendData`\n"); + +static PyObject *bpy_rna_data_temp_data(PyObject *UNUSED(self), PyObject *args, PyObject *kw) +{ + BPy_DataContext *ret; + const char *filepath = NULL; + static const char *_keywords[] = {"filepath", NULL}; + static _PyArg_Parser _parser = {"|$z:temp_data", _keywords, 0}; + if (!_PyArg_ParseTupleAndKeywordsFast(args, kw, &_parser, &filepath)) { + return NULL; + } + + ret = PyObject_GC_New(BPy_DataContext, &bpy_rna_data_context_Type); + + STRNCPY(ret->filepath, filepath ? filepath : G_MAIN->name); + + return (PyObject *)ret; +} + +static PyObject *bpy_rna_data_context_enter(BPy_DataContext *self) +{ + Main *bmain_temp = BKE_main_new(); + PointerRNA ptr; + RNA_pointer_create(NULL, &RNA_BlendData, bmain_temp, &ptr); + + self->data_rna = (BPy_StructRNA *)pyrna_struct_CreatePyObject(&ptr); + + PyObject_GC_Track(self); + + return (PyObject *)self->data_rna; +} + +static PyObject *bpy_rna_data_context_exit(BPy_DataContext *self, PyObject *UNUSED(args)) +{ + BKE_main_free(self->data_rna->ptr.data); + RNA_POINTER_INVALIDATE(&self->data_rna->ptr); + Py_RETURN_NONE; +} + +PyMethodDef BPY_rna_data_context_method_def = { + "temp_data", + (PyCFunction)bpy_rna_data_temp_data, + METH_STATIC | METH_VARARGS | METH_KEYWORDS, + bpy_rna_data_context_load_doc, +}; + +int BPY_rna_data_context_type_ready(void) +{ + if (PyType_Ready(&bpy_rna_data_context_Type) < 0) { + return -1; + } + + return 0; +} diff --git a/source/blender/python/intern/bpy_rna_data.h b/source/blender/python/intern/bpy_rna_data.h new file mode 100644 index 00000000000..b1d226d9dc4 --- /dev/null +++ b/source/blender/python/intern/bpy_rna_data.h @@ -0,0 +1,29 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/** \file + * \ingroup pythonintern + */ + +#pragma once + +int BPY_rna_data_context_type_ready(void); + +extern PyMethodDef BPY_rna_data_context_method_def; + +#ifdef __cplusplus +} +#endif diff --git a/source/blender/python/intern/bpy_rna_types_capi.c b/source/blender/python/intern/bpy_rna_types_capi.c index 042f7b6fd67..9b15e84663d 100644 --- a/source/blender/python/intern/bpy_rna_types_capi.c +++ b/source/blender/python/intern/bpy_rna_types_capi.c @@ -36,6 +36,7 @@ #include "bpy_library.h" #include "bpy_rna.h" #include "bpy_rna_callback.h" +#include "bpy_rna_data.h" #include "bpy_rna_id_collection.h" #include "bpy_rna_types_capi.h" #include "bpy_rna_ui.h" @@ -56,6 +57,7 @@ static struct PyMethodDef pyrna_blenddata_methods[] = { {NULL, NULL, 0, NULL}, /* #BPY_rna_id_collection_user_map_method_def */ {NULL, NULL, 0, NULL}, /* #BPY_rna_id_collection_batch_remove_method_def */ {NULL, NULL, 0, NULL}, /* #BPY_rna_id_collection_orphans_purge_method_def */ + {NULL, NULL, 0, NULL}, /* #BPY_rna_data_context_method_def */ {NULL, NULL, 0, NULL}, }; @@ -207,8 +209,9 @@ void BPY_rna_types_extend_capi(void) ARRAY_SET_ITEMS(pyrna_blenddata_methods, BPY_rna_id_collection_user_map_method_def, BPY_rna_id_collection_batch_remove_method_def, - BPY_rna_id_collection_orphans_purge_method_def); - BLI_assert(ARRAY_SIZE(pyrna_blenddata_methods) == 4); + BPY_rna_id_collection_orphans_purge_method_def, + BPY_rna_data_context_method_def); + BLI_assert(ARRAY_SIZE(pyrna_blenddata_methods) == 5); pyrna_struct_type_extend_capi(&RNA_BlendData, pyrna_blenddata_methods, NULL); /* BlendDataLibraries */ diff --git a/source/blender/render/intern/multires_bake.c b/source/blender/render/intern/multires_bake.c index 1859886f563..cba4628b63a 100644 --- a/source/blender/render/intern/multires_bake.c +++ b/source/blender/render/intern/multires_bake.c @@ -658,10 +658,10 @@ static void get_ccgdm_data(DerivedMesh *lodm, /* get the original cage face index */ int cage_face_index = index_mp_to_orig ? index_mp_to_orig[poly_index] : poly_index; /* local offset in total cage face grids - * (1 << (2 * lvl)) is number of all polys for one cage face */ - int loc_cage_poly_offs = poly_index % (1 << (2 * lvl)); + * `(1 << (2 * lvl))` is number of all polys for one cage face */ + int loc_cage_poly_ofs = poly_index % (1 << (2 * lvl)); /* local offset in the vertex grid itself */ - int cell_index = loc_cage_poly_offs % (polys_per_grid_side * polys_per_grid_side); + int cell_index = loc_cage_poly_ofs % (polys_per_grid_side * polys_per_grid_side); int cell_side = (grid_size - 1) / polys_per_grid_side; /* row and column based on grid side */ int row = cell_index / polys_per_grid_side; @@ -1193,7 +1193,7 @@ static void apply_ao_callback(DerivedMesh *lores_dm, MLoopUV *mloopuv = lores_dm->getLoopDataArray(lores_dm, CD_MLOOPUV); MAOBakeData *ao_data = (MAOBakeData *)bake_data; - int i, k, perm_offs; + int i, k, perm_ofs; float pos[3], nrm[3]; float cen[3]; float axisX[3], axisY[3], axisZ[3]; @@ -1236,7 +1236,7 @@ static void apply_ao_callback(DerivedMesh *lores_dm, build_coordinate_frame(axisX, axisY, axisZ); /* static noise */ - perm_offs = (get_ao_random2(get_ao_random1(x) + y)) & (MAX_NUMBER_OF_AO_RAYS - 1); + perm_ofs = (get_ao_random2(get_ao_random1(x) + y)) & (MAX_NUMBER_OF_AO_RAYS - 1); /* importance sample shadow rays (cosine weighted) */ for (i = 0; i < ao_data->number_of_rays; i++) { @@ -1246,12 +1246,12 @@ static void apply_ao_callback(DerivedMesh *lores_dm, * a multi-dimensional domain (2D) */ const unsigned short I = - ao_data->permutation_table_1[(i + perm_offs) % ao_data->number_of_rays]; + ao_data->permutation_table_1[(i + perm_ofs) % ao_data->number_of_rays]; const unsigned short J = ao_data->permutation_table_2[i]; - const float JitPh = (get_ao_random2(I + perm_offs) & (MAX_NUMBER_OF_AO_RAYS - 1)) / + const float JitPh = (get_ao_random2(I + perm_ofs) & (MAX_NUMBER_OF_AO_RAYS - 1)) / ((float)MAX_NUMBER_OF_AO_RAYS); - const float JitTh = (get_ao_random1(J + perm_offs) & (MAX_NUMBER_OF_AO_RAYS - 1)) / + const float JitTh = (get_ao_random1(J + perm_ofs) & (MAX_NUMBER_OF_AO_RAYS - 1)) / ((float)MAX_NUMBER_OF_AO_RAYS); const float SiSqPhi = (I + JitPh) / ao_data->number_of_rays; const float Theta = (float)(2 * M_PI) * ((J + JitTh) / ao_data->number_of_rays); diff --git a/source/blender/render/intern/texture_procedural.c b/source/blender/render/intern/texture_procedural.c index b0ab20de10d..bea9dfbb0ed 100644 --- a/source/blender/render/intern/texture_procedural.c +++ b/source/blender/render/intern/texture_procedural.c @@ -555,10 +555,10 @@ static int mg_mFractalOrfBmTex(const Tex *tex, const float texvec[3], TexResult tex->noisebasis); if (texres->nor != NULL) { - float offs = tex->nabla / tex->noisesize; /* also scaling of texvec */ + float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */ /* calculate bumpnormal */ - texres->nor[0] = tex->ns_outscale * mgravefunc(texvec[0] + offs, + texres->nor[0] = tex->ns_outscale * mgravefunc(texvec[0] + ofs, texvec[1], texvec[2], tex->mg_H, @@ -566,7 +566,7 @@ static int mg_mFractalOrfBmTex(const Tex *tex, const float texvec[3], TexResult tex->mg_octaves, tex->noisebasis); texres->nor[1] = tex->ns_outscale * mgravefunc(texvec[0], - texvec[1] + offs, + texvec[1] + ofs, texvec[2], tex->mg_H, tex->mg_lacunarity, @@ -574,7 +574,7 @@ static int mg_mFractalOrfBmTex(const Tex *tex, const float texvec[3], TexResult tex->noisebasis); texres->nor[2] = tex->ns_outscale * mgravefunc(texvec[0], texvec[1], - texvec[2] + offs, + texvec[2] + ofs, tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, @@ -612,10 +612,10 @@ static int mg_ridgedOrHybridMFTex(const Tex *tex, const float texvec[3], TexResu tex->noisebasis); if (texres->nor != NULL) { - float offs = tex->nabla / tex->noisesize; /* also scaling of texvec */ + float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */ /* calculate bumpnormal */ - texres->nor[0] = tex->ns_outscale * mgravefunc(texvec[0] + offs, + texres->nor[0] = tex->ns_outscale * mgravefunc(texvec[0] + ofs, texvec[1], texvec[2], tex->mg_H, @@ -625,7 +625,7 @@ static int mg_ridgedOrHybridMFTex(const Tex *tex, const float texvec[3], TexResu tex->mg_gain, tex->noisebasis); texres->nor[1] = tex->ns_outscale * mgravefunc(texvec[0], - texvec[1] + offs, + texvec[1] + ofs, texvec[2], tex->mg_H, tex->mg_lacunarity, @@ -635,7 +635,7 @@ static int mg_ridgedOrHybridMFTex(const Tex *tex, const float texvec[3], TexResu tex->noisebasis); texres->nor[2] = tex->ns_outscale * mgravefunc(texvec[0], texvec[1], - texvec[2] + offs, + texvec[2] + ofs, tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, @@ -666,10 +666,10 @@ static int mg_HTerrainTex(const Tex *tex, const float texvec[3], TexResult *texr tex->noisebasis); if (texres->nor != NULL) { - float offs = tex->nabla / tex->noisesize; /* also scaling of texvec */ + float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */ /* calculate bumpnormal */ - texres->nor[0] = tex->ns_outscale * BLI_noise_mg_hetero_terrain(texvec[0] + offs, + texres->nor[0] = tex->ns_outscale * BLI_noise_mg_hetero_terrain(texvec[0] + ofs, texvec[1], texvec[2], tex->mg_H, @@ -678,7 +678,7 @@ static int mg_HTerrainTex(const Tex *tex, const float texvec[3], TexResult *texr tex->mg_offset, tex->noisebasis); texres->nor[1] = tex->ns_outscale * BLI_noise_mg_hetero_terrain(texvec[0], - texvec[1] + offs, + texvec[1] + ofs, texvec[2], tex->mg_H, tex->mg_lacunarity, @@ -687,7 +687,7 @@ static int mg_HTerrainTex(const Tex *tex, const float texvec[3], TexResult *texr tex->noisebasis); texres->nor[2] = tex->ns_outscale * BLI_noise_mg_hetero_terrain(texvec[0], texvec[1], - texvec[2] + offs, + texvec[2] + ofs, tex->mg_H, tex->mg_lacunarity, tex->mg_octaves, @@ -711,24 +711,24 @@ static int mg_distNoiseTex(const Tex *tex, const float texvec[3], TexResult *tex texvec[0], texvec[1], texvec[2], tex->dist_amount, tex->noisebasis, tex->noisebasis2); if (texres->nor != NULL) { - float offs = tex->nabla / tex->noisesize; /* also scaling of texvec */ + float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */ /* calculate bumpnormal */ - texres->nor[0] = BLI_noise_mg_variable_lacunarity(texvec[0] + offs, + texres->nor[0] = BLI_noise_mg_variable_lacunarity(texvec[0] + ofs, texvec[1], texvec[2], tex->dist_amount, tex->noisebasis, tex->noisebasis2); texres->nor[1] = BLI_noise_mg_variable_lacunarity(texvec[0], - texvec[1] + offs, + texvec[1] + ofs, texvec[2], tex->dist_amount, tex->noisebasis, tex->noisebasis2); texres->nor[2] = BLI_noise_mg_variable_lacunarity(texvec[0], texvec[1], - texvec[2] + offs, + texvec[2] + ofs, tex->dist_amount, tex->noisebasis, tex->noisebasis2); @@ -805,14 +805,14 @@ static int voronoiTex(const Tex *tex, const float texvec[3], TexResult *texres) } if (texres->nor != NULL) { - float offs = tex->nabla / tex->noisesize; /* also scaling of texvec */ + float ofs = tex->nabla / tex->noisesize; /* also scaling of texvec */ /* calculate bumpnormal */ - BLI_noise_voronoi(texvec[0] + offs, texvec[1], texvec[2], da, pa, tex->vn_mexp, tex->vn_distm); + BLI_noise_voronoi(texvec[0] + ofs, texvec[1], texvec[2], da, pa, tex->vn_mexp, tex->vn_distm); texres->nor[0] = sc * fabsf(dot_v4v4(&tex->vn_w1, da)); - BLI_noise_voronoi(texvec[0], texvec[1] + offs, texvec[2], da, pa, tex->vn_mexp, tex->vn_distm); + BLI_noise_voronoi(texvec[0], texvec[1] + ofs, texvec[2], da, pa, tex->vn_mexp, tex->vn_distm); texres->nor[1] = sc * fabsf(dot_v4v4(&tex->vn_w1, da)); - BLI_noise_voronoi(texvec[0], texvec[1], texvec[2] + offs, da, pa, tex->vn_mexp, tex->vn_distm); + BLI_noise_voronoi(texvec[0], texvec[1], texvec[2] + ofs, da, pa, tex->vn_mexp, tex->vn_distm); texres->nor[2] = sc * fabsf(dot_v4v4(&tex->vn_w1, da)); tex_normal_derivate(tex, texres); diff --git a/source/blender/shader_fx/intern/FX_ui_common.c b/source/blender/shader_fx/intern/FX_ui_common.c index 9a86e1e96f5..8a259c6aaff 100644 --- a/source/blender/shader_fx/intern/FX_ui_common.c +++ b/source/blender/shader_fx/intern/FX_ui_common.c @@ -241,14 +241,9 @@ static bool shaderfx_ui_poll(const bContext *C, PanelType *UNUSED(pt)) */ PanelType *shaderfx_panel_register(ARegionType *region_type, ShaderFxType type, PanelDrawFn draw) { + PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__); - /* Get the name for the effect's panel. */ - char panel_idname[BKE_ST_MAXNAME]; - BKE_shaderfxType_panel_id(type, panel_idname); - - PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname); - - BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME); + BKE_shaderfxType_panel_id(type, panel_type->idname); BLI_strncpy(panel_type->label, "", BKE_ST_MAXNAME); BLI_strncpy(panel_type->context, "shaderfx", BKE_ST_MAXNAME); BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME); @@ -282,13 +277,9 @@ PanelType *shaderfx_subpanel_register(ARegionType *region_type, PanelDrawFn draw, PanelType *parent) { - /* Create the subpanel's ID name. */ - char panel_idname[BKE_ST_MAXNAME]; - BLI_snprintf(panel_idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name); - - PanelType *panel_type = MEM_callocN(sizeof(PanelType), panel_idname); + PanelType *panel_type = MEM_callocN(sizeof(PanelType), __func__); - BLI_strncpy(panel_type->idname, panel_idname, BKE_ST_MAXNAME); + BLI_snprintf(panel_type->idname, BKE_ST_MAXNAME, "%s_%s", parent->idname, name); BLI_strncpy(panel_type->label, label, BKE_ST_MAXNAME); BLI_strncpy(panel_type->context, "shaderfx", BKE_ST_MAXNAME); BLI_strncpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA, BKE_ST_MAXNAME); diff --git a/source/blender/windowmanager/WM_types.h b/source/blender/windowmanager/WM_types.h index f12832faa45..b46a354c7ae 100644 --- a/source/blender/windowmanager/WM_types.h +++ b/source/blender/windowmanager/WM_types.h @@ -427,6 +427,7 @@ typedef struct wmNotifier { #define ND_SPACE_CHANGED (19 << 16) /*sent to a new editor type after it's replaced an old one*/ #define ND_SPACE_CLIP (20 << 16) #define ND_SPACE_FILE_PREVIEW (21 << 16) +#define ND_SPACE_SPREADSHEET (22 << 16) /* subtype, 256 entries too */ #define NOTE_SUBTYPE 0x0000FF00 @@ -461,6 +462,7 @@ typedef struct wmNotifier { #define NA_SELECTED 6 #define NA_ACTIVATED 7 #define NA_PAINTING 8 +#define NA_JOB_FINISHED 9 /* ************** Gesture Manager data ************** */ diff --git a/source/blender/windowmanager/intern/wm_cursors.c b/source/blender/windowmanager/intern/wm_cursors.c index e32552063af..d6e4a93f6a6 100644 --- a/source/blender/windowmanager/intern/wm_cursors.c +++ b/source/blender/windowmanager/intern/wm_cursors.c @@ -303,7 +303,7 @@ static void wm_cursor_warp_relative(wmWindow *win, int x, int y) { /* note: don't use wmEvent coords because of continuous grab T36409. */ int cx, cy; - wm_get_cursor_position(win, &cx, &cy); + wm_cursor_position_get(win, &cx, &cy); WM_cursor_warp(win, cx + x, cy + y); } diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c index 85611a0be93..e0c4ab8eaf3 100644 --- a/source/blender/windowmanager/intern/wm_draw.c +++ b/source/blender/windowmanager/intern/wm_draw.c @@ -98,7 +98,7 @@ static void wm_paintcursor_draw(bContext *C, ScrArea *area, ARegion *region) return; } - LISTBASE_FOREACH (wmPaintCursor *, pc, &wm->paintcursors) { + LISTBASE_FOREACH_MUTABLE (wmPaintCursor *, pc, &wm->paintcursors) { if ((pc->space_type != SPACE_TYPE_ANY) && (area->spacetype != pc->space_type)) { continue; } @@ -117,7 +117,7 @@ static void wm_paintcursor_draw(bContext *C, ScrArea *area, ARegion *region) if (ELEM(win->grabcursor, GHOST_kGrabWrap, GHOST_kGrabHide)) { int x = 0, y = 0; - wm_get_cursor_position(win, &x, &y); + wm_cursor_position_get(win, &x, &y); pc->draw(C, x, y, pc->customdata); } else { diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 18ec8402482..470952956c8 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -2343,7 +2343,7 @@ static int wm_handler_fileselect_do(bContext *C, wm_window_make_drawable(wm, ctx_win); /* Ensure correct cursor position, otherwise, popups may close immediately after * opening (UI_BLOCK_MOVEMOUSE_QUIT). */ - wm_get_cursor_position(ctx_win, &ctx_win->eventstate->x, &ctx_win->eventstate->y); + wm_cursor_position_get(ctx_win, &ctx_win->eventstate->x, &ctx_win->eventstate->y); wm->winactive = ctx_win; /* Reports use this... */ if (handler->context.win == win) { handler->context.win = NULL; @@ -3002,7 +3002,7 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) * wasn't handled, the KM_RELEASE will become a KM_CLICK */ if (event->val == KM_PRESS) { - if (event->prevval != KM_PRESS) { + if (event->is_repeat == false) { win->event_queue_check_click = true; win->event_queue_check_drag = true; } diff --git a/source/blender/windowmanager/intern/wm_files_link.c b/source/blender/windowmanager/intern/wm_files_link.c index 6a1fc84774c..bf7cf81f0a9 100644 --- a/source/blender/windowmanager/intern/wm_files_link.c +++ b/source/blender/windowmanager/intern/wm_files_link.c @@ -229,6 +229,7 @@ static void wm_link_do(WMLinkAppendData *lapp_data, Library *lib; const int flag = lapp_data->flag; + const int id_tag_extra = 0; LinkNode *liblink, *itemlink; int lib_idx, item_idx; @@ -255,7 +256,7 @@ static void wm_link_do(WMLinkAppendData *lapp_data, /* here appending/linking starts */ struct LibraryLink_Params liblink_params; BLO_library_link_params_init_with_context( - &liblink_params, bmain, flag, scene, view_layer, v3d); + &liblink_params, bmain, flag, id_tag_extra, scene, view_layer, v3d); mainl = BLO_library_link_begin(&bh, libname, &liblink_params); lib = mainl->curlib; diff --git a/source/blender/windowmanager/intern/wm_platform_support.c b/source/blender/windowmanager/intern/wm_platform_support.c index 65e1cd45e02..45618e9d6d3 100644 --- a/source/blender/windowmanager/intern/wm_platform_support.c +++ b/source/blender/windowmanager/intern/wm_platform_support.c @@ -43,7 +43,9 @@ #define WM_PLATFORM_SUPPORT_TEXT_SIZE 1024 -/* Check if user has already approved the given platform_support_key. */ +/** + * Check if user has already approved the given `platform_support_key`. + */ static bool wm_platform_support_check_approval(const char *platform_support_key, bool update) { const char *const cfgdir = BKE_appdir_folder_id(BLENDER_USER_CONFIG, NULL); @@ -120,11 +122,11 @@ bool WM_platform_support_perform_checks() eGPUSupportLevel support_level = GPU_platform_support_level(); const char *platform_key = GPU_platform_support_level_key(); - /* check if previous check matches the current check. Don't update the approval when running in - * `background`. this could have been triggered by installing addons via installers. */ + /* Check if previous check matches the current check. Don't update the approval when running in + * `background`. this could have been triggered by installing add-ons via installers. */ if (support_level != GPU_SUPPORT_LEVEL_UNSUPPORTED && !G.factory_startup && wm_platform_support_check_approval(platform_key, !G.background)) { - /* if it matches the user has confirmed and whishes to use it */ + /* If it matches the user has confirmed and wishes to use it. */ return result; } diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index f09a9aecb1d..2fc941c3d6b 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -520,7 +520,7 @@ void WM_window_set_dpi(const wmWindow *win) static void wm_window_update_eventstate(wmWindow *win) { /* Update mouse position when a window is activated. */ - wm_get_cursor_position(win, &win->eventstate->x, &win->eventstate->y); + wm_cursor_position_get(win, &win->eventstate->x, &win->eventstate->y); } static void wm_window_ensure_eventstate(wmWindow *win) @@ -983,15 +983,15 @@ void wm_cursor_position_to_ghost(wmWindow *win, int *x, int *y) GHOST_ClientToScreen(win->ghostwin, *x, *y, x, y); } -void wm_get_cursor_position(wmWindow *win, int *x, int *y) +void wm_cursor_position_get(wmWindow *win, int *r_x, int *r_y) { if (UNLIKELY(G.f & G_FLAG_EVENT_SIMULATE)) { - *x = win->eventstate->x; - *y = win->eventstate->y; + *r_x = win->eventstate->x; + *r_y = win->eventstate->y; return; } - GHOST_GetCursorPosition(g_system, x, y); - wm_cursor_position_from_ghost(win, x, y); + GHOST_GetCursorPosition(g_system, r_x, r_y); + wm_cursor_position_from_ghost(win, r_x, r_y); } typedef enum { diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h index 0ac67b987d7..f205f923ec8 100644 --- a/source/blender/windowmanager/wm_window.h +++ b/source/blender/windowmanager/wm_window.h @@ -69,8 +69,8 @@ void wm_window_swap_buffers(wmWindow *win); void wm_window_set_swap_interval(wmWindow *win, int interval); bool wm_window_get_swap_interval(wmWindow *win, int *intervalOut); -void wm_get_cursor_position(wmWindow *win, int *x, int *y); -void wm_cursor_position_from_ghost(wmWindow *win, int *x, int *y); +void wm_cursor_position_get(wmWindow *win, int *r_x, int *r_y); +void wm_cursor_position_from_ghost(wmWindow *win, int *r_x, int *r_y); void wm_cursor_position_to_ghost(wmWindow *win, int *x, int *y); #ifdef WITH_INPUT_IME |