diff options
author | Clément Foucault <foucault.clem@gmail.com> | 2022-01-27 16:37:24 +0300 |
---|---|---|
committer | Clément Foucault <foucault.clem@gmail.com> | 2022-01-27 16:37:24 +0300 |
commit | 6016dbb1a75566e1fb3ca257a1f13b9bba4467fd (patch) | |
tree | 30ca1741378f36e7c6af17beb1b12c46fb487d05 /source/blender/editors | |
parent | c453aaa0b2408b50af7d47722114f1903f27a6fc (diff) | |
parent | 0379ddac7d68114798c8963821fd821c1b3d7d28 (diff) |
Merge branch 'master' into temp-gpu-image-engine
# Conflicts:
# source/blender/blenkernel/CMakeLists.txt
# source/blender/draw/CMakeLists.txt
Diffstat (limited to 'source/blender/editors')
351 files changed, 14187 insertions, 13524 deletions
diff --git a/source/blender/editors/animation/drivers.c b/source/blender/editors/animation/drivers.c index f509898f2ee..bdcbac80699 100644 --- a/source/blender/editors/animation/drivers.c +++ b/source/blender/editors/animation/drivers.c @@ -879,10 +879,10 @@ EnumPropertyItem prop_driver_create_mapping_types[] = { }; /* Filtering callback for driver mapping types enum */ -static const EnumPropertyItem *driver_mapping_type_itemsf(bContext *C, - PointerRNA *UNUSED(owner_ptr), - PropertyRNA *UNUSED(owner_prop), - bool *r_free) +static const EnumPropertyItem *driver_mapping_type_itemf(bContext *C, + PointerRNA *UNUSED(owner_ptr), + PropertyRNA *UNUSED(owner_prop), + bool *r_free) { EnumPropertyItem *input = prop_driver_create_mapping_types; EnumPropertyItem *item = NULL; @@ -961,7 +961,7 @@ static int add_driver_button_none(bContext *C, wmOperator *op, short mapping_typ } if (ptr.owner_id && ptr.data && prop && RNA_property_animateable(&ptr, prop)) { - char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL); + char *path = RNA_path_from_ID_to_property(&ptr, prop); short flags = CREATEDRIVER_WITH_DEFAULT_DVAR; if (path) { @@ -1039,7 +1039,7 @@ static void UNUSED_FUNCTION(ANIM_OT_driver_button_add_menu)(wmOperatorType *ot) 0, "Mapping Type", "Method used to match target and driven properties"); - RNA_def_enum_funcs(ot->prop, driver_mapping_type_itemsf); + RNA_def_enum_funcs(ot->prop, driver_mapping_type_itemf); } /* Add Driver Button Operator ------------------------ */ @@ -1055,7 +1055,7 @@ static int add_driver_button_invoke(bContext *C, wmOperator *op, const wmEvent * if (ptr.owner_id && ptr.data && prop && RNA_property_animateable(&ptr, prop)) { /* 1) Create a new "empty" driver for this property */ - char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL); + char *path = RNA_path_from_ID_to_property(&ptr, prop); short flags = CREATEDRIVER_WITH_DEFAULT_DVAR; bool changed = false; @@ -1115,7 +1115,7 @@ static int remove_driver_button_exec(bContext *C, wmOperator *op) } if (ptr.owner_id && ptr.data && prop) { - char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL); + char *path = RNA_path_from_ID_to_property(&ptr, prop); if (path) { changed = ANIM_remove_driver(op->reports, ptr.owner_id, path, index, 0); @@ -1200,7 +1200,7 @@ static int copy_driver_button_exec(bContext *C, wmOperator *op) UI_context_active_but_prop_get(C, &ptr, &prop, &index); if (ptr.owner_id && ptr.data && prop && RNA_property_animateable(&ptr, prop)) { - char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL); + char *path = RNA_path_from_ID_to_property(&ptr, prop); if (path) { /* only copy the driver for the button that this was involved for */ @@ -1244,7 +1244,7 @@ static int paste_driver_button_exec(bContext *C, wmOperator *op) UI_context_active_but_prop_get(C, &ptr, &prop, &index); if (ptr.owner_id && ptr.data && prop && RNA_property_animateable(&ptr, prop)) { - char *path = BKE_animdata_driver_path_hack(C, &ptr, prop, NULL); + char *path = RNA_path_from_ID_to_property(&ptr, prop); if (path) { /* only copy the driver for the button that this was involved for */ diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c index 6fba2d9c258..ae8d04f51d3 100644 --- a/source/blender/editors/animation/keyframes_draw.c +++ b/source/blender/editors/animation/keyframes_draw.c @@ -496,7 +496,7 @@ static void ED_keylist_draw_list_elem_prepare_for_drawing(AnimKeylistDrawListEle } typedef struct AnimKeylistDrawList { - ListBase /* AnimKeylistDrawListElem*/ channels; + ListBase /* AnimKeylistDrawListElem */ channels; } AnimKeylistDrawList; AnimKeylistDrawList *ED_keylist_draw_list_create(void) diff --git a/source/blender/editors/animation/keyframes_edit.c b/source/blender/editors/animation/keyframes_edit.c index 145d67b7810..dfe6566df67 100644 --- a/source/blender/editors/animation/keyframes_edit.c +++ b/source/blender/editors/animation/keyframes_edit.c @@ -1283,6 +1283,61 @@ static short set_bezt_sine(KeyframeEditData *UNUSED(ked), BezTriple *bezt) return 0; } +static void handle_flatten(float vec[3][3], const int idx, const float direction[2]) +{ + BLI_assert_msg(idx == 0 || idx == 2, "handle_flatten() expects a handle index"); + + add_v2_v2v2(vec[idx], vec[1], direction); +} + +static void handle_set_length(float vec[3][3], const int idx, const float handle_length) +{ + BLI_assert_msg(idx == 0 || idx == 2, "handle_set_length() expects a handle index"); + + float handle_direction[2]; + sub_v2_v2v2(handle_direction, vec[idx], vec[1]); + normalize_v2_length(handle_direction, handle_length); + add_v2_v2v2(vec[idx], vec[1], handle_direction); +} + +void ANIM_fcurve_equalize_keyframes_loop(FCurve *fcu, + const eEditKeyframes_Equalize mode, + const float handle_length, + const bool flatten) +{ + uint i; + BezTriple *bezt; + const float flat_direction_left[2] = {-handle_length, 0.f}; + const float flat_direction_right[2] = {handle_length, 0.f}; + + /* Loop through an F-Curves keyframes. */ + for (bezt = fcu->bezt, i = 0; i < fcu->totvert; bezt++, i++) { + if ((bezt->f2 & SELECT) == 0) { + continue; + } + + /* Perform handle equalization if mode is 'Both' or 'Left'. */ + if (mode & EQUALIZE_HANDLES_LEFT) { + if (flatten) { + handle_flatten(bezt->vec, 0, flat_direction_left); + } + else { + handle_set_length(bezt->vec, 0, handle_length); + } + } + + /* Perform handle equalization if mode is 'Both' or 'Right'. */ + if (mode & EQUALIZE_HANDLES_RIGHT) { + if (flatten) { + handle_flatten(bezt->vec, 2, flat_direction_right); + } + else { + handle_set_length(bezt->vec, 2, handle_length); + } + } + } +} + KeyframeEditFunc ANIM_editkeyframes_ipo(short mode) { switch (mode) { diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c index dc5d71b5a1e..92017c02858 100644 --- a/source/blender/editors/animation/keyframes_general.c +++ b/source/blender/editors/animation/keyframes_general.c @@ -307,11 +307,13 @@ void clean_fcurve(struct bAnimContext *ac, bAnimListElem *ale, float thresh, boo } } -/** Find the first segment of consecutive selected curve points, starting from \a start_index. +/** + * Find the first segment of consecutive selected curve points, starting from \a start_index. * Keys that have BEZT_FLAG_IGNORE_TAG set are treated as unselected. * \param r_segment_start_idx: returns the start index of the segment. * \param r_segment_len: returns the number of curve points in the segment. - * \return whether such a segment was found or not.*/ + * \return whether such a segment was found or not. + */ static bool find_fcurve_segment(FCurve *fcu, const int start_index, int *r_segment_start_idx, @@ -345,6 +347,67 @@ static bool find_fcurve_segment(FCurve *fcu, return in_segment; } +ListBase find_fcurve_segments(FCurve *fcu) +{ + ListBase segments = {NULL, NULL}; + int segment_start_idx = 0; + int segment_len = 0; + int current_index = 0; + + while (find_fcurve_segment(fcu, current_index, &segment_start_idx, &segment_len)) { + FCurveSegment *segment; + segment = MEM_callocN(sizeof(*segment), "FCurveSegment"); + segment->start_index = segment_start_idx; + segment->length = segment_len; + BLI_addtail(&segments, segment); + current_index = segment_start_idx + segment_len; + } + return segments; +} + +static BezTriple fcurve_segment_start_get(FCurve *fcu, int index) +{ + BezTriple start_bezt = index - 1 >= 0 ? fcu->bezt[index - 1] : fcu->bezt[index]; + return start_bezt; +} + +static BezTriple fcurve_segment_end_get(FCurve *fcu, int index) +{ + BezTriple end_bezt = index < fcu->totvert ? fcu->bezt[index] : fcu->bezt[index - 1]; + return end_bezt; +} + +/* ---------------- */ + +void blend_to_neighbor_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float factor) +{ + const float blend_factor = fabs(factor * 2 - 1); + BezTriple target_bezt; + /* Find which key to blend towards. */ + if (factor < 0.5f) { + target_bezt = fcurve_segment_start_get(fcu, segment->start_index); + } + else { + target_bezt = fcurve_segment_end_get(fcu, segment->start_index + segment->length); + } + /* Blend each key individually. */ + for (int i = segment->start_index; i < segment->start_index + segment->length; i++) { + fcu->bezt[i].vec[1][1] = interpf(target_bezt.vec[1][1], fcu->bezt[i].vec[1][1], blend_factor); + } +} + +/* ---------------- */ + +void breakdown_fcurve_segment(FCurve *fcu, FCurveSegment *segment, const float factor) +{ + BezTriple left_bezt = fcurve_segment_start_get(fcu, segment->start_index); + BezTriple right_bezt = fcurve_segment_end_get(fcu, segment->start_index + segment->length); + + for (int i = segment->start_index; i < segment->start_index + segment->length; i++) { + fcu->bezt[i].vec[1][1] = interpf(right_bezt.vec[1][1], left_bezt.vec[1][1], factor); + } +} + /* ---------------- */ /* Check if the keyframe interpolation type is supported */ @@ -440,15 +503,12 @@ bool decimate_fcurve(bAnimListElem *ale, float remove_ratio, float error_sq_max) fcu->bezt[i].f2 &= ~BEZT_FLAG_TEMP_TAG; } - /* Only decimate the individual selected curve segments. */ - int segment_start_idx = 0; - int segment_len = 0; - int current_index = 0; - - while (find_fcurve_segment(fcu, current_index, &segment_start_idx, &segment_len)) { - decimate_fcurve_segment(fcu, segment_start_idx, segment_len, remove_ratio, error_sq_max); - current_index = segment_start_idx + segment_len; + ListBase segments = find_fcurve_segments(fcu); + LISTBASE_FOREACH (FCurveSegment *, segment, &segments) { + decimate_fcurve_segment( + fcu, segment->start_index, segment->length, remove_ratio, error_sq_max); } + BLI_freelistN(&segments); uint old_totvert = fcu->totvert; fcu->bezt = NULL; diff --git a/source/blender/editors/animation/keyframes_keylist.cc b/source/blender/editors/animation/keyframes_keylist.cc index 8dae46766fa..aba73ec141b 100644 --- a/source/blender/editors/animation/keyframes_keylist.cc +++ b/source/blender/editors/animation/keyframes_keylist.cc @@ -80,7 +80,7 @@ struct AnimKeylist { ListBase /* ActKeyColumn */ key_columns; /* Last accessed column in the key_columns list base. Inserting columns are typically done in * order. The last accessed column is used as starting point to search for a location to add or - * update the next column.*/ + * update the next column. */ std::optional<ActKeyColumn *> last_accessed_column = std::nullopt; struct { @@ -850,7 +850,6 @@ bool actkeyblock_is_valid(const ActKeyColumn *ac) return ac != nullptr && ac->next != nullptr && ac->totblock > 0; } -/* Checks if ActKeyBlock should exist... */ int actkeyblock_get_valid_hold(const ActKeyColumn *ac) { /* check that block is valid */ diff --git a/source/blender/editors/animation/keyframes_keylist_test.cc b/source/blender/editors/animation/keyframes_keylist_test.cc index 17a21be5ae8..914693842ca 100644 --- a/source/blender/editors/animation/keyframes_keylist_test.cc +++ b/source/blender/editors/animation/keyframes_keylist_test.cc @@ -26,12 +26,12 @@ static void build_fcurve(FCurve &fcurve) fcurve.totvert = 3; fcurve.bezt = static_cast<BezTriple *>( MEM_callocN(sizeof(BezTriple) * fcurve.totvert, "BezTriples")); - fcurve.bezt[0].vec[1][0] = 10.f; - fcurve.bezt[0].vec[1][1] = 1.f; - fcurve.bezt[1].vec[1][0] = 20.f; - fcurve.bezt[1].vec[1][1] = 2.f; - fcurve.bezt[2].vec[1][0] = 30.f; - fcurve.bezt[2].vec[1][1] = 1.f; + fcurve.bezt[0].vec[1][0] = 10.0f; + fcurve.bezt[0].vec[1][1] = 1.0f; + fcurve.bezt[1].vec[1][0] = 20.0f; + fcurve.bezt[1].vec[1][1] = 2.0f; + fcurve.bezt[2].vec[1][0] = 30.0f; + fcurve.bezt[2].vec[1][1] = 1.0f; } static AnimKeylist *create_test_keylist() diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c index 25d2f6c510b..0a435a9034a 100644 --- a/source/blender/editors/animation/keyframing.c +++ b/source/blender/editors/animation/keyframing.c @@ -580,7 +580,7 @@ int insert_vert_fcurve( beztr.ipo = BEZT_IPO_BEZ; } else { - /* for UI usage - defaults should come from the userprefs and/or toolsettings */ + /* For UI usage - defaults should come from the user-preferences and/or tool-settings. */ beztr.h1 = beztr.h2 = U.keyhandles_new; /* use default handle type here */ /* use default interpolation mode, with exceptions for int/discrete values */ diff --git a/source/blender/editors/armature/armature_intern.h b/source/blender/editors/armature/armature_intern.h index 97f8c0cf630..252cf806e34 100644 --- a/source/blender/editors/armature/armature_intern.h +++ b/source/blender/editors/armature/armature_intern.h @@ -297,7 +297,7 @@ void armature_tag_select_mirrored(struct bArmature *arm); * Helper function for tools to work on mirrored parts. * it leaves mirrored bones selected then too, which is a good indication of what happened. */ -void armature_select_mirrored_ex(struct bArmature *arm, const int flag); +void armature_select_mirrored_ex(struct bArmature *arm, int flag); void armature_select_mirrored(struct bArmature *arm); /** Only works when tagged. */ void armature_tag_unselect(struct bArmature *arm); diff --git a/source/blender/editors/armature/meshlaplacian.c b/source/blender/editors/armature/meshlaplacian.c index 990e7589d9d..787d7cbaab0 100644 --- a/source/blender/editors/armature/meshlaplacian.c +++ b/source/blender/editors/armature/meshlaplacian.c @@ -1618,8 +1618,7 @@ static void harmonic_coordinates_bind(MeshDeformModifierData *mmd, MeshDeformBin mdb->cagemesh_cache.mpoly = me->mpoly; mdb->cagemesh_cache.mloop = me->mloop; mdb->cagemesh_cache.looptri = BKE_mesh_runtime_looptri_ensure(me); - /* can be NULL */ - mdb->cagemesh_cache.poly_nors = CustomData_get_layer(&me->pdata, CD_NORMAL); + mdb->cagemesh_cache.poly_nors = BKE_mesh_poly_normals_ensure(me); } /* make bounding box equal size in all directions, add padding, and compute diff --git a/source/blender/editors/armature/pose_edit.c b/source/blender/editors/armature/pose_edit.c index 772fe8f3196..8bd6c9f54fd 100644 --- a/source/blender/editors/armature/pose_edit.c +++ b/source/blender/editors/armature/pose_edit.c @@ -160,7 +160,7 @@ static bool pose_has_protected_selected(Object *ob, short warn) bArmature *arm = ob->data; for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - if (pchan->bone && (pchan->bone->layer & arm->layer)) { + if (pchan->bone && BKE_pose_is_layer_visible(arm, pchan)) { if (pchan->bone->layer & arm->layer_protected) { if (pchan->bone->flag & BONE_SELECTED) { break; diff --git a/source/blender/editors/armature/pose_lib.c b/source/blender/editors/armature/pose_lib.c index 646356e7a45..dc96c777be0 100644 --- a/source/blender/editors/armature/pose_lib.c +++ b/source/blender/editors/armature/pose_lib.c @@ -1070,7 +1070,7 @@ static void poselib_apply_pose(tPoseLib_PreviewData *pld, else if (pchan->bone) { /* only ok if bone is visible and selected */ if ((pchan->bone->flag & BONE_SELECTED) && (pchan->bone->flag & BONE_HIDDEN_P) == 0 && - (pchan->bone->layer & arm->layer)) { + BKE_pose_is_layer_visible(arm, pchan)) { ok = 1; } } diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c index 17347aa57fe..0b889149f9d 100644 --- a/source/blender/editors/armature/pose_select.c +++ b/source/blender/editors/armature/pose_select.c @@ -746,7 +746,7 @@ static int pose_select_hierarchy_exec(bContext *C, wmOperator *op) const bool add_to_sel = RNA_boolean_get(op->ptr, "extend"); bool changed = false; - pchan_act = BKE_pose_channel_active(ob); + pchan_act = BKE_pose_channel_active_if_layer_visible(ob); if (pchan_act == NULL) { return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/asset/CMakeLists.txt b/source/blender/editors/asset/CMakeLists.txt index 2391f4af14d..086fab4ab47 100644 --- a/source/blender/editors/asset/CMakeLists.txt +++ b/source/blender/editors/asset/CMakeLists.txt @@ -48,6 +48,7 @@ set(SRC ED_asset_catalog.hh ED_asset_filter.h ED_asset_handle.h + ED_asset_indexer.h ED_asset_library.h ED_asset_list.h ED_asset_list.hh diff --git a/source/blender/editors/asset/ED_asset_catalog.h b/source/blender/editors/asset/ED_asset_catalog.h index be99de01173..acb0b67d9c0 100644 --- a/source/blender/editors/asset/ED_asset_catalog.h +++ b/source/blender/editors/asset/ED_asset_catalog.h @@ -28,8 +28,8 @@ extern "C" { #endif -struct Main; struct AssetLibrary; +struct Main; void ED_asset_catalogs_save_from_main_path(struct AssetLibrary *library, const struct Main *bmain); diff --git a/source/blender/editors/asset/ED_asset_mark_clear.h b/source/blender/editors/asset/ED_asset_mark_clear.h index 8e6a8e11d69..8f10e769c52 100644 --- a/source/blender/editors/asset/ED_asset_mark_clear.h +++ b/source/blender/editors/asset/ED_asset_mark_clear.h @@ -25,8 +25,8 @@ extern "C" { #endif struct ID; -struct bContext; struct Main; +struct bContext; /** * Mark the datablock as asset. @@ -50,7 +50,8 @@ void ED_asset_generate_preview(const struct bContext *C, struct ID *id); * This clears the Fake User. If for some reason the datablock is meant to be saved anyway, the * caller is responsible for explicitly setting the Fake User. * - * \return whether the asset metadata was actually removed; false when the ID was not an asset. */ + * \return whether the asset metadata was actually removed; false when the ID was not an asset. + */ bool ED_asset_clear_id(struct ID *id); void ED_assets_pre_save(struct Main *bmain); diff --git a/source/blender/editors/asset/ED_asset_type.h b/source/blender/editors/asset/ED_asset_type.h index 36cbb4591e9..e1c327808aa 100644 --- a/source/blender/editors/asset/ED_asset_type.h +++ b/source/blender/editors/asset/ED_asset_type.h @@ -30,7 +30,7 @@ struct ID; bool ED_asset_type_id_is_non_experimental(const struct ID *id); #define ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_FLAGS \ - (FILTER_ID_MA | FILTER_ID_OB | FILTER_ID_AC | FILTER_ID_WO) + (FILTER_ID_MA | FILTER_ID_OB | FILTER_ID_AC | FILTER_ID_WO | FILTER_ID_NT) /** * Check if the asset type for \a id (which doesn't need to be an asset right now) can be an asset, @@ -52,7 +52,8 @@ int64_t ED_asset_types_supported_as_filter_flags(void); * strings with this (not all UI code supports dynamic strings nicely). * Should start with a consonant, so usages can prefix it with "a" (not "an"). */ -#define ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_UI_STRING "Material, Object, Pose Action, or World" +#define ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_UI_STRING \ + "Material, Object, Pose Action, Node Group or World" #ifdef __cplusplus } diff --git a/source/blender/editors/asset/intern/asset_indexer.cc b/source/blender/editors/asset/intern/asset_indexer.cc index 4107d28b5e3..336ccff900c 100644 --- a/source/blender/editors/asset/intern/asset_indexer.cc +++ b/source/blender/editors/asset/intern/asset_indexer.cc @@ -39,6 +39,7 @@ #include "BKE_appdir.h" #include "BKE_asset.h" #include "BKE_asset_catalog.hh" +#include "BKE_idprop.hh" #include "BKE_preferences.h" #include "CLG_log.h" @@ -49,6 +50,7 @@ namespace blender::ed::asset::index { using namespace blender::io::serialize; using namespace blender::bke; +using namespace blender::bke::idprop; /** * \file asset_indexer.cc @@ -69,12 +71,13 @@ using namespace blender::bke; * "catalog_name": "<catalog_name>", * "description": "<description>", * "author": "<author>", - * "tags": ["<tag>"] + * "tags": ["<tag>"], + * "properties": [..] * }] * } * \endcode * - * NOTE: entries, author, description and tags are optional attributes. + * NOTE: entries, author, description, tags and properties are optional attributes. * * NOTE: File browser uses name and idcode separate. Inside the index they are joined together like * #ID.name. @@ -88,6 +91,7 @@ constexpr StringRef ATTRIBUTE_ENTRIES_CATALOG_NAME("catalog_name"); constexpr StringRef ATTRIBUTE_ENTRIES_DESCRIPTION("description"); constexpr StringRef ATTRIBUTE_ENTRIES_AUTHOR("author"); constexpr StringRef ATTRIBUTE_ENTRIES_TAGS("tags"); +constexpr StringRef ATTRIBUTE_ENTRIES_PROPERTIES("properties"); /** Abstract class for #BlendFile and #AssetIndexFile. */ class AbstractFile { @@ -145,7 +149,7 @@ struct AssetEntryReader { /** * \brief Lookup table containing the elements of the entry. */ - ObjectValue::Lookup lookup; + DictionaryValue::Lookup lookup; StringRefNull get_name_with_idcode() const { @@ -153,7 +157,7 @@ struct AssetEntryReader { } public: - AssetEntryReader(const ObjectValue &entry) : lookup(entry.create_lookup()) + AssetEntryReader(const DictionaryValue &entry) : lookup(entry.create_lookup()) { } @@ -204,7 +208,7 @@ struct AssetEntryReader { void add_tags_to_meta_data(AssetMetaData *asset_data) const { - const ObjectValue::LookupValue *value_ptr = lookup.lookup_ptr(ATTRIBUTE_ENTRIES_TAGS); + const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr(ATTRIBUTE_ENTRIES_TAGS); if (value_ptr == nullptr) { return; } @@ -216,14 +220,28 @@ struct AssetEntryReader { BKE_asset_metadata_tag_add(asset_data, tag_name.c_str()); } } + + void add_properties_to_meta_data(AssetMetaData *asset_data) const + { + BLI_assert(asset_data->properties == nullptr); + const DictionaryValue::LookupValue *value_ptr = lookup.lookup_ptr( + ATTRIBUTE_ENTRIES_PROPERTIES); + if (value_ptr == nullptr) { + return; + } + + const Value &value = *(value_ptr->get()); + IDProperty *properties = convert_from_serialize_value(value); + asset_data->properties = properties; + } }; struct AssetEntryWriter { private: - ObjectValue::Items &attributes; + DictionaryValue::Items &attributes; public: - AssetEntryWriter(ObjectValue &entry) : attributes(entry.elements()) + AssetEntryWriter(DictionaryValue &entry) : attributes(entry.elements()) { } @@ -274,6 +292,15 @@ struct AssetEntryWriter { tag_items.append_as(new StringValue(tag->name)); } } + + void add_properties(const IDProperty *properties) + { + std::unique_ptr<Value> value = convert_to_serialize_values(properties); + if (value == nullptr) { + return; + } + attributes.append_as(std::pair(ATTRIBUTE_ENTRIES_PROPERTIES, value.release())); + } }; static void init_value_from_file_indexer_entry(AssetEntryWriter &result, @@ -298,10 +325,14 @@ static void init_value_from_file_indexer_entry(AssetEntryWriter &result, result.add_tags(&asset_data.tags); } + if (asset_data.properties != nullptr) { + result.add_properties(asset_data.properties); + } + /* TODO: asset_data.IDProperties */ } -static void init_value_from_file_indexer_entries(ObjectValue &result, +static void init_value_from_file_indexer_entries(DictionaryValue &result, const FileIndexerEntries &indexer_entries) { ArrayValue *entries = new ArrayValue(); @@ -313,7 +344,7 @@ static void init_value_from_file_indexer_entries(ObjectValue &result, if (indexer_entry->datablock_info.asset_data == nullptr) { continue; } - ObjectValue *entry_value = new ObjectValue(); + DictionaryValue *entry_value = new DictionaryValue(); AssetEntryWriter entry(*entry_value); init_value_from_file_indexer_entry(entry, indexer_entry); items.append_as(entry_value); @@ -326,7 +357,7 @@ static void init_value_from_file_indexer_entries(ObjectValue &result, return; } - ObjectValue::Items &attributes = result.elements(); + DictionaryValue::Items &attributes = result.elements(); attributes.append_as(std::pair(ATTRIBUTE_ENTRIES, entries)); } @@ -363,13 +394,14 @@ static void init_indexer_entry_from_value(FileIndexerEntry &indexer_entry, asset_data->catalog_id = entry.get_catalog_id(); entry.add_tags_to_meta_data(asset_data); + entry.add_properties_to_meta_data(asset_data); } static int init_indexer_entries_from_value(FileIndexerEntries &indexer_entries, - const ObjectValue &value) + const DictionaryValue &value) { - const ObjectValue::Lookup attributes = value.create_lookup(); - const ObjectValue::LookupValue *entries_value = attributes.lookup_ptr(ATTRIBUTE_ENTRIES); + const DictionaryValue::Lookup attributes = value.create_lookup(); + const DictionaryValue::LookupValue *entries_value = attributes.lookup_ptr(ATTRIBUTE_ENTRIES); BLI_assert(entries_value != nullptr); if (entries_value == nullptr) { @@ -379,7 +411,7 @@ static int init_indexer_entries_from_value(FileIndexerEntries &indexer_entries, int num_entries_read = 0; const ArrayValue::Items elements = (*entries_value)->as_array_value()->elements(); for (ArrayValue::Item element : elements) { - const AssetEntryReader asset_entry(*element->as_object_value()); + const AssetEntryReader asset_entry(*element->as_dictionary_value()); FileIndexerEntry *entry = static_cast<FileIndexerEntry *>( MEM_callocN(sizeof(FileIndexerEntry), __func__)); @@ -534,9 +566,9 @@ struct AssetIndex { /** * `blender::io::serialize::Value` representing the contents of an index file. * - * Value is used over #ObjectValue as the contents of the index could be corrupted and doesn't - * represent an object. In case corrupted files are detected the `get_version` would return - * `UNKNOWN_VERSION`. + * Value is used over #DictionaryValue as the contents of the index could be corrupted and + * doesn't represent an object. In case corrupted files are detected the `get_version` would + * return `UNKNOWN_VERSION`. */ std::unique_ptr<Value> contents; @@ -546,8 +578,8 @@ struct AssetIndex { */ AssetIndex(const FileIndexerEntries &indexer_entries) { - std::unique_ptr<ObjectValue> root = std::make_unique<ObjectValue>(); - ObjectValue::Items &root_attributes = root->elements(); + std::unique_ptr<DictionaryValue> root = std::make_unique<DictionaryValue>(); + DictionaryValue::Items &root_attributes = root->elements(); root_attributes.append_as(std::pair(ATTRIBUTE_VERSION, new IntValue(CURRENT_VERSION))); init_value_from_file_indexer_entries(*root, indexer_entries); @@ -564,12 +596,12 @@ struct AssetIndex { int get_version() const { - const ObjectValue *root = contents->as_object_value(); + const DictionaryValue *root = contents->as_dictionary_value(); if (root == nullptr) { return UNKNOWN_VERSION; } - const ObjectValue::Lookup attributes = root->create_lookup(); - const ObjectValue::LookupValue *version_value = attributes.lookup_ptr(ATTRIBUTE_VERSION); + const DictionaryValue::Lookup attributes = root->create_lookup(); + const DictionaryValue::LookupValue *version_value = attributes.lookup_ptr(ATTRIBUTE_VERSION); if (version_value == nullptr) { return UNKNOWN_VERSION; } @@ -588,7 +620,7 @@ struct AssetIndex { */ int extract_into(FileIndexerEntries &indexer_entries) const { - const ObjectValue *root = contents->as_object_value(); + const DictionaryValue *root = contents->as_dictionary_value(); const int num_entries_read = init_indexer_entries_from_value(indexer_entries, *root); return num_entries_read; } @@ -742,16 +774,15 @@ static void update_index(const char *filename, FileIndexerEntries *entries, void static void *init_user_data(const char *root_directory, size_t root_directory_maxlen) { - AssetLibraryIndex *library_index = OBJECT_GUARDED_NEW( - AssetLibraryIndex, - StringRef(root_directory, BLI_strnlen(root_directory, root_directory_maxlen))); + AssetLibraryIndex *library_index = MEM_new<AssetLibraryIndex>( + __func__, StringRef(root_directory, BLI_strnlen(root_directory, root_directory_maxlen))); library_index->init_unused_index_files(); return library_index; } static void free_user_data(void *user_data) { - OBJECT_GUARDED_DELETE(user_data, AssetLibraryIndex); + MEM_delete((AssetLibraryIndex *)user_data); } static void filelist_finished(void *user_data) diff --git a/source/blender/editors/asset/intern/asset_list.cc b/source/blender/editors/asset/intern/asset_list.cc index 1bfdd83b8e3..c075ae390d9 100644 --- a/source/blender/editors/asset/intern/asset_list.cc +++ b/source/blender/editors/asset/intern/asset_list.cc @@ -49,10 +49,6 @@ #include "ED_asset_list.hh" #include "asset_library_reference.hh" -/* Enable asset indexing. Currently disabled as ID properties aren't indexed yet and is needed for - * object snapping. See {D12990}. */ -//#define SPACE_FILE_ENABLE_ASSET_INDEXING - namespace blender::ed::asset { /* -------------------------------------------------------------------- */ @@ -174,9 +170,7 @@ void AssetList::setup() "", ""); -#ifdef SPACE_FILE_ENABLE_ASSET_INDEXING filelist_setindexer(files, &file_indexer_asset); -#endif char path[FILE_MAXDIR] = ""; if (user_library) { diff --git a/source/blender/editors/asset/intern/asset_ops.cc b/source/blender/editors/asset/intern/asset_ops.cc index e4edff19a21..f7755aa9fea 100644 --- a/source/blender/editors/asset/intern/asset_ops.cc +++ b/source/blender/editors/asset/intern/asset_ops.cc @@ -934,10 +934,10 @@ static bool has_external_files(Main *bmain, struct ReportList *reports) BKE_reportf( callback_info.reports, RPT_ERROR, - "Unable to copy bundle due to %ld external dependencies; more details on the console", - callback_info.external_files.size()); - printf("Unable to copy bundle due to %ld external dependencies:\n", - callback_info.external_files.size()); + "Unable to copy bundle due to %zu external dependencies; more details on the console", + (size_t)callback_info.external_files.size()); + printf("Unable to copy bundle due to %zu external dependencies:\n", + (size_t)callback_info.external_files.size()); for (const std::string &path : callback_info.external_files) { printf(" \"%s\"\n", path.c_str()); } diff --git a/source/blender/editors/asset/intern/asset_temp_id_consumer.cc b/source/blender/editors/asset/intern/asset_temp_id_consumer.cc index f136c08f129..8790c907f05 100644 --- a/source/blender/editors/asset/intern/asset_temp_id_consumer.cc +++ b/source/blender/editors/asset/intern/asset_temp_id_consumer.cc @@ -88,12 +88,13 @@ AssetTempIDConsumer *ED_asset_temp_id_consumer_create(const AssetHandle *handle) } BLI_assert(handle->file_data->asset_data != nullptr); return reinterpret_cast<AssetTempIDConsumer *>( - OBJECT_GUARDED_NEW(AssetTemporaryIDConsumer, *handle)); + MEM_new<AssetTemporaryIDConsumer>(__func__, *handle)); } void ED_asset_temp_id_consumer_free(AssetTempIDConsumer **consumer) { - OBJECT_GUARDED_SAFE_DELETE(*consumer, AssetTemporaryIDConsumer); + MEM_delete(reinterpret_cast<AssetTemporaryIDConsumer *>(*consumer)); + *consumer = nullptr; } ID *ED_asset_temp_id_consumer_ensure_local_id(AssetTempIDConsumer *consumer_, diff --git a/source/blender/editors/asset/intern/asset_type.cc b/source/blender/editors/asset/intern/asset_type.cc index 028c0cb9ffc..3d6ce3e3409 100644 --- a/source/blender/editors/asset/intern/asset_type.cc +++ b/source/blender/editors/asset/intern/asset_type.cc @@ -30,7 +30,7 @@ bool ED_asset_type_id_is_non_experimental(const ID *id) { /* Remember to update #ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_UI_STRING and * #ED_ASSET_TYPE_IDS_NON_EXPERIMENTAL_FLAGS() with this! */ - return ELEM(GS(id->name), ID_MA, ID_OB, ID_AC, ID_WO); + return ELEM(GS(id->name), ID_MA, ID_OB, ID_AC, ID_WO, ID_NT); } bool ED_asset_type_is_supported(const ID *id) diff --git a/source/blender/editors/curve/curve_intern.h b/source/blender/editors/curve/curve_intern.h index 03ddeebde42..0d17af1983d 100644 --- a/source/blender/editors/curve/curve_intern.h +++ b/source/blender/editors/curve/curve_intern.h @@ -155,7 +155,7 @@ void ed_editnurb_translate_flag(struct ListBase *editnurb, /** * Only for #OB_SURF. */ -bool ed_editnurb_extrude_flag(struct EditNurb *editnurb, const uint8_t flag); +bool ed_editnurb_extrude_flag(struct EditNurb *editnurb, uint8_t flag); /** * \param axis: is in world-space. * \param cent: is in object-space. diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index a034e4bb10e..a70bc1c0350 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -4953,19 +4953,22 @@ bool ed_editnurb_spin( if ((a & 1) == 0) { rotateflagNurb(editnurb, SELECT, cent, scalemat1); - weightflagNurb(editnurb, SELECT, 0.25 * M_SQRT2); + weightflagNurb(editnurb, SELECT, 0.5 * M_SQRT2); } else { rotateflagNurb(editnurb, SELECT, cent, scalemat2); - weightflagNurb(editnurb, SELECT, 4.0 / M_SQRT2); + weightflagNurb(editnurb, SELECT, 2.0 / M_SQRT2); } } if (ok) { LISTBASE_FOREACH (Nurb *, nu, editnurb) { if (ED_curve_nurb_select_check(v3d, nu)) { - nu->orderv = 4; - nu->flagv |= CU_NURB_CYCLIC; + nu->orderv = 3; + /* It is challenging to create a good approximation of a circle with uniform knots vector + * (which is forced in Blender for cyclic NURBS curves). Here a NURBS circle is constructed + * by connecting four Bezier arcs. */ + nu->flagv |= CU_NURB_CYCLIC | CU_NURB_BEZIER; BKE_nurb_knot_calc_v(nu); } } diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c index 614805a70f5..daef4a21692 100644 --- a/source/blender/editors/curve/editcurve_add.c +++ b/source/blender/editors/curve/editcurve_add.c @@ -306,9 +306,9 @@ Nurb *ED_curve_add_nurbs_primitive( else if (cutype == CU_NURBS) { /* nurb */ nu->pntsu = 8; nu->pntsv = 1; - nu->orderu = 4; + nu->orderu = 3; nu->bp = (BPoint *)MEM_callocN(sizeof(BPoint) * nu->pntsu, "addNurbprim6"); - nu->flagu = CU_NURB_CYCLIC; + nu->flagu = CU_NURB_CYCLIC | CU_NURB_BEZIER; bp = nu->bp; for (a = 0; a < 8; a++) { @@ -322,7 +322,7 @@ Nurb *ED_curve_add_nurbs_primitive( bp->vec[2] += 0.25f * nurbcircle[a][1] * grid; } if (a & 1) { - bp->vec[3] = 0.25 * M_SQRT2; + bp->vec[3] = 0.5 * M_SQRT2; } else { bp->vec[3] = 1.0; diff --git a/source/blender/editors/geometry/CMakeLists.txt b/source/blender/editors/geometry/CMakeLists.txt index 75b334b9ec6..8c920915937 100644 --- a/source/blender/editors/geometry/CMakeLists.txt +++ b/source/blender/editors/geometry/CMakeLists.txt @@ -20,19 +20,21 @@ set(INC ../../blenkernel ../../blenlib ../../depsgraph + ../../functions ../../makesdna ../../makesrna ../../windowmanager + ../../../../intern/guardedalloc ) set(INC_SYS ) set(SRC - geometry_attributes.c - geometry_ops.c + geometry_attributes.cc + geometry_ops.cc - geometry_intern.h + geometry_intern.hh ) set(LIB diff --git a/source/blender/editors/geometry/geometry_attributes.c b/source/blender/editors/geometry/geometry_attributes.c deleted file mode 100644 index 5cb491f116a..00000000000 --- a/source/blender/editors/geometry/geometry_attributes.c +++ /dev/null @@ -1,182 +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) 2020 Blender Foundation. - * All rights reserved. - */ - -/** \file - * \ingroup edgeometry - */ - -#include "BKE_attribute.h" -#include "BKE_context.h" - -#include "RNA_access.h" -#include "RNA_define.h" -#include "RNA_enum_types.h" - -#include "DEG_depsgraph.h" - -#include "WM_api.h" -#include "WM_types.h" - -#include "ED_object.h" - -#include "geometry_intern.h" - -/*********************** Attribute Operators ************************/ - -static bool geometry_attributes_poll(bContext *C) -{ - Object *ob = ED_object_context(C); - ID *data = (ob) ? ob->data : NULL; - return (ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data)) && - BKE_id_attributes_supported(data); -} - -static bool geometry_attributes_remove_poll(bContext *C) -{ - if (!geometry_attributes_poll(C)) { - return false; - } - - Object *ob = ED_object_context(C); - ID *data = (ob) ? ob->data : NULL; - if (BKE_id_attributes_active_get(data) != NULL) { - return true; - } - - return false; -} - -static const EnumPropertyItem *geometry_attribute_domain_itemf(bContext *C, - PointerRNA *UNUSED(ptr), - PropertyRNA *UNUSED(prop), - bool *r_free) -{ - if (C == NULL) { - return DummyRNA_NULL_items; - } - - Object *ob = ED_object_context(C); - if (ob == NULL) { - return DummyRNA_NULL_items; - } - - return rna_enum_attribute_domain_itemf(ob->data, r_free); -} - -static int geometry_attribute_add_exec(bContext *C, wmOperator *op) -{ - Object *ob = ED_object_context(C); - ID *id = ob->data; - - char name[MAX_NAME]; - RNA_string_get(op->ptr, "name", name); - CustomDataType type = (CustomDataType)RNA_enum_get(op->ptr, "data_type"); - AttributeDomain domain = (AttributeDomain)RNA_enum_get(op->ptr, "domain"); - CustomDataLayer *layer = BKE_id_attribute_new(id, name, type, domain, op->reports); - - if (layer == NULL) { - return OPERATOR_CANCELLED; - } - - BKE_id_attributes_active_set(id, layer); - - DEG_id_tag_update(id, ID_RECALC_GEOMETRY); - WM_main_add_notifier(NC_GEOM | ND_DATA, id); - - return OPERATOR_FINISHED; -} - -void GEOMETRY_OT_attribute_add(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Add Geometry Attribute"; - ot->description = "Add attribute to geometry"; - ot->idname = "GEOMETRY_OT_attribute_add"; - - /* api callbacks */ - ot->poll = geometry_attributes_poll; - ot->exec = geometry_attribute_add_exec; - ot->invoke = WM_operator_props_popup_confirm; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; - - /* properties */ - PropertyRNA *prop; - - prop = RNA_def_string(ot->srna, "name", "Attribute", MAX_NAME, "Name", "Name of new attribute"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - - prop = RNA_def_enum(ot->srna, - "domain", - rna_enum_attribute_domain_items, - ATTR_DOMAIN_POINT, - "Domain", - "Type of element that attribute is stored on"); - RNA_def_enum_funcs(prop, geometry_attribute_domain_itemf); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); - - prop = RNA_def_enum(ot->srna, - "data_type", - rna_enum_attribute_type_items, - CD_PROP_FLOAT, - "Data Type", - "Type of data stored in attribute"); - RNA_def_property_flag(prop, PROP_SKIP_SAVE); -} - -static int geometry_attribute_remove_exec(bContext *C, wmOperator *op) -{ - Object *ob = ED_object_context(C); - ID *id = ob->data; - CustomDataLayer *layer = BKE_id_attributes_active_get(id); - - if (layer == NULL) { - return OPERATOR_CANCELLED; - } - - if (!BKE_id_attribute_remove(id, layer, op->reports)) { - return OPERATOR_CANCELLED; - } - - int *active_index = BKE_id_attributes_active_index_p(id); - if (*active_index > 0) { - *active_index -= 1; - } - - DEG_id_tag_update(id, ID_RECALC_GEOMETRY); - WM_main_add_notifier(NC_GEOM | ND_DATA, id); - - return OPERATOR_FINISHED; -} - -void GEOMETRY_OT_attribute_remove(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Remove Geometry Attribute"; - ot->description = "Remove attribute from geometry"; - ot->idname = "GEOMETRY_OT_attribute_remove"; - - /* api callbacks */ - ot->exec = geometry_attribute_remove_exec; - ot->poll = geometry_attributes_remove_poll; - - /* flags */ - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} diff --git a/source/blender/editors/geometry/geometry_attributes.cc b/source/blender/editors/geometry/geometry_attributes.cc new file mode 100644 index 00000000000..56ecd108bba --- /dev/null +++ b/source/blender/editors/geometry/geometry_attributes.cc @@ -0,0 +1,385 @@ +/* + * 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) 2020 Blender Foundation. + * All rights reserved. + */ + +/** \file + * \ingroup edgeometry + */ + +#include "MEM_guardedalloc.h" + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_scene_types.h" + +#include "BKE_attribute.h" +#include "BKE_context.h" +#include "BKE_deform.h" +#include "BKE_geometry_set.hh" +#include "BKE_object_deform.h" +#include "BKE_report.h" + +#include "RNA_access.h" +#include "RNA_define.h" +#include "RNA_enum_types.h" + +#include "DEG_depsgraph.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "ED_object.h" + +#include "geometry_intern.hh" + +namespace blender::ed::geometry { + +using fn::CPPType; +using fn::GArray; +using fn::GVArray; + +/*********************** Attribute Operators ************************/ + +static bool geometry_attributes_poll(bContext *C) +{ + Object *ob = ED_object_context(C); + ID *data = (ob) ? static_cast<ID *>(ob->data) : nullptr; + return (ob && !ID_IS_LINKED(ob) && data && !ID_IS_LINKED(data)) && + BKE_id_attributes_supported(data); +} + +static bool geometry_attributes_remove_poll(bContext *C) +{ + if (!geometry_attributes_poll(C)) { + return false; + } + + Object *ob = ED_object_context(C); + ID *data = (ob) ? static_cast<ID *>(ob->data) : nullptr; + if (BKE_id_attributes_active_get(data) != nullptr) { + return true; + } + + return false; +} + +static const EnumPropertyItem *geometry_attribute_domain_itemf(bContext *C, + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free) +{ + if (C == nullptr) { + return DummyRNA_NULL_items; + } + + Object *ob = ED_object_context(C); + if (ob == nullptr) { + return DummyRNA_NULL_items; + } + + return rna_enum_attribute_domain_itemf(static_cast<ID *>(ob->data), false, r_free); +} + +static int geometry_attribute_add_exec(bContext *C, wmOperator *op) +{ + Object *ob = ED_object_context(C); + ID *id = static_cast<ID *>(ob->data); + + char name[MAX_NAME]; + RNA_string_get(op->ptr, "name", name); + CustomDataType type = (CustomDataType)RNA_enum_get(op->ptr, "data_type"); + AttributeDomain domain = (AttributeDomain)RNA_enum_get(op->ptr, "domain"); + CustomDataLayer *layer = BKE_id_attribute_new(id, name, type, domain, op->reports); + + if (layer == nullptr) { + return OPERATOR_CANCELLED; + } + + BKE_id_attributes_active_set(id, layer); + + DEG_id_tag_update(id, ID_RECALC_GEOMETRY); + WM_main_add_notifier(NC_GEOM | ND_DATA, id); + + return OPERATOR_FINISHED; +} + +void GEOMETRY_OT_attribute_add(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Add Geometry Attribute"; + ot->description = "Add attribute to geometry"; + ot->idname = "GEOMETRY_OT_attribute_add"; + + /* api callbacks */ + ot->poll = geometry_attributes_poll; + ot->exec = geometry_attribute_add_exec; + ot->invoke = WM_operator_props_popup_confirm; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ + PropertyRNA *prop; + + prop = RNA_def_string(ot->srna, "name", "Attribute", MAX_NAME, "Name", "Name of new attribute"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + prop = RNA_def_enum(ot->srna, + "domain", + rna_enum_attribute_domain_items, + ATTR_DOMAIN_POINT, + "Domain", + "Type of element that attribute is stored on"); + RNA_def_enum_funcs(prop, geometry_attribute_domain_itemf); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + + prop = RNA_def_enum(ot->srna, + "data_type", + rna_enum_attribute_type_items, + CD_PROP_FLOAT, + "Data Type", + "Type of data stored in attribute"); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); +} + +static int geometry_attribute_remove_exec(bContext *C, wmOperator *op) +{ + Object *ob = ED_object_context(C); + ID *id = static_cast<ID *>(ob->data); + CustomDataLayer *layer = BKE_id_attributes_active_get(id); + + if (layer == nullptr) { + return OPERATOR_CANCELLED; + } + + if (!BKE_id_attribute_remove(id, layer, op->reports)) { + return OPERATOR_CANCELLED; + } + + int *active_index = BKE_id_attributes_active_index_p(id); + if (*active_index > 0) { + *active_index -= 1; + } + + DEG_id_tag_update(id, ID_RECALC_GEOMETRY); + WM_main_add_notifier(NC_GEOM | ND_DATA, id); + + return OPERATOR_FINISHED; +} + +void GEOMETRY_OT_attribute_remove(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Remove Geometry Attribute"; + ot->description = "Remove attribute from geometry"; + ot->idname = "GEOMETRY_OT_attribute_remove"; + + /* api callbacks */ + ot->exec = geometry_attribute_remove_exec; + ot->poll = geometry_attributes_remove_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +enum class ConvertAttributeMode { + Generic, + UVMap, + VertexGroup, + VertexColor, +}; + +static bool geometry_attribute_convert_poll(bContext *C) +{ + if (!geometry_attributes_poll(C)) { + return false; + } + + Object *ob = ED_object_context(C); + ID *data = static_cast<ID *>(ob->data); + if (GS(data->name) != ID_ME) { + return false; + } + CustomDataLayer *layer = BKE_id_attributes_active_get(data); + if (layer == nullptr) { + return false; + } + return true; +} + +static int geometry_attribute_convert_exec(bContext *C, wmOperator *op) +{ + Object *ob = ED_object_context(C); + ID *ob_data = static_cast<ID *>(ob->data); + CustomDataLayer *layer = BKE_id_attributes_active_get(ob_data); + const std::string name = layer->name; + + const ConvertAttributeMode mode = static_cast<ConvertAttributeMode>( + RNA_enum_get(op->ptr, "mode")); + + Mesh *mesh = reinterpret_cast<Mesh *>(ob_data); + MeshComponent mesh_component; + mesh_component.replace(mesh, GeometryOwnershipType::Editable); + + /* General conversion steps are always the same: + * 1. Convert old data to right domain and data type. + * 2. Copy the data into a new array so that it does not depend on the old attribute anymore. + * 3. Delete the old attribute. + * 4. Create a new attribute based on the previously copied data. */ + switch (mode) { + case ConvertAttributeMode::Generic: { + const AttributeDomain dst_domain = static_cast<AttributeDomain>( + RNA_enum_get(op->ptr, "domain")); + const CustomDataType dst_type = static_cast<CustomDataType>( + RNA_enum_get(op->ptr, "data_type")); + + if (ELEM(dst_type, CD_PROP_STRING, CD_MLOOPCOL)) { + BKE_report(op->reports, RPT_ERROR, "Cannot convert to the selected type"); + return OPERATOR_CANCELLED; + } + + GVArray src_varray = mesh_component.attribute_get_for_read(name, dst_domain, dst_type); + const CPPType &cpp_type = src_varray.type(); + void *new_data = MEM_malloc_arrayN(src_varray.size(), cpp_type.size(), __func__); + src_varray.materialize_to_uninitialized(new_data); + mesh_component.attribute_try_delete(name); + mesh_component.attribute_try_create(name, dst_domain, dst_type, AttributeInitMove(new_data)); + break; + } + case ConvertAttributeMode::UVMap: { + MLoopUV *dst_uvs = static_cast<MLoopUV *>( + MEM_calloc_arrayN(mesh->totloop, sizeof(MLoopUV), __func__)); + VArray<float2> src_varray = mesh_component.attribute_get_for_read<float2>( + name, ATTR_DOMAIN_CORNER, {0.0f, 0.0f}); + for (const int i : IndexRange(mesh->totloop)) { + copy_v2_v2(dst_uvs[i].uv, src_varray[i]); + } + mesh_component.attribute_try_delete(name); + CustomData_add_layer_named( + &mesh->ldata, CD_MLOOPUV, CD_ASSIGN, dst_uvs, mesh->totloop, name.c_str()); + break; + } + case ConvertAttributeMode::VertexColor: { + MLoopCol *dst_colors = static_cast<MLoopCol *>( + MEM_calloc_arrayN(mesh->totloop, sizeof(MLoopCol), __func__)); + VArray<ColorGeometry4f> src_varray = mesh_component.attribute_get_for_read<ColorGeometry4f>( + name, ATTR_DOMAIN_CORNER, ColorGeometry4f{0.0f, 0.0f, 0.0f, 1.0f}); + for (const int i : IndexRange(mesh->totloop)) { + ColorGeometry4b encoded_color = src_varray[i].encode(); + copy_v4_v4_uchar(&dst_colors[i].r, &encoded_color.r); + } + mesh_component.attribute_try_delete(name); + CustomData_add_layer_named( + &mesh->ldata, CD_MLOOPCOL, CD_ASSIGN, dst_colors, mesh->totloop, name.c_str()); + break; + } + case ConvertAttributeMode::VertexGroup: { + Array<float> src_weights(mesh->totvert); + VArray<float> src_varray = mesh_component.attribute_get_for_read<float>( + name, ATTR_DOMAIN_POINT, 0.0f); + src_varray.materialize(src_weights); + mesh_component.attribute_try_delete(name); + + bDeformGroup *defgroup = BKE_object_defgroup_new(ob, name.c_str()); + const int defgroup_index = BLI_findindex(BKE_id_defgroup_list_get(&mesh->id), defgroup); + MDeformVert *dverts = BKE_object_defgroup_data_create(&mesh->id); + for (const int i : IndexRange(mesh->totvert)) { + const float weight = src_weights[i]; + if (weight > 0.0f) { + BKE_defvert_add_index_notest(dverts + i, defgroup_index, weight); + } + } + break; + } + } + + int *active_index = BKE_id_attributes_active_index_p(&mesh->id); + if (*active_index > 0) { + *active_index -= 1; + } + + DEG_id_tag_update(&mesh->id, ID_RECALC_GEOMETRY); + WM_main_add_notifier(NC_GEOM | ND_DATA, &mesh->id); + + return OPERATOR_FINISHED; +} + +static void geometry_attribute_convert_ui(bContext *UNUSED(C), wmOperator *op) +{ + uiLayout *layout = op->layout; + + uiItemR(layout, op->ptr, "mode", 0, nullptr, ICON_NONE); + + const ConvertAttributeMode mode = static_cast<ConvertAttributeMode>( + RNA_enum_get(op->ptr, "mode")); + + if (mode == ConvertAttributeMode::Generic) { + uiItemR(layout, op->ptr, "domain", 0, nullptr, ICON_NONE); + uiItemR(layout, op->ptr, "data_type", 0, nullptr, ICON_NONE); + } +} + +static int geometry_attribute_convert_invoke(bContext *C, + wmOperator *op, + const wmEvent *UNUSED(event)) +{ + return WM_operator_props_dialog_popup(C, op, 300); +} + +void GEOMETRY_OT_attribute_convert(wmOperatorType *ot) +{ + ot->name = "Convert Attribute"; + ot->description = "Change how the attribute is stored"; + ot->idname = "GEOMETRY_OT_attribute_convert"; + + ot->invoke = geometry_attribute_convert_invoke; + ot->exec = geometry_attribute_convert_exec; + ot->poll = geometry_attribute_convert_poll; + ot->ui = geometry_attribute_convert_ui; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + static EnumPropertyItem mode_items[] = { + {int(ConvertAttributeMode::Generic), "GENERIC", 0, "Generic", ""}, + {int(ConvertAttributeMode::UVMap), "UV_MAP", 0, "UV Map", ""}, + {int(ConvertAttributeMode::VertexGroup), "VERTEX_GROUP", 0, "Vertex Group", ""}, + {int(ConvertAttributeMode::VertexColor), "VERTEX_COLOR", 0, "Vertex Color", ""}, + {0, nullptr, 0, nullptr, nullptr}, + }; + + PropertyRNA *prop; + + RNA_def_enum( + ot->srna, "mode", mode_items, static_cast<int>(ConvertAttributeMode::Generic), "Mode", ""); + + prop = RNA_def_enum(ot->srna, + "domain", + rna_enum_attribute_domain_items, + ATTR_DOMAIN_POINT, + "Domain", + "Which geometry element to move the attribute to"); + RNA_def_enum_funcs(prop, geometry_attribute_domain_itemf); + + RNA_def_enum( + ot->srna, "data_type", rna_enum_attribute_type_items, CD_PROP_FLOAT, "Data Type", ""); +} + +} // namespace blender::ed::geometry diff --git a/source/blender/editors/geometry/geometry_intern.h b/source/blender/editors/geometry/geometry_intern.hh index 8a0f9294722..30a2a1d6eb1 100644 --- a/source/blender/editors/geometry/geometry_intern.h +++ b/source/blender/editors/geometry/geometry_intern.hh @@ -25,6 +25,11 @@ struct wmOperatorType; -/* *** geometry_attributes.c *** */ +namespace blender::ed::geometry { + +/* *** geometry_attributes.cc *** */ void GEOMETRY_OT_attribute_add(struct wmOperatorType *ot); void GEOMETRY_OT_attribute_remove(struct wmOperatorType *ot); +void GEOMETRY_OT_attribute_convert(struct wmOperatorType *ot); + +} // namespace blender::ed::geometry diff --git a/source/blender/editors/geometry/geometry_ops.c b/source/blender/editors/geometry/geometry_ops.cc index ed0aeda731b..8933b2a7f00 100644 --- a/source/blender/editors/geometry/geometry_ops.c +++ b/source/blender/editors/geometry/geometry_ops.cc @@ -25,12 +25,15 @@ #include "ED_geometry.h" -#include "geometry_intern.h" +#include "geometry_intern.hh" /**************************** registration **********************************/ void ED_operatortypes_geometry(void) { + using namespace blender::ed::geometry; + WM_operatortype_append(GEOMETRY_OT_attribute_add); WM_operatortype_append(GEOMETRY_OT_attribute_remove); + WM_operatortype_append(GEOMETRY_OT_attribute_convert); } diff --git a/source/blender/editors/gizmo_library/gizmo_library_intern.h b/source/blender/editors/gizmo_library/gizmo_library_intern.h index a75a6b9a6ef..4a481f4bc59 100644 --- a/source/blender/editors/gizmo_library/gizmo_library_intern.h +++ b/source/blender/editors/gizmo_library/gizmo_library_intern.h @@ -52,22 +52,19 @@ typedef struct GizmoInteraction { float precision_offset; } GizmoInteraction; -float gizmo_offset_from_value(GizmoCommonData *data, - const float value, - const bool constrained, - const bool inverted); +float gizmo_offset_from_value(GizmoCommonData *data, float value, bool constrained, bool inverted); float gizmo_value_from_offset(GizmoCommonData *data, GizmoInteraction *inter, - const float offset, - const bool constrained, - const bool inverted, - const bool use_precision); + float offset, + bool constrained, + bool inverted, + bool use_precision); void gizmo_property_data_update(struct wmGizmo *gz, GizmoCommonData *data, wmGizmoProperty *gz_prop, - const bool constrained, - const bool inverted); + bool constrained, + bool inverted); void gizmo_property_value_reset(bContext *C, const struct wmGizmo *gz, @@ -76,7 +73,7 @@ void gizmo_property_value_reset(bContext *C, /* -------------------------------------------------------------------- */ -void gizmo_color_get(const struct wmGizmo *gz, const bool highlight, float r_color[4]); +void gizmo_color_get(const struct wmGizmo *gz, bool highlight, float r_color[4]); /** * Takes mouse coordinates and returns them in relation to the gizmo. @@ -101,7 +98,7 @@ bool gizmo_window_project_3d( * Main draw call for #GizmoGeomInfo data */ void wm_gizmo_geometryinfo_draw(const struct GizmoGeomInfo *info, - const bool select, + bool select, const float color[4]); void wm_gizmo_vec_draw( const float color[4], const float (*verts)[3], uint vert_count, uint pos, uint primitive_type); diff --git a/source/blender/editors/gpencil/annotate_draw.c b/source/blender/editors/gpencil/annotate_draw.c index 3705ea38e11..ae00fc41f40 100644 --- a/source/blender/editors/gpencil/annotate_draw.c +++ b/source/blender/editors/gpencil/annotate_draw.c @@ -165,7 +165,7 @@ static void annotation_draw_stroke_buffer(bGPdata *gps, immBindBuiltinProgram(GPU_SHADER_3D_POINT_UNIFORM_SIZE_UNIFORM_COLOR_AA); immUniformColor3fvAlpha(ink, ink[3]); immBegin(GPU_PRIM_POINTS, 1); - immVertex2fv(pos, &pt->x); + immVertex2fv(pos, pt->m_xy); } else { float oldpressure = points[0].pressure; @@ -191,7 +191,7 @@ static void annotation_draw_stroke_buffer(bGPdata *gps, if (fabsf(pt->pressure - oldpressure) > 0.2f) { /* need to have 2 points to avoid immEnd assert error */ if (draw_points < 2) { - immVertex2fv(pos, &(pt - 1)->x); + immVertex2fv(pos, (pt - 1)->m_xy); } immEnd(); @@ -202,7 +202,7 @@ static void annotation_draw_stroke_buffer(bGPdata *gps, /* need to roll-back one point to ensure that there are no gaps in the stroke */ if (i != 0) { - immVertex2fv(pos, &(pt - 1)->x); + immVertex2fv(pos, (pt - 1)->m_xy); draw_points++; } @@ -210,12 +210,12 @@ static void annotation_draw_stroke_buffer(bGPdata *gps, } /* now the point we want */ - immVertex2fv(pos, &pt->x); + immVertex2fv(pos, pt->m_xy); draw_points++; } /* need to have 2 points to avoid immEnd assert error */ if (draw_points < 2) { - immVertex2fv(pos, &(pt - 1)->x); + immVertex2fv(pos, (pt - 1)->m_xy); } } @@ -227,14 +227,14 @@ static void annotation_draw_stroke_buffer(bGPdata *gps, if ((sflag & GP_STROKE_USE_ARROW_END) && (runtime.arrow_end_style != GP_STROKE_ARROWSTYLE_NONE)) { float end[2]; - copy_v2_fl2(end, points[1].x, points[1].y); + copy_v2_v2(end, points[1].m_xy); annotation_draw_stroke_arrow_buffer(pos, end, runtime.arrow_end, runtime.arrow_end_style); } /* Draw starting arrow stroke. */ if ((sflag & GP_STROKE_USE_ARROW_START) && (runtime.arrow_start_style != GP_STROKE_ARROWSTYLE_NONE)) { float start[2]; - copy_v2_fl2(start, points[0].x, points[0].y); + copy_v2_v2(start, points[0].m_xy); annotation_draw_stroke_arrow_buffer( pos, start, runtime.arrow_start, runtime.arrow_start_style); } diff --git a/source/blender/editors/gpencil/annotate_paint.c b/source/blender/editors/gpencil/annotate_paint.c index fbc44ed58d8..e75e9314659 100644 --- a/source/blender/editors/gpencil/annotate_paint.c +++ b/source/blender/editors/gpencil/annotate_paint.c @@ -426,25 +426,25 @@ static void annotation_smooth_buffer(tGPsdata *p, float inf, int idx) /* Compute smoothed coordinate by taking the ones nearby */ if (pta) { - copy_v2_v2(a, &pta->x); + copy_v2_v2(a, pta->m_xy); madd_v2_v2fl(sco, a, average_fac); } if (ptb) { - copy_v2_v2(b, &ptb->x); + copy_v2_v2(b, ptb->m_xy); madd_v2_v2fl(sco, b, average_fac); } if (ptc) { - copy_v2_v2(c, &ptc->x); + copy_v2_v2(c, ptc->m_xy); madd_v2_v2fl(sco, c, average_fac); } if (ptd) { - copy_v2_v2(d, &ptd->x); + copy_v2_v2(d, ptd->m_xy); madd_v2_v2fl(sco, d, average_fac); } /* Based on influence factor, blend between original and optimal smoothed coordinate */ interp_v2_v2v2(c, c, sco, inf); - copy_v2_v2(&ptc->x, c); + copy_v2_v2(ptc->m_xy, c); } static void annotation_stroke_arrow_calc_points_segment(float stroke_points[8], @@ -492,8 +492,8 @@ static void annotation_stroke_arrow_calc_points(tGPspoint *point, case GP_STROKE_ARROWSTYLE_CLOSED: mul_v2_fl(norm_dir, arrow_length); if (point != NULL) { - add_v2_v2(&point->x, norm_dir); - copy_v2_v2(corner, &point->x); + add_v2_v2(point->m_xy, norm_dir); + copy_v2_v2(corner, point->m_xy); } annotation_stroke_arrow_calc_points_segment(stroke_points, corner, @@ -507,8 +507,8 @@ static void annotation_stroke_arrow_calc_points(tGPspoint *point, case GP_STROKE_ARROWSTYLE_SQUARE: mul_v2_fl(norm_dir, arrow_length * 1.5f); if (point != NULL) { - add_v2_v2(&point->x, norm_dir); - copy_v2_v2(corner, &point->x); + add_v2_v2(point->m_xy, norm_dir); + copy_v2_v2(corner, point->m_xy); } annotation_stroke_arrow_calc_points_segment(stroke_points, corner, @@ -544,7 +544,7 @@ static short annotation_stroke_addpoint(tGPsdata *p, pt = (tGPspoint *)(gpd->runtime.sbuffer); /* store settings */ - copy_v2_v2(&pt->x, mval); + copy_v2_v2(pt->m_xy, mval); /* T44932 - Pressure vals are unreliable, so ignore for now */ pt->pressure = 1.0f; pt->strength = 1.0f; @@ -560,7 +560,7 @@ static short annotation_stroke_addpoint(tGPsdata *p, pt = ((tGPspoint *)(gpd->runtime.sbuffer) + 1); /* store settings */ - copy_v2_v2(&pt->x, mval); + copy_v2_v2(pt->m_xy, mval); /* T44932 - Pressure vals are unreliable, so ignore for now */ pt->pressure = 1.0f; pt->strength = 1.0f; @@ -573,10 +573,10 @@ static short annotation_stroke_addpoint(tGPsdata *p, if (gpd->runtime.sbuffer_sflag & (GP_STROKE_USE_ARROW_START | GP_STROKE_USE_ARROW_END)) { /* Store start and end point coords for arrows. */ float end[2]; - copy_v2_v2(end, &pt->x); + copy_v2_v2(end, pt->m_xy); pt = ((tGPspoint *)(gpd->runtime.sbuffer)); float start[2]; - copy_v2_v2(start, &pt->x); + copy_v2_v2(start, pt->m_xy); /* Arrow end corner. */ if (gpd->runtime.sbuffer_sflag & GP_STROKE_USE_ARROW_END) { @@ -609,7 +609,7 @@ static short annotation_stroke_addpoint(tGPsdata *p, pt = ((tGPspoint *)(gpd->runtime.sbuffer) + gpd->runtime.sbuffer_used); /* store settings */ - copy_v2_v2(&pt->x, mval); + copy_v2_v2(pt->m_xy, mval); pt->pressure = pressure; /* Unused for annotations, but initialize for easier conversions to GP Object. */ pt->strength = 1.0f; @@ -636,7 +636,7 @@ static short annotation_stroke_addpoint(tGPsdata *p, pt = (tGPspoint *)gpd->runtime.sbuffer; /* store settings */ - copy_v2_v2(&pt->x, mval); + copy_v2_v2(pt->m_xy, mval); /* T44932 - Pressure vals are unreliable, so ignore for now */ pt->pressure = 1.0f; pt->strength = 1.0f; @@ -678,7 +678,7 @@ static short annotation_stroke_addpoint(tGPsdata *p, } /* convert screen-coordinates to appropriate coordinates (and store them) */ - annotation_stroke_convertcoords(p, &pt->x, &pts->x, NULL); + annotation_stroke_convertcoords(p, pt->m_xy, &pts->x, NULL); /* copy pressure and time */ pts->pressure = pt->pressure; @@ -717,8 +717,8 @@ static void annotation_stroke_arrow_init_point( { /* NOTE: provided co_idx should be always pair number as it's [x1, y1, x2, y2, x3, y3]. */ const float real_co[2] = {co[co_idx], co[co_idx + 1]}; - copy_v2_v2(&ptc->x, real_co); - annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + copy_v2_v2(ptc->m_xy, real_co); + annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL); annotation_stroke_arrow_init_point_default(pt); } @@ -885,7 +885,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p) ptc = gpd->runtime.sbuffer; /* convert screen-coordinates to appropriate coordinates (and store them) */ - annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL); /* copy pressure and time */ pt->pressure = ptc->pressure; @@ -903,7 +903,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p) ptc = ((tGPspoint *)runtime.sbuffer) + (runtime.sbuffer_used - 1); /* Convert screen-coordinates to appropriate coordinates (and store them). */ - annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL); /* Copy pressure and time. */ pt->pressure = ptc->pressure; @@ -926,7 +926,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p) /* End point. */ ptc = ((tGPspoint *)runtime.sbuffer) + (runtime.sbuffer_used - 1); - annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL); annotation_stroke_arrow_init_point_default(pt); /* Fill and convert arrow points to create arrow shape. */ @@ -947,7 +947,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p) /* Start point. */ ptc = runtime.sbuffer; - annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL); annotation_stroke_arrow_init_point_default(pt); /* Fill and convert arrow points to create arrow shape. */ @@ -961,7 +961,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p) ptc = gpd->runtime.sbuffer; /* convert screen-coordinates to appropriate coordinates (and store them) */ - annotation_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL); /* copy pressure and time */ pt->pressure = ptc->pressure; @@ -981,7 +981,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p) const ViewDepths *depths = p->depths; for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used; i++, ptc++, pt++) { - round_v2i_v2fl(mval_i, &ptc->x); + round_v2i_v2fl(mval_i, ptc->m_xy); if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, depth_arr + i) == 0) && (i && (ED_view3d_depth_read_cached_seg( @@ -1041,7 +1041,7 @@ static void annotation_stroke_newfrombuffer(tGPsdata *p) for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used && ptc; i++, ptc++, pt++) { /* convert screen-coordinates to appropriate coordinates (and store them) */ - annotation_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL); + annotation_stroke_convertcoords(p, ptc->m_xy, &pt->x, depth_arr ? depth_arr + i : NULL); /* copy pressure and time */ pt->pressure = ptc->pressure; @@ -1132,7 +1132,7 @@ static void annotation_stroke_eraser_dostroke(tGPsdata *p, if (!(p->flags & GP_PAINTFLAG_SELECTMASK) || (gps->points->flag & GP_SPOINT_SELECT)) { gpencil_point_to_xy(&p->gsc, gps, gps->points, &pc1[0], &pc1[1]); - /* do boundbox check first */ + /* Do bound-box check first. */ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) { /* only check if point is inside */ if (len_v2v2_int(mval_i, pc1) <= radius) { @@ -1174,7 +1174,7 @@ static void annotation_stroke_eraser_dostroke(tGPsdata *p, gpencil_point_to_xy(&p->gsc, gps, pt1, &pc1[0], &pc1[1]); gpencil_point_to_xy(&p->gsc, gps, pt2, &pc2[0], &pc2[1]); - /* Check that point segment of the boundbox of the eraser stroke */ + /* Check that point segment of the bound-box of the eraser stroke. */ if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) || ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) { /* Check if point segment of stroke had anything to do with @@ -1473,7 +1473,7 @@ static tGPsdata *annotation_session_initpaint(bContext *C) return NULL; } - /* Radius for eraser circle is defined in userprefs */ + /* Radius for eraser circle is defined in user-preferences. */ /* NOTE: we do this here, so that if we exit immediately, * erase size won't get lost */ @@ -1811,7 +1811,7 @@ static void annotation_draw_stabilizer(bContext *C, int x, int y, void *p_ptr) /* Rope Simple. */ immUniformColor4f(color[0], color[1], color[2], 0.8f); immBegin(GPU_PRIM_LINES, 2); - immVertex2f(pos, pt->x + region->winrct.xmin, pt->y + region->winrct.ymin); + immVertex2f(pos, pt->m_xy[0] + region->winrct.xmin, pt->m_xy[1] + region->winrct.ymin); immVertex2f(pos, x, y); immEnd(); @@ -2575,8 +2575,7 @@ static int annotation_draw_modal(bContext *C, wmOperator *op, const wmEvent *eve */ if ((p->region) && (p->region->regiontype == RGN_TYPE_TOOLS)) { /* Change to whatever region is now under the mouse */ - ARegion *current_region = BKE_area_find_region_xy( - p->area, RGN_TYPE_ANY, event->xy[0], event->xy[1]); + ARegion *current_region = BKE_area_find_region_xy(p->area, RGN_TYPE_ANY, event->xy); if (current_region) { /* Assume that since we found the cursor in here, it is in bounds diff --git a/source/blender/editors/gpencil/drawgpencil.c b/source/blender/editors/gpencil/drawgpencil.c index 6f63529298c..23b579b94f1 100644 --- a/source/blender/editors/gpencil/drawgpencil.c +++ b/source/blender/editors/gpencil/drawgpencil.c @@ -61,9 +61,12 @@ #include "WM_api.h" +#include "GPU_batch.h" #include "GPU_immediate.h" #include "GPU_matrix.h" +#include "GPU_shader_shared.h" #include "GPU_state.h" +#include "GPU_uniform_buffer.h" #include "ED_gpencil.h" #include "ED_screen.h" @@ -189,21 +192,27 @@ static void gpencil_draw_stroke_3d(tGPDdraw *tgpw, }; immBindBuiltinProgram(GPU_SHADER_GPENCIL_STROKE); - immUniform2fv("Viewport", viewport); - immUniform1f("pixsize", tgpw->rv3d->pixsize); + float obj_scale = tgpw->ob ? (tgpw->ob->scale[0] + tgpw->ob->scale[1] + tgpw->ob->scale[2]) / 3.0f : 1.0f; - immUniform1f("objscale", obj_scale); + struct GPencilStrokeData gpencil_stroke_data; + copy_v2_v2(gpencil_stroke_data.viewport, viewport); + gpencil_stroke_data.pixsize = tgpw->rv3d->pixsize; + gpencil_stroke_data.objscale = obj_scale; int keep_size = (int)((tgpw->gpd) && (tgpw->gpd->flag & GP_DATA_STROKE_KEEPTHICKNESS)); - immUniform1i("keep_size", keep_size); - immUniform1f("pixfactor", tgpw->gpd->pixfactor); + gpencil_stroke_data.keep_size = keep_size; + gpencil_stroke_data.pixfactor = tgpw->gpd->pixfactor; /* xray mode always to 3D space to avoid wrong zdepth calculation (T60051) */ - immUniform1i("xraymode", GP_XRAY_3DSPACE); - immUniform1i("caps_start", (int)tgpw->gps->caps[0]); - immUniform1i("caps_end", (int)tgpw->gps->caps[1]); - immUniform1i("fill_stroke", (int)tgpw->is_fill_stroke); + gpencil_stroke_data.xraymode = GP_XRAY_3DSPACE; + gpencil_stroke_data.caps_start = tgpw->gps->caps[0]; + gpencil_stroke_data.caps_end = tgpw->gps->caps[1]; + gpencil_stroke_data.fill_stroke = tgpw->is_fill_stroke; + + GPUUniformBuf *ubo = GPU_uniformbuf_create_ex( + sizeof(struct GPencilStrokeData), &gpencil_stroke_data, __func__); + immBindUniformBuf("gpencil_stroke_data", ubo); /* draw stroke curve */ immBeginAtMost(GPU_PRIM_LINE_STRIP_ADJ, totpoints + cyclic_add + 2); @@ -255,6 +264,8 @@ static void gpencil_draw_stroke_3d(tGPDdraw *tgpw, immEnd(); immUnbindProgram(); + + GPU_uniformbuf_free(ubo); } /* ----- Strokes Drawing ------ */ diff --git a/source/blender/editors/gpencil/editaction_gpencil.c b/source/blender/editors/gpencil/editaction_gpencil.c index 046b3088360..3cc47198cbc 100644 --- a/source/blender/editors/gpencil/editaction_gpencil.c +++ b/source/blender/editors/gpencil/editaction_gpencil.c @@ -46,6 +46,8 @@ #include "WM_api.h" +#include "DEG_depsgraph.h" + /* ***************************************** */ /* NOTE ABOUT THIS FILE: * This file contains code for editing Grease Pencil data in the Action Editor @@ -453,6 +455,9 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode) /* get frame to copy data into (if no frame returned, then just ignore) */ gpf = BKE_gpencil_layer_frame_get(gpld, gpfs->framenum, GP_GETFRAME_ADD_NEW); if (gpf) { + /* Ensure to use same keyframe type. */ + gpf->key_type = gpfs->key_type; + bGPDstroke *gps, *gpsn; /* This should be the right frame... as it may be a pre-existing frame, @@ -479,6 +484,9 @@ bool ED_gpencil_anim_copybuf_paste(bAnimContext *ac, const short offset_mode) /* unapply offset from buffer-frame */ gpfs->framenum -= offset; } + + /* Tag destination datablock. */ + DEG_id_tag_update(ale->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); } /* clean up */ diff --git a/source/blender/editors/gpencil/gpencil_data.c b/source/blender/editors/gpencil/gpencil_data.c index bea8126cfcc..916aa8184aa 100644 --- a/source/blender/editors/gpencil/gpencil_data.c +++ b/source/blender/editors/gpencil/gpencil_data.c @@ -1468,6 +1468,10 @@ static int gpencil_layer_change_invoke(bContext *C, wmOperator *op, const wmEven static int gpencil_layer_change_exec(bContext *C, wmOperator *op) { bGPdata *gpd = CTX_data_gpencil_data(C); + if (gpd == NULL) { + return OPERATOR_CANCELLED; + } + bGPDlayer *gpl = NULL; int layer_num = RNA_enum_get(op->ptr, "layer"); diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 2a656ac3aad..e71a56894d0 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -3956,8 +3956,8 @@ static void gpencil_smooth_stroke(bContext *C, wmOperator *op) } if (smooth_thickness) { /* thickness need to repeat process several times */ - for (int r2 = 0; r2 < 20; r2++) { - BKE_gpencil_stroke_smooth_thickness(gps, i, factor); + for (int r2 = 0; r2 < repeat * 2; r2++) { + BKE_gpencil_stroke_smooth_thickness(gps, i, 1.0f - factor); } } if (smooth_uv) { diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index c3af28d4382..541b6673cb6 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -1072,7 +1072,7 @@ static void gpencil_erase_processed_area(tGPDfill *tgpf) /* First set in blue the perimeter. */ for (int i = 0; i < tgpf->sbuffer_used && point2D; i++, point2D++) { - int image_idx = ibuf->x * (int)point2D->y + (int)point2D->x; + int image_idx = ibuf->x * (int)point2D->m_xy[1] + (int)point2D->m_xy[0]; set_pixel(ibuf, image_idx, blue_col); } @@ -1393,7 +1393,7 @@ static void gpencil_get_depth_array(tGPDfill *tgpf) for (i = 0, ptc = tgpf->sbuffer; i < totpoints; i++, ptc++) { int mval_i[2]; - round_v2i_v2fl(mval_i, &ptc->x); + round_v2i_v2fl(mval_i, ptc->m_xy); if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, tgpf->depth_arr + i) == 0) && (i && (ED_view3d_depth_read_cached_seg( @@ -1437,9 +1437,9 @@ static int gpencil_points_from_stack(tGPDfill *tgpf) while (!BLI_stack_is_empty(tgpf->stack)) { int v[2]; BLI_stack_pop(tgpf->stack, &v); - copy_v2fl_v2i(&point2D->x, v); + copy_v2fl_v2i(point2D->m_xy, v); /* shift points to center of pixel */ - add_v2_fl(&point2D->x, 0.5f); + add_v2_fl(point2D->m_xy, 0.5f); point2D->pressure = 1.0f; point2D->strength = 1.0f; point2D->time = 0.0f; @@ -2108,8 +2108,7 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event) /* first time the event is not enabled to show help lines. */ if ((tgpf->oldkey != -1) || (!help_lines)) { - ARegion *region = BKE_area_find_region_xy( - CTX_wm_area(C), RGN_TYPE_ANY, event->xy[0], event->xy[1]); + ARegion *region = BKE_area_find_region_xy(CTX_wm_area(C), RGN_TYPE_ANY, event->xy); if (region) { bool in_bounds = false; /* Perform bounds check */ @@ -2126,7 +2125,7 @@ static int gpencil_fill_modal(bContext *C, wmOperator *op, const wmEvent *event) tgpf->gps_mouse = BKE_gpencil_stroke_new(0, 1, 10.0f); tGPspoint point2D; bGPDspoint *pt = &tgpf->gps_mouse->points[0]; - copy_v2fl_v2i(&point2D.x, tgpf->mouse); + copy_v2fl_v2i(point2D.m_xy, tgpf->mouse); gpencil_stroke_convertcoords_tpoint( tgpf->scene, tgpf->region, tgpf->ob, &point2D, NULL, &pt->x); diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index 601780ea651..0802b806060 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -322,7 +322,7 @@ void gpencil_apply_parent_point(struct Depsgraph *depsgraph, * generic based on gpencil_point_to_xy_fl */ void gpencil_point_3d_to_xy(const GP_SpaceConversion *gsc, - const short flag, + short flag, const float pt[3], float xy[2]); @@ -410,7 +410,7 @@ int gpencil_delete_selected_point_wrap(bContext *C); * \param gps: Stroke data * \param subdivide: Number of times to subdivide */ -void gpencil_subdivide_stroke(bGPdata *gpd, bGPDstroke *gps, const int subdivide); +void gpencil_subdivide_stroke(bGPdata *gpd, bGPDstroke *gps, int subdivide); /* Layers Enums -------------------------------------- */ diff --git a/source/blender/editors/gpencil/gpencil_mesh.c b/source/blender/editors/gpencil/gpencil_mesh.c index 11e02b9832f..efe29e852f2 100644 --- a/source/blender/editors/gpencil/gpencil_mesh.c +++ b/source/blender/editors/gpencil/gpencil_mesh.c @@ -142,6 +142,9 @@ static bool gpencil_bake_ob_list(bContext *C, Depsgraph *depsgraph, Scene *scene /* Add active object. In some files this could not be in selected array. */ Object *obact = CTX_data_active_object(C); + if (obact == NULL) { + return false; + } if (obact->type == OB_MESH) { elem = MEM_callocN(sizeof(GpBakeOb), __func__); diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index dabe2050b28..79dda480a0a 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -54,6 +54,7 @@ #include "BKE_deform.h" #include "BKE_global.h" #include "BKE_gpencil.h" +#include "BKE_gpencil_curve.h" #include "BKE_gpencil_geom.h" #include "BKE_layer.h" #include "BKE_main.h" @@ -493,7 +494,7 @@ static void gpencil_brush_jitter(bGPdata *gpd, tGPspoint *pt, const float amplit /* Mouse movement in ints -> floats. */ if (gpd->runtime.sbuffer_used > 1) { tGPspoint *pt_prev = pt - 1; - sub_v2_v2v2(mvec, &pt->x, &pt_prev->x); + sub_v2_v2v2(mvec, pt->m_xy, pt_prev->m_xy); normalize_v2(mvec); /* Rotate mvec by 90 degrees... */ float angle = angle_v2v2(mvec, axis); @@ -502,7 +503,7 @@ static void gpencil_brush_jitter(bGPdata *gpd, tGPspoint *pt, const float amplit mvec[1] *= sin(angle); /* Scale by displacement amount, and apply. */ - madd_v2_v2fl(&pt->x, mvec, amplitude * 10.0f); + madd_v2_v2fl(pt->m_xy, mvec, amplitude * 10.0f); } } @@ -520,8 +521,7 @@ static void gpencil_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const /* Apply to first point (only if there are 2 points because before no data to do it ) */ if (gpd->runtime.sbuffer_used == 1) { - mvec[0] = (mval[0] - (pt - 1)->x); - mvec[1] = (mval[1] - (pt - 1)->y); + sub_v2_v2v2(mvec, mval, (pt - 1)->m_xy); normalize_v2(mvec); /* uses > 1.0f to get a smooth transition in first point */ @@ -533,8 +533,7 @@ static void gpencil_brush_angle(bGPdata *gpd, Brush *brush, tGPspoint *pt, const /* apply from second point */ if (gpd->runtime.sbuffer_used >= 1) { - mvec[0] = (mval[0] - (pt - 1)->x); - mvec[1] = (mval[1] - (pt - 1)->y); + sub_v2_v2v2(mvec, mval, (pt - 1)->m_xy); normalize_v2(mvec); fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */ @@ -581,25 +580,25 @@ static void gpencil_smooth_buffer(tGPsdata *p, float inf, int idx) /* Compute smoothed coordinate by taking the ones nearby */ if (pta) { - copy_v2_v2(a, &pta->x); + copy_v2_v2(a, pta->m_xy); madd_v2_v2fl(sco, a, average_fac); pressure += pta->pressure * average_fac; strength += pta->strength * average_fac; } if (ptb) { - copy_v2_v2(b, &ptb->x); + copy_v2_v2(b, ptb->m_xy); madd_v2_v2fl(sco, b, average_fac); pressure += ptb->pressure * average_fac; strength += ptb->strength * average_fac; } if (ptc) { - copy_v2_v2(c, &ptc->x); + copy_v2_v2(c, ptc->m_xy); madd_v2_v2fl(sco, c, average_fac); pressure += ptc->pressure * average_fac; strength += ptc->strength * average_fac; } if (ptd) { - copy_v2_v2(d, &ptd->x); + copy_v2_v2(d, ptd->m_xy); madd_v2_v2fl(sco, d, average_fac); pressure += ptd->pressure * average_fac; strength += ptd->strength * average_fac; @@ -609,7 +608,7 @@ static void gpencil_smooth_buffer(tGPsdata *p, float inf, int idx) * for Guide mode. */ if (!guide->use_guide) { interp_v2_v2v2(c, c, sco, inf); - copy_v2_v2(&ptc->x, c); + copy_v2_v2(ptc->m_xy, c); } /* Interpolate pressure. */ ptc->pressure = interpf(ptc->pressure, pressure, inf); @@ -646,37 +645,37 @@ static void gpencil_smooth_segment(bGPdata *gpd, const float inf, int from_idx, /* Compute smoothed coordinate by taking the ones nearby */ if (pta) { - madd_v2_v2fl(sco, &pta->x, average_fac); + madd_v2_v2fl(sco, pta->m_xy, average_fac); pressure += pta->pressure * average_fac; strength += pta->strength * average_fac; } else { - madd_v2_v2fl(sco, &ptc->x, average_fac); + madd_v2_v2fl(sco, ptc->m_xy, average_fac); pressure += ptc->pressure * average_fac; strength += ptc->strength * average_fac; } if (ptb) { - madd_v2_v2fl(sco, &ptb->x, average_fac); + madd_v2_v2fl(sco, ptb->m_xy, average_fac); pressure += ptb->pressure * average_fac; strength += ptb->strength * average_fac; } else { - madd_v2_v2fl(sco, &ptc->x, average_fac); + madd_v2_v2fl(sco, ptc->m_xy, average_fac); pressure += ptc->pressure * average_fac; strength += ptc->strength * average_fac; } - madd_v2_v2fl(sco, &ptc->x, average_fac); + madd_v2_v2fl(sco, ptc->m_xy, average_fac); pressure += ptc->pressure * average_fac; strength += ptc->strength * average_fac; - madd_v2_v2fl(sco, &ptd->x, average_fac); + madd_v2_v2fl(sco, ptd->m_xy, average_fac); pressure += ptd->pressure * average_fac; strength += ptd->strength * average_fac; /* Based on influence factor, blend between original and optimal smoothed coordinate. */ - interp_v2_v2v2(&ptc->x, &ptc->x, sco, inf); + interp_v2_v2v2(ptc->m_xy, ptc->m_xy, sco, inf); /* Interpolate pressure. */ ptc->pressure = interpf(ptc->pressure, pressure, inf); @@ -738,7 +737,8 @@ static void gpencil_apply_randomness(tGPsdata *p, /* Apply randomness to uv texture rotation. */ if ((brush_settings->uv_random > 0.0f) && (uv)) { if ((brush_settings->flag2 & GP_BRUSH_USE_UV_AT_STROKE) == 0) { - float rand = BLI_hash_int_01(BLI_hash_int_2d((int)pt->x, gpd->runtime.sbuffer_used)) * 2.0f - + float rand = BLI_hash_int_01(BLI_hash_int_2d((int)pt->m_xy[0], gpd->runtime.sbuffer_used)) * + 2.0f - 1.0f; value = rand * M_PI_2 * brush_settings->uv_random; } @@ -778,7 +778,7 @@ static short gpencil_stroke_addpoint(tGPsdata *p, pt = (tGPspoint *)(gpd->runtime.sbuffer); /* store settings */ - copy_v2_v2(&pt->x, mval); + copy_v2_v2(pt->m_xy, mval); /* T44932 - Pressure vals are unreliable, so ignore for now */ pt->pressure = 1.0f; pt->strength = 1.0f; @@ -794,7 +794,7 @@ static short gpencil_stroke_addpoint(tGPsdata *p, pt = ((tGPspoint *)(gpd->runtime.sbuffer) + 1); /* store settings */ - copy_v2_v2(&pt->x, mval); + copy_v2_v2(pt->m_xy, mval); /* T44932 - Pressure vals are unreliable, so ignore for now */ pt->pressure = 1.0f; pt->strength = 1.0f; @@ -825,7 +825,7 @@ static short gpencil_stroke_addpoint(tGPsdata *p, pt->strength = brush_settings->draw_strength; pt->pressure = 1.0f; pt->uv_rot = 0.0f; - copy_v2_v2(&pt->x, mval); + copy_v2_v2(pt->m_xy, mval); /* pressure */ if (brush_settings->flag & GP_BRUSH_USE_PRESSURE) { @@ -835,7 +835,7 @@ static short gpencil_stroke_addpoint(tGPsdata *p, /* color strength */ if (brush_settings->flag & GP_BRUSH_USE_STRENGTH_PRESSURE) { pt->strength *= BKE_curvemapping_evaluateF(brush_settings->curve_strength, 0, pressure); - CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); + CLAMP(pt->strength, MIN2(GPENCIL_STRENGTH_MIN, brush_settings->draw_strength), 1.0f); } /* Set vertex colors for buffer. */ @@ -919,6 +919,19 @@ static short gpencil_stroke_addpoint(tGPsdata *p, return GP_STROKEADD_INVALID; } +static void gpencil_stroke_unselect(bGPdata *gpd, bGPDstroke *gps) +{ + gps->flag &= ~GP_STROKE_SELECT; + BKE_gpencil_stroke_select_index_reset(gps); + for (int i = 0; i < gps->totpoints; i++) { + gps->points[i].flag &= ~GP_SPOINT_SELECT; + } + /* Update the selection from the stroke to the curve. */ + if (gps->editcurve) { + BKE_gpencil_editcurve_stroke_sync_selection(gpd, gps, gps->editcurve); + } +} + /* make a new stroke from the buffer data */ static void gpencil_stroke_newfrombuffer(tGPsdata *p) { @@ -929,6 +942,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p) tGPspoint *ptc; MDeformVert *dvert = NULL; Brush *brush = p->brush; + BrushGpencilSettings *brush_settings = brush->gpencil_settings; ToolSettings *ts = p->scene->toolsettings; Depsgraph *depsgraph = p->depsgraph; Object *obact = (Object *)p->ownerPtr.data; @@ -1013,11 +1027,11 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p) ptc = gpd->runtime.sbuffer; /* convert screen-coordinates to appropriate coordinates (and store them) */ - gpencil_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + gpencil_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL); /* copy pressure and time */ pt->pressure = ptc->pressure; pt->strength = ptc->strength; - CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); + CLAMP(pt->strength, MIN2(GPENCIL_STRENGTH_MIN, brush_settings->draw_strength), 1.0f); copy_v4_v4(pt->vert_color, ptc->vert_color); pt->time = ptc->time; /* Apply the vertex color to point. */ @@ -1047,11 +1061,11 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p) ptc = ((tGPspoint *)gpd->runtime.sbuffer) + (gpd->runtime.sbuffer_used - 1); /* convert screen-coordinates to appropriate coordinates (and store them) */ - gpencil_stroke_convertcoords(p, &ptc->x, &pt->x, NULL); + gpencil_stroke_convertcoords(p, ptc->m_xy, &pt->x, NULL); /* copy pressure and time */ pt->pressure = ptc->pressure; pt->strength = ptc->strength; - CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); + CLAMP(pt->strength, MIN2(GPENCIL_STRENGTH_MIN, brush_settings->draw_strength), 1.0f); pt->time = ptc->time; /* Apply the vertex color to point. */ ED_gpencil_point_vertex_color_set(ts, brush, pt, ptc); @@ -1100,7 +1114,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p) int i; for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used; i++, ptc++, pt++) { - round_v2i_v2fl(mval_i, &ptc->x); + round_v2i_v2fl(mval_i, ptc->m_xy); if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, depth_arr + i) == 0) && (i && (ED_view3d_depth_read_cached_seg( @@ -1171,12 +1185,12 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p) for (i = 0, ptc = gpd->runtime.sbuffer; i < gpd->runtime.sbuffer_used && ptc; i++, ptc++, pt++) { /* convert screen-coordinates to appropriate coordinates (and store them) */ - gpencil_stroke_convertcoords(p, &ptc->x, &pt->x, depth_arr ? depth_arr + i : NULL); + gpencil_stroke_convertcoords(p, ptc->m_xy, &pt->x, depth_arr ? depth_arr + i : NULL); /* copy pressure and time */ pt->pressure = ptc->pressure; pt->strength = ptc->strength; - CLAMP(pt->strength, GPENCIL_STRENGTH_MIN, 1.0f); + CLAMP(pt->strength, MIN2(GPENCIL_STRENGTH_MIN, brush_settings->draw_strength), 1.0f); copy_v4_v4(pt->vert_color, ptc->vert_color); pt->time = ptc->time; pt->uv_fac = ptc->uv_fac; @@ -1283,7 +1297,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p) /* Join with existing strokes. */ if (ts->gpencil_flags & GP_TOOL_FLAG_AUTOMERGE_STROKE) { - if (gps->prev != NULL) { + if ((gps->prev != NULL) || (gps->next != NULL)) { BKE_gpencil_stroke_boundingbox_calc(gps); float diff_mat[4][4], ctrl1[2], ctrl2[2]; BKE_gpencil_layer_transform_matrix_get(depsgraph, p->ob, gpl, diff_mat); @@ -1301,7 +1315,12 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p) ctrl2, GPENCIL_MINIMUM_JOIN_DIST, &pt_index); + if (gps_target != NULL) { + /* Unselect all points of source and destination strokes. This is required to avoid + * a change in the resolution of the original strokes during the join. */ + gpencil_stroke_unselect(gpd, gps); + gpencil_stroke_unselect(gpd, gps_target); gps = ED_gpencil_stroke_join_and_trim(p->gpd, p->gpf, gps, gps_target, pt_index); } else { @@ -1487,7 +1506,7 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p, bGPDspoint pt_temp; gpencil_point_to_parent_space(gps->points, p->diff_mat, &pt_temp); gpencil_point_to_xy(&p->gsc, gps, &pt_temp, &pc1[0], &pc1[1]); - /* do boundbox check first */ + /* Do bound-box check first. */ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) { /* only check if point is inside */ if (len_v2v2_int(mval_i, pc1) <= radius) { @@ -1512,7 +1531,7 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p, gpencil_point_to_parent_space(pt1, p->diff_mat, &npt); gpencil_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]); - /* do boundbox check first */ + /* Do bound-box check first. */ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) { /* only check if point is inside */ if (len_v2v2_int(mval_i, pc1) <= radius) { @@ -1567,6 +1586,12 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p, } bGPDspoint npt; + gpencil_point_to_parent_space(pt1, p->diff_mat, &npt); + gpencil_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]); + + gpencil_point_to_parent_space(pt2, p->diff_mat, &npt); + gpencil_point_to_xy(&p->gsc, gps, &npt, &pc2[0], &pc2[1]); + if (pt0) { gpencil_point_to_parent_space(pt0, p->diff_mat, &npt); gpencil_point_to_xy(&p->gsc, gps, &npt, &pc0[0], &pc0[1]); @@ -1576,13 +1601,7 @@ static void gpencil_stroke_eraser_dostroke(tGPsdata *p, copy_v2_v2_int(pc0, pc1); } - gpencil_point_to_parent_space(pt1, p->diff_mat, &npt); - gpencil_point_to_xy(&p->gsc, gps, &npt, &pc1[0], &pc1[1]); - - gpencil_point_to_parent_space(pt2, p->diff_mat, &npt); - gpencil_point_to_xy(&p->gsc, gps, &npt, &pc2[0], &pc2[1]); - - /* Check that point segment of the boundbox of the eraser stroke */ + /* Check that point segment of the bound-box of the eraser stroke. */ if (((!ELEM(V2D_IS_CLIPPED, pc0[0], pc0[1])) && BLI_rcti_isect_pt(rect, pc0[0], pc0[1])) || ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) || ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) { @@ -2798,14 +2817,14 @@ static void gpencil_draw_apply(bContext *C, wmOperator *op, tGPsdata *p, Depsgra pt = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_used - 1; if (p->paintmode != GP_PAINTMODE_ERASER) { - ED_gpencil_toggle_brush_cursor(C, true, &pt->x); + ED_gpencil_toggle_brush_cursor(C, true, pt->m_xy); } } else if ((p->brush->gpencil_settings->flag & GP_BRUSH_STABILIZE_MOUSE_TEMP) && (gpd->runtime.sbuffer_used > 0)) { pt = (tGPspoint *)gpd->runtime.sbuffer + gpd->runtime.sbuffer_used - 1; if (p->paintmode != GP_PAINTMODE_ERASER) { - ED_gpencil_toggle_brush_cursor(C, true, &pt->x); + ED_gpencil_toggle_brush_cursor(C, true, pt->m_xy); } } } @@ -3303,8 +3322,7 @@ static void gpencil_brush_angle_segment(tGPsdata *p, tGPspoint *pt_prev, tGPspoi /* angle vector of the brush with full thickness */ const float v0[2] = {cos(angle), sin(angle)}; - mvec[0] = pt->x - pt_prev->x; - mvec[1] = pt->y - pt_prev->y; + sub_v2_v2v2(mvec, pt->m_xy, pt_prev->m_xy); normalize_v2(mvec); fac = 1.0f - fabs(dot_v2v2(v0, mvec)); /* 0.0 to 1.0 */ /* interpolate with previous point for smoother transitions */ @@ -3355,11 +3373,11 @@ static void gpencil_add_arc_points(tGPsdata *p, const float mval[2], int segment * for arc curve. */ float v_prev[2], v_cur[2], v_half[2]; - sub_v2_v2v2(v_cur, mval, &pt_prev->x); + sub_v2_v2v2(v_cur, mval, pt_prev->m_xy); - sub_v2_v2v2(v_prev, &pt_prev->x, &pt_before->x); - interp_v2_v2v2(v_half, &pt_prev->x, mval, 0.5f); - sub_v2_v2(v_half, &pt_prev->x); + sub_v2_v2v2(v_prev, pt_prev->m_xy, pt_before->m_xy); + interp_v2_v2v2(v_half, pt_prev->m_xy, mval, 0.5f); + sub_v2_v2(v_half, pt_prev->m_xy); /* If angle is too sharp undo all changes and return. */ const float min_angle = DEG2RADF(120.0f); @@ -3378,14 +3396,14 @@ static void gpencil_add_arc_points(tGPsdata *p, const float mval[2], int segment /* Calc the position of the control point. */ float ctl[2]; - add_v2_v2v2(ctl, &pt_prev->x, v_prev); + add_v2_v2v2(ctl, pt_prev->m_xy, v_prev); float step = M_PI_2 / (float)(segments + 1); float a = step; float midpoint[2], start[2], end[2], cp1[2], corner[2]; - mid_v2_v2v2(midpoint, &pt_prev->x, mval); - copy_v2_v2(start, &pt_prev->x); + mid_v2_v2v2(midpoint, pt_prev->m_xy, mval); + copy_v2_v2(start, pt_prev->m_xy); copy_v2_v2(end, mval); copy_v2_v2(cp1, ctl); @@ -3396,8 +3414,8 @@ static void gpencil_add_arc_points(tGPsdata *p, const float mval[2], int segment tGPspoint *pt_step = pt_prev; for (int i = 0; i < segments; i++) { pt = &points[idx_prev + i - 1]; - pt->x = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a); - pt->y = corner[1] + (end[1] - corner[1]) * sinf(a) + (start[1] - corner[1]) * cosf(a); + pt->m_xy[0] = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a); + pt->m_xy[1] = corner[1] + (end[1] - corner[1]) * sinf(a) + (start[1] - corner[1]) * cosf(a); /* Set pressure and strength equals to previous. It will be smoothed later. */ pt->pressure = pt_prev->pressure; @@ -3460,8 +3478,8 @@ static void gpencil_add_guide_points(const tGPsdata *p, for (int i = 0; i < segments; i++) { pt = &points[idx_prev + i - 1]; - gpencil_rotate_v2_v2v2fl(&pt->x, start, p->guide.origin, -a); - gpencil_snap_to_guide(p, guide, &pt->x); + gpencil_rotate_v2_v2v2fl(pt->m_xy, start, p->guide.origin, -a); + gpencil_snap_to_guide(p, guide, pt->m_xy); a += step; /* Set pressure and strength equals to previous. It will be smoothed later. */ @@ -3477,8 +3495,8 @@ static void gpencil_add_guide_points(const tGPsdata *p, for (int i = 0; i < segments; i++) { pt = &points[idx_prev + i - 1]; - interp_v2_v2v2(&pt->x, start, end, a); - gpencil_snap_to_guide(p, guide, &pt->x); + interp_v2_v2v2(pt->m_xy, start, end, a); + gpencil_snap_to_guide(p, guide, pt->m_xy); a += step; /* Set pressure and strength equals to previous. It will be smoothed later. */ @@ -3681,8 +3699,7 @@ static int gpencil_draw_modal(bContext *C, wmOperator *op, const wmEvent *event) */ if ((p->region) && (p->region->regiontype == RGN_TYPE_TOOLS)) { /* Change to whatever region is now under the mouse */ - ARegion *current_region = BKE_area_find_region_xy( - p->area, RGN_TYPE_ANY, event->xy[0], event->xy[1]); + ARegion *current_region = BKE_area_find_region_xy(p->area, RGN_TYPE_ANY, event->xy); if (current_region) { /* Assume that since we found the cursor in here, it is in bounds diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index 8157e9d8fe7..2715491414a 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -423,6 +423,7 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi Scene *scene = tgpi->scene; char status_str[UI_MAX_DRAW_STR]; char msg_str[UI_MAX_DRAW_STR]; + const int cur_subdiv = tgpi->type == GP_STROKE_BOX ? tgpi->tot_edges - 1 : tgpi->tot_edges - 2; if (tgpi->type == GP_STROKE_LINE) { BLI_strncpy(msg_str, @@ -480,7 +481,7 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi sizeof(status_str), "%s: %d (%d, %d) (%d, %d)", msg_str, - tgpi->tot_edges, + cur_subdiv, (int)tgpi->start[0], (int)tgpi->start[1], (int)tgpi->end[0], @@ -491,7 +492,7 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi sizeof(status_str), "%s: %d (%d, %d)", msg_str, - tgpi->tot_edges, + cur_subdiv, (int)tgpi->end[0], (int)tgpi->end[1]); } @@ -503,7 +504,7 @@ static void gpencil_primitive_status_indicators(bContext *C, tGPDprimitive *tgpi sizeof(status_str), "%s: %d (%d, %d) (%d, %d)", msg_str, - tgpi->tot_edges, + cur_subdiv, (int)tgpi->start[0], (int)tgpi->start[1], (int)tgpi->end[0], @@ -540,7 +541,7 @@ static void gpencil_primitive_rectangle(tGPDprimitive *tgpi, tGPspoint *points2D if (tgpi->tot_edges == 1) { for (int j = 0; j < 4; j++) { tGPspoint *p2d = &points2D[j]; - copy_v2_v2(&p2d->x, coords[j]); + copy_v2_v2(p2d->m_xy, coords[j]); } } else { @@ -550,7 +551,7 @@ static void gpencil_primitive_rectangle(tGPDprimitive *tgpi, tGPspoint *points2D float a = 0.0f; for (int k = 0; k < tgpi->tot_edges; k++) { tGPspoint *p2d = &points2D[i]; - interp_v2_v2v2(&p2d->x, coords[j], coords[j + 1], a); + interp_v2_v2v2(p2d->m_xy, coords[j], coords[j + 1], a); a += step; i++; } @@ -581,7 +582,7 @@ static void gpencil_primitive_line(tGPDprimitive *tgpi, tGPspoint *points2D, boo for (int i = tgpi->tot_stored_edges; i < totpoints; i++) { tGPspoint *p2d = &points2D[i]; - interp_v2_v2v2(&p2d->x, tgpi->start, tgpi->end, a); + interp_v2_v2v2(p2d->m_xy, tgpi->start, tgpi->end, a); a += step; } @@ -627,8 +628,8 @@ static void gpencil_primitive_arc(tGPDprimitive *tgpi, tGPspoint *points2D) for (int i = tgpi->tot_stored_edges; i < totpoints; i++) { tGPspoint *p2d = &points2D[i]; - p2d->x = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a); - p2d->y = corner[1] + (end[1] - corner[1]) * sinf(a) + (start[1] - corner[1]) * cosf(a); + p2d->m_xy[0] = corner[0] + (end[0] - corner[0]) * sinf(a) + (start[0] - corner[0]) * cosf(a); + p2d->m_xy[1] = corner[1] + (end[1] - corner[1]) * sinf(a) + (start[1] - corner[1]) * cosf(a); a += step; } float color[4]; @@ -663,7 +664,7 @@ static void gpencil_primitive_bezier(tGPDprimitive *tgpi, tGPspoint *points2D) for (int i = tgpi->tot_stored_edges; i < totpoints; i++) { tGPspoint *p2d = &points2D[i]; - interp_v2_v2v2v2v2_cubic(&p2d->x, bcp1, bcp2, bcp3, bcp4, a); + interp_v2_v2v2v2v2_cubic(p2d->m_xy, bcp1, bcp2, bcp3, bcp4, a); a += step; } float color[4]; @@ -697,8 +698,8 @@ static void gpencil_primitive_circle(tGPDprimitive *tgpi, tGPspoint *points2D) for (int i = tgpi->tot_stored_edges; i < totpoints; i++) { tGPspoint *p2d = &points2D[i]; - p2d->x = (center[0] + cosf(a) * radius[0]); - p2d->y = (center[1] + sinf(a) * radius[1]); + p2d->m_xy[0] = (center[0] + cosf(a) * radius[0]); + p2d->m_xy[1] = (center[1] + sinf(a) * radius[1]); a += step; } float color[4]; @@ -726,7 +727,6 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) const bool is_camera = is_lock_axis_view && (tgpi->rv3d->persp == RV3D_CAMOB) && (!is_depth); if (tgpi->type == GP_STROKE_BOX) { - tgpi->tot_edges--; gps->totpoints = (tgpi->tot_edges * 4 + tgpi->tot_stored_edges); } else { @@ -801,7 +801,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) const ViewDepths *depths = tgpi->depths; tGPspoint *ptc = &points2D[0]; for (int i = 0; i < gps->totpoints; i++, ptc++) { - round_v2i_v2fl(mval_i, &ptc->x); + round_v2i_v2fl(mval_i, ptc->m_xy); if ((ED_view3d_depth_read_cached(depths, mval_i, depth_margin, depth_arr + i) == 0) && (i && (ED_view3d_depth_read_cached_seg( depths, mval_i, mval_prev, depth_margin + 1, depth_arr + i) == 0))) { @@ -894,7 +894,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) /* Store original points */ float tmp_xyp[2]; - copy_v2_v2(tmp_xyp, &p2d->x); + copy_v2_v2(tmp_xyp, p2d->m_xy); /* calc pressure */ float curve_pressure = 1.0; @@ -926,8 +926,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) /* vector */ float mvec[2], svec[2]; if (i > 0) { - mvec[0] = (p2d->x - (p2d - 1)->x); - mvec[1] = (p2d->y - (p2d - 1)->y); + sub_v2_v2v2(mvec, p2d->m_xy, (p2d - 1)->m_xy); normalize_v2(mvec); } else { @@ -942,7 +941,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) else { mul_v2_fl(svec, fac); } - add_v2_v2(&p2d->x, svec); + add_v2_v2(p2d->m_xy, svec); } /* color strength */ @@ -992,7 +991,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) } } - copy_v2_v2(&tpt->x, &p2d->x); + copy_v2_v2(tpt->m_xy, p2d->m_xy); tpt->pressure = pressure; tpt->strength = strength; @@ -1064,7 +1063,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) } /* Restore original points */ - copy_v2_v2(&p2d->x, tmp_xyp); + copy_v2_v2(p2d->m_xy, tmp_xyp); } /* store cps and convert coords */ @@ -1254,7 +1253,7 @@ static void gpencil_primitive_init(bContext *C, wmOperator *op) tgpi->tot_stored_edges = 0; tgpi->subdiv = RNA_int_get(op->ptr, "subdivision"); - RNA_int_set(op->ptr, "edges", tgpi->subdiv + 2); + RNA_int_set(op->ptr, "edges", tgpi->type == GP_STROKE_BOX ? tgpi->subdiv + 1 : tgpi->subdiv + 2); tgpi->tot_edges = RNA_int_get(op->ptr, "edges"); tgpi->flag = IDLE; tgpi->lock_axis = ts->gp_sculpt.lock_axis; @@ -1617,7 +1616,7 @@ static void gpencil_primitive_move(tGPDprimitive *tgpi, bool reset) for (int i = 0; i < gps->totpoints; i++) { tGPspoint *p2d = &points2D[i]; - add_v2_v2(&p2d->x, move); + add_v2_v2(p2d->m_xy, move); } add_v2_v2(tgpi->start, move); @@ -1720,7 +1719,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e case WHEELUPMOUSE: { if ((event->val != KM_RELEASE)) { tgpi->tot_edges = tgpi->tot_edges + 1; - CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES); + CLAMP(tgpi->tot_edges, tgpi->type == GP_STROKE_BOX ? 1 : MIN_EDGES, MAX_EDGES); RNA_int_set(op->ptr, "edges", tgpi->tot_edges); gpencil_primitive_update(C, op, tgpi); } @@ -1730,7 +1729,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e case WHEELDOWNMOUSE: { if ((event->val != KM_RELEASE)) { tgpi->tot_edges = tgpi->tot_edges - 1; - CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES); + CLAMP(tgpi->tot_edges, tgpi->type == GP_STROKE_BOX ? 1 : MIN_EDGES, MAX_EDGES); RNA_int_set(op->ptr, "edges", tgpi->tot_edges); gpencil_primitive_update(C, op, tgpi); } @@ -1886,7 +1885,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e case WHEELUPMOUSE: { if ((event->val != KM_RELEASE)) { tgpi->tot_edges = tgpi->tot_edges + 1; - CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES); + CLAMP(tgpi->tot_edges, tgpi->type == GP_STROKE_BOX ? 1 : MIN_EDGES, MAX_EDGES); RNA_int_set(op->ptr, "edges", tgpi->tot_edges); /* update screen */ @@ -1898,7 +1897,7 @@ static int gpencil_primitive_modal(bContext *C, wmOperator *op, const wmEvent *e case WHEELDOWNMOUSE: { if ((event->val != KM_RELEASE)) { tgpi->tot_edges = tgpi->tot_edges - 1; - CLAMP(tgpi->tot_edges, MIN_EDGES, MAX_EDGES); + CLAMP(tgpi->tot_edges, tgpi->type == GP_STROKE_BOX ? 1 : MIN_EDGES, MAX_EDGES); RNA_int_set(op->ptr, "edges", tgpi->tot_edges); /* update screen */ @@ -2038,15 +2037,8 @@ static void gpencil_primitive_common_props(wmOperatorType *ot, int subdiv, int t RNA_def_property_flag(prop, PROP_SKIP_SAVE); /* Internal prop. */ - prop = RNA_def_int(ot->srna, - "edges", - MIN_EDGES, - MIN_EDGES, - MAX_EDGES, - "Edges", - "Number of points by edge", - MIN_EDGES, - MAX_EDGES); + prop = RNA_def_int( + ot->srna, "edges", 1, 1, MAX_EDGES, "Edges", "Number of points by edge", 1, MAX_EDGES); RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); RNA_def_enum(ot->srna, "type", gpencil_primitive_type, type, "Type", "Type of shape"); diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c index 186c45c9f39..50c7202599a 100644 --- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c +++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c @@ -1454,7 +1454,7 @@ static bool gpencil_sculpt_brush_do_stroke(tGP_BrushEditData *gso, gpencil_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]); pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; - /* do boundbox check first */ + /* Do bound-box check first. */ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) { /* only check if point is inside */ int mval_i[2]; @@ -1492,7 +1492,7 @@ static bool gpencil_sculpt_brush_do_stroke(tGP_BrushEditData *gso, gpencil_point_to_parent_space(pt2, diff_mat, &npt); gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]); - /* Check that point segment of the boundbox of the selection stroke */ + /* Check that point segment of the bound-box of the selection stroke. */ if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) || ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) { /* Check if point segment of stroke had anything to do with diff --git a/source/blender/editors/gpencil/gpencil_trace.h b/source/blender/editors/gpencil/gpencil_trace.h index 7c62288f65d..77fb823b3b6 100644 --- a/source/blender/editors/gpencil/gpencil_trace.h +++ b/source/blender/editors/gpencil/gpencil_trace.h @@ -91,7 +91,7 @@ void ED_gpencil_trace_bitmap_invert(const potrace_bitmap_t *bm); */ void ED_gpencil_trace_image_to_bitmap(struct ImBuf *ibuf, const potrace_bitmap_t *bm, - const float threshold); + float threshold); /** * Convert Potrace Bitmap to Grease Pencil strokes @@ -106,7 +106,7 @@ void ED_gpencil_trace_data_to_strokes(struct Main *bmain, struct Object *ob, struct bGPDframe *gpf, int32_t offset[2], - const float scale, - const float sample, - const int32_t resolution, - const int32_t thickness); + float scale, + float sample, + int32_t resolution, + int32_t thickness); diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index f082af979a1..81a844cf6e1 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -870,7 +870,7 @@ void gpencil_stroke_convertcoords_tpoint(Scene *scene, } int mval_i[2]; - round_v2i_v2fl(mval_i, &point2D->x); + round_v2i_v2fl(mval_i, point2D->m_xy); if ((depth != NULL) && (ED_view3d_autodist_simple(region, mval_i, r_out, 0, depth))) { /* projecting onto 3D-Geometry @@ -878,7 +878,7 @@ void gpencil_stroke_convertcoords_tpoint(Scene *scene, */ } else { - float mval_f[2] = {point2D->x, point2D->y}; + float mval_f[2] = {UNPACK2(point2D->m_xy)}; float mval_prj[2]; float rvec[3], dvec[3]; float zfac; @@ -2020,7 +2020,7 @@ static void gpencil_stroke_convertcoords(ARegion *region, const float origin[3], float out[3]) { - float mval_f[2] = {(float)point2D->x, (float)point2D->y}; + float mval_f[2] = {UNPACK2(point2D->m_xy)}; float mval_prj[2]; float rvec[3], dvec[3]; float zfac; @@ -2808,8 +2808,8 @@ static void gpencil_sbuffer_vertex_color_random( if (brush_settings->flag & GP_BRUSH_GROUP_RANDOM) { int seed = ((uint)(ceil(PIL_check_seconds_timer())) + 1) % 128; - int ix = (int)(tpt->x * seed); - int iy = (int)(tpt->y * seed); + int ix = (int)(tpt->m_xy[0] * seed); + int iy = (int)(tpt->m_xy[1] * seed); int iz = ix + iy * seed; float hsv[3]; float factor_value[3]; diff --git a/source/blender/editors/gpencil/gpencil_vertex_paint.c b/source/blender/editors/gpencil/gpencil_vertex_paint.c index 633e371cbd1..05304f9914f 100644 --- a/source/blender/editors/gpencil/gpencil_vertex_paint.c +++ b/source/blender/editors/gpencil/gpencil_vertex_paint.c @@ -441,12 +441,12 @@ static bool brush_tint_apply(tGP_BrushVertexpaintData *gso, CLAMP_MIN(pt->vert_color[3], 0.0f); } else { - /* Premult. */ + /* Pre-multiply. */ mul_v3_fl(pt->vert_color, pt->vert_color[3]); /* "Alpha over" blending. */ interp_v3_v3v3(pt->vert_color, pt->vert_color, gso->linear_color, inf); pt->vert_color[3] = pt->vert_color[3] * (1.0 - inf) + inf; - /* Un-premult. */ + /* Un pre-multiply. */ if (pt->vert_color[3] > 0.0f) { mul_v3_fl(pt->vert_color, 1.0f / pt->vert_color[3]); } @@ -460,12 +460,12 @@ static bool brush_tint_apply(tGP_BrushVertexpaintData *gso, CLAMP_MIN(gps->vert_color_fill[3], 0.0f); } else { - /* Premult. */ + /* Pre-multiply. */ mul_v3_fl(gps->vert_color_fill, gps->vert_color_fill[3]); /* "Alpha over" blending. */ interp_v3_v3v3(gps->vert_color_fill, gps->vert_color_fill, gso->linear_color, inf_fill); gps->vert_color_fill[3] = gps->vert_color_fill[3] * (1.0 - inf_fill) + inf_fill; - /* Un-premult. */ + /* Un pre-multiply. */ if (gps->vert_color_fill[3] > 0.0f) { mul_v3_fl(gps->vert_color_fill, 1.0f / gps->vert_color_fill[3]); } @@ -865,7 +865,7 @@ static bool gpencil_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, gpencil_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]); pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; - /* do boundbox check first */ + /* Do bound-box check first. */ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) { /* only check if point is inside */ int mval_i[2]; @@ -905,7 +905,7 @@ static bool gpencil_vertexpaint_select_stroke(tGP_BrushVertexpaintData *gso, gpencil_point_to_parent_space(pt2, diff_mat, &npt); gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]); - /* Check that point segment of the boundbox of the selection stroke */ + /* Check that point segment of the bound-box of the selection stroke. */ if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) || ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) { /* Check if point segment of stroke had anything to do with diff --git a/source/blender/editors/gpencil/gpencil_weight_paint.c b/source/blender/editors/gpencil/gpencil_weight_paint.c index b3249294119..15f99d83f6d 100644 --- a/source/blender/editors/gpencil/gpencil_weight_paint.c +++ b/source/blender/editors/gpencil/gpencil_weight_paint.c @@ -432,7 +432,7 @@ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, gpencil_point_to_xy(gsc, gps, &pt_temp, &pc1[0], &pc1[1]); pt_active = (pt->runtime.pt_orig) ? pt->runtime.pt_orig : pt; - /* do boundbox check first */ + /* Do bound-box check first. */ if ((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) { /* only check if point is inside */ int mval_i[2]; @@ -461,7 +461,7 @@ static void gpencil_weightpaint_select_stroke(tGP_BrushWeightpaintData *gso, gpencil_point_to_parent_space(pt2, diff_mat, &npt); gpencil_point_to_xy(gsc, gps, &npt, &pc2[0], &pc2[1]); - /* Check that point segment of the boundbox of the selection stroke */ + /* Check that point segment of the bound-box of the selection stroke */ if (((!ELEM(V2D_IS_CLIPPED, pc1[0], pc1[1])) && BLI_rcti_isect_pt(rect, pc1[0], pc1[1])) || ((!ELEM(V2D_IS_CLIPPED, pc2[0], pc2[1])) && BLI_rcti_isect_pt(rect, pc2[0], pc2[1]))) { /* Check if point segment of stroke had anything to do with diff --git a/source/blender/editors/include/BIF_glutil.h b/source/blender/editors/include/BIF_glutil.h index 8f2a189e35e..61dd0adc84d 100644 --- a/source/blender/editors/include/BIF_glutil.h +++ b/source/blender/editors/include/BIF_glutil.h @@ -55,6 +55,36 @@ typedef struct IMMDrawPixelsTexState { IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin); /** + * Unlike the `immDrawPixelsTexTiled` functions, this doesn't do tiled drawing, but draws into a + * full texture. + * + * Use the currently bound shader. + * + * Use #immDrawPixelsTexSetup to bind the shader you want before calling #immDrawPixelsTex. + * + * If using a special shader double check it uses the same attributes "pos" "texCoord" and uniform + * "image". + * + * If color is NULL then use white by default + * + * Unless <em>state->do_shader_unbind<em> is explicitly set to `false`, the shader is unbound when + * finished. + */ +void immDrawPixelsTexScaledFullSize(const IMMDrawPixelsTexState *state, + const float x, + const float y, + const int img_w, + const int img_h, + const eGPUTextureFormat gpu_format, + const bool use_filter, + const void *rect, + const float scaleX, + const float scaleY, + const float xzoom, + const float yzoom, + const float color[4]); + +/** * #immDrawPixelsTex - Functions like a limited #glDrawPixels, but actually draws the * image using textures, which can be tremendously faster on low-end * cards, and also avoids problems with the raster position being @@ -68,45 +98,45 @@ IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin); * model-view and projection matrices are assumed to define a * 1-to-1 mapping to screen space. */ -void immDrawPixelsTex(IMMDrawPixelsTexState *state, - float x, - float y, - int img_w, - int img_h, - eGPUTextureFormat gpu_format, - bool use_filter, - void *rect, - float xzoom, - float yzoom, - const float color[4]); -void immDrawPixelsTex_clipping(IMMDrawPixelsTexState *state, - float x, - float y, - int img_w, - int img_h, - eGPUTextureFormat gpu_format, - bool use_filter, - void *rect, - float clip_min_x, - float clip_min_y, - float clip_max_x, - float clip_max_y, - float xzoom, - float yzoom, - const float color[4]); -void immDrawPixelsTexScaled(IMMDrawPixelsTexState *state, - float x, - float y, - int img_w, - int img_h, - eGPUTextureFormat gpu_format, - bool use_filter, - void *rect, - float scaleX, - float scaleY, - float xzoom, - float yzoom, - const float color[4]); +void immDrawPixelsTexTiled(IMMDrawPixelsTexState *state, + float x, + float y, + int img_w, + int img_h, + eGPUTextureFormat gpu_format, + bool use_filter, + void *rect, + float xzoom, + float yzoom, + const float color[4]); +void immDrawPixelsTexTiled_clipping(IMMDrawPixelsTexState *state, + float x, + float y, + int img_w, + int img_h, + eGPUTextureFormat gpu_format, + bool use_filter, + void *rect, + float clip_min_x, + float clip_min_y, + float clip_max_x, + float clip_max_y, + float xzoom, + float yzoom, + const float color[4]); +void immDrawPixelsTexTiled_scaling(IMMDrawPixelsTexState *state, + float x, + float y, + int img_w, + int img_h, + eGPUTextureFormat gpu_format, + bool use_filter, + void *rect, + float scaleX, + float scaleY, + float xzoom, + float yzoom, + const float color[4]); /** * Use the currently bound shader. * @@ -118,26 +148,26 @@ void immDrawPixelsTexScaled(IMMDrawPixelsTexState *state, * * If color is NULL then use white by default * - * Be also aware that this function unbinds the shader when - * it's finished. + * Unless <em>state->do_shader_unbind<em> is explicitly set to `false`, the shader is unbound when + * finished. */ -void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state, - float x, - float y, - int img_w, - int img_h, - eGPUTextureFormat gpu_format, - bool use_filter, - void *rect, - float scaleX, - float scaleY, - float clip_min_x, - float clip_min_y, - float clip_max_x, - float clip_max_y, - float xzoom, - float yzoom, - const float color[4]); +void immDrawPixelsTexTiled_scaling_clipping(IMMDrawPixelsTexState *state, + float x, + float y, + int img_w, + int img_h, + eGPUTextureFormat gpu_format, + bool use_filter, + void *rect, + float scaleX, + float scaleY, + float clip_min_x, + float clip_min_y, + float clip_max_x, + float clip_max_y, + float xzoom, + float yzoom, + const float color[4]); /* Image buffer drawing functions, with display transform * diff --git a/source/blender/editors/include/ED_armature.h b/source/blender/editors/include/ED_armature.h index 0053bf5c865..7631bd35e79 100644 --- a/source/blender/editors/include/ED_armature.h +++ b/source/blender/editors/include/ED_armature.h @@ -94,7 +94,7 @@ struct EditBone *ED_armature_ebone_add_primitive(struct Object *obedit_arm, */ float ED_armature_ebone_roll_to_vector(const struct EditBone *bone, const float align_axis[3], - const bool axis_only); + bool axis_only); /** * \param centermode: 0 == do center, 1 == center new, 2 == center cursor. * @@ -105,8 +105,8 @@ void ED_armature_origin_set( /** * See #BKE_armature_transform for object-mode transform. */ -void ED_armature_edit_transform(struct bArmature *arm, const float mat[4][4], const bool do_props); -void ED_armature_transform(struct bArmature *arm, const float mat[4][4], const bool do_props); +void ED_armature_edit_transform(struct bArmature *arm, const float mat[4][4], bool do_props); +void ED_armature_transform(struct bArmature *arm, const float mat[4][4], bool do_props); /* armature_naming.c */ @@ -138,7 +138,7 @@ void ED_armature_bone_rename(struct Main *bmain, void ED_armature_bones_flip_names(struct Main *bmain, struct bArmature *arm, struct ListBase *bones_names, - const bool do_strip_numbers); + bool do_strip_numbers); /* armature_ops.c */ @@ -203,7 +203,7 @@ bool ED_armature_edit_select_pick( * * \note Visibility checks must be done by the caller. */ -bool ED_armature_edit_select_op_from_tagged(struct bArmature *arm, const int sel_op); +bool ED_armature_edit_select_op_from_tagged(struct bArmature *arm, int sel_op); /* armature_skinning.c */ @@ -215,8 +215,8 @@ void ED_object_vgroup_calc_from_armature(struct ReportList *reports, struct Scene *scene, struct Object *ob, struct Object *par, - const int mode, - const bool mirror); + int mode, + bool mirror); /* editarmature_undo.c */ @@ -251,7 +251,7 @@ bool ED_armature_ebone_is_child_recursive(struct EditBone *ebone_parent, * \return The shared parent or NULL. */ struct EditBone *ED_armature_ebone_find_shared_parent(struct EditBone *ebone_child[], - const unsigned int ebone_child_tot); + unsigned int ebone_child_tot); void ED_armature_ebone_to_mat3(struct EditBone *ebone, float r_mat[3][3]); void ED_armature_ebone_to_mat4(struct EditBone *ebone, float r_mat[4][4]); void ED_armature_ebone_from_mat3(struct EditBone *ebone, const float mat[3][3]); @@ -282,10 +282,10 @@ void ED_armature_ebone_listbase_temp_clear(struct ListBase *lb); /** * Free's bones and their properties. */ -void ED_armature_ebone_listbase_free(struct ListBase *lb, const bool do_id_user); +void ED_armature_ebone_listbase_free(struct ListBase *lb, bool do_id_user); void ED_armature_ebone_listbase_copy(struct ListBase *lb_dst, struct ListBase *lb_src, - const bool do_id_user); + bool do_id_user); int ED_armature_ebone_selectflag_get(const struct EditBone *ebone); void ED_armature_ebone_selectflag_set(struct EditBone *ebone, int flag); @@ -353,14 +353,14 @@ void ED_armature_pose_select_in_wpaint_mode(struct ViewLayer *view_layer, bool ED_pose_deselect_all_multi_ex(struct Base **bases, uint bases_len, int select_mode, - const bool ignore_visibility); -bool ED_pose_deselect_all_multi(struct bContext *C, int select_mode, const bool ignore_visibility); + bool ignore_visibility); +bool ED_pose_deselect_all_multi(struct bContext *C, int select_mode, bool ignore_visibility); /** * 'select_mode' is usual SEL_SELECT/SEL_DESELECT/SEL_TOGGLE/SEL_INVERT. * When true, 'ignore_visibility' makes this func also affect invisible bones * (hidden or on hidden layers). */ -bool ED_pose_deselect_all(struct Object *ob, int select_mode, const bool ignore_visibility); +bool ED_pose_deselect_all(struct Object *ob, int select_mode, bool ignore_visibility); void ED_pose_bone_select_tag_update(struct Object *ob); /** * Utility method for changing the selection status of a bone. diff --git a/source/blender/editors/include/ED_buttons.h b/source/blender/editors/include/ED_buttons.h index 79404aada41..c3479c10d58 100644 --- a/source/blender/editors/include/ED_buttons.h +++ b/source/blender/editors/include/ED_buttons.h @@ -36,7 +36,7 @@ struct bContext; * \return The total number of items in the array returned. */ int ED_buttons_tabs_list(struct SpaceProperties *sbuts, short *context_tabs_array); -bool ED_buttons_tab_has_search_result(struct SpaceProperties *sbuts, const int index); +bool ED_buttons_tab_has_search_result(struct SpaceProperties *sbuts, int index); void ED_buttons_search_string_set(struct SpaceProperties *sbuts, const char *value); int ED_buttons_search_string_length(struct SpaceProperties *sbuts); @@ -48,7 +48,7 @@ bool ED_buttons_should_sync_with_outliner(const struct bContext *C, void ED_buttons_set_context(const struct bContext *C, struct SpaceProperties *sbuts, PointerRNA *ptr, - const int context); + int context); #ifdef __cplusplus } diff --git a/source/blender/editors/include/ED_curve.h b/source/blender/editors/include/ED_curve.h index 805d42b6fbc..a9225a5db60 100644 --- a/source/blender/editors/include/ED_curve.h +++ b/source/blender/editors/include/ED_curve.h @@ -100,7 +100,7 @@ void ED_curve_editfont_load(struct Object *obedit); void ED_curve_editfont_make(struct Object *obedit); void ED_curve_editfont_free(struct Object *obedit); -void ED_text_to_object(struct bContext *C, const struct Text *text, const bool split_lines); +void ED_text_to_object(struct bContext *C, const struct Text *text, bool split_lines); void ED_curve_beztcpy(struct EditNurb *editnurb, struct BezTriple *dst, diff --git a/source/blender/editors/include/ED_file_indexer.h b/source/blender/editors/include/ED_file_indexer.h index 0afa8819def..3b19a738b90 100644 --- a/source/blender/editors/include/ED_file_indexer.h +++ b/source/blender/editors/include/ED_file_indexer.h @@ -146,7 +146,7 @@ void ED_file_indexer_entries_clear(FileIndexerEntries *indexer_entries); void ED_file_indexer_entries_extend_from_datablock_infos( FileIndexerEntries *indexer_entries, const LinkNode * /* BLODataBlockInfo */ datablock_infos, - const int idcode); + int idcode); #ifdef __cplusplus } diff --git a/source/blender/editors/include/ED_fileselect.h b/source/blender/editors/include/ED_fileselect.h index 460de58bdb2..0528057fb54 100644 --- a/source/blender/editors/include/ED_fileselect.h +++ b/source/blender/editors/include/ED_fileselect.h @@ -127,7 +127,7 @@ void ED_fileselect_set_params_from_userdef(struct SpaceFile *sfile); */ void ED_fileselect_params_to_userdef(struct SpaceFile *sfile, const int temp_win_size[2], - const bool is_maximized); + bool is_maximized); void ED_fileselect_init_layout(struct SpaceFile *sfile, struct ARegion *region); @@ -171,9 +171,7 @@ void ED_fileselect_activate_asset_catalog(const struct SpaceFile *sfile, bUUID c * Activate and select 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_activate_by_id(struct SpaceFile *sfile, struct ID *asset_id, bool deferred); void ED_fileselect_deselect_all(struct SpaceFile *sfile); void ED_fileselect_activate_by_relpath(struct SpaceFile *sfile, const char *relative_path); @@ -256,7 +254,7 @@ char *ED_fsmenu_entry_get_name(struct FSMenuEntry *fsentry); void ED_fsmenu_entry_set_name(struct FSMenuEntry *fsentry, const char *name); int ED_fsmenu_entry_get_icon(struct FSMenuEntry *fsentry); -void ED_fsmenu_entry_set_icon(struct FSMenuEntry *fsentry, const int icon); +void ED_fsmenu_entry_set_icon(struct FSMenuEntry *fsentry, int icon); #ifdef __cplusplus } diff --git a/source/blender/editors/include/ED_gizmo_library.h b/source/blender/editors/include/ED_gizmo_library.h index 55beff40177..8d4177faa0c 100644 --- a/source/blender/editors/include/ED_gizmo_library.h +++ b/source/blender/editors/include/ED_gizmo_library.h @@ -65,7 +65,7 @@ void ED_gizmo_draw_preset_circle(const struct wmGizmo *gz, void ED_gizmo_draw_preset_facemap(const struct bContext *C, const struct wmGizmo *gz, struct Object *ob, - const int facemap, + int facemap, int select_id); /* -------------------------------------------------------------------- */ @@ -97,13 +97,13 @@ enum { * * \note Needs to be called before #WM_gizmo_target_property_def_rna! */ -void ED_gizmo_arrow3d_set_ui_range(struct wmGizmo *gz, const float min, const float max); +void ED_gizmo_arrow3d_set_ui_range(struct wmGizmo *gz, float min, float max); /** * Define a custom factor for arrow min/max distance. * * \note Needs to be called before #WM_gizmo_target_property_def_rna! */ -void ED_gizmo_arrow3d_set_range_fac(struct wmGizmo *gz, const float range_fac); +void ED_gizmo_arrow3d_set_range_fac(struct wmGizmo *gz, float range_fac); /* -------------------------------------------------------------------- */ /* Cage Gizmo */ @@ -248,9 +248,9 @@ struct Dial3dParams { }; void ED_gizmotypes_dial_3d_draw_util(const float matrix_basis[4][4], const float matrix_final[4][4], - const float line_width, + float line_width, const float color[4], - const bool select, + bool select, struct Dial3dParams *params); /* snap3d_gizmo.c */ diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index 99164bbe439..919ea3e4a6b 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -94,7 +94,7 @@ typedef enum eGP_TargetObjectMode { */ typedef struct tGPspoint { /** Coordinates x and y of cursor (in relative to area). */ - float x, y; + float m_xy[2]; /** Pressure of tablet at this point. */ float pressure; /** Pressure of tablet at this point for alpha factor. */ @@ -193,7 +193,7 @@ bool ED_gpencil_has_keyframe_v3d(struct Scene *scene, struct Object *ob, int cfr /* ----------- Stroke Editing Utilities ---------------- */ bool ED_gpencil_frame_has_selected_stroke(const struct bGPDframe *gpf); -bool ED_gpencil_layer_has_selected_stroke(const struct bGPDlayer *gpl, const bool is_multiedit); +bool ED_gpencil_layer_has_selected_stroke(const struct bGPDlayer *gpl, bool is_multiedit); /** * Check whether given stroke can be edited given the supplied context. @@ -250,12 +250,8 @@ void ED_annotation_draw_view3d(struct Scene *scene, struct View3D *v3d, struct ARegion *region, bool only3d); -void ED_annotation_draw_ex(struct Scene *scene, - struct bGPdata *gpd, - int winx, - int winy, - const int cfra, - const char spacetype); +void ED_annotation_draw_ex( + struct Scene *scene, struct bGPdata *gpd, int winx, int winy, int cfra, char spacetype); /* ----------- Grease-Pencil AnimEdit API ------------------ */ /** @@ -315,7 +311,7 @@ void ED_gpencil_layer_frames_duplicate(struct bGPDlayer *gpl); void ED_gpencil_layer_merge(struct bGPdata *gpd, struct bGPDlayer *gpl_src, struct bGPDlayer *gpl_dst, - const bool reverse); + bool reverse); /** * Set keyframe type for selected frames from given gp-layer @@ -348,14 +344,14 @@ bool ED_gpencil_anim_copybuf_copy(struct bAnimContext *ac); /** * Pastes keyframes from buffer, and reports success. */ -bool ED_gpencil_anim_copybuf_paste(struct bAnimContext *ac, const short copy_mode); +bool ED_gpencil_anim_copybuf_paste(struct bAnimContext *ac, short copy_mode); /* ------------ Grease-Pencil Undo System ------------------ */ int ED_gpencil_session_active(void); /** * \param step: eUndoStepDir. */ -int ED_undo_gpencil_step(struct bContext *C, const int step); /* eUndoStepDir. */ +int ED_undo_gpencil_step(struct bContext *C, int step); /* eUndoStepDir. */ /* ------------ Grease-Pencil Armature ------------------ */ bool ED_gpencil_add_armature(const struct bContext *C, @@ -410,7 +406,7 @@ void ED_gpencil_brush_draw_eraser(struct Brush *brush, int x, int y); */ void ED_gpencil_stroke_init_data(struct bGPDstroke *gps, const float *array, - const int totpoints, + int totpoints, const float mat[4][4]); /** @@ -457,7 +453,7 @@ void ED_gpencil_project_stroke_to_plane(const struct Scene *scene, struct bGPDlayer *gpl, struct bGPDstroke *gps, const float origin[3], - const int axis); + int axis); /** * Reproject given point to a plane locked to axis to avoid stroke offset * \param pt: Point to affect (used for input & output). @@ -467,7 +463,7 @@ void ED_gpencil_project_point_to_plane(const struct Scene *scene, struct bGPDlayer *gpl, const struct RegionView3D *rv3d, const float origin[3], - const int axis, + int axis, struct bGPDspoint *pt); /** * Get drawing reference point for conversion or projection of the stroke @@ -490,8 +486,8 @@ void ED_gpencil_stroke_reproject(struct Depsgraph *depsgraph, struct bGPDlayer *gpl, struct bGPDframe *gpf, struct bGPDstroke *gps, - const eGP_ReprojectModes mode, - const bool keep_original); + eGP_ReprojectModes mode, + bool keep_original); /** * Turn brush cursor in on/off. @@ -513,7 +509,7 @@ void ED_gpencil_vgroup_remove(struct bContext *C, struct Object *ob); */ void ED_gpencil_vgroup_select(struct bContext *C, struct Object *ob); /** - * Unselect points of vertex group. + * Un-select points of vertex group. */ void ED_gpencil_vgroup_deselect(struct bContext *C, struct Object *ob); @@ -552,7 +548,7 @@ int ED_gpencil_select_stroke_segment(struct bGPdata *gpd, struct bGPDspoint *pt, bool select, bool insert, - const float scale, + float scale, float r_hita[3], float r_hitb[3]); @@ -566,7 +562,7 @@ void ED_gpencil_select_curve_toggle_all(struct bContext *C, int action); struct tGPspoint *ED_gpencil_sbuffer_ensure(struct tGPspoint *buffer_array, int *buffer_size, int *buffer_used, - const bool clear); + bool clear); void ED_gpencil_sbuffer_update_eval(struct bGPdata *gpd, struct Object *ob_eval); /** @@ -600,7 +596,7 @@ void ED_gpencil_init_random_settings(struct Brush *brush, bool ED_gpencil_stroke_check_collision(const struct GP_SpaceConversion *gsc, struct bGPDstroke *gps, const float mouse[2], - const int radius, + int radius, const float diff_mat[4][4]); /** * Check if a point is inside of the stroke. @@ -631,7 +627,7 @@ struct bGPDstroke *ED_gpencil_stroke_nearest_to_ends(struct bContext *C, struct bGPDstroke *gps, const float ctrl1[2], const float ctrl2[2], - const float radius, + float radius, int *r_index); /** * Get extremes of stroke in 2D using current view. @@ -649,12 +645,12 @@ struct bGPDstroke *ED_gpencil_stroke_join_and_trim(struct bGPdata *gpd, struct bGPDframe *gpf, struct bGPDstroke *gps, struct bGPDstroke *gps_dst, - const int pt_index); + int pt_index); /** * Close if the distance between extremes is below threshold. */ -void ED_gpencil_stroke_close_by_distance(struct bGPDstroke *gps, const float threshold); +void ED_gpencil_stroke_close_by_distance(struct bGPDstroke *gps, float threshold); #ifdef __cplusplus } diff --git a/source/blender/editors/include/ED_image.h b/source/blender/editors/include/ED_image.h index 3308ae2c178..3c1b8e4ecc1 100644 --- a/source/blender/editors/include/ED_image.h +++ b/source/blender/editors/include/ED_image.h @@ -38,24 +38,24 @@ struct Main; struct ReportList; struct Scene; struct SpaceImage; +struct View2D; struct bContext; struct wmOperator; struct wmWindowManager; -struct View2D; /* image_draw.c */ -float ED_space_image_zoom_level(const struct View2D *v2d, const int grid_dimension); +float ED_space_image_zoom_level(const struct View2D *v2d, int grid_dimension); void ED_space_image_grid_steps(struct SpaceImage *sima, float grid_steps[SI_GRID_STEPS_LEN], - const int grid_dimension); + int grid_dimension); /** * Calculate the increment snapping value for UV/image editor based on the zoom factor * The code in here (except the offset part) is used in `grid_frag.glsl` (see `grid_res`) for * drawing the grid overlay for the UV/Image editor. */ -float ED_space_image_increment_snap_value(const int grid_dimesnions, +float ED_space_image_increment_snap_value(int grid_dimesnions, const float grid_steps[SI_GRID_STEPS_LEN], - const float zoom_factor); + float zoom_factor); /* image_edit.c, exported for transform. */ @@ -198,7 +198,7 @@ typedef struct ImageFrameRange { */ ListBase ED_image_filesel_detect_sequences(struct Main *bmain, struct wmOperator *op, - const bool detect_udim); + bool detect_udim); #ifdef __cplusplus } diff --git a/source/blender/editors/include/ED_keyframes_edit.h b/source/blender/editors/include/ED_keyframes_edit.h index bafe68bd28d..f006378658b 100644 --- a/source/blender/editors/include/ED_keyframes_edit.h +++ b/source/blender/editors/include/ED_keyframes_edit.h @@ -93,6 +93,13 @@ typedef enum eEditKeyframes_Snap { SNAP_KEYS_TIME, } eEditKeyframes_Snap; +/* equalizing tools */ +typedef enum eEditKeyframes_Equalize { + EQUALIZE_HANDLES_LEFT = (1 << 0), + EQUALIZE_HANDLES_RIGHT = (1 << 1), + EQUALIZE_HANDLES_BOTH = (EQUALIZE_HANDLES_LEFT | EQUALIZE_HANDLES_RIGHT), +} eEditKeyframes_Equalize; + /* mirroring tools */ typedef enum eEditKeyframes_Mirror { MIRROR_KEYS_CURFRAME = 1, @@ -259,6 +266,18 @@ short ANIM_fcurve_keyframes_loop(KeyframeEditData *ked, KeyframeEditFunc key_cb, FcuEditFunc fcu_cb); /** + * Sets selected keyframes' bezier handles to an equal length and optionally makes + * the keyframes' handles horizontal. + * \param handle_length: Desired handle length, must be positive. + * \param flatten: Makes the keyframes' handles the same value as the keyframe, + * flattening the curve at that point. + */ +void ANIM_fcurve_equalize_keyframes_loop(struct FCurve *fcu, + eEditKeyframes_Equalize mode, + float handle_length, + bool flatten); + +/** * Function for working with any type (i.e. one of the known types) of animation channel. */ short ANIM_animchannel_keyframes_loop(KeyframeEditData *ked, @@ -327,13 +346,13 @@ KeyframeEditFunc ANIM_editkeyframes_easing(short mode); /** * Get a callback to populate the selection settings map - * requires: ked->custom = char[] of length fcurve->totvert. + * requires: `ked->custom = char[]` of length `fcurve->totvert`. */ KeyframeEditFunc ANIM_editkeyframes_buildselmap(short mode); /** * Change the selection status of the keyframe based on the map entry for this vert - * requires: ked->custom = char[] of length fcurve->totvert. + * requires: `ked->custom = char[]` of length `fcurve->totvert`. */ short bezt_selmap_flush(KeyframeEditData *ked, struct BezTriple *bezt); @@ -380,10 +399,26 @@ bool delete_fcurve_keys(struct FCurve *fcu); void clear_fcurve_keys(struct FCurve *fcu); void duplicate_fcurve_keys(struct FCurve *fcu); +typedef struct FCurveSegment { + struct FCurveSegment *next, *prev; + int start_index, length; +} FCurveSegment; + +/** + * Return a list of #FCurveSegment with a start index and a length. + * A segment is a continuous selection of keyframes. + * Keys that have BEZT_FLAG_IGNORE_TAG set are treated as unselected. + * The caller is responsible for freeing the memory. + */ +ListBase find_fcurve_segments(struct FCurve *fcu); void clean_fcurve(struct bAnimContext *ac, struct bAnimListElem *ale, float thresh, bool cleardefault); +void blend_to_neighbor_fcurve_segment(struct FCurve *fcu, + struct FCurveSegment *segment, + float factor); +void breakdown_fcurve_segment(struct FCurve *fcu, struct FCurveSegment *segment, float factor); bool decimate_fcurve(struct bAnimListElem *ale, float remove_ratio, float error_sq_max); /** * Use a weighted moving-means method to reduce intensity of fluctuations. @@ -397,8 +432,8 @@ void ANIM_fcurves_copybuf_free(void); short copy_animedit_keys(struct bAnimContext *ac, ListBase *anim_data); short paste_animedit_keys(struct bAnimContext *ac, ListBase *anim_data, - const eKeyPasteOffset offset_mode, - const eKeyMergeMode merge_mode, + eKeyPasteOffset offset_mode, + eKeyMergeMode merge_mode, bool flip); /* ************************************************ */ diff --git a/source/blender/editors/include/ED_keyframes_keylist.h b/source/blender/editors/include/ED_keyframes_keylist.h index 4194444ca0f..36a30bd5ee6 100644 --- a/source/blender/editors/include/ED_keyframes_keylist.h +++ b/source/blender/editors/include/ED_keyframes_keylist.h @@ -140,12 +140,9 @@ typedef enum eKeyframeExtremeDrawOpts { struct AnimKeylist *ED_keylist_create(void); void ED_keylist_free(struct AnimKeylist *keylist); void ED_keylist_prepare_for_direct_access(struct AnimKeylist *keylist); -const struct ActKeyColumn *ED_keylist_find_exact(const struct AnimKeylist *keylist, - const float cfra); -const struct ActKeyColumn *ED_keylist_find_next(const struct AnimKeylist *keylist, - const float cfra); -const struct ActKeyColumn *ED_keylist_find_prev(const struct AnimKeylist *keylist, - const float cfra); +const struct ActKeyColumn *ED_keylist_find_exact(const struct AnimKeylist *keylist, float cfra); +const struct ActKeyColumn *ED_keylist_find_next(const struct AnimKeylist *keylist, float cfra); +const struct ActKeyColumn *ED_keylist_find_prev(const struct AnimKeylist *keylist, float cfra); const struct ActKeyColumn *ED_keylist_find_any_between(const struct AnimKeylist *keylist, const Range2f frame_range); bool ED_keylist_is_empty(const struct AnimKeylist *keylist); @@ -160,41 +157,39 @@ int64_t ED_keylist_array_len(const struct AnimKeylist *keylist); void fcurve_to_keylist(struct AnimData *adt, struct FCurve *fcu, struct AnimKeylist *keylist, - const int saction_flag); + int saction_flag); /* Action Group */ void agroup_to_keylist(struct AnimData *adt, struct bActionGroup *agrp, struct AnimKeylist *keylist, - const int saction_flag); + int saction_flag); /* Action */ void action_to_keylist(struct AnimData *adt, struct bAction *act, struct AnimKeylist *keylist, - const int saction_flag); + int saction_flag); /* Object */ void ob_to_keylist(struct bDopeSheet *ads, struct Object *ob, struct AnimKeylist *keylist, - const int saction_flag); + int saction_flag); /* Cache File */ void cachefile_to_keylist(struct bDopeSheet *ads, struct CacheFile *cache_file, struct AnimKeylist *keylist, - const int saction_flag); + int saction_flag); /* Scene */ void scene_to_keylist(struct bDopeSheet *ads, struct Scene *sce, struct AnimKeylist *keylist, - const int saction_flag); + int saction_flag); /* DopeSheet Summary */ -void summary_to_keylist(struct bAnimContext *ac, - struct AnimKeylist *keylist, - const int saction_flag); +void summary_to_keylist(struct bAnimContext *ac, struct AnimKeylist *keylist, int saction_flag); /* Grease Pencil datablock summary */ void gpencil_to_keylist(struct bDopeSheet *ads, struct bGPdata *gpd, struct AnimKeylist *keylist, - const bool active); + bool active); /* Grease Pencil Layer */ void gpl_to_keylist(struct bDopeSheet *ads, struct bGPDlayer *gpl, struct AnimKeylist *keylist); /* Mask */ diff --git a/source/blender/editors/include/ED_keyframing.h b/source/blender/editors/include/ED_keyframing.h index d539c7b688c..8d89555c732 100644 --- a/source/blender/editors/include/ED_keyframing.h +++ b/source/blender/editors/include/ED_keyframing.h @@ -62,7 +62,7 @@ struct NlaKeyframingContext; * \param use_autokey_mode: include settings from key-framing mode in the result * (i.e. replace only). */ -eInsertKeyFlags ANIM_get_keyframing_flags(struct Scene *scene, const bool use_autokey_mode); +eInsertKeyFlags ANIM_get_keyframing_flags(struct Scene *scene, bool use_autokey_mode); /* -------- */ @@ -81,15 +81,13 @@ struct FCurve *ED_action_fcurve_ensure(struct Main *bmain, const char group[], struct PointerRNA *ptr, const char rna_path[], - const int array_index); + int array_index); /** * Find the F-Curve from the Active Action, * for the given Animation Data block. This assumes that all the destinations are valid. */ -struct FCurve *ED_action_fcurve_find(struct bAction *act, - const char rna_path[], - const int array_index); +struct FCurve *ED_action_fcurve_find(struct bAction *act, const char rna_path[], int array_index); /* -------- */ @@ -449,11 +447,11 @@ typedef enum eDriverFCurveCreationMode { */ struct FCurve *verify_driver_fcurve(struct ID *id, const char rna_path[], - const int array_index, + int array_index, eDriverFCurveCreationMode creation_mode); struct FCurve *alloc_driver_fcurve(const char rna_path[], - const int array_index, + int array_index, eDriverFCurveCreationMode creation_mode); /* -------- */ diff --git a/source/blender/editors/include/ED_lattice.h b/source/blender/editors/include/ED_lattice.h index dc800d78007..3d779fd14ef 100644 --- a/source/blender/editors/include/ED_lattice.h +++ b/source/blender/editors/include/ED_lattice.h @@ -43,7 +43,7 @@ bool ED_lattice_flags_set(struct Object *obedit, int flag); bool ED_lattice_select_pick( struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle); -bool ED_lattice_deselect_all_multi_ex(struct Base **bases, const uint bases_len); +bool ED_lattice_deselect_all_multi_ex(struct Base **bases, uint bases_len); bool ED_lattice_deselect_all_multi(struct bContext *C); /* editlattice_undo.c */ diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h index 3aab6882dc2..1a4c36acff9 100644 --- a/source/blender/editors/include/ED_mask.h +++ b/source/blender/editors/include/ED_mask.h @@ -79,7 +79,7 @@ bool ED_mask_selected_minmax(const struct bContext *C, /* mask_draw.c */ -void ED_mask_draw(const struct bContext *C, const char draw_flag, const char draw_type); +void ED_mask_draw(const struct bContext *C, char draw_flag, char draw_type); /** * Sets up the opengl context. * width, height are to match the values from #ED_mask_get_size(). @@ -87,26 +87,25 @@ void ED_mask_draw(const struct bContext *C, const char draw_flag, const char dra void ED_mask_draw_region(struct Depsgraph *depsgraph, struct Mask *mask, struct ARegion *region, - const char draw_flag, - const char draw_type, - const eMaskOverlayMode overlay_mode, - const int width_i, - const int height_i, - const float aspx, - const float aspy, - const bool do_scale_applied, - const bool do_draw_cb, + char draw_flag, + char draw_type, + eMaskOverlayMode overlay_mode, + int width_i, + int height_i, + float aspx, + float aspy, + bool do_scale_applied, + bool do_draw_cb, float stabmat[4][4], const struct bContext *C); -void ED_mask_draw_frames( - struct Mask *mask, struct ARegion *region, const int cfra, const int sfra, const int efra); +void ED_mask_draw_frames(struct Mask *mask, struct ARegion *region, int cfra, int sfra, int efra); /* mask_shapekey.c */ -void ED_mask_layer_shape_auto_key(struct MaskLayer *mask_layer, const int frame); -bool ED_mask_layer_shape_auto_key_all(struct Mask *mask, const int frame); -bool ED_mask_layer_shape_auto_key_select(struct Mask *mask, const int frame); +void ED_mask_layer_shape_auto_key(struct MaskLayer *mask_layer, int frame); +bool ED_mask_layer_shape_auto_key_all(struct Mask *mask, int frame); +bool ED_mask_layer_shape_auto_key_select(struct Mask *mask, int frame); /* ----------- Mask AnimEdit API ------------------ */ diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 35838f4ce48..0721aa21a16 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -60,30 +60,30 @@ struct wmOperator; /* editmesh_utils.c */ /** - * \param em: Editmesh. - * \param use_self: Allow a vertex to point to its self (middle verts). + * \param em: Edit-mesh used for generating mirror data. + * \param use_self: Allow a vertex to point to itself (middle verts). * \param use_select: Restrict to selected verts. * \param respecthide: Skip hidden vertices. * \param use_topology: Use topology mirror. * \param maxdist: Distance for close point test. - * \param r_index: Optional array to write into, as an alternative to a customdata layer + * \param r_index: Optional array to write into, as an alternative to a custom-data layer * (length of total verts). */ void EDBM_verts_mirror_cache_begin_ex(struct BMEditMesh *em, - const int axis, - const bool use_self, - const bool use_select, - const bool respecthide, - const bool use_topology, + int axis, + bool use_self, + bool use_select, + bool respecthide, + bool use_topology, float maxdist, int *r_index); void EDBM_verts_mirror_cache_begin(struct BMEditMesh *em, - const int axis, - const bool use_self, - const bool use_select, - const bool respecthide, - const bool use_topology); -void EDBM_verts_mirror_apply(struct BMEditMesh *em, const int sel_from, const int sel_to); + int axis, + bool use_self, + bool use_select, + bool respecthide, + bool use_topology); +void EDBM_verts_mirror_apply(struct BMEditMesh *em, int sel_from, int sel_to); struct BMVert *EDBM_verts_mirror_get(struct BMEditMesh *em, struct BMVert *v); struct BMEdge *EDBM_verts_mirror_get_edge(struct BMEditMesh *em, struct BMEdge *e); struct BMFace *EDBM_verts_mirror_get_face(struct BMEditMesh *em, struct BMFace *f); @@ -96,7 +96,7 @@ void EDBM_mesh_normals_update(struct BMEditMesh *em); void EDBM_mesh_clear(struct BMEditMesh *em); void EDBM_selectmode_to_scene(struct bContext *C); -void EDBM_mesh_make(struct Object *ob, const int select_mode, const bool add_key_index); +void EDBM_mesh_make(struct Object *ob, int select_mode, bool add_key_index); /** * Should only be called on the active edit-mesh, otherwise call #BKE_editmesh_free_data. */ @@ -115,10 +115,10 @@ void EDBM_mesh_load(struct Main *bmain, struct Object *ob); * edges select/deselect faces and vertices, and in face select mode faces select/deselect * edges and vertices. */ -void EDBM_select_more(struct BMEditMesh *em, const bool use_face_step); -void EDBM_select_less(struct BMEditMesh *em, const bool use_face_step); +void EDBM_select_more(struct BMEditMesh *em, bool use_face_step); +void EDBM_select_less(struct BMEditMesh *em, bool use_face_step); -void EDBM_selectmode_flush_ex(struct BMEditMesh *em, const short selectmode); +void EDBM_selectmode_flush_ex(struct BMEditMesh *em, short selectmode); void EDBM_selectmode_flush(struct BMEditMesh *em); void EDBM_deselect_flush(struct BMEditMesh *em); @@ -145,17 +145,17 @@ void EDBM_update(struct Mesh *me, const struct EDBMUpdate_Params *params); /** * Bad level call from Python API. */ -void EDBM_update_extern(struct Mesh *me, const bool do_tessellation, const bool is_destructive); +void EDBM_update_extern(struct Mesh *me, bool do_tessellation, bool is_destructive); /** * A specialized vert map used by stitch operator. */ struct UvElementMap *BM_uv_element_map_create(struct BMesh *bm, const struct Scene *scene, - const bool face_selected, - const bool uv_selected, - const bool use_winding, - const bool do_islands); + bool face_selected, + bool uv_selected, + bool use_winding, + bool do_islands); void BM_uv_element_map_free(struct UvElementMap *element_map); struct UvElement *BM_uv_element_get(struct UvElementMap *map, struct BMFace *efa, @@ -169,21 +169,17 @@ bool EDBM_uv_check(struct BMEditMesh *em); * last_sel, use em->act_face otherwise get the last selected face in the editselections * at the moment, last_sel is mainly useful for making sure the space image doesn't flicker. */ -struct BMFace *EDBM_uv_active_face_get(struct BMEditMesh *em, - const bool sloppy, - const bool selected); +struct BMFace *EDBM_uv_active_face_get(struct BMEditMesh *em, bool sloppy, bool selected); void BM_uv_vert_map_free(struct UvVertMap *vmap); struct UvMapVert *BM_uv_vert_map_at_index(struct UvVertMap *vmap, unsigned int v); /** * Return a new #UvVertMap from the edit-mesh. */ -struct UvVertMap *BM_uv_vert_map_create(struct BMesh *bm, - const bool use_select, - const bool use_winding); +struct UvVertMap *BM_uv_vert_map_create(struct BMesh *bm, bool use_select, bool use_winding); -void EDBM_flag_enable_all(struct BMEditMesh *em, const char hflag); -void EDBM_flag_disable_all(struct BMEditMesh *em, const char hflag); +void EDBM_flag_enable_all(struct BMEditMesh *em, char hflag); +void EDBM_flag_disable_all(struct BMEditMesh *em, char hflag); bool BMBVH_EdgeVisible(struct BMBVHTree *tree, struct BMEdge *e, @@ -200,13 +196,9 @@ void EDBM_project_snap_verts(struct bContext *C, /* editmesh_automerge.c */ -void EDBM_automerge(struct Object *ob, bool update, const char hflag, const float dist); -void EDBM_automerge_and_split(struct Object *ob, - const bool split_edges, - const bool split_faces, - const bool update, - const char hflag, - const float dist); +void EDBM_automerge(struct Object *ob, bool update, char hflag, float dist); +void EDBM_automerge_and_split( + struct Object *ob, bool split_edges, bool split_faces, bool update, char hflag, float dist); /* editmesh_undo.c */ @@ -217,8 +209,8 @@ void ED_mesh_undosys_type(struct UndoType *ut); void EDBM_select_mirrored(struct BMEditMesh *em, const struct Mesh *me, - const int axis, - const bool extend, + int axis, + bool extend, int *r_totmirr, int *r_totfail); @@ -235,7 +227,7 @@ void EDBM_select_mirrored(struct BMEditMesh *em, */ struct BMVert *EDBM_vert_find_nearest_ex(struct ViewContext *vc, float *dist_px_manhattan_p, - const bool use_select_bias, + bool use_select_bias, bool use_cycle, struct Base **bases, uint bases_len, @@ -245,7 +237,7 @@ struct BMVert *EDBM_vert_find_nearest(struct ViewContext *vc, float *dist_px_man struct BMEdge *EDBM_edge_find_nearest_ex(struct ViewContext *vc, float *dist_px_manhattan, float *r_dist_center, - const bool use_select_bias, + bool use_select_bias, bool use_cycle, struct BMEdge **r_eed_zbuf, struct Base **bases, @@ -263,8 +255,8 @@ struct BMEdge *EDBM_edge_find_nearest(struct ViewContext *vc, float *dist_px_man struct BMFace *EDBM_face_find_nearest_ex(struct ViewContext *vc, float *dist_px_manhattan, float *r_dist_center, - const bool use_zbuf_single_px, - const bool use_select_bias, + bool use_zbuf_single_px, + bool use_select_bias, bool use_cycle, struct BMFace **r_efa_zbuf, struct Base **bases, @@ -274,7 +266,7 @@ struct BMFace *EDBM_face_find_nearest(struct ViewContext *vc, float *dist_px_man bool EDBM_unified_findnearest(struct ViewContext *vc, struct Base **bases, - const uint bases_len, + uint bases_len, int *r_base_index, struct BMVert **r_eve, struct BMEdge **r_eed, @@ -282,7 +274,7 @@ bool EDBM_unified_findnearest(struct ViewContext *vc, bool EDBM_unified_findnearest_from_raycast(struct ViewContext *vc, struct Base **bases, - const uint bases_len, + uint bases_len, bool use_boundary_vertices, bool use_boundary_edges, int *r_base_index_vert, @@ -314,22 +306,17 @@ void EDBM_selectmode_set(struct BMEditMesh *em); * - face -> vert * - edge -> vert */ -void EDBM_selectmode_convert(struct BMEditMesh *em, - const short selectmode_old, - const short selectmode_new); +void EDBM_selectmode_convert(struct BMEditMesh *em, short selectmode_old, short selectmode_new); /** * User access this. */ -bool EDBM_selectmode_set_multi(struct bContext *C, const short selectmode); +bool EDBM_selectmode_set_multi(struct bContext *C, short selectmode); /** * User facing function, does notification. */ -bool EDBM_selectmode_toggle_multi(struct bContext *C, - const short selectmode_new, - const int action, - const bool use_extend, - const bool use_expand); +bool EDBM_selectmode_toggle_multi( + struct bContext *C, short selectmode_new, int action, bool use_extend, bool use_expand); /** * Use to disable a select-mode if its enabled, Using another mode as a fallback @@ -339,10 +326,10 @@ bool EDBM_selectmode_toggle_multi(struct bContext *C, */ bool EDBM_selectmode_disable(struct Scene *scene, struct BMEditMesh *em, - const short selectmode_disable, - const short selectmode_fallback); + short selectmode_disable, + short selectmode_fallback); -bool EDBM_deselect_by_material(struct BMEditMesh *em, const short index, const bool select); +bool EDBM_deselect_by_material(struct BMEditMesh *em, short index, bool select); void EDBM_select_toggle_all(struct BMEditMesh *em); @@ -350,16 +337,16 @@ void EDBM_select_swap(struct BMEditMesh *em); /* exported for UV */ bool EDBM_select_interior_faces(struct BMEditMesh *em); void em_setup_viewcontext(struct bContext *C, struct ViewContext *vc); /* rename? */ -bool EDBM_mesh_deselect_all_multi_ex(struct Base **bases, const uint bases_len); +bool EDBM_mesh_deselect_all_multi_ex(struct Base **bases, uint bases_len); bool EDBM_mesh_deselect_all_multi(struct bContext *C); bool EDBM_selectmode_disable_multi_ex(struct Scene *scene, struct Base **bases, - const uint bases_len, - const short selectmode_disable, - const short selectmode_fallback); + uint bases_len, + short selectmode_disable, + short selectmode_fallback); bool EDBM_selectmode_disable_multi(struct bContext *C, - const short selectmode_disable, - const short selectmode_fallback); + short selectmode_disable, + short selectmode_fallback); /* editmesh_preselect_edgering.c */ struct EditMesh_PreSelEdgeRing; @@ -429,11 +416,11 @@ bool paintface_deselect_all_visible(struct bContext *C, void paintface_select_linked(struct bContext *C, struct Object *ob, const int mval[2], - const bool select); + bool select); bool paintface_minmax(struct Object *ob, float r_min[3], float r_max[3]); -void paintface_hide(struct bContext *C, struct Object *ob, const bool unselected); -void paintface_reveal(struct bContext *C, struct Object *ob, const bool select); +void paintface_hide(struct bContext *C, struct Object *ob, bool unselected); +void paintface_reveal(struct bContext *C, struct Object *ob, bool select); /** * \note if the caller passes false to flush_flags, @@ -463,7 +450,7 @@ bool ED_mesh_mirrtopo_recalc_check(struct BMEditMesh *em, void ED_mesh_mirrtopo_init(struct BMEditMesh *em, struct Mesh *me, MirrTopoStore_t *mesh_topo_store, - const bool skip_em_vert_array_init); + bool skip_em_vert_array_init); void ED_mesh_mirrtopo_free(MirrTopoStore_t *mesh_topo_store); /* object_vgroup.c */ @@ -476,7 +463,7 @@ void ED_vgroup_select_by_name(struct Object *ob, const char *name); /** * Removes out of range #MDeformWeights */ -void ED_vgroup_data_clamp_range(struct ID *id, const int total); +void ED_vgroup_data_clamp_range(struct ID *id, int total); /** * Matching index only. */ @@ -484,7 +471,7 @@ bool ED_vgroup_array_copy(struct Object *ob, struct Object *ob_from); bool ED_vgroup_parray_alloc(struct ID *id, struct MDeformVert ***dvert_arr, int *dvert_tot, - const bool use_vert_sel); + bool use_vert_sel); /** * For use with tools that use ED_vgroup_parray_alloc with \a use_vert_sel == true. * This finds the unselected mirror deform verts and copies the weights to them from the selected. @@ -494,9 +481,9 @@ bool ED_vgroup_parray_alloc(struct ID *id, */ void ED_vgroup_parray_mirror_sync(struct Object *ob, struct MDeformVert **dvert_array, - const int dvert_tot, + int dvert_tot, const bool *vgroup_validmap, - const int vgroup_tot); + int vgroup_tot); /** * Fill in the pointers for mirror verts (as if all mirror verts were selected too). * @@ -504,27 +491,27 @@ void ED_vgroup_parray_mirror_sync(struct Object *ob, */ void ED_vgroup_parray_mirror_assign(struct Object *ob, struct MDeformVert **dvert_array, - const int dvert_tot); + int dvert_tot); void ED_vgroup_parray_remove_zero(struct MDeformVert **dvert_array, - const int dvert_tot, + int dvert_tot, const bool *vgroup_validmap, - const int vgroup_tot, - const float epsilon, - const bool keep_single); + int vgroup_tot, + float epsilon, + bool keep_single); void ED_vgroup_parray_to_weight_array(const struct MDeformVert **dvert_array, - const int dvert_tot, + int dvert_tot, float *dvert_weights, - const int def_nr); + int def_nr); void ED_vgroup_parray_from_weight_array(struct MDeformVert **dvert_array, - const int dvert_tot, + int dvert_tot, const float *dvert_weights, - const int def_nr, - const bool remove_zero); + int def_nr, + bool remove_zero); void ED_vgroup_mirror(struct Object *ob, - const bool mirror_weights, - const bool flip_vgroups, - const bool all_vgroups, - const bool use_topology, + bool mirror_weights, + bool flip_vgroups, + bool all_vgroups, + bool use_topology, int *r_totmirr, int *r_totfail); @@ -560,36 +547,27 @@ void ED_mesh_geometry_clear(struct Mesh *mesh); void ED_mesh_update(struct Mesh *mesh, struct bContext *C, bool calc_edges, bool calc_edges_loose); void ED_mesh_uv_texture_ensure(struct Mesh *me, const char *name); -int ED_mesh_uv_texture_add(struct Mesh *me, - const char *name, - const bool active_set, - const bool do_init, - struct ReportList *reports); -bool ED_mesh_uv_texture_remove_index(struct Mesh *me, const int n); +int ED_mesh_uv_texture_add( + struct Mesh *me, const char *name, bool active_set, bool do_init, struct ReportList *reports); +bool ED_mesh_uv_texture_remove_index(struct Mesh *me, int n); bool ED_mesh_uv_texture_remove_active(struct Mesh *me); bool ED_mesh_uv_texture_remove_named(struct Mesh *me, const char *name); void ED_mesh_uv_loop_reset(struct bContext *C, struct Mesh *me); /** * Without a #bContext, called when UV-editing. */ -void ED_mesh_uv_loop_reset_ex(struct Mesh *me, const int layernum); +void ED_mesh_uv_loop_reset_ex(struct Mesh *me, int layernum); bool ED_mesh_color_ensure(struct Mesh *me, const char *name); -int ED_mesh_color_add(struct Mesh *me, - const char *name, - const bool active_set, - const bool do_init, - struct ReportList *reports); -bool ED_mesh_color_remove_index(struct Mesh *me, const int n); +int ED_mesh_color_add( + struct Mesh *me, const char *name, bool active_set, bool do_init, struct ReportList *reports); +bool ED_mesh_color_remove_index(struct Mesh *me, int n); bool ED_mesh_color_remove_active(struct Mesh *me); bool ED_mesh_color_remove_named(struct Mesh *me, const char *name); bool ED_mesh_sculpt_color_ensure(struct Mesh *me, const char *name); -int ED_mesh_sculpt_color_add(struct Mesh *me, - const char *name, - const bool active_set, - const bool do_init, - struct ReportList *reports); -bool ED_mesh_sculpt_color_remove_index(struct Mesh *me, const int n); +int ED_mesh_sculpt_color_add( + struct Mesh *me, const char *name, bool active_set, bool do_init, struct ReportList *reports); +bool ED_mesh_sculpt_color_remove_index(struct Mesh *me, int n); bool ED_mesh_sculpt_color_remove_active(struct Mesh *me); bool ED_mesh_sculpt_color_remove_named(struct Mesh *me, const char *name); @@ -654,16 +632,13 @@ void ED_mesh_mirror_topo_table_end(struct Object *ob); * Retrieves mirrored cache vert, or NULL if there isn't one. * \note calling this without ensuring the mirror cache state is bad. */ -int mesh_get_x_mirror_vert(struct Object *ob, - struct Mesh *me_eval, - int index, - const bool use_topology); +int mesh_get_x_mirror_vert(struct Object *ob, struct Mesh *me_eval, int index, bool use_topology); struct BMVert *editbmesh_get_x_mirror_vert(struct Object *ob, struct BMEditMesh *em, struct BMVert *eve, const float co[3], int index, - const bool use_topology); + bool use_topology); /** * This is a Mesh-based copy of #mesh_get_x_mirror_faces(). */ @@ -672,7 +647,7 @@ int *mesh_get_x_mirror_faces(struct Object *ob, struct BMEditMesh *em, struct Me /** * Wrapper for object-mode/edit-mode. * - * call #BM_mesh_elem_table_ensure first for editmesh. + * call #BM_mesh_elem_table_ensure first for edit-mesh. */ int ED_mesh_mirror_get_vert(struct Object *ob, int index); @@ -702,12 +677,10 @@ struct MDeformVert *ED_mesh_active_dvert_get_ob(struct Object *ob, int *r_index) struct MDeformVert *ED_mesh_active_dvert_get_only(struct Object *ob); void EDBM_mesh_stats_multi(struct Object **objects, - const uint objects_len, + uint objects_len, int totelem[3], int totelem_sel[3]); -void EDBM_mesh_elem_index_ensure_multi(struct Object **objects, - const uint objects_len, - const char htype); +void EDBM_mesh_elem_index_ensure_multi(struct Object **objects, uint objects_len, char htype); #define ED_MESH_PICK_DEFAULT_VERT_DIST 25 #define ED_MESH_PICK_DEFAULT_FACE_DIST 1 diff --git a/source/blender/editors/include/ED_node.h b/source/blender/editors/include/ED_node.h index 5bac452c7c9..181b6848ac7 100644 --- a/source/blender/editors/include/ED_node.h +++ b/source/blender/editors/include/ED_node.h @@ -100,12 +100,7 @@ void ED_node_socket_draw(struct bNodeSocket *sock, float scale); void ED_node_tree_update(const struct bContext *C); void ED_node_tag_update_id(struct ID *id); -void ED_node_tag_update_nodetree(struct Main *bmain, struct bNodeTree *ntree, struct bNode *node); -/** - * Sort nodes by selection: unselected nodes first, then selected, - * then the active node at the very end. Relative order is kept intact. - */ -void ED_node_sort(struct bNodeTree *ntree); + float ED_node_grid_size(void); /* node_relationships.c */ @@ -142,8 +137,6 @@ void ED_node_composit_default(const struct bContext *C, struct Scene *scene); * Called from shading buttons or header. */ void ED_node_texture_default(const struct bContext *C, struct Tex *tex); -bool ED_node_select_check(const ListBase *lb); -void ED_node_select_all(ListBase *lb, int action); void ED_node_post_apply_transform(struct bContext *C, struct bNodeTree *ntree); void ED_node_set_active(struct Main *bmain, struct SpaceNode *snode, @@ -152,6 +145,26 @@ void ED_node_set_active(struct Main *bmain, bool *r_active_texture_changed); /** + * Call after one or more node trees have been changed and tagged accordingly. + * + * This function will make sure that other parts of Blender update accordingly. For example, if the + * node group interface changed, parent node groups have to be updated as well. + * + * Additionally, this will send notifiers and tag the depsgraph based on the changes. Depsgraph + * relation updates have to be triggered by the caller. + * + * \param C: Context if available. This can be null. + * \param bmain: Main whose data-blocks should be updated based on the changes. + * \param ntree: Under some circumstances the caller knows that only one node tree has + * changed since the last update. In this case the function may be able to skip scanning #bmain + * for other things that have to be changed. It may still scan #bmain if the interface of the + * node tree has changed. + */ +void ED_node_tree_propagate_change(const struct bContext *C, + struct Main *bmain, + struct bNodeTree *ntree); + +/** * \param scene_owner: is the owner of the job, * we don't use it for anything else currently so could also be a void pointer, * but for now keep it an 'Scene' for consistency. diff --git a/source/blender/editors/include/ED_numinput.h b/source/blender/editors/include/ED_numinput.h index 84fa4488374..9fd77fa858e 100644 --- a/source/blender/editors/include/ED_numinput.h +++ b/source/blender/editors/include/ED_numinput.h @@ -114,7 +114,7 @@ bool user_string_to_number(bContext *C, const struct UnitSettings *unit, int type, double *r_value, - const bool use_single_line_error, + bool use_single_line_error, char **r_error); /** \} */ diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 576c6f51362..805b48d9195 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -82,12 +82,12 @@ Object **ED_object_array_in_mode_or_selected(struct bContext *C, /* object_utils.c */ bool ED_object_calc_active_center_for_editmode(struct Object *obedit, - const bool select_only, + bool select_only, float r_center[3]); bool ED_object_calc_active_center_for_posemode(struct Object *ob, - const bool select_only, + bool select_only, float r_center[3]); -bool ED_object_calc_active_center(struct Object *ob, const bool select_only, float r_center[3]); +bool ED_object_calc_active_center(struct Object *ob, bool select_only, float r_center[3]); /* Object Data Container helper API. */ struct XFormObjectData_Container; @@ -189,10 +189,10 @@ bool ED_object_parent_set(struct ReportList *reports, struct Object *const ob, struct Object *const par, int partype, - const bool xmirror, - const bool keep_transform, + bool xmirror, + bool keep_transform, const int vert_par[3]); -void ED_object_parent_clear(struct Object *ob, const int type); +void ED_object_parent_clear(struct Object *ob, int type); /** * Simple API for object selection, rather than just using the flag @@ -243,12 +243,9 @@ struct Base *ED_object_add_duplicate(struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, struct Base *base, - const eDupli_ID_Flags dupflag); + eDupli_ID_Flags dupflag); -void ED_object_parent(struct Object *ob, - struct Object *parent, - const int type, - const char *substr); +void ED_object_parent(struct Object *ob, struct Object *parent, int type, const char *substr); char *ED_object_ot_drop_named_material_tooltip(struct bContext *C, struct PointerRNA *properties, const int mval[2]); @@ -323,7 +320,7 @@ void ED_object_sculptmode_enter_ex(struct Main *bmain, struct Depsgraph *depsgraph, struct Scene *scene, struct Object *ob, - const bool force_dyntopo, + bool force_dyntopo, struct ReportList *reports); void ED_object_sculptmode_enter(struct bContext *C, struct Depsgraph *depsgraph, @@ -335,8 +332,8 @@ void ED_object_sculptmode_exit_ex(struct Main *bmain, void ED_object_sculptmode_exit(struct bContext *C, struct Depsgraph *depsgraph); void ED_object_location_from_view(struct bContext *C, float loc[3]); -void ED_object_rotation_from_quat(float rot[3], const float quat[4], const char align_axis); -void ED_object_rotation_from_view(struct bContext *C, float rot[3], const char align_axis); +void ED_object_rotation_from_quat(float rot[3], const float quat[4], char align_axis); +void ED_object_rotation_from_view(struct bContext *C, float rot[3], char align_axis); void ED_object_base_init_transform_on_add(struct Object *object, const float loc[3], const float rot[3]); @@ -363,7 +360,7 @@ void ED_object_add_generic_props(struct wmOperatorType *ot, bool do_editmode); void ED_object_add_mesh_props(struct wmOperatorType *ot); bool ED_object_add_generic_get_opts(struct bContext *C, struct wmOperator *op, - const char view_align_axis, + char view_align_axis, float r_loc[3], float r_rot[3], float r_scale[3], @@ -378,20 +375,20 @@ bool ED_object_add_generic_get_opts(struct bContext *C, * \note Do not call undo push in this function (users of this function have to). */ struct Object *ED_object_add_type_with_obdata(struct bContext *C, - const int type, + int type, const char *name, const float loc[3], const float rot[3], - const bool enter_editmode, - const ushort local_view_bits, + bool enter_editmode, + ushort local_view_bits, struct ID *obdata); struct Object *ED_object_add_type(struct bContext *C, - const int type, + int type, const char *name, const float loc[3], const float rot[3], - const bool enter_editmode, - const unsigned short local_view_bits) + bool enter_editmode, + unsigned short local_view_bits) ATTR_NONNULL(1) ATTR_RETURNS_NONNULL; /** @@ -468,9 +465,7 @@ void ED_object_constraint_dependency_tag_update(struct Main *bmain, struct Object *ob, struct bConstraint *con); -bool ED_object_constraint_move_to_index(struct Object *ob, - struct bConstraint *con, - const int index); +bool ED_object_constraint_move_to_index(struct Object *ob, struct bConstraint *con, int index); void ED_object_constraint_link(struct Main *bmain, struct Object *ob_dst, struct ListBase *dst, @@ -514,7 +509,7 @@ bool ED_object_mode_generic_has_data(struct Depsgraph *depsgraph, const struct O void ED_object_posemode_set_for_weight_paint(struct bContext *C, struct Main *bmain, struct Object *ob, - const bool is_mode_set); + bool is_mode_set); /* object_modifier.c */ @@ -550,7 +545,7 @@ bool ED_object_modifier_move_up(struct ReportList *reports, bool ED_object_modifier_move_to_index(struct ReportList *reports, struct Object *ob, struct ModifierData *md, - const int index); + int index); bool ED_object_modifier_convert(struct ReportList *reports, struct Main *bmain, @@ -588,7 +583,7 @@ void ED_object_modifier_copy_to_object(struct bContext *C, */ bool ED_object_iter_other(struct Main *bmain, struct Object *orig_ob, - const bool include_orig, + bool include_orig, bool (*callback)(struct Object *ob, void *callback_data), void *callback_data); @@ -619,7 +614,7 @@ bool ED_object_gpencil_modifier_move_up(struct ReportList *reports, bool ED_object_gpencil_modifier_move_to_index(struct ReportList *reports, struct Object *ob, struct GpencilModifierData *md, - const int index); + int index); bool ED_object_gpencil_modifier_apply(struct Main *bmain, struct ReportList *reports, struct Depsgraph *depsgraph, @@ -653,7 +648,7 @@ int ED_object_shaderfx_move_up(struct ReportList *reports, bool ED_object_shaderfx_move_to_index(struct ReportList *reports, struct Object *ob, struct ShaderFxData *fx, - const int index); + int index); void ED_object_shaderfx_link(struct Object *dst, struct Object *src); void ED_object_shaderfx_copy(struct Object *dst, struct ShaderFxData *fx); @@ -665,7 +660,7 @@ const struct EnumPropertyItem *ED_object_vgroup_selection_itemf_helper( struct PointerRNA *ptr, struct PropertyRNA *prop, bool *r_free, - const unsigned int selection_mask); + unsigned int selection_mask); void ED_object_check_force_modifiers(struct Main *bmain, struct Scene *scene, @@ -683,7 +678,7 @@ struct Base *ED_object_find_first_by_data_id(struct ViewLayer *view_layer, struc * * \returns false if not found in current view layer */ -bool ED_object_jump_to_object(struct bContext *C, struct Object *ob, const bool reveal_hidden); +bool ED_object_jump_to_object(struct bContext *C, struct Object *ob, bool reveal_hidden); /** * Select and make the target object and bone active. * Switches to Pose mode if in Object mode so the selection is visible. @@ -694,7 +689,7 @@ bool ED_object_jump_to_object(struct bContext *C, struct Object *ob, const bool bool ED_object_jump_to_bone(struct bContext *C, struct Object *ob, const char *bone_name, - const bool reveal_hidden); + bool reveal_hidden); /* object_facemap_ops.c */ diff --git a/source/blender/editors/include/ED_particle.h b/source/blender/editors/include/ED_particle.h index ce25943b40a..9671f5b2b09 100644 --- a/source/blender/editors/include/ED_particle.h +++ b/source/blender/editors/include/ED_particle.h @@ -72,16 +72,13 @@ void PE_update_object(struct Depsgraph *depsgraph, bool PE_mouse_particles( struct bContext *C, const int mval[2], bool extend, bool deselect, bool toggle); -bool PE_box_select(struct bContext *C, const struct rcti *rect, const int sel_op); +bool PE_box_select(struct bContext *C, const struct rcti *rect, int sel_op); bool PE_circle_select(struct bContext *C, struct wmGenericUserData *wm_userdata, - const int sel_op, + int sel_op, const int mval[2], float rad); -int PE_lasso_select(struct bContext *C, - const int mcoords[][2], - const int mcoords_len, - const int sel_op); +int PE_lasso_select(struct bContext *C, const int mcoords[][2], int mcoords_len, int sel_op); bool PE_deselect_all_visible_ex(struct PTCacheEdit *edit); bool PE_deselect_all_visible(struct bContext *C); diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h index 50d7bfc3960..dabf8fb838b 100644 --- a/source/blender/editors/include/ED_render.h +++ b/source/blender/editors/include/ED_render.h @@ -23,6 +23,7 @@ #pragma once +#include "DNA_ID_enums.h" #include "DNA_vec_types.h" #ifdef __cplusplus @@ -41,7 +42,6 @@ struct bContext; struct bScreen; struct wmWindow; struct wmWindowManager; -enum eIconSizes; /* render_ops.c */ @@ -49,7 +49,7 @@ void ED_operatortypes_render(void); /* render_update.c */ -void ED_render_engine_changed(struct Main *bmain, const bool update_scene_data); +void ED_render_engine_changed(struct Main *bmain, bool update_scene_data); void ED_render_engine_area_exit(struct Main *bmain, struct ScrArea *area); void ED_render_view_layer_changed(struct Main *bmain, struct bScreen *screen); @@ -60,14 +60,14 @@ void ED_render_id_flush_update(const struct DEGEditorUpdateContext *update_ctx, * Update all 3D viewport render and draw engines on changes to the scene. * This is called by the dependency graph when it detects changes. */ -void ED_render_scene_update(const struct DEGEditorUpdateContext *update_ctx, const bool updated); +void ED_render_scene_update(const struct DEGEditorUpdateContext *update_ctx, bool updated); /** * Update 3D viewport render or draw engine on changes to the scene or view settings. */ void ED_render_view3d_update(struct Depsgraph *depsgraph, struct wmWindow *window, struct ScrArea *area, - const bool updated); + bool updated); struct Scene *ED_render_job_get_scene(const struct bContext *C); struct Scene *ED_render_job_get_current_scene(const struct bContext *C); @@ -77,14 +77,12 @@ struct Scene *ED_render_job_get_current_scene(const struct bContext *C); * pr_method: * - PR_BUTS_RENDER: preview is rendered for buttons window * - PR_ICON_RENDER: preview is rendered for icons. hopefully fast enough for at least 32x32 - * - PR_NODE_RENDER: preview is rendered for node editor * - PR_ICON_DEFERRED: No render, we just ensure deferred icon data gets generated. */ typedef enum ePreviewRenderMethod { PR_BUTS_RENDER = 0, PR_ICON_RENDER = 1, - PR_NODE_RENDER = 2, - PR_ICON_DEFERRED = 3, + PR_ICON_DEFERRED = 2, } ePreviewRenderMethod; void ED_preview_ensure_dbase(void); @@ -102,7 +100,7 @@ void ED_preview_shader_job(const struct bContext *C, struct MTex *slot, int sizex, int sizey, - int method); + ePreviewRenderMethod method); void ED_preview_icon_render(const struct bContext *C, struct Scene *scene, struct ID *id, @@ -115,7 +113,7 @@ void ED_preview_icon_job(const struct bContext *C, unsigned int *rect, int sizex, int sizey, - const bool delay); + bool delay); void ED_preview_restart_queue_free(void); void ED_preview_restart_queue_add(struct ID *id, enum eIconSizes size); diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index c65ef3e397d..651ae1de8be 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -160,11 +160,11 @@ void ED_region_visibility_change_update_animated(struct bContext *C, void ED_region_info_draw(struct ARegion *region, const char *text, float fill_color[4], - const bool full_redraw); + bool full_redraw); void ED_region_info_draw_multiline(ARegion *region, const char *text_array[], float fill_color[4], - const bool full_redraw); + bool full_redraw); void ED_region_image_metadata_panel_draw(struct ImBuf *ibuf, struct uiLayout *layout); void ED_region_grid_draw(struct ARegion *region, float zoomx, float zoomy, float x0, float y0); float ED_region_blend_alpha(struct ARegion *region); @@ -238,7 +238,7 @@ void ED_area_status_text(ScrArea *area, const char *str); /** * \param skip_region_exit: Skip calling area exit callback. Set for opening temp spaces. */ -void ED_area_newspace(struct bContext *C, ScrArea *area, int type, const bool skip_region_exit); +void ED_area_newspace(struct bContext *C, ScrArea *area, int type, bool skip_region_exit); void ED_area_prevspace(struct bContext *C, ScrArea *area); void ED_area_swapspace(struct bContext *C, ScrArea *sa1, ScrArea *sa2); int ED_area_headersize(void); @@ -316,7 +316,7 @@ bool ED_screen_change(struct bContext *C, struct bScreen *screen); void ED_screen_scene_change(struct bContext *C, struct wmWindow *win, struct Scene *scene, - const bool refresh_toolsystem); + bool refresh_toolsystem); /** * Called in wm_event_system.c. sets state vars in screen, cursors. * event type is mouse move. @@ -360,7 +360,7 @@ bScreen *ED_screen_state_maximized_create(struct bContext *C); struct ScrArea *ED_screen_state_toggle(struct bContext *C, struct wmWindow *win, struct ScrArea *area, - const short state); + short state); /** * Wrapper to open a temporary space either as fullscreen space, or as separate window, as defined * by \a display_type. @@ -397,7 +397,7 @@ Scene *ED_screen_scene_find_with_window(const struct bScreen *screen, struct wmWindow **r_window); ScrArea *ED_screen_area_find_with_spacedata(const bScreen *screen, const struct SpaceLink *sl, - const bool only_visible); + bool only_visible); struct wmWindow *ED_screen_window_find(const struct bScreen *screen, const struct wmWindowManager *wm); /** @@ -473,9 +473,8 @@ struct WorkSpaceLayout *ED_workspace_layout_duplicate(struct Main *bmain, bool ED_workspace_layout_delete(struct WorkSpace *workspace, struct WorkSpaceLayout *layout_old, struct bContext *C) ATTR_NONNULL(); -bool ED_workspace_layout_cycle(struct WorkSpace *workspace, - const short direction, - struct bContext *C) ATTR_NONNULL(); +bool ED_workspace_layout_cycle(struct WorkSpace *workspace, short direction, struct bContext *C) + ATTR_NONNULL(); void ED_workspace_status_text(struct bContext *C, const char *str); @@ -644,12 +643,9 @@ void ED_screen_user_menu_register(void); /* Cache display helpers */ void ED_region_cache_draw_background(struct ARegion *region); -void ED_region_cache_draw_curfra_label(const int framenr, const float x, const float y); -void ED_region_cache_draw_cached_segments(struct ARegion *region, - const int num_segments, - const int *points, - const int sfra, - const int efra); +void ED_region_cache_draw_curfra_label(int framenr, float x, float y); +void ED_region_cache_draw_cached_segments( + struct ARegion *region, int num_segments, const int *points, int sfra, int efra); /* area_utils.c */ @@ -664,19 +660,15 @@ void ED_region_generic_tools_region_message_subscribe( int ED_region_generic_tools_region_snap_size(const struct ARegion *region, int size, int axis); /* area_query.c */ -bool ED_region_overlap_isect_x(const ARegion *region, const int event_x); -bool ED_region_overlap_isect_y(const ARegion *region, const int event_y); +bool ED_region_overlap_isect_x(const ARegion *region, int event_x); +bool ED_region_overlap_isect_y(const ARegion *region, int event_y); bool ED_region_overlap_isect_xy(const ARegion *region, const int event_xy[2]); bool ED_region_overlap_isect_any_xy(const ScrArea *area, const int event_xy[2]); -bool ED_region_overlap_isect_x_with_margin(const ARegion *region, - const int event_x, - const int margin); -bool ED_region_overlap_isect_y_with_margin(const ARegion *region, - const int event_y, - const int margin); +bool ED_region_overlap_isect_x_with_margin(const ARegion *region, int event_x, int margin); +bool ED_region_overlap_isect_y_with_margin(const ARegion *region, int event_y, int margin); bool ED_region_overlap_isect_xy_with_margin(const ARegion *region, const int event_xy[2], - const int margin); + int margin); bool ED_region_panel_category_gutter_calc_rect(const ARegion *region, rcti *r_region_gutter); bool ED_region_panel_category_gutter_isect_xy(const ARegion *region, const int event_xy[2]); diff --git a/source/blender/editors/include/ED_sculpt.h b/source/blender/editors/include/ED_sculpt.h index 0cdd8873cb2..7c1124d705f 100644 --- a/source/blender/editors/include/ED_sculpt.h +++ b/source/blender/editors/include/ED_sculpt.h @@ -60,7 +60,7 @@ void ED_sculpt_undo_geometry_end(struct Object *ob); /* Face sets. */ int ED_sculpt_face_sets_find_next_available_id(struct Mesh *mesh); -void ED_sculpt_face_sets_initialize_none_to_id(struct Mesh *mesh, const int new_id); +void ED_sculpt_face_sets_initialize_none_to_id(struct Mesh *mesh, int new_id); int ED_sculpt_face_sets_active_update_and_get(struct bContext *C, struct Object *ob, diff --git a/source/blender/editors/include/ED_select_utils.h b/source/blender/editors/include/ED_select_utils.h index 4656099799b..295268c7719 100644 --- a/source/blender/editors/include/ED_select_utils.h +++ b/source/blender/editors/include/ED_select_utils.h @@ -64,27 +64,25 @@ enum { * Use when we've de-selected all first for 'SEL_OP_SET'. * 1: select, 0: deselect, -1: pass. */ -int ED_select_op_action(const eSelectOp sel_op, const bool is_select, const bool is_inside); +int ED_select_op_action(eSelectOp sel_op, bool is_select, bool is_inside); /** * Use when we've de-selected all items first (for modes that need it). * * \note In some cases changing selection needs to perform other checks, * so it's more straightforward to deselect all, then select. */ -int ED_select_op_action_deselected(const eSelectOp sel_op, - const bool is_select, - const bool is_inside); +int ED_select_op_action_deselected(eSelectOp sel_op, bool is_select, bool is_inside); -int ED_select_similar_compare_float(const float delta, const float thresh, const int compare); +int ED_select_similar_compare_float(float delta, float thresh, int compare); bool ED_select_similar_compare_float_tree(const struct KDTree_1d *tree, - const float length, - const float thresh, - const int compare); + float length, + float thresh, + int compare); /** * Utility to use for selection operations that run multiple times (circle select). */ -eSelectOp ED_select_op_modal(const eSelectOp sel_op, const bool is_first); +eSelectOp ED_select_op_modal(eSelectOp sel_op, bool is_first); #ifdef __cplusplus } diff --git a/source/blender/editors/include/ED_space_api.h b/source/blender/editors/include/ED_space_api.h index f4a69737da1..fb76b36baef 100644 --- a/source/blender/editors/include/ED_space_api.h +++ b/source/blender/editors/include/ED_space_api.h @@ -86,7 +86,7 @@ void *ED_region_draw_cb_activate(struct ARegionType *art, int type); void ED_region_draw_cb_draw(const struct bContext *C, struct ARegion *region, int type); void ED_region_surface_draw_cb_draw(struct ARegionType *art, int type); -void ED_region_draw_cb_exit(struct ARegionType *art, void *handle); +bool ED_region_draw_cb_exit(struct ARegionType *art, void *handle); void ED_region_draw_cb_remove_by_type(struct ARegionType *art, void *draw_fn, void (*free)(void *)); diff --git a/source/blender/editors/include/ED_transform.h b/source/blender/editors/include/ED_transform.h index f0d6072fdbc..573f9b4939b 100644 --- a/source/blender/editors/include/ED_transform.h +++ b/source/blender/editors/include/ED_transform.h @@ -54,7 +54,8 @@ typedef enum { TFM_TILT, TFM_TRACKBALL, TFM_PUSHPULL, - TFM_CREASE, + TFM_EDGE_CREASE, + TFM_VERT_CREASE, TFM_MIRROR, TFM_BONESIZE, TFM_BONE_ENVELOPE, @@ -104,16 +105,16 @@ void BIF_removeTransformOrientationIndex(struct bContext *C, int index); bool BIF_createTransformOrientation(struct bContext *C, struct ReportList *reports, const char *name, - const bool use_view, - const bool activate, - const bool overwrite); + bool use_view, + bool activate, + bool overwrite); void BIF_selectTransformOrientation(struct bContext *C, struct TransformOrientation *target); void ED_getTransformOrientationMatrix(struct ViewLayer *view_layer, const struct View3D *v3d, struct Object *ob, struct Object *obedit, - const short around, + short around, float r_orientation_mat[3][3]); int BIF_countTransformOrientation(const struct bContext *C); @@ -161,8 +162,8 @@ short ED_transform_calc_orientation_from_type_ex(const struct Scene *scene, const struct RegionView3D *rv3d, struct Object *ob, struct Object *obedit, - const short orientation_index, - const int pivot_point, + short orientation_index, + int pivot_point, float r_mat[3][3]); /* transform gizmos */ @@ -188,7 +189,7 @@ void ED_widgetgroup_gizmo2d_rotate_callbacks_set(struct wmGizmoGroupType *gzgt); struct TransformBounds { float center[3]; /* Center for transform widget. */ - float min[3], max[3]; /* Boundbox of selection for transform widget. */ + float min[3], max[3]; /* Bounding-box of selection for transform widget. */ /* Normalized axis */ float axis[3][3]; diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h index 6f25a63188d..fd65d8f3663 100644 --- a/source/blender/editors/include/ED_transform_snap_object_context.h +++ b/source/blender/editors/include/ED_transform_snap_object_context.h @@ -138,7 +138,7 @@ short ED_transform_snap_object_project_view3d_ex(struct SnapObjectContext *sctx, struct Depsgraph *depsgraph, const ARegion *region, const View3D *v3d, - const unsigned short snap_to, + unsigned short snap_to, const struct SnapObjectParams *params, const float mval[2], const float prev_co[3], @@ -166,7 +166,7 @@ short ED_transform_snap_object_project_view3d(struct SnapObjectContext *sctx, struct Depsgraph *depsgraph, const ARegion *region, const View3D *v3d, - const unsigned short snap_to, + unsigned short snap_to, const struct SnapObjectParams *params, const float mval[2], const float prev_co[3], diff --git a/source/blender/editors/include/ED_transverts.h b/source/blender/editors/include/ED_transverts.h index 28955da6ef1..cbcf28d53d5 100644 --- a/source/blender/editors/include/ED_transverts.h +++ b/source/blender/editors/include/ED_transverts.h @@ -42,7 +42,7 @@ typedef struct TransVertStore { int mode; } TransVertStore; -void ED_transverts_create_from_obedit(TransVertStore *tvs, struct Object *obedit, const int mode); +void ED_transverts_create_from_obedit(TransVertStore *tvs, struct Object *obedit, int mode); void ED_transverts_update_obedit(TransVertStore *tvs, struct Object *obedit); void ED_transverts_free(TransVertStore *tvs); bool ED_transverts_check_obedit(Object *obedit); diff --git a/source/blender/editors/include/ED_util.h b/source/blender/editors/include/ED_util.h index 69378d436ab..4e794838b2f 100644 --- a/source/blender/editors/include/ED_util.h +++ b/source/blender/editors/include/ED_util.h @@ -33,6 +33,7 @@ extern "C" { struct GPUBatch; struct Main; struct bContext; +struct IDRemapper; /* ed_util.c */ @@ -60,10 +61,13 @@ bool ED_editors_flush_edits(struct Main *bmain); * * \param new_id: may be NULL to unlink \a old_id. */ +void ED_spacedata_id_remap_single(struct ScrArea *area, + struct SpaceLink *sl, + struct ID *old_id, + struct ID *new_id); void ED_spacedata_id_remap(struct ScrArea *area, struct SpaceLink *sl, - struct ID *old_id, - struct ID *new_id); + const struct IDRemapper *mappings); void ED_operatortypes_edutils(void); @@ -102,13 +106,13 @@ void ED_slider_destroy(struct bContext *C, struct tSlider *slider); */ void ED_slider_status_string_get(const struct tSlider *slider, char *status_string, - const size_t size_of_status_string); + size_t size_of_status_string); float ED_slider_factor_get(struct tSlider *slider); void ED_slider_factor_set(struct tSlider *slider, float factor); bool ED_slider_allow_overshoot_get(struct tSlider *slider); -void ED_slider_allow_overshoot_set(struct tSlider *slider, const bool value); +void ED_slider_allow_overshoot_set(struct tSlider *slider, bool value); /* ************** XXX OLD CRUFT WARNING ************* */ diff --git a/source/blender/editors/include/ED_uvedit.h b/source/blender/editors/include/ED_uvedit.h index d5303904842..0af98fc367f 100644 --- a/source/blender/editors/include/ED_uvedit.h +++ b/source/blender/editors/include/ED_uvedit.h @@ -100,93 +100,87 @@ bool ED_uvedit_test(struct Object *obedit); bool uvedit_face_visible_test_ex(const struct ToolSettings *ts, struct BMFace *efa); bool uvedit_face_select_test_ex(const struct ToolSettings *ts, struct BMFace *efa, - const int cd_loop_uv_offset); + int cd_loop_uv_offset); bool uvedit_edge_select_test_ex(const struct ToolSettings *ts, struct BMLoop *l, - const int cd_loop_uv_offset); + int cd_loop_uv_offset); bool uvedit_uv_select_test_ex(const struct ToolSettings *ts, struct BMLoop *l, - const int cd_loop_uv_offset); + int cd_loop_uv_offset); bool uvedit_face_visible_test(const struct Scene *scene, struct BMFace *efa); -bool uvedit_face_select_test(const struct Scene *scene, - struct BMFace *efa, - const int cd_loop_uv_offset); -bool uvedit_edge_select_test(const struct Scene *scene, - struct BMLoop *l, - const int cd_loop_uv_offset); -bool uvedit_uv_select_test(const struct Scene *scene, - struct BMLoop *l, - const int cd_loop_uv_offset); +bool uvedit_face_select_test(const struct Scene *scene, struct BMFace *efa, int cd_loop_uv_offset); +bool uvedit_edge_select_test(const struct Scene *scene, struct BMLoop *l, int cd_loop_uv_offset); +bool uvedit_uv_select_test(const struct Scene *scene, struct BMLoop *l, int cd_loop_uv_offset); /* uv face */ void uvedit_face_select_set_with_sticky(const struct SpaceImage *sima, const struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, - const bool select, - const bool do_history, - const int cd_loop_uv_offset); + bool select, + bool do_history, + int cd_loop_uv_offset); void uvedit_face_select_set(const struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, - const bool select, - const bool do_history, - const int cd_loop_uv_offset); + bool select, + bool do_history, + int cd_loop_uv_offset); void uvedit_face_select_enable(const struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, - const bool do_history, - const int cd_loop_uv_offset); + bool do_history, + int cd_loop_uv_offset); void uvedit_face_select_disable(const struct Scene *scene, struct BMEditMesh *em, struct BMFace *efa, - const int cd_loop_uv_offset); + int cd_loop_uv_offset); /* uv edge */ void uvedit_edge_select_set_with_sticky(const struct SpaceImage *sima, const struct Scene *scene, struct BMEditMesh *em, struct BMLoop *l, - const bool select, - const bool do_history, - const uint cd_loop_uv_offset); + bool select, + bool do_history, + uint cd_loop_uv_offset); void uvedit_edge_select_set(const struct Scene *scene, struct BMEditMesh *em, struct BMLoop *l, - const bool select, - const bool do_history, - const int cd_loop_uv_offset); + bool select, + bool do_history, + int cd_loop_uv_offset); void uvedit_edge_select_enable(const struct Scene *scene, struct BMEditMesh *em, struct BMLoop *l, - const bool do_history, - const int cd_loop_uv_offset); + bool do_history, + int cd_loop_uv_offset); void uvedit_edge_select_disable(const struct Scene *scene, struct BMEditMesh *em, struct BMLoop *l, - const int cd_loop_uv_offset); + int cd_loop_uv_offset); /* uv vert */ void uvedit_uv_select_set_with_sticky(const struct SpaceImage *sima, const struct Scene *scene, struct BMEditMesh *em, struct BMLoop *l, - const bool select, - const bool do_history, - const uint cd_loop_uv_offset); + bool select, + bool do_history, + uint cd_loop_uv_offset); void uvedit_uv_select_set(const struct Scene *scene, struct BMEditMesh *em, struct BMLoop *l, - const bool select, - const bool do_history, - const int cd_loop_uv_offset); + bool select, + bool do_history, + int cd_loop_uv_offset); void uvedit_uv_select_enable(const struct Scene *scene, struct BMEditMesh *em, struct BMLoop *l, - const bool do_history, - const int cd_loop_uv_offset); + bool do_history, + int cd_loop_uv_offset); void uvedit_uv_select_disable(const struct Scene *scene, struct BMEditMesh *em, struct BMLoop *l, - const int cd_loop_uv_offset); + int cd_loop_uv_offset); bool ED_uvedit_nearest_uv(const struct Scene *scene, struct Object *obedit, @@ -195,7 +189,7 @@ bool ED_uvedit_nearest_uv(const struct Scene *scene, float r_uv[2]); bool ED_uvedit_nearest_uv_multi(const struct Scene *scene, struct Object **objects, - const uint objects_len, + uint objects_len, const float co[2], float *dist_sq, float r_uv[2]); @@ -228,7 +222,7 @@ struct BMLoop *ED_uvedit_active_edge_loop_get(struct BMesh *bm); char ED_uvedit_select_mode_get(const struct Scene *scene); void ED_uvedit_select_sync_flush(const struct ToolSettings *ts, struct BMEditMesh *em, - const bool select); + bool select); /* uvedit_unwrap_ops.c */ @@ -278,7 +272,7 @@ bool uv_coords_isect_udim(const struct Image *image, const float coords[2]); void ED_uvedit_pack_islands_multi(const struct Scene *scene, Object **objects, - const uint objects_len, + uint objects_len, const struct UVMapUDIM_Params *udim_params, const struct UVPackIsland_Params *params); diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index 6c986d8efe1..0398c209c68 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -114,17 +114,17 @@ bool ED_view3d_has_workbench_in_texture_color(const struct Scene *scene, */ void ED_view3d_cursor3d_position(struct bContext *C, const int mval[2], - const bool use_depth, + bool use_depth, float r_cursor_co[3]); void ED_view3d_cursor3d_position_rotation(struct bContext *C, const int mval[2], - const bool use_depth, + bool use_depth, enum eV3DCursorOrient orientation, float r_cursor_co[3], float r_cursor_quat[4]); void ED_view3d_cursor3d_update(struct bContext *C, const int mval[2], - const bool use_depth, + bool use_depth, enum eV3DCursorOrient orientation); struct Camera *ED_view3d_camera_data_get(struct View3D *v3d, struct RegionView3D *rv3d); @@ -137,7 +137,7 @@ struct Camera *ED_view3d_camera_data_get(struct View3D *v3d, struct RegionView3D * \param quat: The view rotation, quaternion normally from #RegionView3D.viewquat. * \param dist: The view distance from ofs, normally from #RegionView3D.dist. */ -void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], const float dist); +void ED_view3d_to_m4(float mat[4][4], const float ofs[3], const float quat[4], float dist); /** * Set the view transformation from a 4x4 matrix. * @@ -171,7 +171,7 @@ void ED_view3d_to_object(const struct Depsgraph *depsgraph, struct Object *ob, const float ofs[3], const float quat[4], - const float dist); + float dist); bool ED_view3d_camera_to_view_selected(struct Main *bmain, struct Depsgraph *depsgraph, @@ -213,7 +213,7 @@ bool ED_view3d_depth_read_cached_normal(const struct ARegion *region, float r_normal[3]); bool ED_view3d_depth_unproject_v3(const struct ARegion *region, const int mval[2], - const double depth, + double depth, float r_location_world[3]); /* Projection */ @@ -280,7 +280,7 @@ typedef enum { /* view3d_snap.c */ bool ED_view3d_snap_selected_to_location(struct bContext *C, const float snap_target_global[3], - const int pivot_point); + int pivot_point); /* view3d_cursor_snap.c */ #define USE_SNAP_DETECT_FROM_KEYMAP_HACK @@ -343,8 +343,8 @@ void ED_view3d_cursor_snap_deactive(V3DSnapCursorState *state); void ED_view3d_cursor_snap_prevpoint_set(V3DSnapCursorState *state, const float prev_point[3]); V3DSnapCursorData *ED_view3d_cursor_snap_data_get(V3DSnapCursorState *state, const struct bContext *C, - const int x, - const int y); + int x, + int y); struct SnapObjectContext *ED_view3d_cursor_snap_context_ensure(struct Scene *scene); void ED_view3d_cursor_snap_draw_util(struct RegionView3D *rv3d, const float loc_prev[3], @@ -352,7 +352,7 @@ void ED_view3d_cursor_snap_draw_util(struct RegionView3D *rv3d, const float normal[3], const uchar color_line[4], const uchar color_point[4], - const short snap_elem_type); + short snap_elem_type); /* view3d_iterators.c */ @@ -362,12 +362,12 @@ void meshobject_foreachScreenVert( struct ViewContext *vc, void (*func)(void *userData, struct MVert *eve, const float screen_co[2], int index), void *userData, - const eV3DProjTest clip_flag); + eV3DProjTest clip_flag); void mesh_foreachScreenVert( struct ViewContext *vc, void (*func)(void *userData, struct BMVert *eve, const float screen_co[2], int index), void *userData, - const eV3DProjTest clip_flag); + eV3DProjTest clip_flag); void mesh_foreachScreenEdge(struct ViewContext *vc, void (*func)(void *userData, struct BMEdge *eed, @@ -375,7 +375,7 @@ void mesh_foreachScreenEdge(struct ViewContext *vc, const float screen_co_b[2], int index), void *userData, - const eV3DProjTest clip_flag); + eV3DProjTest clip_flag); /** * A version of #mesh_foreachScreenEdge that clips the segment when @@ -388,13 +388,13 @@ void mesh_foreachScreenEdge_clip_bb_segment(struct ViewContext *vc, const float screen_co_b[2], int index), void *userData, - const eV3DProjTest clip_flag); + eV3DProjTest clip_flag); void mesh_foreachScreenFace( struct ViewContext *vc, void (*func)(void *userData, struct BMFace *efa, const float screen_co[2], int index), void *userData, - const eV3DProjTest clip_flag); + eV3DProjTest clip_flag); void nurbs_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct Nurb *nu, @@ -404,7 +404,7 @@ void nurbs_foreachScreenVert(struct ViewContext *vc, bool handle_visible, const float screen_co[2]), void *userData, - const eV3DProjTest clip_flag); + eV3DProjTest clip_flag); /** * #ED_view3d_init_mats_rv3d must be called first. */ @@ -413,13 +413,13 @@ void mball_foreachScreenElem(struct ViewContext *vc, struct MetaElem *ml, const float screen_co[2]), void *userData, - const eV3DProjTest clip_flag); + eV3DProjTest clip_flag); void lattice_foreachScreenVert(struct ViewContext *vc, void (*func)(void *userData, struct BPoint *bp, const float screen_co[2]), void *userData, - const eV3DProjTest clip_flag); + eV3DProjTest clip_flag); /** * #ED_view3d_init_mats_rv3d must be called first. */ @@ -429,7 +429,7 @@ void armature_foreachScreenBone(struct ViewContext *vc, const float screen_co_a[2], const float screen_co_b[2]), void *userData, - const eV3DProjTest clip_flag); + eV3DProjTest clip_flag); /** * ED_view3d_init_mats_rv3d must be called first. @@ -440,7 +440,7 @@ void pose_foreachScreenBone(struct ViewContext *vc, const float screen_co_a[2], const float screen_co_b[2]), void *userData, - const eV3DProjTest clip_flag); + eV3DProjTest clip_flag); /* *** end iterators *** */ /* view3d_project.c */ @@ -465,58 +465,58 @@ eV3DProjStatus ED_view3d_project_base(const struct ARegion *region, struct Base /* *** short *** */ eV3DProjStatus ED_view3d_project_short_ex(const struct ARegion *region, float perspmat[4][4], - const bool is_local, + bool is_local, const float co[3], short r_co[2], - const eV3DProjTest flag); + eV3DProjTest flag); /* --- short --- */ eV3DProjStatus ED_view3d_project_short_global(const struct ARegion *region, const float co[3], short r_co[2], - const eV3DProjTest flag); + eV3DProjTest flag); /* object space, use ED_view3d_init_mats_rv3d before calling */ eV3DProjStatus ED_view3d_project_short_object(const struct ARegion *region, const float co[3], short r_co[2], - const eV3DProjTest flag); + eV3DProjTest flag); /* *** int *** */ eV3DProjStatus ED_view3d_project_int_ex(const struct ARegion *region, float perspmat[4][4], - const bool is_local, + bool is_local, const float co[3], int r_co[2], - const eV3DProjTest flag); + eV3DProjTest flag); /* --- int --- */ eV3DProjStatus ED_view3d_project_int_global(const struct ARegion *region, const float co[3], int r_co[2], - const eV3DProjTest flag); + eV3DProjTest flag); /* object space, use ED_view3d_init_mats_rv3d before calling */ eV3DProjStatus ED_view3d_project_int_object(const struct ARegion *region, const float co[3], int r_co[2], - const eV3DProjTest flag); + eV3DProjTest flag); /* *** float *** */ eV3DProjStatus ED_view3d_project_float_ex(const struct ARegion *region, float perspmat[4][4], - const bool is_local, + bool is_local, const float co[3], float r_co[2], - const eV3DProjTest flag); + eV3DProjTest flag); /* --- float --- */ eV3DProjStatus ED_view3d_project_float_global(const struct ARegion *region, const float co[3], float r_co[2], - const eV3DProjTest flag); + eV3DProjTest flag); /** * Object space, use #ED_view3d_init_mats_rv3d before calling. */ eV3DProjStatus ED_view3d_project_float_object(const struct ARegion *region, const float co[3], float r_co[2], - const eV3DProjTest flag); + eV3DProjTest flag); float ED_view3d_pixel_size(const struct RegionView3D *rv3d, const float co[3]); float ED_view3d_pixel_size_no_ui_scale(const struct RegionView3D *rv3d, const float co[3]); @@ -550,7 +550,7 @@ bool ED_view3d_win_to_ray_clipped(struct Depsgraph *depsgraph, const float mval[2], float r_ray_start[3], float r_ray_normal[3], - const bool do_clip_planes); + bool do_clip_planes); /** * Calculate a 3d viewpoint and direction vector from 2d window coordinates. * This ray_start is located at the viewpoint, ray_normal is the direction towards `mval`. @@ -620,7 +620,7 @@ void ED_view3d_win_to_3d_int(const struct View3D *v3d, bool ED_view3d_win_to_3d_on_plane(const struct ARegion *region, const float plane[4], const float mval[2], - const bool do_clip, + bool do_clip, float r_out[3]); /** * A wrapper for #ED_view3d_win_to_3d_on_plane that projects onto \a plane_fallback @@ -632,13 +632,13 @@ bool ED_view3d_win_to_3d_on_plane(const struct ARegion *region, bool ED_view3d_win_to_3d_on_plane_with_fallback(const struct ARegion *region, const float plane[4], const float mval[2], - const bool do_clip, + bool do_clip, const float plane_fallback[4], float r_out[3]); bool ED_view3d_win_to_3d_on_plane_int(const struct ARegion *region, const float plane[4], const int mval[2], - const bool do_clip, + bool do_clip, float r_out[3]); /** * Calculate a 3d difference vector from 2d window offset. @@ -651,7 +651,7 @@ bool ED_view3d_win_to_3d_on_plane_int(const struct ARegion *region, void ED_view3d_win_to_delta(const struct ARegion *region, const float mval[2], float out[3], - const float zfac); + float zfac); /** * Calculate a 3d origin from 2d window coordinates. * \note Orthographic views have a less obvious origin, @@ -697,7 +697,7 @@ bool ED_view3d_win_to_segment_clipped(struct Depsgraph *depsgraph, const float mval[2], float r_ray_start[3], float r_ray_end[3], - const bool do_clip_planes); + bool do_clip_planes); void ED_view3d_ob_project_mat_get(const struct RegionView3D *v3d, const struct Object *ob, float r_pmat[4][4]); @@ -729,7 +729,7 @@ bool ED_view3d_clip_range_get(struct Depsgraph *depsgraph, const struct RegionView3D *rv3d, float *r_clipsta, float *r_clipend, - const bool use_ortho_factor); + bool use_ortho_factor); bool ED_view3d_viewplane_get(struct Depsgraph *depsgraph, const struct View3D *v3d, const struct RegionView3D *rv3d, @@ -743,7 +743,7 @@ bool ED_view3d_viewplane_get(struct Depsgraph *depsgraph, /** * Use instead of: `GPU_polygon_offset(rv3d->dist, ...)` see bug T37727. */ -void ED_view3d_polygon_offset(const struct RegionView3D *rv3d, const float dist); +void ED_view3d_polygon_offset(const struct RegionView3D *rv3d, float dist); void ED_view3d_calc_camera_border(const struct Scene *scene, struct Depsgraph *depsgraph, @@ -751,7 +751,7 @@ void ED_view3d_calc_camera_border(const struct Scene *scene, const struct View3D *v3d, const struct RegionView3D *rv3d, struct rctf *r_viewborder, - const bool no_shift); + bool no_shift); void ED_view3d_calc_camera_border_size(const struct Scene *scene, struct Depsgraph *depsgraph, const struct ARegion *region, @@ -766,7 +766,7 @@ bool ED_view3d_calc_render_border(const struct Scene *scene, void ED_view3d_clipping_calc_from_boundbox(float clip[4][4], const struct BoundBox *clipbb, - const bool is_flip); + bool is_flip); void ED_view3d_clipping_calc(struct BoundBox *bb, float planes[4][4], const struct ARegion *region, @@ -796,12 +796,10 @@ void ED_view3d_clipping_local(struct RegionView3D *rv3d, const float mat[4][4]); * * \note Callers should check #RV3D_CLIPPING_ENABLED first. */ -bool ED_view3d_clipping_test(const struct RegionView3D *rv3d, - const float co[3], - const bool is_local); +bool ED_view3d_clipping_test(const struct RegionView3D *rv3d, const float co[3], bool is_local); -float ED_view3d_radius_to_dist_persp(const float angle, const float radius); -float ED_view3d_radius_to_dist_ortho(const float lens, const float radius); +float ED_view3d_radius_to_dist_persp(float angle, float radius); +float ED_view3d_radius_to_dist_ortho(float lens, float radius); /** * Return a new #RegionView3D.dist value to fit the \a radius. * @@ -830,9 +828,9 @@ float ED_view3d_radius_to_dist_ortho(const float lens, const float radius); float ED_view3d_radius_to_dist(const struct View3D *v3d, const struct ARegion *region, const struct Depsgraph *depsgraph, - const char persp, - const bool use_aspect, - const float radius); + char persp, + bool use_aspect, + float radius); /** * Back-buffer select and draw support. @@ -842,7 +840,7 @@ void ED_view3d_backbuf_depth_validate(struct ViewContext *vc); * allow for small values [0.5 - 2.5], * and large values, FLT_MAX by clamping by the area size */ -int ED_view3d_backbuf_sample_size_clamp(struct ARegion *region, const float dist); +int ED_view3d_backbuf_sample_size_clamp(struct ARegion *region, float dist); void ED_view3d_select_id_validate(struct ViewContext *vc); @@ -859,7 +857,7 @@ bool ED_view3d_autodist(struct Depsgraph *depsgraph, struct View3D *v3d, const int mval[2], float mouse_worldloc[3], - const bool alphaoverride, + bool alphaoverride, const float fallback_depth_pt[3]); /** @@ -919,7 +917,7 @@ int view3d_opengl_select_ex(struct ViewContext *vc, const struct rcti *input, eV3DSelectMode select_mode, eV3DSelectObjectFilter select_filter, - const bool do_material_slot_selection); + bool do_material_slot_selection); int view3d_opengl_select(struct ViewContext *vc, unsigned int *buffer, unsigned int bufsize, @@ -1004,7 +1002,7 @@ void ED_view3d_mats_rv3d_restore(struct RegionView3D *rv3d, struct RV3DMatrixSto void ED_draw_object_facemap(struct Depsgraph *depsgraph, struct Object *ob, const float col[4], - const int facemap); + int facemap); struct RenderEngineType *ED_view3d_engine_type(const struct Scene *scene, int drawtype); @@ -1046,9 +1044,9 @@ void ED_view3d_update_viewmat(struct Depsgraph *depsgraph, const float winmat[4][4], const struct rcti *rect, bool offscreen); -bool ED_view3d_quat_from_axis_view(const char view, const char view_axis_roll, float r_quat[4]); +bool ED_view3d_quat_from_axis_view(char view, char view_axis_roll, float r_quat[4]); bool ED_view3d_quat_to_axis_view(const float viewquat[4], - const float epsilon, + float epsilon, char *r_view, char *r_view_axis_rotation); @@ -1079,7 +1077,7 @@ bool ED_view3d_offset_lock_check(const struct View3D *v3d, const struct RegionVi void ED_view3d_persp_switch_from_camera(const struct Depsgraph *depsgraph, struct View3D *v3d, struct RegionView3D *rv3d, - const char persp); + char persp); /** * Action to take when rotating the view, * handle auto-perspective and logic for switching out of views. @@ -1105,7 +1103,7 @@ bool ED_view3d_camera_lock_check(const struct View3D *v3d, const struct RegionVi void ED_view3d_camera_lock_init_ex(const struct Depsgraph *depsgraph, struct View3D *v3d, struct RegionView3D *rv3d, - const bool calc_dist); + bool calc_dist); void ED_view3d_camera_lock_init(const struct Depsgraph *depsgraph, struct View3D *v3d, struct RegionView3D *rv3d); @@ -1123,8 +1121,8 @@ bool ED_view3d_camera_lock_sync(const struct Depsgraph *depsgraph, bool ED_view3d_camera_autokey(const struct Scene *scene, struct ID *id_key, struct bContext *C, - const bool do_rotate, - const bool do_translate); + bool do_rotate, + bool do_translate); /** * Call after modifying a locked view. * @@ -1134,8 +1132,8 @@ bool ED_view3d_camera_autokey(const struct Scene *scene, bool ED_view3d_camera_lock_autokey(struct View3D *v3d, struct RegionView3D *rv3d, struct bContext *C, - const bool do_rotate, - const bool do_translate); + bool do_rotate, + bool do_translate); void ED_view3d_lock_clear(struct View3D *v3d); @@ -1154,15 +1152,13 @@ void ED_view3d_lock_clear(struct View3D *v3d); * \param fallback_dist: The distance to use if the object is too near or in front of \a ofs. * \returns A newly calculated distance or the fallback. */ -float ED_view3d_offset_distance(const float mat[4][4], - const float ofs[3], - const float fallback_dist); +float ED_view3d_offset_distance(const float mat[4][4], const float ofs[3], float fallback_dist); /** * Set the dist without moving the view (compensate with #RegionView3D.ofs) * * \note take care that #RegionView3d.viewinv is up to date, #ED_view3d_update_viewmat first. */ -void ED_view3d_distance_set(struct RegionView3D *rv3d, const float dist); +void ED_view3d_distance_set(struct RegionView3D *rv3d, float dist); /** * Change the distance & offset to match the depth of \a dist_co along the view axis. * @@ -1172,7 +1168,7 @@ void ED_view3d_distance_set(struct RegionView3D *rv3d, const float dist); */ bool ED_view3d_distance_set_from_location(struct RegionView3D *rv3d, const float dist_co[3], - const float dist_min); + float dist_min); /** * Could move this elsewhere, but tied into #ED_view3d_grid_scale @@ -1223,8 +1219,8 @@ void ED_view3d_draw_bgpic_test(const struct Scene *scene, struct Depsgraph *depsgraph, struct ARegion *region, struct View3D *v3d, - const bool do_foreground, - const bool do_camera_frame); + bool do_foreground, + bool do_camera_frame); /* view3d_gizmo_preselect_type.c */ @@ -1247,12 +1243,10 @@ void ED_view3d_buttons_region_layout_ex(const struct bContext *C, * Try to keep the same UUID previously used to allow users to quickly toggle back and forth. */ bool ED_view3d_local_collections_set(struct Main *bmain, struct View3D *v3d); -void ED_view3d_local_collections_reset(struct bContext *C, const bool reset_all); +void ED_view3d_local_collections_reset(struct bContext *C, bool reset_all); #ifdef WITH_XR_OPENXR -void ED_view3d_xr_mirror_update(const struct ScrArea *area, - const struct View3D *v3d, - const bool enable); +void ED_view3d_xr_mirror_update(const struct ScrArea *area, const struct View3D *v3d, bool enable); void ED_view3d_xr_shading_update(struct wmWindowManager *wm, const View3D *v3d, const struct Scene *scene); diff --git a/source/blender/editors/include/ED_view3d_offscreen.h b/source/blender/editors/include/ED_view3d_offscreen.h index 1da0a282697..ae2329c457b 100644 --- a/source/blender/editors/include/ED_view3d_offscreen.h +++ b/source/blender/editors/include/ED_view3d_offscreen.h @@ -53,8 +53,8 @@ void ED_view3d_draw_offscreen(struct Depsgraph *depsgraph, bool is_image_render, bool draw_background, const char *viewname, - const bool do_color_management, - const bool restore_rv3d_mats, + bool do_color_management, + bool restore_rv3d_mats, struct GPUOffScreen *ofs, struct GPUViewport *viewport); /** @@ -76,7 +76,7 @@ void ED_view3d_draw_offscreen_simple(struct Depsgraph *depsgraph, bool is_image_render, bool draw_background, const char *viewname, - const bool do_color_management, + bool do_color_management, struct GPUOffScreen *ofs, struct GPUViewport *viewport); @@ -96,7 +96,7 @@ struct ImBuf *ED_view3d_draw_offscreen_imbuf(struct Depsgraph *depsgraph, eImBufFlags imbuf_flag, int alpha_mode, const char *viewname, - const bool restore_rv3d_mats, + bool restore_rv3d_mats, struct GPUOffScreen *ofs, char err_out[256]); /** diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index ba83b259267..3796fa51499 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -494,9 +494,9 @@ void UI_draw_widget_scroll(struct uiWidgetColors *wcol, float UI_text_clip_middle_ex(const struct uiFontStyle *fstyle, char *str, float okwidth, - const float minwidth, - const size_t max_len, - const char rpart_sep); + float minwidth, + size_t max_len, + char rpart_sep); /** * Callbacks @@ -531,11 +531,8 @@ typedef struct ARegion *(*uiButSearchCreateFn)(struct bContext *C, * to display the full list of options. The value will be false after the button's text is edited * (for every call except the first). */ -typedef void (*uiButSearchUpdateFn)(const struct bContext *C, - void *arg, - const char *str, - uiSearchItems *items, - const bool is_first); +typedef void (*uiButSearchUpdateFn)( + const struct bContext *C, void *arg, const char *str, uiSearchItems *items, bool is_first); typedef bool (*uiButSearchContextMenuFn)(struct bContext *C, void *arg, void *active, @@ -621,7 +618,7 @@ bool UI_but_is_tool(const uiBut *but); bool UI_but_is_utf8(const uiBut *but); #define UI_but_is_decorator(but) ((but)->type == UI_BTYPE_DECORATOR) -bool UI_block_is_empty_ex(const uiBlock *block, const bool skip_title); +bool UI_block_is_empty_ex(const uiBlock *block, bool skip_title); bool UI_block_is_empty(const uiBlock *block); bool UI_block_can_add_separator(const uiBlock *block); @@ -662,7 +659,7 @@ int UI_popup_menu_invoke(struct bContext *C, const char *idname, struct ReportLi * Allow setting menu return value from externals. * E.g. WM might need to do this for exiting files correctly. */ -void UI_popup_menu_retval_set(const uiBlock *block, const int retval, const bool enable); +void UI_popup_menu_retval_set(const uiBlock *block, int retval, bool enable); /** * Setting the button makes the popup open from the button instead of the cursor. */ @@ -866,7 +863,7 @@ void UI_but_drag_set_id(uiBut *but, struct ID *id); * Set an image to display while dragging. This works for any drag type (`WM_DRAG_XXX`). * Not to be confused with #UI_but_drag_set_image(), which sets up dragging of an image. */ -void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, const float scale); +void UI_but_drag_attach_image(uiBut *but, struct ImBuf *imb, float scale); /** * \param asset: May be passed from a temporary variable, drag data only stores a copy of this. */ @@ -879,14 +876,14 @@ void UI_but_drag_set_asset(uiBut *but, struct ImBuf *imb, float scale); void UI_but_drag_set_rna(uiBut *but, struct PointerRNA *ptr); -void UI_but_drag_set_path(uiBut *but, const char *path, const bool use_free); +void UI_but_drag_set_path(uiBut *but, const char *path, bool use_free); void UI_but_drag_set_name(uiBut *but, const char *name); /** * Value from button itself. */ void UI_but_drag_set_value(uiBut *but); void UI_but_drag_set_image( - uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale, const bool use_free); + uiBut *but, const char *path, int icon, struct ImBuf *imb, float scale, bool use_free); uiBut *UI_but_active_drop_name_button(const struct bContext *C); /** @@ -918,7 +915,7 @@ bool UI_but_active_only_ex(const struct bContext *C, struct ARegion *region, uiBlock *block, uiBut *but, - const bool remove_on_failure); + bool remove_on_failure); bool UI_but_active_only(const struct bContext *C, struct ARegion *region, uiBlock *block, @@ -982,21 +979,6 @@ uiBut *uiDefButF(uiBlock *block, float a1, float a2, const char *tip); -uiBut *uiDefButBitF(uiBlock *block, - int type, - int bit, - int retval, - const char *str, - int x, - int y, - short width, - short height, - float *poin, - float min, - float max, - float a1, - float a2, - const char *tip); uiBut *uiDefButI(uiBlock *block, int type, int retval, @@ -1154,35 +1136,6 @@ uiBut *uiDefIconBut(uiBlock *block, float a1, float a2, const char *tip); -uiBut *uiDefIconButF(uiBlock *block, - int type, - int retval, - int icon, - int x, - int y, - short width, - short height, - float *poin, - float min, - float max, - float a1, - float a2, - const char *tip); -uiBut *uiDefIconButBitF(uiBlock *block, - int type, - int bit, - int retval, - int icon, - int x, - int y, - short width, - short height, - float *poin, - float min, - float max, - float a1, - float a2, - const char *tip); uiBut *uiDefIconButI(uiBlock *block, int type, int retval, @@ -1241,20 +1194,6 @@ uiBut *uiDefIconButBitS(uiBlock *block, float a1, float a2, const char *tip); -uiBut *uiDefIconButC(uiBlock *block, - int type, - int retval, - int icon, - int x, - int y, - short width, - short height, - char *poin, - float min, - float max, - float a1, - float a2, - const char *tip); uiBut *uiDefIconButBitC(uiBlock *block, int type, int bit, @@ -1356,22 +1295,6 @@ uiBut *uiDefIconTextButF(uiBlock *block, float a1, float a2, const char *tip); -uiBut *uiDefIconTextButBitF(uiBlock *block, - int type, - int bit, - int retval, - int icon, - const char *str, - int x, - int y, - short width, - short height, - float *poin, - float min, - float max, - float a1, - float a2, - const char *tip); uiBut *uiDefIconTextButI(uiBlock *block, int type, int retval, @@ -1387,84 +1310,6 @@ uiBut *uiDefIconTextButI(uiBlock *block, float a1, float a2, const char *tip); -uiBut *uiDefIconTextButBitI(uiBlock *block, - int type, - int bit, - int retval, - int icon, - const char *str, - int x, - int y, - short width, - short height, - int *poin, - float min, - float max, - float a1, - float a2, - const char *tip); -uiBut *uiDefIconTextButS(uiBlock *block, - int type, - int retval, - int icon, - const char *str, - int x, - int y, - short width, - short height, - short *poin, - float min, - float max, - float a1, - float a2, - const char *tip); -uiBut *uiDefIconTextButBitS(uiBlock *block, - int type, - int bit, - int retval, - int icon, - const char *str, - int x, - int y, - short width, - short height, - short *poin, - float min, - float max, - float a1, - float a2, - const char *tip); -uiBut *uiDefIconTextButC(uiBlock *block, - int type, - int retval, - int icon, - const char *str, - int x, - int y, - short width, - short height, - char *poin, - float min, - float max, - float a1, - float a2, - const char *tip); -uiBut *uiDefIconTextButBitC(uiBlock *block, - int type, - int bit, - int retval, - int icon, - const char *str, - int x, - int y, - short width, - short height, - char *poin, - float min, - float max, - float a1, - float a2, - const char *tip); uiBut *uiDefIconTextButR(uiBlock *block, int type, int retval, @@ -1525,7 +1370,7 @@ uiBut *uiDefIconTextButO_ptr(uiBlock *block, /* for passing inputs to ButO buttons */ struct PointerRNA *UI_but_operator_ptr_get(uiBut *but); -void UI_but_unit_type_set(uiBut *but, const int unit_type); +void UI_but_unit_type_set(uiBut *but, int unit_type); int UI_but_unit_type_get(const uiBut *but); typedef enum uiStringInfoType { @@ -1793,7 +1638,7 @@ eAutoPropButsReturn uiDefAutoButsRNA(uiLayout *layout, void *user_data, struct PropertyRNA *prop_activate_init, eButLabelAlign label_align, - const bool compact); + bool compact); /** * Public function exported for functions that use #UI_BTYPE_SEARCH_MENU. @@ -1813,7 +1658,7 @@ bool UI_search_item_add(uiSearchItems *items, void *poin, int iconid, int state, - const uint8_t name_prefix_offset); + uint8_t name_prefix_offset); /** * \note The item-pointer (referred to below) is a per search item user pointer @@ -1834,7 +1679,7 @@ void UI_but_func_search_set(uiBut *but, uiButSearchCreateFn search_create_fn, uiButSearchUpdateFn search_update_fn, void *arg, - const bool free_arg, + bool free_arg, uiFreeArgFunc search_arg_free_fn, uiButHandleFunc search_exec_fn, void *active); @@ -1845,7 +1690,7 @@ void UI_but_func_search_set_tooltip(uiBut *but, uiButSearchTooltipFn tooltip_fn) * showing the icon and highlighted text after the last instance of this string. */ void UI_but_func_search_set_sep_string(uiBut *but, const char *search_sep_string); -void UI_but_func_search_set_results_are_suggestions(uiBut *but, const bool value); +void UI_but_func_search_set_results_are_suggestions(uiBut *but, bool value); /** * Height in pixels, it's using hard-coded values still. @@ -2070,7 +1915,7 @@ void UI_region_handlers_add(struct ListBase *handlers); void UI_popup_handlers_add(struct bContext *C, struct ListBase *handlers, uiPopupBlockHandle *popup, - const char flag); + char flag); void UI_popup_handlers_remove(struct ListBase *handlers, uiPopupBlockHandle *popup); void UI_popup_handlers_remove_all(struct bContext *C, struct ListBase *handlers); @@ -2196,6 +2041,7 @@ uiLayout *UI_block_layout(uiBlock *block, const struct uiStyle *style); void UI_block_layout_set_current(uiBlock *block, uiLayout *layout); void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y); +bool UI_block_layout_needs_resolving(const uiBlock *block); /** * Used for property search when the layout process needs to be cancelled in order to avoid * computing the locations for buttons, but the layout items created while adding the buttons @@ -2319,7 +2165,7 @@ void uiTemplateID(uiLayout *layout, const char *openop, const char *unlinkop, int filter, - const bool live_icon, + bool live_icon, const char *text); void uiTemplateIDBrowse(uiLayout *layout, struct bContext *C, @@ -2340,7 +2186,7 @@ void uiTemplateIDPreview(uiLayout *layout, int rows, int cols, int filter, - const bool hide_buttons); + bool hide_buttons); /** * Version of #uiTemplateID using tabs. */ @@ -2384,8 +2230,8 @@ void uiTemplateSearchPreview(uiLayout *layout, const char *searchpropname, const char *newop, const char *unlinkop, - const int rows, - const int cols); + int rows, + int cols); /** * This is creating/editing RNA-Paths * @@ -2544,11 +2390,49 @@ void uiTemplateComponentMenu(uiLayout *layout, const char *propname, const char *name); void uiTemplateNodeSocket(uiLayout *layout, struct bContext *C, float color[4]); + +/** + * Draw the main CacheFile properties and operators (file path, scale, etc.), that is those which + * do not have their own dedicated template functions. + */ void uiTemplateCacheFile(uiLayout *layout, const struct bContext *C, struct PointerRNA *ptr, const char *propname); +/** + * Lookup the CacheFile PointerRNA of the given pointer and return it in the output parameter. + * Returns true if `ptr` has a RNACacheFile, false otherwise. If false, the output parameter is not + * initialized. + */ +bool uiTemplateCacheFilePointer(struct PointerRNA *ptr, + const char *propname, + struct PointerRNA *r_file_ptr); + +/** + * Draw the velocity related properties of the CacheFile. + */ +void uiTemplateCacheFileVelocity(uiLayout *layout, struct PointerRNA *fileptr); + +/** + * Draw the render procedural related properties of the CacheFile. + */ +void uiTemplateCacheFileProcedural(uiLayout *layout, + const struct bContext *C, + struct PointerRNA *fileptr); + +/** + * Draw the time related properties of the CacheFile. + */ +void uiTemplateCacheFileTimeSettings(uiLayout *layout, struct PointerRNA *fileptr); + +/** + * Draw the override layers related properties of the CacheFile. + */ +void uiTemplateCacheFileLayers(uiLayout *layout, + const struct bContext *C, + struct PointerRNA *fileptr); + /* Default UIList class name, keep in sync with its declaration in bl_ui/__init__.py */ #define UI_UL_DEFAULT_CLASS_NAME "UI_UL_list" enum uiTemplateListFlags { @@ -2661,7 +2545,7 @@ void uiTemplateAssetView(struct uiLayout *layout, struct PointerRNA *active_dataptr, const char *active_propname, const struct AssetFilterSettings *filter_settings, - const int display_flags, + int display_flags, const char *activate_opname, struct PointerRNA *r_activate_op_properties, const char *drag_opname, @@ -2870,8 +2754,7 @@ typedef struct uiPropertySplitWrapper { uiPropertySplitWrapper uiItemPropertySplitWrapperCreate(uiLayout *parent_layout); void uiItemL(uiLayout *layout, const char *name, int icon); /* label */ -void uiItemL_ex( - uiLayout *layout, const char *name, int icon, const bool highlight, const bool redalert); +void uiItemL_ex(uiLayout *layout, const char *name, int icon, bool highlight, bool redalert); /** * Helper to add a label and creates a property split layout if needed. */ @@ -2982,7 +2865,7 @@ const char *UI_layout_introspect(uiLayout *layout); * Helper to add a big icon and create a split layout for alert popups. * Returns the layout to place further items into the alert box. */ -uiLayout *uiItemsAlertBox(uiBlock *block, const int size, const eAlertIcon icon); +uiLayout *uiItemsAlertBox(uiBlock *block, int size, eAlertIcon icon); /* UI Operators */ typedef struct uiDragColorHandle { @@ -3007,6 +2890,13 @@ bool UI_context_copy_to_selected_list(struct bContext *C, struct ListBase *r_lb, bool *r_use_path_from_id, char **r_path); +bool UI_context_copy_to_selected_check(struct PointerRNA *ptr, + struct PointerRNA *ptr_link, + struct PropertyRNA *prop, + const char *path, + bool use_path_from_id, + struct PointerRNA *r_ptr, + struct PropertyRNA **r_prop); /* Helpers for Operators */ uiBut *UI_context_active_but_get(const struct bContext *C); @@ -3074,15 +2964,17 @@ void UI_fontstyle_set(const struct uiFontStyle *fs); void UI_fontstyle_draw_ex(const struct uiFontStyle *fs, const struct rcti *rect, const char *str, + size_t str_len, const uchar col[4], const struct uiFontStyleDraw_Params *fs_params, - size_t len, int *r_xofs, int *r_yofs, struct ResultBLF *r_info); + void UI_fontstyle_draw(const struct uiFontStyle *fs, const struct rcti *rect, const char *str, + size_t str_len, const uchar col[4], const struct uiFontStyleDraw_Params *fs_params); /** @@ -3124,7 +3016,7 @@ int UI_fontstyle_string_width(const struct uiFontStyle *fs, */ int UI_fontstyle_string_width_with_block_aspect(const struct uiFontStyle *fs, const char *str, - const float aspect) ATTR_WARN_UNUSED_RESULT + float aspect) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2); int UI_fontstyle_height_max(const struct uiFontStyle *fs); diff --git a/source/blender/editors/include/UI_interface.hh b/source/blender/editors/include/UI_interface.hh index d18ec009108..8d1ca54b7a1 100644 --- a/source/blender/editors/include/UI_interface.hh +++ b/source/blender/editors/include/UI_interface.hh @@ -31,8 +31,8 @@ namespace blender::nodes::geometry_nodes_eval_log { struct GeometryAttributeInfo; } -struct uiBlock; struct StructRNA; +struct uiBlock; struct uiSearchItems; namespace blender::ui { @@ -59,10 +59,10 @@ void template_breadcrumbs(uiLayout &layout, Span<ContextPathItem> context_path); void attribute_search_add_items( StringRefNull str, - const bool is_output, + bool is_output, Span<const nodes::geometry_nodes_eval_log::GeometryAttributeInfo *> infos, uiSearchItems *items, - const bool is_first); + bool is_first); } // namespace blender::ui diff --git a/source/blender/editors/include/UI_interface_icons.h b/source/blender/editors/include/UI_interface_icons.h index 242b8504ae1..1009ae5cd3f 100644 --- a/source/blender/editors/include/UI_interface_icons.h +++ b/source/blender/editors/include/UI_interface_icons.h @@ -82,13 +82,27 @@ int UI_icon_get_height(int icon_id); bool UI_icon_get_theme_color(int icon_id, unsigned char color[4]); /** + * Render a #PreviewImage for the data block. + * * Note that if an ID doesn't support jobs for preview creation, \a use_job will be ignored. */ void UI_icon_render_id(const struct bContext *C, struct Scene *scene, struct ID *id, - const enum eIconSizes size, - const bool use_job); + enum eIconSizes size, + bool use_job); + +/** + * Render the data block into the provided #PreviewImage. + */ +void UI_icon_render_id_ex(const struct bContext *C, + struct Scene *scene, + struct ID *id_to_render, + const enum eIconSizes size, + const bool use_job, + struct PreviewImage *r_preview_image); + + /** * Render size for preview images and icons */ @@ -108,7 +122,7 @@ void UI_icon_draw_ex(float x, float alpha, float desaturate, const uchar mono_color[4], - const bool mono_border); + bool mono_border); void UI_icons_free(void); void UI_icons_free_drawinfo(void *drawinfo); @@ -121,13 +135,10 @@ int UI_iconfile_get_index(const char *filename); struct PreviewImage *UI_icon_to_preview(int icon_id); -int UI_icon_from_rnaptr(const struct bContext *C, - struct PointerRNA *ptr, - int rnaicon, - const bool big); -int UI_icon_from_idcode(const int idcode); +int UI_icon_from_rnaptr(const struct bContext *C, struct PointerRNA *ptr, int rnaicon, bool big); +int UI_icon_from_idcode(int idcode); int UI_icon_from_library(const struct ID *id); -int UI_icon_from_object_mode(const int mode); +int UI_icon_from_object_mode(int mode); int UI_icon_color_from_collection(const struct Collection *collection); #ifdef __cplusplus diff --git a/source/blender/editors/include/UI_resources.h b/source/blender/editors/include/UI_resources.h index 98e141c65b5..40e4d8cee9c 100644 --- a/source/blender/editors/include/UI_resources.h +++ b/source/blender/editors/include/UI_resources.h @@ -502,7 +502,7 @@ int UI_ThemeMenuShadowWidth(void); */ const unsigned char *UI_ThemeGetColorPtr(struct bTheme *btheme, int spacetype, int colorid); -void UI_make_axis_color(const unsigned char src_col[3], unsigned char dst_col[3], const char axis); +void UI_make_axis_color(const unsigned char src_col[3], unsigned char dst_col[3], char axis); #ifdef __cplusplus } diff --git a/source/blender/editors/include/UI_tree_view.hh b/source/blender/editors/include/UI_tree_view.hh index 8208f8daf5d..8dee88defb3 100644 --- a/source/blender/editors/include/UI_tree_view.hh +++ b/source/blender/editors/include/UI_tree_view.hh @@ -40,8 +40,8 @@ struct uiBlock; struct uiBut; struct uiButTreeRow; struct uiLayout; -struct wmEvent; struct wmDrag; +struct wmEvent; namespace blender::ui { diff --git a/source/blender/editors/include/UI_view2d.h b/source/blender/editors/include/UI_view2d.h index 37246c2fe8f..a3f39e1286e 100644 --- a/source/blender/editors/include/UI_view2d.h +++ b/source/blender/editors/include/UI_view2d.h @@ -175,7 +175,7 @@ void UI_view2d_view_ortho(const struct View2D *v2d); * \param xaxis: if non-zero, only use cur x-axis, * otherwise use cur-yaxis (mostly this will be used for x). */ -void UI_view2d_view_orthoSpecial(struct ARegion *region, struct View2D *v2d, const bool xaxis); +void UI_view2d_view_orthoSpecial(struct ARegion *region, struct View2D *v2d, bool xaxis); /** * Restore view matrices after drawing. */ @@ -435,7 +435,7 @@ void ED_keymap_view2d(struct wmKeyConfig *keyconf); void UI_view2d_smooth_view(struct bContext *C, struct ARegion *region, const struct rctf *cur, - const int smooth_viewtx); + int smooth_viewtx); #define UI_MARKER_MARGIN_Y (42 * UI_DPI_FAC) #define UI_TIME_SCRUB_MARGIN_Y (23 * UI_DPI_FAC) diff --git a/source/blender/editors/interface/CMakeLists.txt b/source/blender/editors/interface/CMakeLists.txt index bc3075f9de8..95c9f7cc8b2 100644 --- a/source/blender/editors/interface/CMakeLists.txt +++ b/source/blender/editors/interface/CMakeLists.txt @@ -24,8 +24,8 @@ set(INC ../../blentranslation ../../depsgraph ../../draw - ../../gpu ../../functions + ../../gpu ../../imbuf ../../makesdna ../../makesrna @@ -71,8 +71,8 @@ set(SRC interface_regions.c interface_style.c interface_template_asset_view.cc - interface_template_list.cc interface_template_attribute_search.cc + interface_template_list.cc interface_template_search_menu.cc interface_template_search_operator.c interface_templates.c diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index df508b87ce4..636281ba373 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -661,8 +661,43 @@ static float ui_but_get_float_precision(uiBut *but) return but->a2; } +static float ui_but_get_float_step_size(uiBut *but) +{ + if (but->type == UI_BTYPE_NUM) { + return ((uiButNumber *)but)->step_size; + } + + return but->a1; +} + +static bool ui_but_hide_fraction(uiBut *but, double value) +{ + /* Hide the fraction if both the value and the step are exact integers. */ + if (floor(value) == value) { + const float step = ui_but_get_float_step_size(but) * UI_PRECISION_FLOAT_SCALE; + + if (floorf(step) == step) { + /* Don't hide if it has any unit except frame count. */ + switch (UI_but_unit_type_get(but)) { + case PROP_UNIT_NONE: + case PROP_UNIT_TIME: + return true; + + default: + return false; + } + } + } + + return false; +} + static int ui_but_calc_float_precision(uiBut *but, double value) { + if (ui_but_hide_fraction(but, value)) { + return 0; + } + int prec = (int)ui_but_get_float_precision(but); /* first check for various special cases: @@ -2813,8 +2848,14 @@ void ui_but_string_get_ex(uiBut *but, } if (ui_but_is_float(but)) { - int prec = (float_precision == -1) ? ui_but_calc_float_precision(but, value) : - float_precision; + int prec = float_precision; + + if (float_precision == -1) { + prec = ui_but_calc_float_precision(but, value); + } + else if (!use_exp_float && ui_but_hide_fraction(but, value)) { + prec = 0; + } if (ui_but_is_unit(but)) { ui_get_but_string_unit(but, str, maxlen, value, false, prec); @@ -4859,7 +4900,7 @@ int UI_autocomplete_end(AutoComplete *autocpl, char *autoname) BLI_strncpy(autoname, autocpl->truncate, autocpl->maxlen); } else { - if (autoname != autocpl->startname) { /* don't copy a string over its self */ + if (autoname != autocpl->startname) { /* don't copy a string over itself */ BLI_strncpy(autoname, autocpl->startname, autocpl->maxlen); } } @@ -4943,38 +4984,6 @@ uiBut *uiDefButF(uiBlock *block, a2, tip); } -uiBut *uiDefButBitF(uiBlock *block, - int type, - int bit, - int retval, - const char *str, - int x, - int y, - short width, - short height, - float *poin, - float min, - float max, - float a1, - float a2, - const char *tip) -{ - return uiDefButBit(block, - type | UI_BUT_POIN_FLOAT, - bit, - retval, - str, - x, - y, - width, - height, - (void *)poin, - min, - max, - a1, - a2, - tip); -} uiBut *uiDefButI(uiBlock *block, int type, int retval, @@ -5295,68 +5304,6 @@ static uiBut *uiDefIconButBit(uiBlock *block, tip); } -uiBut *uiDefIconButF(uiBlock *block, - int type, - int retval, - int icon, - int x, - int y, - short width, - short height, - float *poin, - float min, - float max, - float a1, - float a2, - const char *tip) -{ - return uiDefIconBut(block, - type | UI_BUT_POIN_FLOAT, - retval, - icon, - x, - y, - width, - height, - (void *)poin, - min, - max, - a1, - a2, - tip); -} -uiBut *uiDefIconButBitF(uiBlock *block, - int type, - int bit, - int retval, - int icon, - int x, - int y, - short width, - short height, - float *poin, - float min, - float max, - float a1, - float a2, - const char *tip) -{ - return uiDefIconButBit(block, - type | UI_BUT_POIN_FLOAT, - bit, - retval, - icon, - x, - y, - width, - height, - (void *)poin, - min, - max, - a1, - a2, - tip); -} uiBut *uiDefIconButI(uiBlock *block, int type, int retval, @@ -5481,36 +5428,6 @@ uiBut *uiDefIconButBitS(uiBlock *block, a2, tip); } -uiBut *uiDefIconButC(uiBlock *block, - int type, - int retval, - int icon, - int x, - int y, - short width, - short height, - char *poin, - float min, - float max, - float a1, - float a2, - const char *tip) -{ - return uiDefIconBut(block, - type | UI_BUT_POIN_CHAR, - retval, - icon, - x, - y, - width, - height, - (void *)poin, - min, - max, - a1, - a2, - tip); -} uiBut *uiDefIconButBitC(uiBlock *block, int type, int bit, @@ -5640,44 +5557,6 @@ uiBut *uiDefIconTextBut(uiBlock *block, but->drawflag |= UI_BUT_ICON_LEFT; return but; } -static uiBut *uiDefIconTextButBit(uiBlock *block, - int type, - int bit, - int retval, - int icon, - const char *str, - int x, - int y, - short width, - short height, - void *poin, - float min, - float max, - float a1, - float a2, - const char *tip) -{ - const int bitIdx = findBitIndex(bit); - if (bitIdx == -1) { - return NULL; - } - return uiDefIconTextBut(block, - type | UI_BUT_POIN_BIT | bitIdx, - retval, - icon, - str, - x, - y, - width, - height, - poin, - min, - max, - a1, - a2, - tip); -} - uiBut *uiDefIconTextButF(uiBlock *block, int type, int retval, @@ -5710,40 +5589,6 @@ uiBut *uiDefIconTextButF(uiBlock *block, a2, tip); } -uiBut *uiDefIconTextButBitF(uiBlock *block, - int type, - int bit, - int retval, - int icon, - const char *str, - int x, - int y, - short width, - short height, - float *poin, - float min, - float max, - float a1, - float a2, - const char *tip) -{ - return uiDefIconTextButBit(block, - type | UI_BUT_POIN_FLOAT, - bit, - retval, - icon, - str, - x, - y, - width, - height, - (void *)poin, - min, - max, - a1, - a2, - tip); -} uiBut *uiDefIconTextButI(uiBlock *block, int type, int retval, @@ -5776,172 +5621,6 @@ uiBut *uiDefIconTextButI(uiBlock *block, a2, tip); } -uiBut *uiDefIconTextButBitI(uiBlock *block, - int type, - int bit, - int retval, - int icon, - const char *str, - int x, - int y, - short width, - short height, - int *poin, - float min, - float max, - float a1, - float a2, - const char *tip) -{ - return uiDefIconTextButBit(block, - type | UI_BUT_POIN_INT, - bit, - retval, - icon, - str, - x, - y, - width, - height, - (void *)poin, - min, - max, - a1, - a2, - tip); -} -uiBut *uiDefIconTextButS(uiBlock *block, - int type, - int retval, - int icon, - const char *str, - int x, - int y, - short width, - short height, - short *poin, - float min, - float max, - float a1, - float a2, - const char *tip) -{ - return uiDefIconTextBut(block, - type | UI_BUT_POIN_SHORT, - retval, - icon, - str, - x, - y, - width, - height, - (void *)poin, - min, - max, - a1, - a2, - tip); -} -uiBut *uiDefIconTextButBitS(uiBlock *block, - int type, - int bit, - int retval, - int icon, - const char *str, - int x, - int y, - short width, - short height, - short *poin, - float min, - float max, - float a1, - float a2, - const char *tip) -{ - return uiDefIconTextButBit(block, - type | UI_BUT_POIN_SHORT, - bit, - retval, - icon, - str, - x, - y, - width, - height, - (void *)poin, - min, - max, - a1, - a2, - tip); -} -uiBut *uiDefIconTextButC(uiBlock *block, - int type, - int retval, - int icon, - const char *str, - int x, - int y, - short width, - short height, - char *poin, - float min, - float max, - float a1, - float a2, - const char *tip) -{ - return uiDefIconTextBut(block, - type | UI_BUT_POIN_CHAR, - retval, - icon, - str, - x, - y, - width, - height, - (void *)poin, - min, - max, - a1, - a2, - tip); -} -uiBut *uiDefIconTextButBitC(uiBlock *block, - int type, - int bit, - int retval, - int icon, - const char *str, - int x, - int y, - short width, - short height, - char *poin, - float min, - float max, - float a1, - float a2, - const char *tip) -{ - return uiDefIconTextButBit(block, - type | UI_BUT_POIN_CHAR, - bit, - retval, - icon, - str, - x, - y, - width, - height, - (void *)poin, - min, - max, - a1, - a2, - tip); -} uiBut *uiDefIconTextButR(uiBlock *block, int type, int retval, diff --git a/source/blender/editors/interface/interface_draw.c b/source/blender/editors/interface/interface_draw.c index 285c82b0fb3..f7492e56b62 100644 --- a/source/blender/editors/interface/interface_draw.c +++ b/source/blender/editors/interface/interface_draw.c @@ -57,6 +57,7 @@ #include "GPU_immediate.h" #include "GPU_immediate_util.h" #include "GPU_matrix.h" +#include "GPU_shader_shared.h" #include "GPU_state.h" #include "UI_interface.h" @@ -324,17 +325,17 @@ void ui_draw_but_IMAGE(ARegion *UNUSED(region), } IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); - immDrawPixelsTex(&state, - (float)rect->xmin, - (float)rect->ymin, - ibuf->x, - ibuf->y, - GPU_RGBA8, - false, - ibuf->rect, - 1.0f, - 1.0f, - col); + immDrawPixelsTexTiled(&state, + (float)rect->xmin, + (float)rect->ymin, + ibuf->x, + ibuf->y, + GPU_RGBA8, + false, + ibuf->rect, + 1.0f, + 1.0f, + col); GPU_blend(GPU_BLEND_NONE); @@ -1384,10 +1385,16 @@ void ui_draw_but_UNITVEC(uiBut *but, GPU_matrix_scale_1f(size); GPUBatch *sphere = GPU_batch_preset_sphere(2); + struct SimpleLightingData simple_lighting_data; + copy_v4_fl4(simple_lighting_data.color, diffuse[0], diffuse[1], diffuse[2], 1.0f); + copy_v3_v3(simple_lighting_data.light, light); + GPUUniformBuf *ubo = GPU_uniformbuf_create_ex( + sizeof(struct SimpleLightingData), &simple_lighting_data, __func__); + GPU_batch_program_set_builtin(sphere, GPU_SHADER_SIMPLE_LIGHTING); - GPU_batch_uniform_4f(sphere, "color", diffuse[0], diffuse[1], diffuse[2], 1.0f); - GPU_batch_uniform_3fv(sphere, "light", light); + GPU_batch_uniformbuf_bind(sphere, "simple_lighting_data", ubo); GPU_batch_draw(sphere); + GPU_uniformbuf_free(ubo); /* Restore. */ GPU_face_culling(GPU_CULL_NONE); @@ -2128,17 +2135,17 @@ void ui_draw_but_TRACKPREVIEW(ARegion *UNUSED(region), } IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); - immDrawPixelsTex(&state, - rect.xmin, - rect.ymin + 1, - drawibuf->x, - drawibuf->y, - GPU_RGBA8, - true, - drawibuf->rect, - 1.0f, - 1.0f, - NULL); + immDrawPixelsTexTiled(&state, + rect.xmin, + rect.ymin + 1, + drawibuf->x, + drawibuf->y, + GPU_RGBA8, + true, + drawibuf->rect, + 1.0f, + 1.0f, + NULL); /* draw cross for pixel position */ GPU_matrix_translate_2f(rect.xmin + scopes->track_pos[0], rect.ymin + scopes->track_pos[1]); diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c index 27fa2e5a22f..fd03cc5e12c 100644 --- a/source/blender/editors/interface/interface_eyedropper.c +++ b/source/blender/editors/interface/interface_eyedropper.c @@ -146,8 +146,8 @@ void eyedropper_draw_cursor_text_region(const int x, const int y, const char *na uiBut *eyedropper_get_property_button_under_mouse(bContext *C, const wmEvent *event) { bScreen *screen = CTX_wm_screen(C); - ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy[0], event->xy[1]); - const ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_ANY, event->xy[0], event->xy[1]); + ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy); + const ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_ANY, event->xy); uiBut *but = ui_but_find_mouse_over(region, event); @@ -163,13 +163,13 @@ void datadropper_win_area_find( bScreen *screen = CTX_wm_screen(C); *r_win = CTX_wm_window(C); - *r_area = BKE_screen_find_area_xy(screen, -1, mval[0], mval[1]); + *r_area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mval); if (*r_area == NULL) { wmWindowManager *wm = CTX_wm_manager(C); *r_win = WM_window_find_under_cursor(wm, NULL, *r_win, mval, r_mval); if (*r_win) { screen = WM_window_get_active_screen(*r_win); - *r_area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, r_mval[0], r_mval[1]); + *r_area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, r_mval); } } else if (mval != r_mval) { diff --git a/source/blender/editors/interface/interface_eyedropper_color.c b/source/blender/editors/interface/interface_eyedropper_color.c index 0ac6ea4021b..05840175fab 100644 --- a/source/blender/editors/interface/interface_eyedropper_color.c +++ b/source/blender/editors/interface/interface_eyedropper_color.c @@ -42,6 +42,8 @@ #include "BKE_node.h" #include "BKE_screen.h" +#include "NOD_composite.h" + #include "RNA_access.h" #include "UI_interface.h" @@ -263,32 +265,32 @@ static bool eyedropper_cryptomatte_sample_fl( } bScreen *screen = CTX_wm_screen(C); - ScrArea *sa = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my); - if (!sa || !ELEM(sa->spacetype, SPACE_IMAGE, SPACE_NODE, SPACE_CLIP)) { + ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, (const int[2]){mx, my}); + if (!area || !ELEM(area->spacetype, SPACE_IMAGE, SPACE_NODE, SPACE_CLIP)) { return false; } - ARegion *region = BKE_area_find_region_xy(sa, RGN_TYPE_WINDOW, mx, my); + ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, (const int[2]){mx, my}); if (!region) { return false; } int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin}; float fpos[2] = {-1.0f, -1.0}; - switch (sa->spacetype) { + switch (area->spacetype) { case SPACE_IMAGE: { - SpaceImage *sima = sa->spacedata.first; + SpaceImage *sima = area->spacedata.first; ED_space_image_get_position(sima, region, mval, fpos); break; } case SPACE_NODE: { Main *bmain = CTX_data_main(C); - SpaceNode *snode = sa->spacedata.first; + SpaceNode *snode = area->spacedata.first; ED_space_node_get_position(bmain, snode, region, mval, fpos); break; } case SPACE_CLIP: { - SpaceClip *sc = sa->spacedata.first; + SpaceClip *sc = area->spacedata.first; ED_space_clip_get_position(sc, region, mval, fpos); break; } @@ -337,7 +339,7 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3]) if (area) { if (area->spacetype == SPACE_IMAGE) { - ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval[0], mval[1]); + ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval); if (region) { SpaceImage *sima = area->spacedata.first; int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin}; @@ -348,7 +350,7 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3]) } } else if (area->spacetype == SPACE_NODE) { - ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval[0], mval[1]); + ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval); if (region) { SpaceNode *snode = area->spacedata.first; int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin}; @@ -359,7 +361,7 @@ void eyedropper_color_sample_fl(bContext *C, int mx, int my, float r_col[3]) } } else if (area->spacetype == SPACE_CLIP) { - ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval[0], mval[1]); + ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mval); if (region) { SpaceClip *sc = area->spacedata.first; int region_mval[2] = {mval[0] - region->winrct.xmin, mval[1] - region->winrct.ymin}; diff --git a/source/blender/editors/interface/interface_eyedropper_datablock.c b/source/blender/editors/interface/interface_eyedropper_datablock.c index 261aa997d06..cf53ef0ec75 100644 --- a/source/blender/editors/interface/interface_eyedropper_datablock.c +++ b/source/blender/editors/interface/interface_eyedropper_datablock.c @@ -162,7 +162,7 @@ static void datadropper_id_sample_pt( if (area) { if (ELEM(area->spacetype, SPACE_VIEW3D, SPACE_OUTLINER)) { - ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my); + ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, (const int[2]){mx, my}); if (region) { const int mval[2] = {mx - region->winrct.xmin, my - region->winrct.ymin}; Base *base; diff --git a/source/blender/editors/interface/interface_eyedropper_depth.c b/source/blender/editors/interface/interface_eyedropper_depth.c index 4172c474f4a..8c6b0ac9cfe 100644 --- a/source/blender/editors/interface/interface_eyedropper_depth.c +++ b/source/blender/editors/interface/interface_eyedropper_depth.c @@ -157,7 +157,7 @@ static void depthdropper_depth_sample_pt( { /* we could use some clever */ bScreen *screen = CTX_wm_screen(C); - ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, mx, my); + ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, (const int[2]){mx, my}); Scene *scene = CTX_data_scene(C); ScrArea *area_prev = CTX_wm_area(C); @@ -167,7 +167,7 @@ static void depthdropper_depth_sample_pt( if (area) { if (area->spacetype == SPACE_VIEW3D) { - ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my); + ARegion *region = BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, (const int[2]){mx, my}); if (region) { struct Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); View3D *v3d = area->spacedata.first; diff --git a/source/blender/editors/interface/interface_eyedropper_driver.c b/source/blender/editors/interface/interface_eyedropper_driver.c index ccf0e727da8..6fe930b74d2 100644 --- a/source/blender/editors/interface/interface_eyedropper_driver.c +++ b/source/blender/editors/interface/interface_eyedropper_driver.c @@ -107,7 +107,7 @@ static void driverdropper_sample(bContext *C, wmOperator *op, const wmEvent *eve char *target_path = RNA_path_from_ID_to_property(target_ptr, target_prop); /* ... and destination */ - char *dst_path = BKE_animdata_driver_path_hack(C, &ddr->ptr, ddr->prop, NULL); + char *dst_path = RNA_path_from_ID_to_property(&ddr->ptr, ddr->prop); /* Now create driver(s) */ if (target_path && dst_path) { diff --git a/source/blender/editors/interface/interface_eyedropper_intern.h b/source/blender/editors/interface/interface_eyedropper_intern.h index 17bb78a7861..ec448ef9b9f 100644 --- a/source/blender/editors/interface/interface_eyedropper_intern.h +++ b/source/blender/editors/interface/interface_eyedropper_intern.h @@ -25,7 +25,7 @@ /* interface_eyedropper.c */ void eyedropper_draw_cursor_text_window(const struct wmWindow *window, const char *name); -void eyedropper_draw_cursor_text_region(const int x, const int y, const char *name); +void eyedropper_draw_cursor_text_region(int x, int y, const char *name); /** * Utility to retrieve a button representing a RNA property that is currently under the cursor. * diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index f947572f41b..905fd452b6c 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -1787,7 +1787,7 @@ static bool ui_but_is_drag_toggle(const uiBut *but) static bool ui_selectcontext_begin(bContext *C, uiBut *but, uiSelectContextStore *selctx_data) { - PointerRNA lptr, idptr; + PointerRNA lptr; PropertyRNA *lprop; bool success = false; @@ -1821,68 +1821,48 @@ static bool ui_selectcontext_begin(bContext *C, uiBut *but, uiSelectContextStore if (i >= selctx_data->elems_len) { break; } + + if (!UI_context_copy_to_selected_check( + &ptr, &link->ptr, prop, path, use_path_from_id, &lptr, &lprop)) { + selctx_data->elems_len -= 1; + i -= 1; + continue; + } + uiSelectContextElem *other = &selctx_data->elems[i]; - /* TODO: de-duplicate copy_to_selected_button. */ - if (link->ptr.data != ptr.data) { - if (use_path_from_id) { - /* Path relative to ID. */ - lprop = NULL; - RNA_id_pointer_create(link->ptr.owner_id, &idptr); - RNA_path_resolve_property(&idptr, path, &lptr, &lprop); - } - else if (path) { - /* Path relative to elements from list. */ - lprop = NULL; - RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop); + other->ptr = lptr; + if (is_array) { + if (rna_type == PROP_FLOAT) { + other->val_f = RNA_property_float_get_index(&lptr, lprop, index); } - else { - lptr = link->ptr; - lprop = prop; + else if (rna_type == PROP_INT) { + other->val_i = RNA_property_int_get_index(&lptr, lprop, index); } - - /* lptr might not be the same as link->ptr! */ - if ((lptr.data != ptr.data) && (lprop == prop) && RNA_property_editable(&lptr, lprop)) { - other->ptr = lptr; - if (is_array) { - if (rna_type == PROP_FLOAT) { - other->val_f = RNA_property_float_get_index(&lptr, lprop, index); - } - else if (rna_type == PROP_INT) { - other->val_i = RNA_property_int_get_index(&lptr, lprop, index); - } - /* ignored for now */ + /* ignored for now */ # if 0 - else if (rna_type == PROP_BOOLEAN) { - other->val_b = RNA_property_boolean_get_index(&lptr, lprop, index); - } -# endif + else if (rna_type == PROP_BOOLEAN) { + other->val_b = RNA_property_boolean_get_index(&lptr, lprop, index); } - else { - if (rna_type == PROP_FLOAT) { - other->val_f = RNA_property_float_get(&lptr, lprop); - } - else if (rna_type == PROP_INT) { - other->val_i = RNA_property_int_get(&lptr, lprop); - } - /* ignored for now */ -# if 0 - else if (rna_type == PROP_BOOLEAN) { - other->val_b = RNA_property_boolean_get(&lptr, lprop); - } - else if (rna_type == PROP_ENUM) { - other->val_i = RNA_property_enum_get(&lptr, lprop); - } # endif - } - - continue; + } + else { + if (rna_type == PROP_FLOAT) { + other->val_f = RNA_property_float_get(&lptr, lprop); + } + else if (rna_type == PROP_INT) { + other->val_i = RNA_property_int_get(&lptr, lprop); } + /* ignored for now */ +# if 0 + else if (rna_type == PROP_BOOLEAN) { + other->val_b = RNA_property_boolean_get(&lptr, lprop); + } + else if (rna_type == PROP_ENUM) { + other->val_i = RNA_property_enum_get(&lptr, lprop); + } +# endif } - - selctx_data->elems_len -= 1; - i -= 1; } - success = (selctx_data->elems_len != 0); } } @@ -3515,8 +3495,17 @@ static void ui_textedit_begin(bContext *C, uiBut *but, uiHandleButtonData *data) ui_but_update(but); - /* Popup blocks don't support moving after creation, so don't change the view for them. */ - if (!data->searchbox) { + /* Make sure the edited button is in view. */ + if (data->searchbox) { + /* Popup blocks don't support moving after creation, so don't change the view for them. */ + } + else if (UI_block_layout_needs_resolving(but->block)) { + /* Layout isn't resolved yet (may happen when activating while drawing through + * #UI_but_active_only()), so can't move it into view yet. This causes + * #ui_but_update_view_for_active() to run after the layout is resolved. */ + but->changed = true; + } + else { UI_but_ensure_in_view(C, data->region, but); } @@ -3773,7 +3762,12 @@ static void ui_do_but_textedit( case EVT_VKEY: case EVT_XKEY: case EVT_CKEY: - if (IS_EVENT_MOD(event, ctrl, oskey)) { +#if defined(__APPLE__) + if ((event->oskey && !IS_EVENT_MOD(event, shift, alt, ctrl)) || + (event->ctrl && !IS_EVENT_MOD(event, shift, alt, oskey))) { +#else + if (event->ctrl && !IS_EVENT_MOD(event, shift, alt, oskey)) { +#endif if (event->type == EVT_VKEY) { changed = ui_textedit_copypaste(but, data, UI_TEXTEDIT_PASTE); } @@ -5490,7 +5484,7 @@ static int ui_do_but_NUM( log10f(number_but->step_size)); } else { - value_step = (double)number_but->step_size * UI_PRECISION_FLOAT_SCALE; + value_step = (double)(number_but->step_size * UI_PRECISION_FLOAT_SCALE); } BLI_assert(value_step > 0.0f); const double value_test = (but->drawflag & UI_BUT_ACTIVE_LEFT) ? @@ -7938,7 +7932,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * const bool do_copy = event->type == EVT_CKEY && is_press_ctrl_but_no_shift; const bool do_paste = event->type == EVT_VKEY && is_press_ctrl_but_no_shift; - /* Specific handling for listrows, we try to find their overlapping tex button. */ + /* Specific handling for list-rows, we try to find their overlapping text button. */ if ((do_copy || do_paste) && but->type == UI_BTYPE_LISTROW) { uiBut *labelbut = ui_but_list_row_text_activate(C, but, data, event, BUTTON_ACTIVATE_OVER); if (labelbut) { diff --git a/source/blender/editors/interface/interface_icons.c b/source/blender/editors/interface/interface_icons.c index ca5d08ba40e..c0d6b8a1a6c 100644 --- a/source/blender/editors/interface/interface_icons.c +++ b/source/blender/editors/interface/interface_icons.c @@ -31,6 +31,7 @@ #include "GPU_batch_presets.h" #include "GPU_immediate.h" #include "GPU_matrix.h" +#include "GPU_shader_shared.h" #include "GPU_state.h" #include "GPU_texture.h" @@ -1478,78 +1479,6 @@ PreviewImage *UI_icon_to_preview(int icon_id) return NULL; } -/** - * Version of #icon_draw_rect() that uses the GPU for scaling. This is only used for - * #ICON_TYPE_IMBUF because it's a back-ported fix for performance issues, see T92922. Only - * File/Asset Browser use #ICON_TYPE_IMBUF right now, which makes implications more predictable. - * - * TODO(Julian): This code is mostly duplicated. #icon_draw_rect() should be ported to use the GPU - * instead (D13144). - */ -static void icon_draw_rect_fast(float x, - float y, - int w, - int h, - float UNUSED(aspect), - int rw, - int rh, - uint *rect, - float alpha, - const float desaturate) -{ - int draw_w = w; - int draw_h = h; - int draw_x = x; - /* We need to round y, to avoid the icon jittering in some cases. */ - int draw_y = round_fl_to_int(y); - - /* sanity check */ - if (w <= 0 || h <= 0 || w > 2000 || h > 2000) { - printf("%s: icons are %i x %i pixels?\n", __func__, w, h); - BLI_assert_msg(0, "invalid icon size"); - return; - } - /* modulate color */ - const float col[4] = {alpha, alpha, alpha, alpha}; - - float scale_x = 1.0f; - float scale_y = 1.0f; - /* rect contains image in 'rendersize', we only scale if needed */ - if (rw != w || rh != h) { - /* preserve aspect ratio and center */ - if (rw > rh) { - draw_w = w; - draw_h = (int)(((float)rh / (float)rw) * (float)w); - draw_y += (h - draw_h) / 2; - } - else if (rw < rh) { - draw_w = (int)(((float)rw / (float)rh) * (float)h); - draw_h = h; - draw_x += (w - draw_w) / 2; - } - scale_x = draw_w / (float)rw; - scale_y = draw_h / (float)rh; - /* If the image is squared, the `draw_*` initialization values are good. */ - } - - /* draw */ - eGPUBuiltinShader shader; - if (desaturate != 0.0f) { - shader = GPU_SHADER_2D_IMAGE_DESATURATE_COLOR; - } - else { - shader = GPU_SHADER_2D_IMAGE_COLOR; - } - IMMDrawPixelsTexState state = immDrawPixelsTexSetup(shader); - - if (shader == GPU_SHADER_2D_IMAGE_DESATURATE_COLOR) { - immUniform1f("factor", desaturate); - } - - immDrawPixelsTexScaled( - &state, draw_x, draw_y, rw, rh, GPU_RGBA8, true, rect, scale_x, scale_y, 1.0f, 1.0f, col); -} - static void icon_draw_rect(float x, float y, int w, @@ -1561,7 +1490,6 @@ static void icon_draw_rect(float x, float alpha, const float desaturate) { - ImBuf *ima = NULL; int draw_w = w; int draw_h = h; int draw_x = x; @@ -1577,6 +1505,8 @@ static void icon_draw_rect(float x, /* modulate color */ const float col[4] = {alpha, alpha, alpha, alpha}; + float scale_x = 1.0f; + float scale_y = 1.0f; /* rect contains image in 'rendersize', we only scale if needed */ if (rw != w || rh != h) { /* preserve aspect ratio and center */ @@ -1590,13 +1520,9 @@ static void icon_draw_rect(float x, draw_h = h; draw_x += (w - draw_w) / 2; } + scale_x = draw_w / (float)rw; + scale_y = draw_h / (float)rh; /* If the image is squared, the `draw_*` initialization values are good. */ - - /* first allocate imbuf for scaling and copy preview into it */ - ima = IMB_allocImBuf(rw, rh, 32, IB_rect); - memcpy(ima->rect, rect, rw * rh * sizeof(uint)); - IMB_scaleImBuf(ima, draw_w, draw_h); /* scale it */ - rect = ima->rect; } /* draw */ @@ -1613,12 +1539,8 @@ static void icon_draw_rect(float x, immUniform1f("factor", desaturate); } - immDrawPixelsTex( - &state, draw_x, draw_y, draw_w, draw_h, GPU_RGBA8, false, rect, 1.0f, 1.0f, col); - - if (ima) { - IMB_freeImBuf(ima); - } + immDrawPixelsTexScaledFullSize( + &state, draw_x, draw_y, rw, rh, GPU_RGBA8, true, rect, scale_x, scale_y, 1.0f, 1.0f, col); } /* High enough to make a difference, low enough so that @@ -1661,18 +1583,21 @@ static void icon_draw_cache_texture_flush_ex(GPUTexture *texture, GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_IMAGE_MULTI_RECT_COLOR); GPU_shader_bind(shader); - const int img_binding = GPU_shader_get_texture_binding(shader, "image"); - const int data_loc = GPU_shader_get_uniform(shader, "calls_data"); + const int data_loc = GPU_shader_get_uniform_block(shader, "multi_rect_data"); + GPUUniformBuf *ubo = GPU_uniformbuf_create_ex( + sizeof(struct MultiRectCallData), texture_draw_calls->drawcall_cache, __func__); + GPU_uniformbuf_bind(ubo, data_loc); + const int img_binding = GPU_shader_get_texture_binding(shader, "image"); GPU_texture_bind_ex(texture, GPU_SAMPLER_ICON, img_binding, false); - GPU_shader_uniform_vector( - shader, data_loc, 4, ICON_DRAW_CACHE_SIZE * 3, (float *)texture_draw_calls->drawcall_cache); GPUBatch *quad = GPU_batch_preset_quad(); GPU_batch_set_shader(quad, shader); GPU_batch_draw_instanced(quad, texture_draw_calls->calls); GPU_texture_unbind(texture); + GPU_uniformbuf_unbind(ubo); + GPU_uniformbuf_free(ubo); texture_draw_calls->calls = 0; } @@ -1874,9 +1799,7 @@ static void icon_draw_size(float x, ImBuf *ibuf = icon->obj; GPU_blend(GPU_BLEND_ALPHA_PREMULT); - /* These icons are only used by the File/Asset Browser currently. Without this `_fast()` - * version, there may be performance issues, see T92922. */ - icon_draw_rect_fast(x, y, w, h, aspect, ibuf->x, ibuf->y, ibuf->rect, alpha, desaturate); + icon_draw_rect(x, y, w, h, aspect, ibuf->x, ibuf->y, ibuf->rect, alpha, desaturate); GPU_blend(GPU_BLEND_ALPHA); } else if (di->type == ICON_TYPE_VECTOR) { @@ -2026,6 +1949,16 @@ static void ui_id_preview_image_render_size( } } +void UI_icon_render_id_ex(const bContext *C, + Scene *scene, + ID *id_to_render, + const enum eIconSizes size, + const bool use_job, + PreviewImage *r_preview_image) +{ + ui_id_preview_image_render_size(C, scene, id_to_render, r_preview_image, size, use_job); +} + void UI_icon_render_id( const bContext *C, Scene *scene, ID *id, const enum eIconSizes size, const bool use_job) { @@ -2034,19 +1967,21 @@ void UI_icon_render_id( return; } + ID *id_to_render = id; + /* For objects, first try if a preview can created via the object data. */ if (GS(id->name) == ID_OB) { Object *ob = (Object *)id; if (ED_preview_id_is_supported(ob->data)) { - id = ob->data; + id_to_render = ob->data; } } - if (!ED_preview_id_is_supported(id)) { + if (!ED_preview_id_is_supported(id_to_render)) { return; } - ui_id_preview_image_render_size(C, scene, id, pi, size, use_job); + UI_icon_render_id_ex(C, scene, id_to_render, size, use_job, pi); } static void ui_id_icon_render(const bContext *C, ID *id, bool use_jobs) diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index dc8744aaae9..2d1138b46a7 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -671,7 +671,7 @@ extern void ui_but_v3_get(uiBut *but, float vec[3]); extern void ui_but_v3_set(uiBut *but, const float vec[3]); extern void ui_hsvcircle_vals_from_pos( - const rcti *rect, const float mx, const float my, float *r_val_rad, float *r_val_dist); + const rcti *rect, float mx, float my, float *r_val_rad, float *r_val_dist); /** * Cursor in HSV circle, in float units -1 to 1, to map on radius. */ @@ -688,11 +688,11 @@ extern void ui_hsvcube_pos_from_vals( */ extern void ui_but_string_get_ex(uiBut *but, char *str, - const size_t maxlen, - const int float_precision, - const bool use_exp_float, + size_t maxlen, + int float_precision, + bool use_exp_float, bool *r_use_exp_float) ATTR_NONNULL(1, 2); -extern void ui_but_string_get(uiBut *but, char *str, const size_t maxlen) ATTR_NONNULL(); +extern void ui_but_string_get(uiBut *but, char *str, size_t maxlen) ATTR_NONNULL(); /** * A version of #ui_but_string_get_ex for dynamic buffer sizes * (where #ui_but_string_get_max_length returns 0). @@ -722,7 +722,7 @@ extern void ui_but_active_string_clear_and_exit(struct bContext *C, uiBut *but) extern void ui_but_set_string_interactive(struct bContext *C, uiBut *but, const char *value); extern uiBut *ui_but_drag_multi_edit_get(uiBut *but); -void ui_def_but_icon(uiBut *but, const int icon, const int flag); +void ui_def_but_icon(uiBut *but, int icon, int flag); /** * Avoid using this where possible since it's better not to ask for an icon in the first place. */ @@ -905,7 +905,7 @@ int ui_searchbox_find_index(struct ARegion *region, const char *name); /** * Region is the search box itself. */ -void ui_searchbox_update(struct bContext *C, struct ARegion *region, uiBut *but, const bool reset); +void ui_searchbox_update(struct bContext *C, struct ARegion *region, uiBut *but, bool reset); int ui_searchbox_autocomplete(struct bContext *C, struct ARegion *region, uiBut *but, char *str); bool ui_searchbox_event(struct bContext *C, struct ARegion *region, @@ -1000,9 +1000,9 @@ extern int ui_handler_panel_region(struct bContext *C, extern void ui_draw_aligned_panel(const struct uiStyle *style, const uiBlock *block, const rcti *rect, - const bool show_pin, - const bool show_background, - const bool region_search_filter_active); + bool show_pin, + bool show_background, + bool region_search_filter_active); void ui_panel_tag_search_filter_match(struct Panel *panel); /* interface_draw.c */ @@ -1013,10 +1013,7 @@ extern void ui_draw_dropshadow( /** * Draws in resolution of 48x4 colors. */ -void ui_draw_gradient(const rcti *rect, - const float hsv[3], - const eButGradientType type, - const float alpha); +void ui_draw_gradient(const rcti *rect, const float hsv[3], eButGradientType type, float alpha); /* based on UI_draw_roundbox_gl_mode, * check on making a version which allows us to skip some sides */ @@ -1040,7 +1037,7 @@ void ui_draw_but_COLORBAND(uiBut *but, const struct uiWidgetColors *wcol, const void ui_draw_but_UNITVEC(uiBut *but, const struct uiWidgetColors *wcol, const rcti *rect, - const float radius); + float radius); void ui_draw_but_CURVE(struct ARegion *region, uiBut *but, const struct uiWidgetColors *wcol, @@ -1118,7 +1115,7 @@ extern void ui_but_active_free(const struct bContext *C, uiBut *but); */ extern void ui_but_update_view_for_active(const struct bContext *C, const uiBlock *block); extern int ui_but_menu_direction(uiBut *but); -extern void ui_but_text_password_hide(char password_str[128], uiBut *but, const bool restore); +extern void ui_but_text_password_hide(char password_str[128], uiBut *but, bool restore); /** * Finds the pressed button in an aligned row (typically an expanded enum). * @@ -1131,7 +1128,7 @@ float ui_block_calc_pie_segment(struct uiBlock *block, const float event_xy[2]); /* XXX, this code will shorten any allocated string to 'UI_MAX_NAME_STR' * since this is really long its unlikely to be an issue, * but this could be supported */ -void ui_but_add_shortcut(uiBut *but, const char *shortcut_str, const bool do_strip); +void ui_but_add_shortcut(uiBut *but, const char *shortcut_str, bool do_strip); void ui_but_clipboard_free(void); bool ui_but_rna_equals(const uiBut *a, const uiBut *b); bool ui_but_rna_equals_ex(const uiBut *but, @@ -1272,8 +1269,8 @@ void uiStyleInit(void); /* interface_icons.c */ -void ui_icon_ensure_deferred(const struct bContext *C, const int icon_id, const bool big); -int ui_id_icon_get(const struct bContext *C, struct ID *id, const bool big); +void ui_icon_ensure_deferred(const struct bContext *C, int icon_id, bool big); +int ui_id_icon_get(const struct bContext *C, struct ID *id, bool big); /* interface_icons_event.c */ @@ -1365,7 +1362,7 @@ bool ui_but_is_toggle(const uiBut *but) ATTR_WARN_UNUSED_RESULT; * \note ctrl is kind of a hack currently, * so that non-embossed UI_BTYPE_TEXT button behaves as a label when ctrl is not pressed. */ -bool ui_but_is_interactive(const uiBut *but, const bool labeledit) ATTR_WARN_UNUSED_RESULT; +bool ui_but_is_interactive(const uiBut *but, bool labeledit) ATTR_WARN_UNUSED_RESULT; bool ui_but_is_popover_once_compat(const uiBut *but) ATTR_WARN_UNUSED_RESULT; bool ui_but_has_array_value(const uiBut *but) ATTR_WARN_UNUSED_RESULT; int ui_but_icon(const uiBut *but); @@ -1388,7 +1385,7 @@ uiBut *ui_list_find_from_row(const struct ARegion *region, uiBut *ui_list_row_find_mouse_over(const struct ARegion *region, const int xy[2]) ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT; uiBut *ui_list_row_find_from_index(const struct ARegion *region, - const int index, + int index, uiBut *listbox) ATTR_WARN_UNUSED_RESULT; uiBut *ui_tree_row_find_mouse_over(const struct ARegion *region, const int xy[2]) ATTR_NONNULL(1, 2); @@ -1400,7 +1397,7 @@ typedef bool (*uiButFindPollFn)(const uiBut *but, const void *customdata); */ uiBut *ui_but_find_mouse_over_ex(const struct ARegion *region, const int xy[2], - const bool labeledit, + bool labeledit, const uiButFindPollFn find_poll, const void *find_custom_data) ATTR_NONNULL(1, 2) ATTR_WARN_UNUSED_RESULT; @@ -1512,11 +1509,8 @@ typedef struct uiRNACollectionSearch { /* Block has to be stored for freeing butstore (uiBut.block doesn't work with undo). */ uiBlock *butstore_block; } uiRNACollectionSearch; -void ui_rna_collection_search_update_fn(const struct bContext *C, - void *arg, - const char *str, - uiSearchItems *items, - const bool is_first); +void ui_rna_collection_search_update_fn( + const struct bContext *C, void *arg, const char *str, uiSearchItems *items, bool is_first); /* interface_ops.c */ @@ -1534,6 +1528,9 @@ uiTreeViewHandle *ui_block_view_find_matching_in_old_block(const uiBlock *new_bl uiButTreeRow *ui_block_view_find_treerow_in_old_block(const uiBlock *new_block, const uiTreeViewItemHandle *new_item_handle); +/* interface_templates.c */ +struct uiListType *UI_UL_cache_file_layers(void); + #ifdef __cplusplus } #endif diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index cbdb284c66b..98fcb36b778 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -5661,6 +5661,11 @@ void UI_block_layout_resolve(uiBlock *block, int *r_x, int *r_y) } } +bool UI_block_layout_needs_resolving(const uiBlock *block) +{ + return !BLI_listbase_is_empty(&block->layouts); +} + void uiLayoutSetContextPointer(uiLayout *layout, const char *name, PointerRNA *ptr) { uiBlock *block = layout->root->block; diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 0000c850a10..f7424066ad8 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -26,7 +26,8 @@ #include "MEM_guardedalloc.h" #include "DNA_armature_types.h" -#include "DNA_object_types.h" /* for OB_DATA_SUPPORT_ID */ +#include "DNA_modifier_types.h" /* for handling geometry nodes properties */ +#include "DNA_object_types.h" /* for OB_DATA_SUPPORT_ID */ #include "DNA_screen_types.h" #include "DNA_text_types.h" @@ -985,6 +986,97 @@ bool UI_context_copy_to_selected_list(bContext *C, return true; } +bool UI_context_copy_to_selected_check(PointerRNA *ptr, + PointerRNA *ptr_link, + PropertyRNA *prop, + const char *path, + bool use_path_from_id, + PointerRNA *r_ptr, + PropertyRNA **r_prop) +{ + PointerRNA idptr; + PropertyRNA *lprop; + PointerRNA lptr; + + if (ptr_link->data == ptr->data) { + return false; + } + + if (use_path_from_id) { + /* Path relative to ID. */ + lprop = NULL; + RNA_id_pointer_create(ptr_link->owner_id, &idptr); + RNA_path_resolve_property(&idptr, path, &lptr, &lprop); + } + else if (path) { + /* Path relative to elements from list. */ + lprop = NULL; + RNA_path_resolve_property(ptr_link, path, &lptr, &lprop); + } + else { + lptr = *ptr_link; + lprop = prop; + } + + if (lptr.data == ptr->data) { + /* temp_ptr might not be the same as ptr_link! */ + return false; + } + + /* Skip non-existing properties on link. This was previously covered with the `lprop != prop` + * check but we are now more permissive when it comes to ID properties, see below. */ + if (lprop == NULL) { + return false; + } + + if (RNA_property_type(lprop) != RNA_property_type(prop)) { + return false; + } + + /* Check property pointers matching. + * For ID properties, these pointers match: + * - If the property is API defined on an existing class (and they are equally named). + * - Never for ID properties on specific ID (even if they are equally named). + * - Never for NodesModifierSettings properties (even if they are equally named). + * + * Be permissive on ID properties in the following cases: + * - #NodesModifierSettings properties + * - (special check: only if the node-group matches, since the 'Input_n' properties are name + * based and similar on potentially very different node-groups). + * - ID properties on specific ID + * - (no special check, copying seems OK [even if type does not match -- does not do anything + * then]) + */ + bool ignore_prop_eq = RNA_property_is_idprop(lprop) && RNA_property_is_idprop(prop); + if (RNA_struct_is_a(lptr.type, &RNA_NodesModifier) && + RNA_struct_is_a(ptr->type, &RNA_NodesModifier)) { + ignore_prop_eq = false; + + NodesModifierData *nmd_link = (NodesModifierData *)lptr.data; + NodesModifierData *nmd_src = (NodesModifierData *)ptr->data; + if (nmd_link->node_group == nmd_src->node_group) { + ignore_prop_eq = true; + } + } + + if ((lprop != prop) && !ignore_prop_eq) { + return false; + } + + if (!RNA_property_editable(&lptr, lprop)) { + return false; + } + + if (r_ptr) { + *r_ptr = lptr; + } + if (r_prop) { + *r_prop = lprop; + } + + return true; +} + /** * Called from both exec & poll. * @@ -995,7 +1087,7 @@ bool UI_context_copy_to_selected_list(bContext *C, static bool copy_to_selected_button(bContext *C, bool all, bool poll) { Main *bmain = CTX_data_main(C); - PointerRNA ptr, lptr, idptr; + PointerRNA ptr, lptr; PropertyRNA *prop, *lprop; bool success = false; int index; @@ -1025,32 +1117,8 @@ static bool copy_to_selected_button(bContext *C, bool all, bool poll) continue; } - if (use_path_from_id) { - /* Path relative to ID. */ - lprop = NULL; - RNA_id_pointer_create(link->ptr.owner_id, &idptr); - RNA_path_resolve_property(&idptr, path, &lptr, &lprop); - } - else if (path) { - /* Path relative to elements from list. */ - lprop = NULL; - RNA_path_resolve_property(&link->ptr, path, &lptr, &lprop); - } - else { - lptr = link->ptr; - lprop = prop; - } - - if (lptr.data == ptr.data) { - /* lptr might not be the same as link->ptr! */ - continue; - } - - if (lprop != prop) { - continue; - } - - if (!RNA_property_editable(&lptr, lprop)) { + if (!UI_context_copy_to_selected_check( + &ptr, &link->ptr, prop, path, use_path_from_id, &lptr, &lprop)) { continue; } @@ -1685,9 +1753,7 @@ static int ui_button_press_invoke(bContext *C, wmOperator *op, const wmEvent *ev bScreen *screen = CTX_wm_screen(C); const bool skip_depressed = RNA_boolean_get(op->ptr, "skip_depressed"); ARegion *region_prev = CTX_wm_region(C); - ARegion *region = screen ? BKE_screen_find_region_xy( - screen, RGN_TYPE_ANY, event->xy[0], event->xy[1]) : - NULL; + ARegion *region = screen ? BKE_screen_find_region_xy(screen, RGN_TYPE_ANY, event->xy) : NULL; if (region == NULL) { region = region_prev; diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c index bc1d3387ad7..135cef5fe53 100644 --- a/source/blender/editors/interface/interface_panel.c +++ b/source/blender/editors/interface/interface_panel.c @@ -1146,6 +1146,7 @@ static void panel_draw_aligned_widgets(const uiStyle *style, UI_fontstyle_draw(fontstyle, &title_rect, panel->drawname, + sizeof(panel->drawname), title_color, &(struct uiFontStyleDraw_Params){ .align = UI_STYLE_TEXT_LEFT, diff --git a/source/blender/editors/interface/interface_region_search.cc b/source/blender/editors/interface/interface_region_search.cc index f4c99fb3c16..e27dd2a7981 100644 --- a/source/blender/editors/interface/interface_region_search.cc +++ b/source/blender/editors/interface/interface_region_search.cc @@ -725,7 +725,7 @@ static ARegion *ui_searchbox_create_generic_ex(bContext *C, region->type = &type; /* create searchbox data */ - uiSearchboxData *data = (uiSearchboxData *)MEM_callocN(sizeof(uiSearchboxData), __func__); + uiSearchboxData *data = MEM_cnew<uiSearchboxData>(__func__); /* set font, get bb */ data->fstyle = style->widget; /* copy struct */ @@ -1021,7 +1021,7 @@ void ui_but_search_refresh(uiButSearch *search_but) return; } - uiSearchItems *items = (uiSearchItems *)MEM_callocN(sizeof(uiSearchItems), __func__); + uiSearchItems *items = MEM_cnew<uiSearchItems>(__func__); /* setup search struct */ items->maxitem = 10; diff --git a/source/blender/editors/interface/interface_region_tooltip.c b/source/blender/editors/interface/interface_region_tooltip.c index e146443faaa..fe58a6a05ae 100644 --- a/source/blender/editors/interface/interface_region_tooltip.c +++ b/source/blender/editors/interface/interface_region_tooltip.c @@ -74,6 +74,8 @@ #define UI_TIP_PADDING (int)(UI_TIP_PAD_FAC * UI_UNIT_Y) #define UI_TIP_MAXWIDTH 600 +#define UI_TIP_STR_MAX 1024 + typedef struct uiTooltipFormat { enum { UI_TIP_STYLE_NORMAL = 0, @@ -214,7 +216,7 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *region /* draw header and active data (is done here to be able to change color) */ rgb_float_to_uchar(drawcol, tip_colors[UI_TIP_LC_MAIN]); UI_fontstyle_set(&data->fstyle); - UI_fontstyle_draw(&data->fstyle, &bbox, field->text, drawcol, &fs_params); + UI_fontstyle_draw(&data->fstyle, &bbox, field->text, UI_TIP_STR_MAX, drawcol, &fs_params); /* offset to the end of the last line */ if (field->text_suffix) { @@ -224,7 +226,8 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *region bbox.ymax -= yofs; rgb_float_to_uchar(drawcol, tip_colors[UI_TIP_LC_ACTIVE]); - UI_fontstyle_draw(&data->fstyle, &bbox, field->text_suffix, drawcol, &fs_params); + UI_fontstyle_draw( + &data->fstyle, &bbox, field->text_suffix, UI_TIP_STR_MAX, drawcol, &fs_params); /* undo offset */ bbox.xmin -= xofs; @@ -243,7 +246,7 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *region /* XXX, needed because we don't have mono in 'U.uifonts' */ BLF_size(fstyle_mono.uifont_id, fstyle_mono.points * U.pixelsize, U.dpi); rgb_float_to_uchar(drawcol, tip_colors[field->format.color_id]); - UI_fontstyle_draw(&fstyle_mono, &bbox, field->text, drawcol, &fs_params); + UI_fontstyle_draw(&fstyle_mono, &bbox, field->text, UI_TIP_STR_MAX, drawcol, &fs_params); } else { BLI_assert(field->format.style == UI_TIP_STYLE_NORMAL); @@ -255,7 +258,7 @@ static void ui_tooltip_region_draw_cb(const bContext *UNUSED(C), ARegion *region /* draw remaining data */ rgb_float_to_uchar(drawcol, tip_colors[field->format.color_id]); UI_fontstyle_set(&data->fstyle); - UI_fontstyle_draw(&data->fstyle, &bbox, field->text, drawcol, &fs_params); + UI_fontstyle_draw(&data->fstyle, &bbox, field->text, UI_TIP_STR_MAX, drawcol, &fs_params); } bbox.ymax -= data->lineh * field->geom.lines; @@ -1215,12 +1218,12 @@ static ARegion *ui_tooltip_create_with_data(bContext *C, BLI_assert(ELEM(field->format.style, UI_TIP_STYLE_NORMAL, UI_TIP_STYLE_HEADER)); font_id = data->fstyle.uifont_id; } - w = BLF_width_ex(font_id, field->text, BLF_DRAW_STR_DUMMY_MAX, &info); + w = BLF_width_ex(font_id, field->text, UI_TIP_STR_MAX, &info); /* check for suffix (enum label) */ if (field->text_suffix && field->text_suffix[0]) { x_pos = info.width; - w = max_ii(w, x_pos + BLF_width(font_id, field->text_suffix, BLF_DRAW_STR_DUMMY_MAX)); + w = max_ii(w, x_pos + BLF_width(font_id, field->text_suffix, UI_TIP_STR_MAX)); } fontw = max_ii(fontw, w); diff --git a/source/blender/editors/interface/interface_style.c b/source/blender/editors/interface/interface_style.c index 643fa128d08..44942d508ca 100644 --- a/source/blender/editors/interface/interface_style.c +++ b/source/blender/editors/interface/interface_style.c @@ -140,9 +140,9 @@ static uiFont *uifont_to_blfont(int id) void UI_fontstyle_draw_ex(const uiFontStyle *fs, const rcti *rect, const char *str, + const size_t str_len, const uchar col[4], const struct uiFontStyleDraw_Params *fs_params, - size_t len, int *r_xofs, int *r_yofs, struct ResultBLF *r_info) @@ -173,20 +173,20 @@ void UI_fontstyle_draw_ex(const uiFontStyle *fs, BLF_enable(fs->uifont_id, font_flag); if (fs_params->word_wrap == 1) { - /* draw from boundbox top */ + /* Draw from bound-box top. */ yofs = BLI_rcti_size_y(rect) - BLF_height_max(fs->uifont_id); } else { - /* draw from boundbox center */ + /* Draw from bound-box center. */ const float height = BLF_ascender(fs->uifont_id) + BLF_descender(fs->uifont_id); yofs = ceil(0.5f * (BLI_rcti_size_y(rect) - height)); } if (fs_params->align == UI_STYLE_TEXT_CENTER) { - xofs = floor(0.5f * (BLI_rcti_size_x(rect) - BLF_width(fs->uifont_id, str, len))); + xofs = floor(0.5f * (BLI_rcti_size_x(rect) - BLF_width(fs->uifont_id, str, str_len))); } else if (fs_params->align == UI_STYLE_TEXT_RIGHT) { - xofs = BLI_rcti_size_x(rect) - BLF_width(fs->uifont_id, str, len); + xofs = BLI_rcti_size_x(rect) - BLF_width(fs->uifont_id, str, str_len); } yofs = MAX2(0, yofs); @@ -196,7 +196,7 @@ void UI_fontstyle_draw_ex(const uiFontStyle *fs, BLF_position(fs->uifont_id, rect->xmin + xofs, rect->ymin + yofs, 0.0f); BLF_color4ubv(fs->uifont_id, col); - BLF_draw_ex(fs->uifont_id, str, len, r_info); + BLF_draw_ex(fs->uifont_id, str, str_len, r_info); BLF_disable(fs->uifont_id, font_flag); @@ -211,12 +211,11 @@ void UI_fontstyle_draw_ex(const uiFontStyle *fs, void UI_fontstyle_draw(const uiFontStyle *fs, const rcti *rect, const char *str, + const size_t str_len, const uchar col[4], const struct uiFontStyleDraw_Params *fs_params) { - int xofs, yofs; - - UI_fontstyle_draw_ex(fs, rect, str, col, fs_params, BLF_DRAW_STR_DUMMY_MAX, &xofs, &yofs, NULL); + UI_fontstyle_draw_ex(fs, rect, str, str_len, col, fs_params, NULL, NULL, NULL); } void UI_fontstyle_draw_rotated(const uiFontStyle *fs, @@ -427,11 +426,11 @@ void uiStyleInit(void) } if (U.font_path_ui[0]) { - BLI_strncpy(font_first->filename, U.font_path_ui, sizeof(font_first->filename)); + BLI_strncpy(font_first->filepath, U.font_path_ui, sizeof(font_first->filepath)); font_first->uifont_id = UIFONT_CUSTOM1; } else { - BLI_strncpy(font_first->filename, "default", sizeof(font_first->filename)); + BLI_strncpy(font_first->filepath, "default", sizeof(font_first->filepath)); font_first->uifont_id = UIFONT_DEFAULT; } @@ -442,7 +441,7 @@ void uiStyleInit(void) font->blf_id = BLF_load_default(unique); } else { - font->blf_id = BLF_load(font->filename); + font->blf_id = BLF_load(font->filepath); if (font->blf_id == -1) { font->blf_id = BLF_load_default(unique); } diff --git a/source/blender/editors/interface/interface_template_list.cc b/source/blender/editors/interface/interface_template_list.cc index 13e539b5095..817599605a9 100644 --- a/source/blender/editors/interface/interface_template_list.cc +++ b/source/blender/editors/interface/interface_template_list.cc @@ -1322,6 +1322,7 @@ PointerRNA *UI_list_custom_drag_operator_set(uiList *ui_list, void ED_uilisttypes_ui() { WM_uilisttype_add(UI_UL_asset_view()); + WM_uilisttype_add(UI_UL_cache_file_layers()); } /** \} */ diff --git a/source/blender/editors/interface/interface_template_search_menu.cc b/source/blender/editors/interface/interface_template_search_menu.cc index 7a079e01e61..0ce3a0d8af1 100644 --- a/source/blender/editors/interface/interface_template_search_menu.cc +++ b/source/blender/editors/interface/interface_template_search_menu.cc @@ -465,6 +465,9 @@ static MenuSearch_Data *menu_items_from_ui_create( const char *idname_array[] = { /* While we could include this, it's just showing filenames to load. */ "TOPBAR_MT_file_open_recent", + /* Showing undo history is not helpful since users may accidentally undo + * an action they intend to run. */ + "TOPBAR_MT_undo_history", }; for (int i = 0; i < ARRAY_SIZE(idname_array); i++) { MenuType *mt = WM_menutype_find(idname_array[i], false); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index b8026cbb40c..8330f8c0db7 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -2672,7 +2672,7 @@ static void constraint_ops_extra_draw(bContext *C, uiLayout *layout, void *con_v static void draw_constraint_header(uiLayout *layout, Object *ob, bConstraint *con) { - bPoseChannel *pchan = BKE_pose_channel_active(ob); + bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob); short proxy_protected, xco = 0, yco = 0; // int rb_col; // UNUSED @@ -6395,21 +6395,154 @@ void uiTemplateNodeSocket(uiLayout *layout, bContext *UNUSED(C), float color[4]) /** \name Cache File Template * \{ */ -void uiTemplateCacheFile(uiLayout *layout, - const bContext *C, - PointerRNA *ptr, - const char *propname) +void uiTemplateCacheFileVelocity(uiLayout *layout, PointerRNA *fileptr) { - if (!ptr->data) { - return; + /* Ensure that the context has a CacheFile as this may not be set inside of modifiers panels. */ + uiLayoutSetContextPointer(layout, "edit_cachefile", fileptr); + + uiItemR(layout, fileptr, "velocity_name", 0, NULL, ICON_NONE); + uiItemR(layout, fileptr, "velocity_unit", 0, NULL, ICON_NONE); +} + +void uiTemplateCacheFileProcedural(uiLayout *layout, const bContext *C, PointerRNA *fileptr) +{ + /* Ensure that the context has a CacheFile as this may not be set inside of modifiers panels. */ + uiLayoutSetContextPointer(layout, "edit_cachefile", fileptr); + + uiLayout *row, *sub; + + /* Only enable render procedural option if the active engine supports it. */ + const struct RenderEngineType *engine_type = CTX_data_engine_type(C); + + Scene *scene = CTX_data_scene(C); + const bool engine_supports_procedural = RE_engine_supports_alembic_procedural(engine_type, + scene); + + if (!engine_supports_procedural) { + row = uiLayoutRow(layout, false); + /* For Cycles, verify that experimental features are enabled. */ + if (BKE_scene_uses_cycles(scene) && !BKE_scene_uses_cycles_experimental_features(scene)) { + uiItemL( + row, + TIP_( + "The Cycles Alembic Procedural is only available with the experimental feature set"), + ICON_INFO); + } + else { + uiItemL( + row, TIP_("The active render engine does not have an Alembic Procedural"), ICON_INFO); + } + } + + row = uiLayoutRow(layout, false); + uiLayoutSetActive(row, engine_supports_procedural); + uiItemR(row, fileptr, "use_render_procedural", 0, NULL, ICON_NONE); + + const bool use_render_procedural = RNA_boolean_get(fileptr, "use_render_procedural"); + const bool use_prefetch = RNA_boolean_get(fileptr, "use_prefetch"); + + row = uiLayoutRow(layout, false); + uiLayoutSetEnabled(row, use_render_procedural); + uiItemR(row, fileptr, "use_prefetch", 0, NULL, ICON_NONE); + + sub = uiLayoutRow(layout, false); + uiLayoutSetEnabled(sub, use_prefetch && use_render_procedural); + uiItemR(sub, fileptr, "prefetch_cache_size", 0, NULL, ICON_NONE); +} + +void uiTemplateCacheFileTimeSettings(uiLayout *layout, PointerRNA *fileptr) +{ + /* Ensure that the context has a CacheFile as this may not be set inside of modifiers panels. */ + uiLayoutSetContextPointer(layout, "edit_cachefile", fileptr); + + uiLayout *row, *sub, *subsub; + + row = uiLayoutRow(layout, false); + uiItemR(row, fileptr, "is_sequence", 0, NULL, ICON_NONE); + + row = uiLayoutRowWithHeading(layout, true, IFACE_("Override Frame")); + sub = uiLayoutRow(row, true); + uiLayoutSetPropDecorate(sub, false); + uiItemR(sub, fileptr, "override_frame", 0, "", ICON_NONE); + subsub = uiLayoutRow(sub, true); + uiLayoutSetActive(subsub, RNA_boolean_get(fileptr, "override_frame")); + uiItemR(subsub, fileptr, "frame", 0, "", ICON_NONE); + uiItemDecoratorR(row, fileptr, "frame", 0); + + row = uiLayoutRow(layout, false); + uiItemR(row, fileptr, "frame_offset", 0, NULL, ICON_NONE); + uiLayoutSetActive(row, !RNA_boolean_get(fileptr, "is_sequence")); +} + +static void cache_file_layer_item(uiList *UNUSED(ui_list), + bContext *UNUSED(C), + uiLayout *layout, + PointerRNA *UNUSED(dataptr), + PointerRNA *itemptr, + int UNUSED(icon), + PointerRNA *UNUSED(active_dataptr), + const char *UNUSED(active_propname), + int UNUSED(index), + int UNUSED(flt_flag)) +{ + uiLayout *row = uiLayoutRow(layout, true); + uiItemR(row, itemptr, "hide_layer", UI_ITEM_R_NO_BG, "", ICON_NONE); + uiItemR(row, itemptr, "filepath", UI_ITEM_R_NO_BG, "", ICON_NONE); +} + +uiListType *UI_UL_cache_file_layers() +{ + uiListType *list_type = (uiListType *)MEM_callocN(sizeof(*list_type), __func__); + + BLI_strncpy(list_type->idname, "UI_UL_cache_file_layers", sizeof(list_type->idname)); + list_type->draw_item = cache_file_layer_item; + + return list_type; +} + +void uiTemplateCacheFileLayers(uiLayout *layout, const bContext *C, PointerRNA *fileptr) +{ + /* Ensure that the context has a CacheFile as this may not be set inside of modifiers panels. */ + uiLayoutSetContextPointer(layout, "edit_cachefile", fileptr); + + uiLayout *row = uiLayoutRow(layout, false); + uiLayout *col = uiLayoutColumn(row, true); + + uiTemplateList(col, + (bContext *)C, + "UI_UL_cache_file_layers", + "cache_file_layers", + fileptr, + "layers", + fileptr, + "active_index", + "", + 1, + 5, + UILST_LAYOUT_DEFAULT, + 1, + UI_TEMPLATE_LIST_FLAG_NONE); + + col = uiLayoutColumn(row, true); + uiItemO(col, "", ICON_ADD, "cachefile.layer_add"); + uiItemO(col, "", ICON_REMOVE, "cachefile.layer_remove"); + + CacheFile *file = fileptr->data; + if (BLI_listbase_count(&file->layers) > 1) { + uiItemS_ex(col, 1.0f); + uiItemO(col, "", ICON_TRIA_UP, "cachefile.layer_move"); + uiItemO(col, "", ICON_TRIA_DOWN, "cachefile.layer_move"); } +} +bool uiTemplateCacheFilePointer(PointerRNA *ptr, const char *propname, PointerRNA *r_file_ptr) +{ PropertyRNA *prop = RNA_struct_find_property(ptr, propname); if (!prop) { printf( "%s: property not found: %s.%s\n", __func__, RNA_struct_identifier(ptr->type), propname); - return; + return false; } if (RNA_property_type(prop) != PROP_POINTER) { @@ -6417,10 +6550,27 @@ void uiTemplateCacheFile(uiLayout *layout, __func__, RNA_struct_identifier(ptr->type), propname); + return false; + } + + *r_file_ptr = RNA_property_pointer_get(ptr, prop); + return true; +} + +void uiTemplateCacheFile(uiLayout *layout, + const bContext *C, + PointerRNA *ptr, + const char *propname) +{ + if (!ptr->data) { + return; + } + + PointerRNA fileptr; + if (!uiTemplateCacheFilePointer(ptr, propname, &fileptr)) { return; } - PointerRNA fileptr = RNA_property_pointer_get(ptr, prop); CacheFile *file = fileptr.data; uiLayoutSetContextPointer(layout, "edit_cachefile", &fileptr); @@ -6442,7 +6592,7 @@ void uiTemplateCacheFile(uiLayout *layout, SpaceProperties *sbuts = CTX_wm_space_properties(C); - uiLayout *row, *sub, *subsub; + uiLayout *row, *sub; uiLayoutSetPropSep(layout, true); @@ -6451,68 +6601,11 @@ void uiTemplateCacheFile(uiLayout *layout, sub = uiLayoutRow(row, true); uiItemO(sub, "", ICON_FILE_REFRESH, "cachefile.reload"); - row = uiLayoutRow(layout, false); - uiItemR(row, &fileptr, "is_sequence", 0, NULL, ICON_NONE); - - /* Only enable render procedural option if the active engine supports it. */ - const struct RenderEngineType *engine_type = CTX_data_engine_type(C); - - Scene *scene = CTX_data_scene(C); - const bool engine_supports_procedural = RE_engine_supports_alembic_procedural(engine_type, - scene); - - if (!engine_supports_procedural) { - row = uiLayoutRow(layout, false); - /* For Cycles, verify that experimental features are enabled. */ - if (BKE_scene_uses_cycles(scene) && !BKE_scene_uses_cycles_experimental_features(scene)) { - uiItemL( - row, - TIP_( - "The Cycles Alembic Procedural is only available with the experimental feature set"), - ICON_INFO); - } - else { - uiItemL( - row, TIP_("The active render engine does not have an Alembic Procedural"), ICON_INFO); - } - } - - row = uiLayoutRow(layout, false); - uiLayoutSetActive(row, engine_supports_procedural); - uiItemR(row, &fileptr, "use_render_procedural", 0, NULL, ICON_NONE); - - const bool use_render_procedural = RNA_boolean_get(&fileptr, "use_render_procedural"); - const bool use_prefetch = RNA_boolean_get(&fileptr, "use_prefetch"); - - row = uiLayoutRow(layout, false); - uiLayoutSetEnabled(row, use_render_procedural); - uiItemR(row, &fileptr, "use_prefetch", 0, NULL, ICON_NONE); - - sub = uiLayoutRow(layout, false); - uiLayoutSetEnabled(sub, use_prefetch && use_render_procedural); - uiItemR(sub, &fileptr, "prefetch_cache_size", 0, NULL, ICON_NONE); - - row = uiLayoutRowWithHeading(layout, true, IFACE_("Override Frame")); - sub = uiLayoutRow(row, true); - uiLayoutSetPropDecorate(sub, false); - uiItemR(sub, &fileptr, "override_frame", 0, "", ICON_NONE); - subsub = uiLayoutRow(sub, true); - uiLayoutSetActive(subsub, RNA_boolean_get(&fileptr, "override_frame")); - uiItemR(subsub, &fileptr, "frame", 0, "", ICON_NONE); - uiItemDecoratorR(row, &fileptr, "frame", 0); - - row = uiLayoutRow(layout, false); - uiItemR(row, &fileptr, "frame_offset", 0, NULL, ICON_NONE); - uiLayoutSetActive(row, !RNA_boolean_get(&fileptr, "is_sequence")); - if (sbuts->mainb == BCONTEXT_CONSTRAINT) { row = uiLayoutRow(layout, false); uiItemR(row, &fileptr, "scale", 0, IFACE_("Manual Scale"), ICON_NONE); } - uiItemR(layout, &fileptr, "velocity_name", 0, NULL, ICON_NONE); - uiItemR(layout, &fileptr, "velocity_unit", 0, NULL, ICON_NONE); - /* TODO: unused for now, so no need to expose. */ #if 0 row = uiLayoutRow(layout, false); diff --git a/source/blender/editors/interface/interface_view.cc b/source/blender/editors/interface/interface_view.cc index 500834f4434..81b24c75020 100644 --- a/source/blender/editors/interface/interface_view.cc +++ b/source/blender/editors/interface/interface_view.cc @@ -60,7 +60,7 @@ AbstractTreeView *UI_block_add_view(uiBlock &block, StringRef idname, std::unique_ptr<AbstractTreeView> tree_view) { - ViewLink *view_link = OBJECT_GUARDED_NEW(ViewLink); + ViewLink *view_link = MEM_new<ViewLink>(__func__); BLI_addtail(&block.views, view_link); view_link->view = std::move(tree_view); @@ -72,7 +72,7 @@ AbstractTreeView *UI_block_add_view(uiBlock &block, void ui_block_free_views(uiBlock *block) { LISTBASE_FOREACH_MUTABLE (ViewLink *, link, &block->views) { - OBJECT_GUARDED_DELETE(link, ViewLink); + MEM_delete(link); } } diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index ad8c0842657..b44496731f7 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -2130,11 +2130,11 @@ static void widget_draw_text(const uiFontStyle *fstyle, UI_fontstyle_draw_ex(fstyle, rect, drawstr + but->ofs, + drawlen, wcol->text, &(struct uiFontStyleDraw_Params){ .align = align, }, - drawlen, &font_xofs, &font_yofs, NULL); @@ -2194,6 +2194,7 @@ static void widget_draw_text(const uiFontStyle *fstyle, UI_fontstyle_draw(fstyle, rect, drawstr_right, + UI_MAX_DRAW_STR, col, &(struct uiFontStyleDraw_Params){ .align = UI_STYLE_TEXT_RIGHT, @@ -5417,11 +5418,11 @@ void ui_draw_menu_item(const uiFontStyle *fstyle, UI_fontstyle_draw_ex(fstyle, rect, drawstr, + sizeof(drawstr), wt->wcol.text, &(struct uiFontStyleDraw_Params){ .align = UI_STYLE_TEXT_LEFT, }, - BLF_DRAW_STR_DUMMY_MAX, &xofs, &yofs, &info); @@ -5468,6 +5469,7 @@ void ui_draw_menu_item(const uiFontStyle *fstyle, UI_fontstyle_draw(fstyle, rect, hint_drawstr, + sizeof(hint_drawstr), wt->wcol.text, &(struct uiFontStyleDraw_Params){ .align = UI_STYLE_TEXT_RIGHT, @@ -5523,6 +5525,7 @@ void ui_draw_preview_item_stateless(const uiFontStyle *fstyle, UI_fontstyle_draw(fstyle, &trect, drawstr, + sizeof(drawstr), text_col, &(struct uiFontStyleDraw_Params){ .align = text_align, diff --git a/source/blender/editors/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt index 44b5f85050f..cb1c3cedf8e 100644 --- a/source/blender/editors/io/CMakeLists.txt +++ b/source/blender/editors/io/CMakeLists.txt @@ -26,6 +26,7 @@ set(INC ../../io/collada ../../io/gpencil ../../io/usd + ../../io/wavefront_obj ../../makesdna ../../makesrna ../../windowmanager @@ -43,6 +44,7 @@ set(SRC io_gpencil_export.c io_gpencil_import.c io_gpencil_utils.c + io_obj.c io_ops.c io_usd.c @@ -50,6 +52,7 @@ set(SRC io_cache.h io_collada.h io_gpencil.h + io_obj.h io_ops.h io_usd.h ) @@ -57,6 +60,7 @@ set(SRC set(LIB bf_blenkernel bf_blenlib + bf_wavefront_obj ) if(WITH_OPENCOLLADA) diff --git a/source/blender/editors/io/io_cache.c b/source/blender/editors/io/io_cache.c index bf20c1f6438..4f71a804986 100644 --- a/source/blender/editors/io/io_cache.c +++ b/source/blender/editors/io/io_cache.c @@ -26,6 +26,7 @@ #include "DNA_cachefile_types.h" #include "DNA_space_types.h" +#include "BLI_listbase.h" #include "BLI_path_util.h" #include "BLI_string.h" @@ -36,6 +37,7 @@ #include "BKE_report.h" #include "RNA_access.h" +#include "RNA_define.h" #include "DEG_depsgraph.h" @@ -46,6 +48,12 @@ #include "io_cache.h" +static void reload_cachefile(bContext *C, CacheFile *cache_file) +{ + Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + BKE_cachefile_reload(depsgraph, cache_file); +} + static void cachefile_init(bContext *C, wmOperator *op) { PropertyPointerRNA *pprop; @@ -146,8 +154,7 @@ static int cachefile_reload_exec(bContext *C, wmOperator *UNUSED(op)) return OPERATOR_CANCELLED; } - Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - BKE_cachefile_reload(depsgraph, cache_file); + reload_cachefile(C, cache_file); return OPERATOR_FINISHED; } @@ -164,3 +171,160 @@ void CACHEFILE_OT_reload(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } + +/* ***************************** Add Layer Operator **************************** */ + +static int cachefile_layer_open_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + if (!RNA_struct_property_is_set(op->ptr, "filepath")) { + char filepath[FILE_MAX]; + Main *bmain = CTX_data_main(C); + + BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath)); + BLI_path_extension_replace(filepath, sizeof(filepath), ".abc"); + RNA_string_set(op->ptr, "filepath", filepath); + } + + /* There is no more CacheFile set when returning from the file selector, so store it here. */ + op->customdata = CTX_data_edit_cachefile(C); + + WM_event_add_fileselect(C, op); + + return OPERATOR_RUNNING_MODAL; + + UNUSED_VARS(event); +} + +static int cachefile_layer_add_exec(bContext *C, wmOperator *op) +{ + if (!RNA_struct_property_is_set(op->ptr, "filepath")) { + BKE_report(op->reports, RPT_ERROR, "No filename given"); + return OPERATOR_CANCELLED; + } + + CacheFile *cache_file = op->customdata; + + if (!cache_file) { + return OPERATOR_CANCELLED; + } + + char filename[FILE_MAX]; + RNA_string_get(op->ptr, "filepath", filename); + + CacheFileLayer *layer = BKE_cachefile_add_layer(cache_file, filename); + + if (!layer) { + WM_report(RPT_ERROR, "Could not add a layer to the cache file"); + return OPERATOR_CANCELLED; + } + + reload_cachefile(C, cache_file); + WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); + return OPERATOR_FINISHED; +} + +void CACHEFILE_OT_layer_add(wmOperatorType *ot) +{ + ot->name = "Add layer"; + ot->description = "Add an override layer to the archive"; + ot->idname = "CACHEFILE_OT_layer_add"; + + /* api callbacks */ + ot->invoke = cachefile_layer_open_invoke; + ot->exec = cachefile_layer_add_exec; + + WM_operator_properties_filesel(ot, + FILE_TYPE_ALEMBIC | FILE_TYPE_FOLDER, + FILE_BLENDER, + FILE_OPENFILE, + WM_FILESEL_FILEPATH | WM_FILESEL_RELPATH, + FILE_DEFAULTDISPLAY, + FILE_SORT_DEFAULT); +} + +/* ***************************** Remove Layer Operator **************************** */ + +static int cachefile_layer_remove_exec(bContext *C, wmOperator *UNUSED(op)) +{ + CacheFile *cache_file = CTX_data_edit_cachefile(C); + + if (!cache_file) { + return OPERATOR_CANCELLED; + } + + CacheFileLayer *layer = BKE_cachefile_get_active_layer(cache_file); + BKE_cachefile_remove_layer(cache_file, layer); + + reload_cachefile(C, cache_file); + WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); + return OPERATOR_FINISHED; +} + +void CACHEFILE_OT_layer_remove(wmOperatorType *ot) +{ + ot->name = "Add layer"; + ot->description = "Remove an override layer to the archive"; + ot->idname = "CACHEFILE_OT_layer_remove"; + + /* api callbacks */ + ot->exec = cachefile_layer_remove_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/* ***************************** Move Layer Operator **************************** */ + +static int cachefile_layer_move_exec(bContext *C, wmOperator *op) +{ + CacheFile *cache_file = CTX_data_edit_cachefile(C); + + if (!cache_file) { + return OPERATOR_CANCELLED; + } + + CacheFileLayer *layer = BKE_cachefile_get_active_layer(cache_file); + + if (!layer) { + return OPERATOR_CANCELLED; + } + + const int dir = RNA_enum_get(op->ptr, "direction"); + + if (BLI_listbase_link_move(&cache_file->layers, layer, dir)) { + cache_file->active_layer = BLI_findindex(&cache_file->layers, layer) + 1; + /* Only reload if something moved, might be expensive. */ + reload_cachefile(C, cache_file); + WM_main_add_notifier(NC_OBJECT | ND_DRAW, NULL); + } + + return OPERATOR_FINISHED; +} + +void CACHEFILE_OT_layer_move(wmOperatorType *ot) +{ + static const EnumPropertyItem layer_slot_move[] = { + {-1, "UP", 0, "Up", ""}, + {1, "DOWN", 0, "Down", ""}, + {0, NULL, 0, NULL, NULL}, + }; + + ot->name = "Move layer"; + ot->description = + "Move layer in the list, layers further down the list will overwrite data from the layers " + "higher up"; + ot->idname = "CACHEFILE_OT_layer_move"; + + /* api callbacks */ + ot->exec = cachefile_layer_move_exec; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_enum(ot->srna, + "direction", + layer_slot_move, + 0, + "Direction", + "Direction to move the active vertex group towards"); +} diff --git a/source/blender/editors/io/io_cache.h b/source/blender/editors/io/io_cache.h index be6e31842af..297e065434f 100644 --- a/source/blender/editors/io/io_cache.h +++ b/source/blender/editors/io/io_cache.h @@ -27,3 +27,7 @@ struct wmOperatorType; void CACHEFILE_OT_open(struct wmOperatorType *ot); void CACHEFILE_OT_reload(struct wmOperatorType *ot); + +void CACHEFILE_OT_layer_add(struct wmOperatorType *ot); +void CACHEFILE_OT_layer_remove(struct wmOperatorType *ot); +void CACHEFILE_OT_layer_move(struct wmOperatorType *ot); diff --git a/source/blender/editors/io/io_obj.c b/source/blender/editors/io/io_obj.c new file mode 100644 index 00000000000..2bc2a832d20 --- /dev/null +++ b/source/blender/editors/io/io_obj.c @@ -0,0 +1,369 @@ +/* + * 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 editor/io + */ + +#include "DNA_space_types.h" + +#include "BKE_context.h" +#include "BKE_main.h" +#include "BKE_report.h" + +#include "BLI_path_util.h" +#include "BLI_string.h" +#include "BLI_utildefines.h" + +#include "BLT_translation.h" + +#include "MEM_guardedalloc.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "WM_api.h" +#include "WM_types.h" + +#include "DEG_depsgraph.h" + +#include "IO_wavefront_obj.h" +#include "io_obj.h" + +static const EnumPropertyItem io_obj_transform_axis_forward[] = { + {OBJ_AXIS_X_FORWARD, "X_FORWARD", 0, "X", "Positive X axis"}, + {OBJ_AXIS_Y_FORWARD, "Y_FORWARD", 0, "Y", "Positive Y axis"}, + {OBJ_AXIS_Z_FORWARD, "Z_FORWARD", 0, "Z", "Positive Z axis"}, + {OBJ_AXIS_NEGATIVE_X_FORWARD, "NEGATIVE_X_FORWARD", 0, "-X", "Negative X axis"}, + {OBJ_AXIS_NEGATIVE_Y_FORWARD, "NEGATIVE_Y_FORWARD", 0, "-Y", "Negative Y axis"}, + {OBJ_AXIS_NEGATIVE_Z_FORWARD, "NEGATIVE_Z_FORWARD", 0, "-Z (Default)", "Negative Z axis"}, + {0, NULL, 0, NULL, NULL}}; + +static const EnumPropertyItem io_obj_transform_axis_up[] = { + {OBJ_AXIS_X_UP, "X_UP", 0, "X", "Positive X axis"}, + {OBJ_AXIS_Y_UP, "Y_UP", 0, "Y (Default)", "Positive Y axis"}, + {OBJ_AXIS_Z_UP, "Z_UP", 0, "Z", "Positive Z axis"}, + {OBJ_AXIS_NEGATIVE_X_UP, "NEGATIVE_X_UP", 0, "-X", "Negative X axis"}, + {OBJ_AXIS_NEGATIVE_Y_UP, "NEGATIVE_Y_UP", 0, "-Y", "Negative Y axis"}, + {OBJ_AXIS_NEGATIVE_Z_UP, "NEGATIVE_Z_UP", 0, "-Z", "Negative Z axis"}, + {0, NULL, 0, NULL, NULL}}; + +static const EnumPropertyItem io_obj_export_evaluation_mode[] = { + {DAG_EVAL_RENDER, "DAG_EVAL_RENDER", 0, "Render", "Export objects as they appear in render"}, + {DAG_EVAL_VIEWPORT, + "DAG_EVAL_VIEWPORT", + 0, + "Viewport (Default)", + "Export objects as they appear in the viewport"}, + {0, NULL, 0, NULL, NULL}}; + +static int wm_obj_export_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + if (!RNA_struct_property_is_set(op->ptr, "filepath")) { + Main *bmain = CTX_data_main(C); + char filepath[FILE_MAX]; + + if (BKE_main_blendfile_path(bmain)[0] == '\0') { + BLI_strncpy(filepath, "untitled", sizeof(filepath)); + } + else { + BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath)); + } + + BLI_path_extension_replace(filepath, sizeof(filepath), ".obj"); + RNA_string_set(op->ptr, "filepath", filepath); + } + + WM_event_add_fileselect(C, op); + return OPERATOR_RUNNING_MODAL; +} + +static int wm_obj_export_exec(bContext *C, wmOperator *op) +{ + if (!RNA_struct_property_is_set(op->ptr, "filepath")) { + BKE_report(op->reports, RPT_ERROR, "No filename given"); + return OPERATOR_CANCELLED; + } + struct OBJExportParams export_params; + RNA_string_get(op->ptr, "filepath", export_params.filepath); + export_params.blen_filepath = CTX_data_main(C)->filepath; + export_params.export_animation = RNA_boolean_get(op->ptr, "export_animation"); + export_params.start_frame = RNA_int_get(op->ptr, "start_frame"); + export_params.end_frame = RNA_int_get(op->ptr, "end_frame"); + + export_params.forward_axis = RNA_enum_get(op->ptr, "forward_axis"); + export_params.up_axis = RNA_enum_get(op->ptr, "up_axis"); + export_params.scaling_factor = RNA_float_get(op->ptr, "scaling_factor"); + export_params.export_eval_mode = RNA_enum_get(op->ptr, "export_eval_mode"); + + export_params.export_selected_objects = RNA_boolean_get(op->ptr, "export_selected_objects"); + export_params.export_uv = RNA_boolean_get(op->ptr, "export_uv"); + export_params.export_normals = RNA_boolean_get(op->ptr, "export_normals"); + export_params.export_materials = RNA_boolean_get(op->ptr, "export_materials"); + export_params.export_triangulated_mesh = RNA_boolean_get(op->ptr, "export_triangulated_mesh"); + export_params.export_curves_as_nurbs = RNA_boolean_get(op->ptr, "export_curves_as_nurbs"); + + export_params.export_object_groups = RNA_boolean_get(op->ptr, "export_object_groups"); + export_params.export_material_groups = RNA_boolean_get(op->ptr, "export_material_groups"); + export_params.export_vertex_groups = RNA_boolean_get(op->ptr, "export_vertex_groups"); + export_params.export_smooth_groups = RNA_boolean_get(op->ptr, "export_smooth_groups"); + export_params.smooth_groups_bitflags = RNA_boolean_get(op->ptr, "smooth_group_bitflags"); + + OBJ_export(C, &export_params); + + return OPERATOR_FINISHED; +} + +static void ui_obj_export_settings(uiLayout *layout, PointerRNA *imfptr) +{ + + const bool export_animation = RNA_boolean_get(imfptr, "export_animation"); + const bool export_smooth_groups = RNA_boolean_get(imfptr, "export_smooth_groups"); + + uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); + + /* Animation options. */ + uiLayout *box = uiLayoutBox(layout); + uiItemL(box, IFACE_("Animation"), ICON_ANIM); + uiLayout *col = uiLayoutColumn(box, false); + uiLayout *sub = uiLayoutColumn(col, false); + uiItemR(sub, imfptr, "export_animation", 0, NULL, ICON_NONE); + sub = uiLayoutColumn(sub, true); + uiItemR(sub, imfptr, "start_frame", 0, IFACE_("Frame Start"), ICON_NONE); + uiItemR(sub, imfptr, "end_frame", 0, IFACE_("End"), ICON_NONE); + uiLayoutSetEnabled(sub, export_animation); + + /* Object Transform options. */ + box = uiLayoutBox(layout); + uiItemL(box, IFACE_("Object Properties"), ICON_OBJECT_DATA); + col = uiLayoutColumn(box, false); + sub = uiLayoutColumn(col, false); + uiItemR(sub, imfptr, "forward_axis", 0, IFACE_("Axis Forward"), ICON_NONE); + uiItemR(sub, imfptr, "up_axis", 0, IFACE_("Up"), ICON_NONE); + sub = uiLayoutColumn(col, false); + uiItemR(sub, imfptr, "scaling_factor", 0, NULL, ICON_NONE); + sub = uiLayoutColumnWithHeading(col, false, IFACE_("Objects")); + uiItemR(sub, imfptr, "export_selected_objects", 0, IFACE_("Selected Only"), ICON_NONE); + uiItemR(sub, imfptr, "export_eval_mode", 0, IFACE_("Properties"), ICON_NONE); + + /* Options for what to write. */ + box = uiLayoutBox(layout); + uiItemL(box, IFACE_("Geometry Export"), ICON_EXPORT); + col = uiLayoutColumn(box, false); + sub = uiLayoutColumnWithHeading(col, false, IFACE_("Export")); + uiItemR(sub, imfptr, "export_uv", 0, IFACE_("UV Coordinates"), ICON_NONE); + uiItemR(sub, imfptr, "export_normals", 0, IFACE_("Normals"), ICON_NONE); + uiItemR(sub, imfptr, "export_materials", 0, IFACE_("Materials"), ICON_NONE); + uiItemR(sub, imfptr, "export_triangulated_mesh", 0, IFACE_("Triangulated Mesh"), ICON_NONE); + uiItemR(sub, imfptr, "export_curves_as_nurbs", 0, IFACE_("Curves as NURBS"), ICON_NONE); + + box = uiLayoutBox(layout); + uiItemL(box, IFACE_("Grouping"), ICON_GROUP); + col = uiLayoutColumn(box, false); + sub = uiLayoutColumnWithHeading(col, false, IFACE_("Export")); + uiItemR(sub, imfptr, "export_object_groups", 0, IFACE_("Object Groups"), ICON_NONE); + uiItemR(sub, imfptr, "export_material_groups", 0, IFACE_("Material Groups"), ICON_NONE); + uiItemR(sub, imfptr, "export_vertex_groups", 0, IFACE_("Vertex Groups"), ICON_NONE); + uiItemR(sub, imfptr, "export_smooth_groups", 0, IFACE_("Smooth Groups"), ICON_NONE); + sub = uiLayoutColumn(sub, false); + uiLayoutSetEnabled(sub, export_smooth_groups); + uiItemR(sub, imfptr, "smooth_group_bitflags", 0, IFACE_("Smooth Group Bitflags"), ICON_NONE); +} + +static void wm_obj_export_draw(bContext *UNUSED(C), wmOperator *op) +{ + PointerRNA ptr; + RNA_pointer_create(NULL, op->type->srna, op->properties, &ptr); + ui_obj_export_settings(op->layout, &ptr); +} + +/** + * Return true if any property in the UI is changed. + */ +static bool wm_obj_export_check(bContext *C, wmOperator *op) +{ + char filepath[FILE_MAX]; + Scene *scene = CTX_data_scene(C); + bool changed = false; + RNA_string_get(op->ptr, "filepath", filepath); + + if (!BLI_path_extension_check(filepath, ".obj")) { + BLI_path_extension_ensure(filepath, FILE_MAX, ".obj"); + RNA_string_set(op->ptr, "filepath", filepath); + changed = true; + } + + { + int start = RNA_int_get(op->ptr, "start_frame"); + int end = RNA_int_get(op->ptr, "end_frame"); + /* Set the defaults. */ + if (start == INT_MIN) { + start = SFRA; + changed = true; + } + if (end == INT_MAX) { + end = EFRA; + changed = true; + } + /* Fix user errors. */ + if (end < start) { + end = start; + changed = true; + } + RNA_int_set(op->ptr, "start_frame", start); + RNA_int_set(op->ptr, "end_frame", end); + } + + /* Both forward and up axes cannot be the same (or same except opposite sign). */ + if (RNA_enum_get(op->ptr, "forward_axis") % TOTAL_AXES == + (RNA_enum_get(op->ptr, "up_axis") % TOTAL_AXES)) { + /* TODO(@ankitm): Show a warning here. */ + RNA_enum_set(op->ptr, "up_axis", RNA_enum_get(op->ptr, "up_axis") % TOTAL_AXES + 1); + changed = true; + } + return changed; +} + +void WM_OT_obj_export(struct wmOperatorType *ot) +{ + ot->name = "Export Wavefront OBJ"; + ot->description = "Save the scene to a Wavefront OBJ file"; + ot->idname = "WM_OT_obj_export"; + + ot->invoke = wm_obj_export_invoke; + ot->exec = wm_obj_export_exec; + ot->poll = WM_operator_winactive; + ot->ui = wm_obj_export_draw; + ot->check = wm_obj_export_check; + + WM_operator_properties_filesel(ot, + FILE_TYPE_FOLDER | FILE_TYPE_OBJECT_IO, + FILE_BLENDER, + FILE_SAVE, + WM_FILESEL_FILEPATH | WM_FILESEL_SHOW_PROPS, + FILE_DEFAULTDISPLAY, + FILE_SORT_ALPHA); + + /* Animation options. */ + RNA_def_boolean(ot->srna, + "export_animation", + false, + "Export Animation", + "Export multiple frames instead of the current frame only"); + RNA_def_int(ot->srna, + "start_frame", + INT_MIN, /* wm_obj_export_check uses this to set SFRA. */ + INT_MIN, + INT_MAX, + "Start Frame", + "The first frame to be exported", + INT_MIN, + INT_MAX); + RNA_def_int(ot->srna, + "end_frame", + INT_MAX, /* wm_obj_export_check uses this to set EFRA. */ + INT_MIN, + INT_MAX, + "End Frame", + "The last frame to be exported", + INT_MIN, + INT_MAX); + /* Object transform options. */ + RNA_def_enum(ot->srna, + "forward_axis", + io_obj_transform_axis_forward, + OBJ_AXIS_NEGATIVE_Z_FORWARD, + "Forward Axis", + ""); + RNA_def_enum(ot->srna, "up_axis", io_obj_transform_axis_up, OBJ_AXIS_Y_UP, "Up Axis", ""); + RNA_def_float(ot->srna, + "scaling_factor", + 1.0f, + 0.001f, + 10000.0f, + "Scale", + "Upscale the object by this factor", + 0.01, + 1000.0f); + /* File Writer options. */ + RNA_def_enum(ot->srna, + "export_eval_mode", + io_obj_export_evaluation_mode, + DAG_EVAL_VIEWPORT, + "Object Properties", + "Determines properties like object visibility, modifiers etc., where they differ " + "for Render and Viewport"); + RNA_def_boolean(ot->srna, + "export_selected_objects", + false, + "Export Selected Objects", + "Export only selected objects instead of all supported objects"); + RNA_def_boolean(ot->srna, "export_uv", true, "Export UVs", ""); + RNA_def_boolean(ot->srna, + "export_normals", + true, + "Export Normals", + "Export per-face normals if the face is flat-shaded, per-face-per-loop " + "normals if smooth-shaded"); + RNA_def_boolean(ot->srna, + "export_materials", + true, + "Export Materials", + "Export MTL library. There must be a Principled-BSDF node for image textures to " + "be exported to the MTL file"); + RNA_def_boolean(ot->srna, + "export_triangulated_mesh", + false, + "Export Triangulated Mesh", + "All ngons with four or more vertices will be triangulated. Meshes in " + "the scene will not be affected. Behaves like Triangulate Modifier with " + "ngon-method: \"Beauty\", quad-method: \"Shortest Diagonal\", min vertices: 4"); + RNA_def_boolean(ot->srna, + "export_curves_as_nurbs", + false, + "Export Curves as NURBS", + "Export curves in parametric form instead of exporting as mesh"); + + RNA_def_boolean(ot->srna, + "export_object_groups", + false, + "Export Object Groups", + "Append mesh name to object name, separated by a '_'"); + RNA_def_boolean(ot->srna, + "export_material_groups", + false, + "Export Material Groups", + "Append mesh name and material name to object name, separated by a '_'"); + RNA_def_boolean( + ot->srna, + "export_vertex_groups", + false, + "Export Vertex Groups", + "Export the name of the vertex group of a face. It is approximated " + "by choosing the vertex group with the most members among the vertices of a face"); + RNA_def_boolean( + ot->srna, + "export_smooth_groups", + false, + "Export Smooth Groups", + "Every smooth-shaded face is assigned group \"1\" and every flat-shaded face \"off\""); + RNA_def_boolean( + ot->srna, "smooth_group_bitflags", false, "Generate Bitflags for Smooth Groups", ""); +} diff --git a/source/blender/editors/io/io_obj.h b/source/blender/editors/io/io_obj.h new file mode 100644 index 00000000000..5a0e6971edd --- /dev/null +++ b/source/blender/editors/io/io_obj.h @@ -0,0 +1,25 @@ +/* + * 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 editor/io + */ + +#pragma once + +struct wmOperatorType; + +void WM_OT_obj_export(struct wmOperatorType *ot); diff --git a/source/blender/editors/io/io_ops.c b/source/blender/editors/io/io_ops.c index b2788ee49a2..d9bbd7d8692 100644 --- a/source/blender/editors/io/io_ops.c +++ b/source/blender/editors/io/io_ops.c @@ -39,6 +39,7 @@ #include "io_cache.h" #include "io_gpencil.h" +#include "io_obj.h" void ED_operatortypes_io(void) { @@ -68,4 +69,10 @@ void ED_operatortypes_io(void) WM_operatortype_append(CACHEFILE_OT_open); WM_operatortype_append(CACHEFILE_OT_reload); + + WM_operatortype_append(CACHEFILE_OT_layer_add); + WM_operatortype_append(CACHEFILE_OT_layer_remove); + WM_operatortype_append(CACHEFILE_OT_layer_move); + + WM_operatortype_append(WM_OT_obj_export); } diff --git a/source/blender/editors/mask/mask_draw.c b/source/blender/editors/mask/mask_draw.c index 9504a8783a0..0e207df7f94 100644 --- a/source/blender/editors/mask/mask_draw.c +++ b/source/blender/editors/mask/mask_draw.c @@ -722,8 +722,8 @@ void ED_mask_draw_region( /* find window pixel coordinates of origin */ UI_view2d_view_to_region(®ion->v2d, 0.0f, 0.0f, &x, &y); - /* w = BLI_rctf_size_x(&v2d->tot); */ - /* h = BLI_rctf_size_y(&v2d->tot); */ + // w = BLI_rctf_size_x(&v2d->tot); + // h = BLI_rctf_size_y(&v2d->tot); zoomx = (float)(BLI_rcti_size_x(®ion->winrct) + 1) / BLI_rctf_size_x(®ion->v2d.cur); zoomy = (float)(BLI_rcti_size_y(®ion->winrct) + 1) / BLI_rctf_size_y(®ion->v2d.cur); @@ -768,7 +768,8 @@ void ED_mask_draw_region( IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_SHUFFLE_COLOR); GPU_shader_uniform_vector( state.shader, GPU_shader_get_uniform(state.shader, "shuffle"), 4, 1, red); - immDrawPixelsTex(&state, 0.0f, 0.0f, width, height, GPU_R16F, false, buffer, 1.0f, 1.0f, NULL); + immDrawPixelsTexTiled( + &state, 0.0f, 0.0f, width, height, GPU_R16F, false, buffer, 1.0f, 1.0f, NULL); GPU_matrix_pop(); @@ -835,7 +836,7 @@ void ED_mask_draw_frames( mask_layer_shape = mask_layer_shape->next) { int frame = mask_layer_shape->frame; - /* draw_keyframe(i, CFRA, sfra, framelen, 1); */ + // draw_keyframe(i, CFRA, sfra, framelen, 1); int height = (frame == cfra) ? 22 : 10; int x = (frame - sfra) * framelen; immVertex2i(pos, x, region_bottom); diff --git a/source/blender/editors/mask/mask_intern.h b/source/blender/editors/mask/mask_intern.h index 41ff14dcd5f..19a3b3966a1 100644 --- a/source/blender/editors/mask/mask_intern.h +++ b/source/blender/editors/mask/mask_intern.h @@ -95,8 +95,8 @@ bool ED_mask_spline_select_check(const struct MaskSpline *spline); bool ED_mask_layer_select_check(const struct MaskLayer *mask_layer); bool ED_mask_select_check(const struct Mask *mask); -void ED_mask_spline_select_set(struct MaskSpline *spline, const bool do_select); -void ED_mask_layer_select_set(struct MaskLayer *mask_layer, const bool do_select); +void ED_mask_spline_select_set(struct MaskSpline *spline, bool do_select); +void ED_mask_layer_select_set(struct MaskLayer *mask_layer, bool do_select); void ED_mask_select_toggle_all(struct Mask *mask, int action); void ED_mask_select_flush_all(struct Mask *mask); @@ -126,8 +126,8 @@ bool ED_mask_find_nearest_diff_point(const struct bContext *C, int threshold, bool feather, float tangent[2], - const bool use_deform, - const bool use_project, + bool use_deform, + bool use_project, struct MaskLayer **r_mask_layer, struct MaskSpline **r_spline, struct MaskSplinePoint **r_point, @@ -136,7 +136,7 @@ bool ED_mask_find_nearest_diff_point(const struct bContext *C, bool ED_mask_feather_find_nearest(const struct bContext *C, struct Mask *mask, const float normal_co[2], - const float threshold, + float threshold, struct MaskLayer **r_mask_layer, struct MaskSpline **r_spline, struct MaskSplinePoint **r_point, @@ -145,7 +145,7 @@ bool ED_mask_feather_find_nearest(const struct bContext *C, struct MaskSplinePoint *ED_mask_point_find_nearest(const struct bContext *C, struct Mask *mask, const float normal_co[2], - const float threshold, + float threshold, struct MaskLayer **r_mask_layer, struct MaskSpline **r_spline, eMaskWhichHandle *r_which_handle, diff --git a/source/blender/editors/mesh/editmesh_intersect.c b/source/blender/editors/mesh/editmesh_intersect.c index 18fe9cf7ad3..81dc34f894f 100644 --- a/source/blender/editors/mesh/editmesh_intersect.c +++ b/source/blender/editors/mesh/editmesh_intersect.c @@ -57,7 +57,7 @@ #define USE_NET_ISLAND_CONNECT /** - * Compare selected with its self. + * Compare selected with itself. */ static int bm_face_isect_self(BMFace *f, void *UNUSED(user_data)) { diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index 3772a37ac44..cae781327d5 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -2605,6 +2605,7 @@ static bool knife_ray_intersect_face(KnifeTool_OpData *kcd, /** * Calculate the center and maximum excursion of mesh. + * (Considers all meshes in multi-object edit mode) */ static void calc_ortho_extent(KnifeTool_OpData *kcd) { @@ -2613,6 +2614,7 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd) BMIter iter; BMVert *v; float min[3], max[3]; + float ws[3]; INIT_MINMAX(min, max); for (uint b = 0; b < kcd->objects_len; b++) { @@ -2620,11 +2622,17 @@ static void calc_ortho_extent(KnifeTool_OpData *kcd) em = BKE_editmesh_from_object(ob); if (kcd->cagecos[b]) { - minmax_v3v3_v3_array(min, max, kcd->cagecos[b], em->bm->totvert); + for (int i = 0; i < em->bm->totvert; i++) { + copy_v3_v3(ws, kcd->cagecos[b][i]); + mul_m4_v3(ob->obmat, ws); + minmax_v3v3_v3(min, max, ws); + } } else { BM_ITER_MESH (v, &iter, em->bm, BM_VERTS_OF_MESH) { - minmax_v3v3_v3(min, max, v->co); + copy_v3_v3(ws, v->co); + mul_m4_v3(ob->obmat, ws); + minmax_v3v3_v3(min, max, ws); } } } @@ -3009,6 +3017,12 @@ static void knife_find_line_hits(KnifeTool_OpData *kcd) for (val = BLI_smallhash_iternew(&kfes, &hiter, (uintptr_t *)&kfe); val; val = BLI_smallhash_iternext(&hiter, (uintptr_t *)&kfe)) { + /* If we intersect any of the vertices, don't attempt to intersect the edge. */ + if (BLI_smallhash_lookup(&kfvs, (intptr_t)kfe->v1) || + BLI_smallhash_lookup(&kfvs, (intptr_t)kfe->v2)) { + continue; + } + knife_project_v2(kcd, kfe->v1->cageco, se1); knife_project_v2(kcd, kfe->v2->cageco, se2); int isect_kind = 1; diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c index 8cfcc96517c..a1a7dfac282 100644 --- a/source/blender/editors/mesh/editmesh_mask_extract.c +++ b/source/blender/editors/mesh/editmesh_mask_extract.c @@ -388,8 +388,7 @@ static int face_set_extract_modal(bContext *C, wmOperator *op, const wmEvent *ev * that the mouse clicked in a viewport region and its coordinates can be used to ray-cast * the PBVH and update the active Face Set ID. */ bScreen *screen = CTX_wm_screen(C); - ARegion *region = BKE_screen_find_main_region_at_xy( - screen, SPACE_VIEW3D, event->xy[0], event->xy[1]); + ARegion *region = BKE_screen_find_main_region_at_xy(screen, SPACE_VIEW3D, event->xy); if (!region) { return OPERATOR_CANCELLED; diff --git a/source/blender/editors/mesh/editmesh_path.c b/source/blender/editors/mesh/editmesh_path.c index 30a453a32ee..e48b5d8255e 100644 --- a/source/blender/editors/mesh/editmesh_path.c +++ b/source/blender/editors/mesh/editmesh_path.c @@ -377,7 +377,7 @@ static void edgetag_ensure_cd_flag(Mesh *me, const char edge_mode) } } -/* mesh shortest path select, uses prev-selected edge */ +/* Mesh shortest path select, uses previously-selected edge. */ /* since you want to create paths with multiple selects, it doesn't have extend option */ static void mouse_mesh_shortest_path_edge(Scene *scene, diff --git a/source/blender/editors/mesh/editmesh_select_similar.c b/source/blender/editors/mesh/editmesh_select_similar.c index f2311eb926d..949b12f9a65 100644 --- a/source/blender/editors/mesh/editmesh_select_similar.c +++ b/source/blender/editors/mesh/editmesh_select_similar.c @@ -1334,6 +1334,33 @@ static const EnumPropertyItem *select_similar_type_itemf(bContext *C, return prop_similar_types; } +static bool edbm_select_similar_poll_property(const bContext *UNUSED(C), + wmOperator *op, + const PropertyRNA *prop) +{ + const char *prop_id = RNA_property_identifier(prop); + const int type = RNA_enum_get(op->ptr, "type"); + + /* Only show threshold when it is used. */ + if (STREQ(prop_id, "threshold")) { + if (!ELEM(type, + SIMVERT_NORMAL, + SIMEDGE_BEVEL, + SIMEDGE_CREASE, + SIMEDGE_DIR, + SIMEDGE_LENGTH, + SIMEDGE_FACE_ANGLE, + SIMFACE_AREA, + SIMFACE_PERIMETER, + SIMFACE_NORMAL, + SIMFACE_COPLANAR)) { + return false; + } + } + + return true; +} + void MESH_OT_select_similar(wmOperatorType *ot) { PropertyRNA *prop; @@ -1347,6 +1374,7 @@ void MESH_OT_select_similar(wmOperatorType *ot) ot->invoke = WM_menu_invoke; ot->exec = edbm_select_similar_exec; ot->poll = ED_operator_editmesh; + ot->poll_property = edbm_select_similar_poll_property; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; diff --git a/source/blender/editors/mesh/editmesh_undo.c b/source/blender/editors/mesh/editmesh_undo.c index f22d4bbe580..59c357aa416 100644 --- a/source/blender/editors/mesh/editmesh_undo.c +++ b/source/blender/editors/mesh/editmesh_undo.c @@ -104,7 +104,7 @@ typedef struct UndoMesh { int selectmode; /** \note - * this isn't a prefect solution, if you edit keys and change shapes this works well + * This isn't a perfect solution, if you edit keys and change shapes this works well * (fixing T32442), but editing shape keys, going into object mode, removing or changing their * order, then go back into editmode and undo will give issues - where the old index will be * out of sync with the new object index. @@ -690,12 +690,12 @@ static void undomesh_to_editmesh(UndoMesh *um, Object *ob, BMEditMesh *em, Key * em_tmp = BKE_editmesh_create(bm); *em = *em_tmp; - /* Calculate face normals and tessellation at once since it's multi-threaded. - * The vertex normals are stored in the undo-mesh, so this doesn't need to be updated. */ - BKE_editmesh_looptri_calc_ex(em, - &(const struct BMeshCalcTessellation_Params){ - .face_normals = true, - }); + /* Normals should not be stored in the undo mesh, so recalculate them. The edit + * mesh is expected to have valid normals and there is no tracked dirty state. */ + BLI_assert(BKE_mesh_vertex_normals_are_dirty(&um->me)); + + /* Calculate face normals and tessellation at once since it's multi-threaded. */ + BKE_editmesh_looptri_and_normals_calc(em); em->selectmode = um->selectmode; bm->selectmode = um->selectmode; diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index 013d5e5a661..f3db8f1f0d2 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -334,9 +334,6 @@ void EDBM_mesh_clear(BMEditMesh *em) /* clear bmesh */ BM_mesh_clear(em->bm); - /* Free evaluated meshes & cache. */ - BKE_editmesh_free_derived_caches(em); - /* free tessellation data */ em->tottri = 0; MEM_SAFE_FREE(em->looptris); @@ -1404,8 +1401,6 @@ void EDBM_update(Mesh *mesh, const struct EDBMUpdate_Params *params) BM_lnorspace_invalidate(em->bm, false); em->bm->spacearr_dirty &= ~BM_SPACEARR_BMO_SET; } - /* Don't keep stale evaluated mesh data around, see: T38872. */ - BKE_editmesh_free_derived_caches(em); #ifdef DEBUG { diff --git a/source/blender/editors/mesh/mesh_data.c b/source/blender/editors/mesh/mesh_data.c index d7d1dc7dcae..0f58752f323 100644 --- a/source/blender/editors/mesh/mesh_data.c +++ b/source/blender/editors/mesh/mesh_data.c @@ -1019,11 +1019,6 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator /* Tag edges as sharp according to smooth threshold if needed, * to preserve autosmooth shading. */ if (me->flag & ME_AUTOSMOOTH) { - float(*polynors)[3] = MEM_mallocN(sizeof(*polynors) * (size_t)me->totpoly, __func__); - - BKE_mesh_calc_normals_poly( - me->mvert, me->totvert, me->mloop, me->totloop, me->mpoly, me->totpoly, polynors); - BKE_edges_sharp_from_angle_set(me->mvert, me->totvert, me->medge, @@ -1031,11 +1026,9 @@ static int mesh_customdata_custom_splitnormals_add_exec(bContext *C, wmOperator me->mloop, me->totloop, me->mpoly, - polynors, + BKE_mesh_poly_normals_ensure(me), me->totpoly, me->smoothresh); - - MEM_freeN(polynors); } CustomData_add_layer(data, CD_CUSTOMLOOPNORMAL, CD_DEFAULT, NULL, me->totloop); diff --git a/source/blender/editors/mesh/mesh_intern.h b/source/blender/editors/mesh/mesh_intern.h index bba142133a6..575e6d66ccd 100644 --- a/source/blender/editors/mesh/mesh_intern.h +++ b/source/blender/editors/mesh/mesh_intern.h @@ -48,7 +48,7 @@ bool EDBM_op_callf(struct BMEditMesh *em, struct wmOperator *op, const char *fmt bool EDBM_op_call_and_selectf(struct BMEditMesh *em, struct wmOperator *op, const char *select_slot, - const bool select_replace, + bool select_replace, const char *fmt, ...); /** @@ -74,7 +74,7 @@ bool EDBM_op_init( bool EDBM_op_finish(struct BMEditMesh *em, struct BMOperator *bmop, struct wmOperator *op, - const bool do_report); + bool do_report); void EDBM_stats_update(struct BMEditMesh *em); @@ -110,8 +110,8 @@ struct BMElem *EDBM_elem_from_index_any_multi(struct ViewLayer *view_layer, */ bool edbm_extrude_edges_indiv(struct BMEditMesh *em, struct wmOperator *op, - const char hflag, - const bool use_normal_flip); + char hflag, + bool use_normal_flip); /* *** editmesh_add.c *** */ diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index ebe8b758aa2..c9615698c46 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -1363,8 +1363,7 @@ typedef struct VertPickData { static void ed_mesh_pick_vert__mapFunc(void *userData, int index, const float co[3], - const float UNUSED(no_f[3]), - const short UNUSED(no_s[3])) + const float UNUSED(no[3])) { VertPickData *data = userData; if ((data->mvert[index].flag & ME_HIDE) == 0) { diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 9354171a1e4..06e21f91d04 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1742,15 +1742,16 @@ void OBJECT_OT_collection_instance_add(wmOperatorType *ot) ot->prop = prop; ED_object_add_generic_props(ot, false); - RNA_def_int(ot->srna, - "session_uuid", - 0, - INT32_MIN, - INT32_MAX, - "Session UUID", - "Session UUID of the collection to add", - INT32_MIN, - INT32_MAX); + prop = RNA_def_int(ot->srna, + "session_uuid", + 0, + INT32_MIN, + INT32_MAX, + "Session UUID", + "Session UUID of the collection to add", + INT32_MIN, + INT32_MAX); + RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); object_add_drop_xy_props(ot); } @@ -3526,6 +3527,8 @@ static int object_add_named_exec(bContext *C, wmOperator *op) } basen->object->visibility_flag &= ~OB_HIDE_VIEWPORT; + /* Do immediately, as #copy_object_set_idnew() below operates on visible objects. */ + BKE_base_eval_flags(basen); /* object_add_duplicate_internal() doesn't deselect other objects, unlike object_add_common() or * BKE_view_layer_base_deselect_all(). */ diff --git a/source/blender/editors/object/object_bake.c b/source/blender/editors/object/object_bake.c index 1b6b0c78037..b903d664c9b 100644 --- a/source/blender/editors/object/object_bake.c +++ b/source/blender/editors/object/object_bake.c @@ -108,8 +108,10 @@ typedef struct { ListBase data; /** Clear the images before baking */ bool bake_clear; - /** Bake-filter, aka margin */ - int bake_filter; + /** Margin size in pixels. */ + int bake_margin; + /** margin type */ + char bake_margin_type; /** mode of baking (displacement, normals, AO) */ short mode; /** Use low-resolution mesh when baking displacement maps */ @@ -372,7 +374,8 @@ static int multiresbake_image_exec_locked(bContext *C, wmOperator *op) /* copy data stored in job descriptor */ bkr.scene = scene; - bkr.bake_filter = scene->r.bake_filter; + bkr.bake_margin = scene->r.bake_margin; + bkr.bake_margin_type = scene->r.bake_margin_type; bkr.mode = scene->r.bake_mode; bkr.use_lores_mesh = scene->r.bake_flag & R_BAKE_LORES_MESH; bkr.bias = scene->r.bake_biasdist; @@ -416,7 +419,8 @@ static void init_multiresbake_job(bContext *C, MultiresBakeJob *bkj) /* backup scene settings, so their changing in UI would take no effect on baker */ bkj->scene = scene; - bkj->bake_filter = scene->r.bake_filter; + bkj->bake_margin = scene->r.bake_margin; + bkj->bake_margin_type = scene->r.bake_margin_type; bkj->mode = scene->r.bake_mode; bkj->use_lores_mesh = scene->r.bake_flag & R_BAKE_LORES_MESH; bkj->bake_clear = scene->r.bake_flag & R_BAKE_CLEAR; @@ -477,7 +481,8 @@ static void multiresbake_startjob(void *bkv, short *stop, short *do_update, floa /* copy data stored in job descriptor */ bkr.scene = bkj->scene; - bkr.bake_filter = bkj->bake_filter; + bkr.bake_margin = bkj->bake_margin; + bkr.bake_margin_type = bkj->bake_margin_type; bkr.mode = bkj->mode; bkr.use_lores_mesh = bkj->use_lores_mesh; bkr.user_scale = bkj->user_scale; diff --git a/source/blender/editors/object/object_bake_api.c b/source/blender/editors/object/object_bake_api.c index 0de34e21462..d56d0edd5a2 100644 --- a/source/blender/editors/object/object_bake_api.c +++ b/source/blender/editors/object/object_bake_api.c @@ -89,6 +89,7 @@ typedef struct BakeAPIRender { eScenePassType pass_type; int pass_filter; int margin; + eBakeMarginType margin_type; bool is_clear; bool is_selected_to_active; @@ -184,8 +185,11 @@ static bool write_internal_bake_pixels(Image *image, const int width, const int height, const int margin, + const char margin_type, const bool is_clear, - const bool is_noncolor) + const bool is_noncolor, + Mesh const *mesh, + char const *uv_layer) { ImBuf *ibuf; void *lock; @@ -281,7 +285,7 @@ static bool write_internal_bake_pixels(Image *image, /* margins */ if (margin > 0) { - RE_bake_margin(ibuf, mask_buffer, margin); + RE_bake_margin(ibuf, mask_buffer, margin, margin_type, mesh, uv_layer); } ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; @@ -327,8 +331,11 @@ static bool write_external_bake_pixels(const char *filepath, const int width, const int height, const int margin, + const int margin_type, ImageFormatData *im_format, - const bool is_noncolor) + const bool is_noncolor, + Mesh const *mesh, + char const *uv_layer) { ImBuf *ibuf = NULL; bool ok = false; @@ -385,7 +392,7 @@ static bool write_external_bake_pixels(const char *filepath, mask_buffer = MEM_callocN(sizeof(char) * num_pixels, "Bake Mask"); RE_bake_mask_fill(pixel_array, num_pixels, mask_buffer); - RE_bake_margin(ibuf, mask_buffer, margin); + RE_bake_margin(ibuf, mask_buffer, margin, margin_type, mesh, uv_layer); if (mask_buffer) { MEM_freeN(mask_buffer); @@ -770,6 +777,7 @@ static bool bake_targets_output_internal(const BakeAPIRender *bkr, ReportList *reports) { bool all_ok = true; + const Mesh *me = (Mesh *)ob->data; for (int i = 0; i < targets->num_images; i++) { BakeImage *bk_image = &targets->images[i]; @@ -780,8 +788,11 @@ static bool bake_targets_output_internal(const BakeAPIRender *bkr, bk_image->width, bk_image->height, bkr->margin, + bkr->margin_type, bkr->is_clear, - targets->is_noncolor); + targets->is_noncolor, + me, + bkr->uv_layer); /* might be read by UI to set active image for display */ bake_update_image(bkr->area, bk_image->image); @@ -895,8 +906,11 @@ static bool bake_targets_output_external(const BakeAPIRender *bkr, bk_image->width, bk_image->height, bkr->margin, + bkr->margin_type, &bake->im_format, - targets->is_noncolor); + targets->is_noncolor, + me, + bkr->uv_layer); if (!ok) { BKE_reportf(reports, RPT_ERROR, "Problem saving baked map in \"%s\"", name); @@ -1625,6 +1639,7 @@ static void bake_init_api_data(wmOperator *op, bContext *C, BakeAPIRender *bkr) bkr->pass_type = RNA_enum_get(op->ptr, "type"); bkr->pass_filter = RNA_enum_get(op->ptr, "pass_filter"); bkr->margin = RNA_int_get(op->ptr, "margin"); + bkr->margin_type = RNA_enum_get(op->ptr, "margin_type"); bkr->save_mode = (eBakeSaveMode)RNA_enum_get(op->ptr, "save_mode"); bkr->target = (eBakeTarget)RNA_enum_get(op->ptr, "target"); @@ -1818,6 +1833,11 @@ static void bake_set_props(wmOperator *op, Scene *scene) RNA_property_int_set(op->ptr, prop, bake->margin); } + prop = RNA_struct_find_property(op->ptr, "margin_type"); + if (!RNA_property_is_set(op->ptr, prop)) { + RNA_property_enum_set(op->ptr, prop, bake->margin_type); + } + prop = RNA_struct_find_property(op->ptr, "use_selected_to_active"); if (!RNA_property_is_set(op->ptr, prop)) { RNA_property_boolean_set(op->ptr, prop, (bake->flag & R_BAKE_TO_ACTIVE) != 0); @@ -2008,6 +2028,12 @@ void OBJECT_OT_bake(wmOperatorType *ot) "Extends the baked result as a post process filter", 0, 64); + RNA_def_enum(ot->srna, + "margin_type", + rna_enum_bake_margin_type_items, + R_BAKE_EXTEND, + "Margin Type", + "Which algorithm to use to generate the margin"); RNA_def_boolean(ot->srna, "use_selected_to_active", false, diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c index 5c3a8fc2277..91a512ae8e9 100644 --- a/source/blender/editors/object/object_constraint.c +++ b/source/blender/editors/object/object_constraint.c @@ -89,7 +89,7 @@ ListBase *ED_object_constraint_active_list(Object *ob) if (ob->mode & OB_MODE_POSE) { bPoseChannel *pchan; - pchan = BKE_pose_channel_active(ob); + pchan = BKE_pose_channel_active_if_layer_visible(ob); if (pchan) { return &pchan->constraints; } @@ -2215,7 +2215,7 @@ static bool get_new_constraint_target( bContext *C, int con_type, Object **tar_ob, bPoseChannel **tar_pchan, bool add) { Object *obact = ED_object_active_context(C); - bPoseChannel *pchanact = BKE_pose_channel_active(obact); + bPoseChannel *pchanact = BKE_pose_channel_active_if_layer_visible(obact); bool only_curve = false, only_mesh = false, only_ob = false; bool found = false; @@ -2370,7 +2370,7 @@ static int constraint_add_exec( pchan = NULL; } else { - pchan = BKE_pose_channel_active(ob); + pchan = BKE_pose_channel_active_if_layer_visible(ob); /* ensure not to confuse object/pose adding */ if (pchan == NULL) { @@ -2650,7 +2650,7 @@ void POSE_OT_constraint_add_with_targets(wmOperatorType *ot) static int pose_ik_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C)); - bPoseChannel *pchan = BKE_pose_channel_active(ob); + bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob); bConstraint *con = NULL; uiPopupMenu *pup; diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index f06744068d5..38d0a044cb4 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -1638,10 +1638,10 @@ void OBJECT_OT_shade_smooth(wmOperatorType *ot) /** \name Object Mode Set Operator * \{ */ -static const EnumPropertyItem *object_mode_set_itemsf(bContext *C, - PointerRNA *UNUSED(ptr), - PropertyRNA *UNUSED(prop), - bool *r_free) +static const EnumPropertyItem *object_mode_set_itemf(bContext *C, + PointerRNA *UNUSED(ptr), + PropertyRNA *UNUSED(prop), + bool *r_free) { const EnumPropertyItem *input = rna_enum_object_mode_items; EnumPropertyItem *item = NULL; @@ -1790,7 +1790,7 @@ void OBJECT_OT_mode_set(wmOperatorType *ot) ot->prop = RNA_def_enum( ot->srna, "mode", rna_enum_object_mode_items, OB_MODE_OBJECT, "Mode", ""); - RNA_def_enum_funcs(ot->prop, object_mode_set_itemsf); + RNA_def_enum_funcs(ot->prop, object_mode_set_itemf); RNA_def_property_flag(ot->prop, PROP_SKIP_SAVE); prop = RNA_def_boolean(ot->srna, "toggle", 0, "Toggle", ""); diff --git a/source/blender/editors/object/object_gpencil_modifier.c b/source/blender/editors/object/object_gpencil_modifier.c index e3c2932e17a..5a6c25caacc 100644 --- a/source/blender/editors/object/object_gpencil_modifier.c +++ b/source/blender/editors/object/object_gpencil_modifier.c @@ -533,6 +533,10 @@ static GpencilModifierData *gpencil_edit_modifier_property_get(wmOperator *op, Object *ob, int type) { + if (ob == NULL) { + return NULL; + } + char modifier_name[MAX_NAME]; GpencilModifierData *md; RNA_string_get(op->ptr, "modifier", modifier_name); @@ -968,6 +972,9 @@ static int dash_segment_add_exec(bContext *C, wmOperator *op) DashGpencilModifierData *dmd = (DashGpencilModifierData *)gpencil_edit_modifier_property_get( op, ob, eGpencilModifierType_Dash); + if (dmd == NULL) { + return OPERATOR_CANCELLED; + } const int new_active_index = dmd->segment_active_index + 1; DashGpencilModifierSegment *new_segments = MEM_malloc_arrayN( dmd->segments_len + 1, sizeof(DashGpencilModifierSegment), __func__); @@ -1032,6 +1039,10 @@ static int dash_segment_remove_exec(bContext *C, wmOperator *op) DashGpencilModifierData *dmd = (DashGpencilModifierData *)gpencil_edit_modifier_property_get( op, ob, eGpencilModifierType_Dash); + if (dmd == NULL) { + return OPERATOR_CANCELLED; + } + if (dmd->segment_active_index < 0 || dmd->segment_active_index >= dmd->segments_len) { return OPERATOR_CANCELLED; } @@ -1108,6 +1119,10 @@ static int dash_segment_move_exec(bContext *C, wmOperator *op) DashGpencilModifierData *dmd = (DashGpencilModifierData *)gpencil_edit_modifier_property_get( op, ob, eGpencilModifierType_Dash); + if (dmd == NULL) { + return OPERATOR_CANCELLED; + } + if (dmd->segments_len < 2) { return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/object/object_hook.c b/source/blender/editors/object/object_hook.c index 5065a2c00f0..51967ff35c7 100644 --- a/source/blender/editors/object/object_hook.c +++ b/source/blender/editors/object/object_hook.c @@ -582,7 +582,7 @@ static int add_hook_object(const bContext *C, BLI_strncpy(hmd->subtarget, arm->act_bone->name, sizeof(hmd->subtarget)); - pchan_act = BKE_pose_channel_active(ob); + pchan_act = BKE_pose_channel_active_if_layer_visible(ob); if (LIKELY(pchan_act)) { invert_m4_m4(pose_mat, pchan_act->pose_mat); mul_v3_m4v3(cent, ob->obmat, pchan_act->pose_mat[3]); diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index 9a1b4b48464..d517d68f1fc 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -176,8 +176,8 @@ void COLLECTION_OT_objects_remove_active(struct wmOperatorType *ot); bool edit_modifier_poll_generic(struct bContext *C, struct StructRNA *rna_type, int obtype_flag, - const bool is_editmode_allowed, - const bool is_liboverride_allowed); + bool is_editmode_allowed, + bool is_liboverride_allowed); void edit_modifier_properties(struct wmOperatorType *ot); bool edit_modifier_invoke_properties(struct bContext *C, struct wmOperator *op); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 811f20e82be..a6eb35d49b9 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -583,8 +583,8 @@ bool ED_object_parent_set(ReportList *reports, } case PAR_BONE: case PAR_BONE_RELATIVE: - pchan = BKE_pose_channel_active(par); - pchan_eval = BKE_pose_channel_active(parent_eval); + pchan = BKE_pose_channel_active_if_layer_visible(par); + pchan_eval = BKE_pose_channel_active_if_layer_visible(parent_eval); if (pchan == NULL) { BKE_report(reports, RPT_ERROR, "No active bone"); @@ -2355,7 +2355,8 @@ static bool make_override_library_poll(bContext *C) /* Object must be directly linked to be overridable. */ return (ED_operator_objectmode(C) && obact != NULL && (ID_IS_LINKED(obact) || (obact->instance_collection != NULL && - ID_IS_OVERRIDABLE_LIBRARY(obact->instance_collection)))); + ID_IS_OVERRIDABLE_LIBRARY(obact->instance_collection) && + !ID_IS_OVERRIDE_LIBRARY(obact)))); } static const EnumPropertyItem *make_override_collections_of_linked_object_itemf( diff --git a/source/blender/editors/object/object_remesh.cc b/source/blender/editors/object/object_remesh.cc index 719ffd36f03..e4103db8e21 100644 --- a/source/blender/editors/object/object_remesh.cc +++ b/source/blender/editors/object/object_remesh.cc @@ -168,8 +168,6 @@ static int voxel_remesh_exec(bContext *C, wmOperator *op) new_mesh = mesh_fixed_poles; } - BKE_mesh_calc_normals(new_mesh); - if (mesh->flag & ME_REMESH_REPROJECT_VOLUME || mesh->flag & ME_REMESH_REPROJECT_PAINT_MASK || mesh->flag & ME_REMESH_REPROJECT_SCULPT_FACE_SETS) { BKE_mesh_runtime_clear_geometry(mesh); @@ -463,8 +461,8 @@ static int voxel_size_edit_invoke(bContext *C, wmOperator *op, const wmEvent *ev Object *active_object = CTX_data_active_object(C); Mesh *mesh = (Mesh *)active_object->data; - VoxelSizeEditCustomData *cd = (VoxelSizeEditCustomData *)MEM_callocN( - sizeof(VoxelSizeEditCustomData), "Voxel Size Edit OP Custom Data"); + VoxelSizeEditCustomData *cd = MEM_cnew<VoxelSizeEditCustomData>( + "Voxel Size Edit OP Custom Data"); /* Initial operator Custom Data setup. */ cd->draw_handle = ED_region_draw_cb_activate( diff --git a/source/blender/editors/object/object_shapekey.c b/source/blender/editors/object/object_shapekey.c index fd649854d8f..a871ddea48c 100644 --- a/source/blender/editors/object/object_shapekey.c +++ b/source/blender/editors/object/object_shapekey.c @@ -43,13 +43,16 @@ #include "DNA_object_types.h" #include "BKE_context.h" +#include "BKE_crazyspace.h" #include "BKE_key.h" #include "BKE_lattice.h" #include "BKE_main.h" #include "BKE_object.h" +#include "BKE_report.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" #include "BLI_sys_types.h" /* for intptr_t support */ diff --git a/source/blender/editors/object/object_transform.c b/source/blender/editors/object/object_transform.c index 4c4727f51ee..c9114c7a925 100644 --- a/source/blender/editors/object/object_transform.c +++ b/source/blender/editors/object/object_transform.c @@ -811,8 +811,8 @@ static int apply_objects_internal(bContext *C, /* adjust data */ BKE_mesh_transform(me, mat, true); - /* update normals */ - BKE_mesh_calc_normals(me); + /* If normal layers exist, they are now dirty. */ + BKE_mesh_normals_tag_dirty(me); } else if (ob->type == OB_ARMATURE) { bArmature *arm = ob->data; @@ -1408,6 +1408,19 @@ static int object_origin_set_exec(bContext *C, wmOperator *op) sub_v3_v3(mpt, offset_local); mul_v3_m4v3(&pt->x, diff_mat, mpt); } + + /* Apply transform to edit-curve. */ + if (gps->editcurve != NULL) { + for (i = 0; i < gps->editcurve->tot_curve_points; i++) { + BezTriple *bezt = &gps->editcurve->curve_points[i].bezt; + for (int j = 0; j < 3; j++) { + float mpt[3]; + mul_v3_m4v3(mpt, inverse_diff_mat, bezt->vec[j]); + sub_v3_v3(mpt, offset_local); + mul_v3_m4v3(bezt->vec[j], diff_mat, mpt); + } + } + } } } } diff --git a/source/blender/editors/object/object_utils.c b/source/blender/editors/object/object_utils.c index 5f85f6ea0eb..df44d840ad3 100644 --- a/source/blender/editors/object/object_utils.c +++ b/source/blender/editors/object/object_utils.c @@ -115,7 +115,7 @@ bool ED_object_calc_active_center_for_posemode(Object *ob, const bool select_only, float r_center[3]) { - bPoseChannel *pchan = BKE_pose_channel_active(ob); + bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob); if (pchan && (!select_only || (pchan->bone->flag & BONE_SELECTED))) { copy_v3_v3(r_center, pchan->pose_head); return true; diff --git a/source/blender/editors/physics/dynamicpaint_ops.c b/source/blender/editors/physics/dynamicpaint_ops.c index 80e3f934c80..3214180309b 100644 --- a/source/blender/editors/physics/dynamicpaint_ops.c +++ b/source/blender/editors/physics/dynamicpaint_ops.c @@ -373,7 +373,7 @@ static void dynamicPaint_bakeImageSequence(DynamicPaintBakeJob *job) /* Show progress bar. */ *(job->do_update) = true; - /* Set frame to start point (also inits modifier data) */ + /* Set frame to start point (also initializes modifier data). */ frame = surface->start_frame; orig_frame = input_scene->r.cfra; input_scene->r.cfra = (int)frame; diff --git a/source/blender/editors/physics/particle_edit.c b/source/blender/editors/physics/particle_edit.c index f1e6f02cb39..1407ca598a7 100644 --- a/source/blender/editors/physics/particle_edit.c +++ b/source/blender/editors/physics/particle_edit.c @@ -1441,7 +1441,7 @@ void recalc_emitter_field(Depsgraph *UNUSED(depsgraph), Object *UNUSED(ob), Part PTCacheEdit *edit = psys->edit; Mesh *mesh = edit->psmd_eval->mesh_final; float *vec, *nor; - int i, totface /*, totvert*/; + int i, totface; if (!mesh) { return; @@ -1454,7 +1454,7 @@ void recalc_emitter_field(Depsgraph *UNUSED(depsgraph), Object *UNUSED(ob), Part BLI_kdtree_3d_free(edit->emitter_field); totface = mesh->totface; - // totvert = dm->getNumVerts(dm); /* UNUSED */ + // int totvert = dm->getNumVerts(dm); /* UNUSED */ edit->emitter_cosnos = MEM_callocN(sizeof(float[6]) * totface, "emitter cosnos"); @@ -1463,26 +1463,28 @@ void recalc_emitter_field(Depsgraph *UNUSED(depsgraph), Object *UNUSED(ob), Part vec = edit->emitter_cosnos; nor = vec + 3; + const float(*vert_normals)[3] = BKE_mesh_vertex_normals_ensure(mesh); + for (i = 0; i < totface; i++, vec += 6, nor += 6) { MFace *mface = &mesh->mface[i]; MVert *mvert; mvert = &mesh->mvert[mface->v1]; copy_v3_v3(vec, mvert->co); - copy_v3fl_v3s(nor, mvert->no); + copy_v3_v3(nor, vert_normals[mface->v1]); mvert = &mesh->mvert[mface->v2]; add_v3_v3v3(vec, vec, mvert->co); - add_v3fl_v3fl_v3s(nor, nor, mvert->no); + add_v3_v3(nor, vert_normals[mface->v2]); mvert = &mesh->mvert[mface->v3]; add_v3_v3v3(vec, vec, mvert->co); - add_v3fl_v3fl_v3s(nor, nor, mvert->no); + add_v3_v3(nor, vert_normals[mface->v3]); if (mface->v4) { mvert = &mesh->mvert[mface->v4]; add_v3_v3v3(vec, vec, mvert->co); - add_v3fl_v3fl_v3s(nor, nor, mvert->no); + add_v3_v3(nor, vert_normals[mface->v4]); mul_v3_fl(vec, 0.25); } diff --git a/source/blender/editors/physics/particle_object.c b/source/blender/editors/physics/particle_object.c index 367d72b0ad7..987b9e49057 100644 --- a/source/blender/editors/physics/particle_object.c +++ b/source/blender/editors/physics/particle_object.c @@ -743,8 +743,10 @@ static bool remap_hair_emitter(Depsgraph *depsgraph, invert_m4_m4(from_imat, from_mat); invert_m4_m4(to_imat, to_mat); - if (target_psmd->mesh_final->runtime.deformed_only) { - /* we don't want to mess up target_psmd->dm when converting to global coordinates below */ + const bool use_dm_final_indices = (target_psys->part->use_modifier_stack && + !target_psmd->mesh_final->runtime.deformed_only); + + if (use_dm_final_indices || !target_psmd->mesh_original) { mesh = target_psmd->mesh_final; } else { @@ -755,6 +757,7 @@ static bool remap_hair_emitter(Depsgraph *depsgraph, return false; } /* don't modify the original vertices */ + /* we don't want to mess up target_psmd->dm when converting to global coordinates below */ mesh = (Mesh *)BKE_id_copy_ex(NULL, &mesh->id, NULL, LIB_ID_COPY_LOCALIZE); /* BMESH_ONLY, deform dm may not have tessface */ @@ -825,7 +828,13 @@ static bool remap_hair_emitter(Depsgraph *depsgraph, tpa->foffset = 0.0f; tpa->num = nearest.index; - tpa->num_dmcache = psys_particle_dm_face_lookup(target_mesh, mesh, tpa->num, tpa->fuv, NULL); + if (use_dm_final_indices) { + tpa->num_dmcache = DMCACHE_ISCHILD; + } + else { + tpa->num_dmcache = psys_particle_dm_face_lookup( + target_psmd->mesh_final, target_psmd->mesh_original, tpa->num, tpa->fuv, NULL); + } } else { me = &medge[nearest.index]; @@ -930,7 +939,9 @@ static bool connect_hair(Depsgraph *depsgraph, Scene *scene, Object *ob, Particl ob->obmat, psys->flag & PSYS_GLOBAL_HAIR, false); - psys->flag &= ~PSYS_GLOBAL_HAIR; + if (ok) { + psys->flag &= ~PSYS_GLOBAL_HAIR; + } return ok; } diff --git a/source/blender/editors/render/CMakeLists.txt b/source/blender/editors/render/CMakeLists.txt index 46afa390997..1f867c6f1f7 100644 --- a/source/blender/editors/render/CMakeLists.txt +++ b/source/blender/editors/render/CMakeLists.txt @@ -28,6 +28,7 @@ set(INC ../../imbuf ../../makesdna ../../makesrna + ../../nodes ../../render ../../sequencer ../../windowmanager @@ -36,15 +37,15 @@ set(INC ) set(SRC - render_internal.c - render_opengl.c - render_ops.c - render_preview.c - render_shading.c - render_update.c - render_view.c + render_internal.cc + render_opengl.cc + render_ops.cc + render_preview.cc + render_shading.cc + render_update.cc + render_view.cc - render_intern.h + render_intern.hh ) set(LIB diff --git a/source/blender/editors/render/render_intern.h b/source/blender/editors/render/render_intern.hh index d374717664b..d374717664b 100644 --- a/source/blender/editors/render/render_intern.h +++ b/source/blender/editors/render/render_intern.hh diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.cc index 0ed303d8f6d..8e9a052381c 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.cc @@ -21,9 +21,9 @@ * \ingroup edrend */ -#include <math.h> -#include <stddef.h> -#include <string.h> +#include <cmath> +#include <cstddef> +#include <cstring> #include "MEM_guardedalloc.h" @@ -50,11 +50,14 @@ #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BKE_node_tree_update.h" #include "BKE_object.h" #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_screen.h" +#include "NOD_composite.h" + #include "DEG_depsgraph.h" #include "WM_api.h" @@ -77,12 +80,12 @@ #include "SEQ_relations.h" -#include "render_intern.h" +#include "render_intern.hh" /* Render Callbacks */ static int render_break(void *rjv); -typedef struct RenderJob { +struct RenderJob { Main *main; Scene *scene; ViewLayer *single_layer; @@ -109,7 +112,7 @@ typedef struct RenderJob { ColorManagedDisplaySettings display_settings; bool supports_glsl_draw; bool interface_locked; -} RenderJob; +}; /* called inside thread! */ static bool image_buffer_calc_tile_rect(const RenderResult *rr, @@ -121,15 +124,15 @@ static bool image_buffer_calc_tile_rect(const RenderResult *rr, { int tile_y, tile_height, tile_x, tile_width; - /* When `renrect` argument is not NULL, we only refresh scan-lines. */ + /* When `renrect` argument is not nullptr, we only refresh scan-lines. */ if (renrect) { - /* if (tile_height == recty), rendering of layer is ready, + /* `if (tile_height == recty)`, rendering of layer is ready, * we should not draw, other things happen... */ - if (rr->renlay == NULL || renrect->ymax >= rr->recty) { + if (rr->renlay == nullptr || renrect->ymax >= rr->recty) { return false; } - /* tile_x here is first subrect x coord, tile_width defines subrect width */ + /* `tile_x` here is first sub-rectangle x coord, tile_width defines sub-rectangle width. */ tile_x = renrect->xmin; tile_width = renrect->xmax - tile_x; if (tile_width < 2) { @@ -189,7 +192,7 @@ static void image_buffer_rect_update(RenderJob *rj, const char *viewname) { Scene *scene = rj->scene; - const float *rectf = NULL; + const float *rectf = nullptr; int linear_stride, linear_offset_x, linear_offset_y; ColorManagedViewSettings *view_settings; ColorManagedDisplaySettings *display_settings; @@ -230,12 +233,12 @@ static void image_buffer_rect_update(RenderJob *rj, ibuf->userflags |= IB_DISPLAY_BUFFER_INVALID; return; } - if (rr->renlay == NULL) { + if (rr->renlay == nullptr) { return; } rectf = RE_RenderLayerGetPass(rr->renlay, RE_PASSNAME_COMBINED, viewname); } - if (rectf == NULL) { + if (rectf == nullptr) { return; } @@ -256,7 +259,7 @@ static void image_buffer_rect_update(RenderJob *rj, IMB_partial_display_buffer_update(ibuf, rectf, - NULL, + nullptr, linear_stride, linear_offset_x, linear_offset_y, @@ -315,17 +318,17 @@ static int screen_render_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); RenderEngineType *re_type = RE_engines_find(scene->r.engine); ViewLayer *active_layer = CTX_data_view_layer(C); - ViewLayer *single_layer = NULL; + ViewLayer *single_layer = nullptr; Render *re; Image *ima; View3D *v3d = CTX_wm_view3d(C); Main *mainp = CTX_data_main(C); const bool is_animation = RNA_boolean_get(op->ptr, "animation"); const bool is_write_still = RNA_boolean_get(op->ptr, "write_still"); - struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL; + struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : nullptr; /* Cannot do render if there is not this function. */ - if (re_type->render == NULL) { + if (re_type->render == nullptr) { return OPERATOR_CANCELLED; } @@ -342,11 +345,11 @@ static int screen_render_exec(bContext *C, wmOperator *op) G.is_break = false; - RE_draw_lock_cb(re, NULL, NULL); - RE_test_break_cb(re, NULL, render_break); + RE_draw_lock_cb(re, nullptr, nullptr); + RE_test_break_cb(re, nullptr, render_break); ima = BKE_image_ensure_viewer(mainp, IMA_TYPE_R_RESULT, "Render Result"); - BKE_image_signal(mainp, ima, NULL, IMA_SIGNAL_FREE); + BKE_image_signal(mainp, ima, nullptr, IMA_SIGNAL_FREE); BKE_image_backup_render(scene, ima, true); /* cleanup sequencer caches before starting user triggered render. @@ -371,7 +374,7 @@ static int screen_render_exec(bContext *C, wmOperator *op) RE_RenderFrame(re, mainp, scene, single_layer, camera_override, scene->r.cfra, is_write_still); } - RE_SetReports(re, NULL); + RE_SetReports(re, nullptr); /* No redraw needed, we leave state as we entered it. */ ED_update_for_newframe(mainp, CTX_data_depsgraph_pointer(C)); @@ -383,7 +386,7 @@ static int screen_render_exec(bContext *C, wmOperator *op) static void render_freejob(void *rjv) { - RenderJob *rj = rjv; + RenderJob *rj = static_cast<RenderJob *>(rjv); BKE_color_managed_view_settings_free(&rj->view_settings); MEM_freeN(rj); @@ -471,15 +474,15 @@ static void make_renderinfo_string(const RenderStats *rs, static void image_renderinfo_cb(void *rjv, RenderStats *rs) { - RenderJob *rj = rjv; + RenderJob *rj = static_cast<RenderJob *>(rjv); RenderResult *rr; rr = RE_AcquireResultRead(rj->re); if (rr) { /* malloc OK here, stats_draw is not in tile threads */ - if (rr->text == NULL) { - rr->text = MEM_callocN(IMA_MAX_RENDER_TEXT, "rendertext"); + if (rr->text == nullptr) { + rr->text = static_cast<char *>(MEM_callocN(IMA_MAX_RENDER_TEXT, "rendertext")); } make_renderinfo_string(rs, rj->scene, rj->v3d_override, rr->error, rr->text); @@ -493,7 +496,7 @@ static void image_renderinfo_cb(void *rjv, RenderStats *rs) static void render_progress_update(void *rjv, float progress) { - RenderJob *rj = rjv; + RenderJob *rj = static_cast<RenderJob *>(rjv); if (rj->progress && *rj->progress != progress) { *rj->progress = progress; @@ -511,20 +514,22 @@ static void render_progress_update(void *rjv, float progress) static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr, ImageUser *iuser) { wmWindowManager *wm; - ScrArea *first_area = NULL, *matched_area = NULL; + ScrArea *first_area = nullptr, *matched_area = nullptr; /* image window, compo node users */ - for (wm = rj->main->wm.first; wm && matched_area == NULL; wm = wm->id.next) { /* only 1 wm */ + for (wm = static_cast<wmWindowManager *>(rj->main->wm.first); wm && matched_area == nullptr; + wm = static_cast<wmWindowManager *>(wm->id.next)) { /* only 1 wm */ wmWindow *win; - for (win = wm->windows.first; win && matched_area == NULL; win = win->next) { + for (win = static_cast<wmWindow *>(wm->windows.first); win && matched_area == nullptr; + win = win->next) { const bScreen *screen = WM_window_get_active_screen(win); LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { if (area->spacetype == SPACE_IMAGE) { - SpaceImage *sima = area->spacedata.first; + SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first); /* area->spacedata might be empty when toggling full-screen mode. */ - if (sima != NULL && sima->image == rj->image) { - if (first_area == NULL) { + if (sima != nullptr && sima->image == rj->image) { + if (first_area == nullptr) { first_area = area; } if (area == rj->area) { @@ -537,12 +542,12 @@ static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr, } } - if (matched_area == NULL) { + if (matched_area == nullptr) { matched_area = first_area; } if (matched_area) { - SpaceImage *sima = matched_area->spacedata.first; + SpaceImage *sima = static_cast<SpaceImage *>(matched_area->spacedata.first); RenderResult *main_rr = RE_AcquireResultRead(rj->re); /* TODO(sergey): is there faster way to get the layer index? */ @@ -562,7 +567,7 @@ static void render_image_update_pass_and_layer(RenderJob *rj, RenderResult *rr, static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrect) { - RenderJob *rj = rjv; + RenderJob *rj = static_cast<RenderJob *>(rjv); Image *ima = rj->image; ImBuf *ibuf; void *lock; @@ -584,7 +589,7 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec return; } - if (rr == NULL) { + if (rr == nullptr) { return; } @@ -628,14 +633,14 @@ static void image_rect_update(void *rjv, RenderResult *rr, volatile rcti *renrec static void current_scene_update(void *rjv, Scene *scene) { - RenderJob *rj = rjv; + RenderJob *rj = static_cast<RenderJob *>(rjv); rj->current_scene = scene; rj->iuser.scene = scene; } static void render_startjob(void *rjv, short *stop, short *do_update, float *progress) { - RenderJob *rj = rjv; + RenderJob *rj = static_cast<RenderJob *>(rjv); rj->stop = stop; rj->do_update = do_update; @@ -663,7 +668,7 @@ static void render_startjob(void *rjv, short *stop, short *do_update, float *pro rj->write_still); } - RE_SetReports(rj->re, NULL); + RE_SetReports(rj->re, nullptr); } static void render_image_restore_layer(RenderJob *rj) @@ -671,15 +676,16 @@ static void render_image_restore_layer(RenderJob *rj) wmWindowManager *wm; /* image window, compo node users */ - for (wm = rj->main->wm.first; wm; wm = wm->id.next) { /* only 1 wm */ + for (wm = static_cast<wmWindowManager *>(rj->main->wm.first); wm; + wm = static_cast<wmWindowManager *>(wm->id.next)) { /* only 1 wm */ wmWindow *win; - for (win = wm->windows.first; win; win = win->next) { + for (win = static_cast<wmWindow *>(wm->windows.first); win; win = win->next) { const bScreen *screen = WM_window_get_active_screen(win); LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { if (area == rj->area) { if (area->spacetype == SPACE_IMAGE) { - SpaceImage *sima = area->spacedata.first; + SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first); if (RE_HasSingleLayer(rj->re)) { /* For single layer renders keep the active layer @@ -705,11 +711,11 @@ static void render_image_restore_layer(RenderJob *rj) static void render_endjob(void *rjv) { - RenderJob *rj = rjv; + RenderJob *rj = static_cast<RenderJob *>(rjv); - /* this render may be used again by the sequencer without the active + /* This render may be used again by the sequencer without the active * 'Render' where the callbacks would be re-assigned. assign dummy callbacks - * to avoid referencing freed renderjobs bug T24508. */ + * to avoid referencing freed render-jobs bug T24508. */ RE_InitRenderCB(rj->re); if (rj->main != G_MAIN) { @@ -731,7 +737,8 @@ static void render_endjob(void *rjv) rj->scene->r.scemode &= ~R_NO_FRAME_UPDATE; if (rj->single_layer) { - nodeUpdateID(rj->scene->nodetree, &rj->scene->id); + BKE_ntree_update_tag_id_changed(rj->main, &rj->scene->id); + BKE_ntree_update_main(rj->main, nullptr); WM_main_add_notifier(NC_NODE | NA_EDITED, rj->scene); } @@ -741,7 +748,7 @@ static void render_endjob(void *rjv) /* XXX render stability hack */ G.is_rendering = false; - WM_main_add_notifier(NC_SCENE | ND_RENDER_RESULT, NULL); + WM_main_add_notifier(NC_SCENE | ND_RENDER_RESULT, nullptr); /* Partial render result will always update display buffer * for first render layer only. This is nice because you'll @@ -778,7 +785,7 @@ static void render_endjob(void *rjv) * and using one from Global will unlock exactly the same manager as * was locked before running the job. */ - WM_set_locked_interface(G_MAIN->wm.first, false); + WM_set_locked_interface(static_cast<wmWindowManager *>(G_MAIN->wm.first), false); DEG_tag_on_visible_update(G_MAIN, false); } } @@ -786,7 +793,7 @@ static void render_endjob(void *rjv) /* called by render, check job 'stop' value or the global */ static int render_breakjob(void *rjv) { - RenderJob *rj = rjv; + RenderJob *rj = static_cast<RenderJob *>(rjv); if (G.is_break) { return 1; @@ -813,7 +820,7 @@ static int render_break(void *UNUSED(rjv)) /* maybe need a way to get job send notifier? */ static void render_drawlock(void *rjv, bool lock) { - RenderJob *rj = rjv; + RenderJob *rj = static_cast<RenderJob *>(rjv); /* If interface is locked, renderer callback shall do nothing. */ if (!rj->interface_locked) { @@ -875,11 +882,12 @@ static void clean_viewport_memory(Main *bmain, Scene *scene) BKE_main_id_tag_listbase(&bmain->objects, LIB_TAG_DOIT, true); /* Go over all the visible objects. */ - for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) { + for (wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first); wm; + wm = static_cast<wmWindowManager *>(wm->id.next)) { LISTBASE_FOREACH (wmWindow *, win, &wm->windows) { ViewLayer *view_layer = WM_window_get_active_view_layer(win); - for (base = view_layer->object_bases.first; base; base = base->next) { + for (base = static_cast<Base *>(view_layer->object_bases.first); base; base = base->next) { clean_viewport_memory_base(base); } } @@ -897,7 +905,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); ViewLayer *active_layer = CTX_data_view_layer(C); - ViewLayer *single_layer = NULL; + ViewLayer *single_layer = nullptr; RenderEngineType *re_type = RE_engines_find(scene->r.engine); Render *re; wmJob *wm_job; @@ -906,13 +914,13 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even const bool is_animation = RNA_boolean_get(op->ptr, "animation"); const bool is_write_still = RNA_boolean_get(op->ptr, "write_still"); const bool use_viewport = RNA_boolean_get(op->ptr, "use_viewport"); - View3D *v3d = use_viewport ? CTX_wm_view3d(C) : NULL; - struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : NULL; + View3D *v3d = use_viewport ? CTX_wm_view3d(C) : nullptr; + struct Object *camera_override = v3d ? V3D_CAMERA_LOCAL(v3d) : nullptr; const char *name; ScrArea *area; /* Cannot do render if there is not this function. */ - if (re_type->render == NULL) { + if (re_type->render == nullptr) { return OPERATOR_CANCELLED; } @@ -968,7 +976,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even area = render_view_open(C, event->xy[0], event->xy[1], op->reports); /* job custom data */ - rj = MEM_callocN(sizeof(RenderJob), "render job"); + rj = MEM_cnew<RenderJob>("render job"); rj->main = bmain; rj->scene = scene; rj->current_scene = rj->scene; @@ -992,7 +1000,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even BKE_color_managed_view_settings_copy(&rj->view_settings, &scene->view_settings); if (area) { - SpaceImage *sima = area->spacedata.first; + SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first); rj->orig_layer = sima->iuser.layer; } @@ -1036,7 +1044,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even WM_JOB_TYPE_RENDER); WM_jobs_customdata_set(wm_job, rj, render_freejob); WM_jobs_timer(wm_job, 0.2, NC_SCENE | ND_RENDER_RESULT, 0); - WM_jobs_callbacks(wm_job, render_startjob, NULL, NULL, render_endjob); + WM_jobs_callbacks(wm_job, render_startjob, nullptr, nullptr, render_endjob); if (RNA_struct_property_is_set(op->ptr, "layer")) { WM_jobs_delay_start(wm_job, 0.2); @@ -1044,7 +1052,7 @@ static int screen_render_invoke(bContext *C, wmOperator *op, const wmEvent *even /* get a render result image, and make sure it is empty */ ima = BKE_image_ensure_viewer(bmain, IMA_TYPE_R_RESULT, "Render Result"); - BKE_image_signal(rj->main, ima, NULL, IMA_SIGNAL_FREE); + BKE_image_signal(rj->main, ima, nullptr, IMA_SIGNAL_FREE); BKE_image_backup_render(rj->scene, ima, true); rj->image = ima; @@ -1104,32 +1112,32 @@ void RENDER_OT_render(wmOperatorType *ot) prop = RNA_def_boolean(ot->srna, "animation", - 0, + false, "Animation", "Render files from the animation range of this scene"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); RNA_def_boolean( ot->srna, "write_still", - 0, + false, "Write Image", "Save rendered the image to the output path (used only when animation is disabled)"); prop = RNA_def_boolean(ot->srna, "use_viewport", - 0, + false, "Use 3D Viewport", "When inside a 3D viewport, use layers and camera of the viewport"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); prop = RNA_def_string(ot->srna, "layer", - NULL, + nullptr, RE_MAXNAME, "Render Layer", "Single render layer to re-render (used only when animation is disabled)"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); prop = RNA_def_string(ot->srna, "scene", - NULL, + nullptr, MAX_ID_NAME - 2, "Scene", "Scene to render, current scene if not specified"); @@ -1145,7 +1153,7 @@ Scene *ED_render_job_get_scene(const bContext *C) return rj->scene; } - return NULL; + return nullptr; } Scene *ED_render_job_get_current_scene(const bContext *C) @@ -1155,7 +1163,7 @@ Scene *ED_render_job_get_current_scene(const bContext *C) if (rj) { return rj->current_scene; } - return NULL; + return nullptr; } /* Motion blur curve preset */ @@ -1186,7 +1194,7 @@ void RENDER_OT_shutter_curve_preset(wmOperatorType *ot) {CURVE_PRESET_LINE, "LINE", 0, "Line", ""}, {CURVE_PRESET_ROUND, "ROUND", 0, "Round", ""}, {CURVE_PRESET_ROOT, "ROOT", 0, "Root", ""}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; ot->name = "Shutter Curve Preset"; diff --git a/source/blender/editors/render/render_opengl.c b/source/blender/editors/render/render_opengl.cc index 1e1a95f2965..8bd0244c899 100644 --- a/source/blender/editors/render/render_opengl.c +++ b/source/blender/editors/render/render_opengl.cc @@ -21,9 +21,9 @@ * \ingroup render */ -#include <math.h> -#include <stddef.h> -#include <string.h> +#include <cmath> +#include <cstddef> +#include <cstring> #include "MEM_guardedalloc.h" @@ -82,7 +82,7 @@ #include "GPU_framebuffer.h" #include "GPU_matrix.h" -#include "render_intern.h" +#include "render_intern.hh" /* Define this to get timing information. */ // #define DEBUG_TIME @@ -92,10 +92,10 @@ #endif /* TODO(sergey): Find better approximation of the scheduled frames. - * For really highres renders it might fail still. */ + * For really high-resolution renders it might fail still. */ #define MAX_SCHEDULED_FRAMES 8 -typedef struct OGLRender { +struct OGLRender { Main *bmain; Render *re; Scene *scene; @@ -141,7 +141,7 @@ typedef struct OGLRender { wmWindowManager *wm; wmWindow *win; - /** Use to check if running modal or not (invoke'd or exec'd). */ + /** Use to check if running modal or not (invoked or executed). */ wmTimer *timer; void **movie_ctx_arr; @@ -159,7 +159,7 @@ typedef struct OGLRender { #ifdef DEBUG_TIME double time_start; #endif -} OGLRender; +}; static bool screen_opengl_is_multiview(OGLRender *oglrender) { @@ -167,12 +167,12 @@ static bool screen_opengl_is_multiview(OGLRender *oglrender) RegionView3D *rv3d = oglrender->rv3d; RenderData *rd = &oglrender->scene->r; - if ((rd == NULL) || ((v3d != NULL) && (rv3d == NULL))) { + if ((rd == nullptr) || ((v3d != nullptr) && (rv3d == nullptr))) { return false; } return (rd->scemode & R_MULTIVIEW) && - ((v3d == NULL) || (rv3d->persp == RV3D_CAMOB && v3d->camera)); + ((v3d == nullptr) || (rv3d->persp == RV3D_CAMOB && v3d->camera)); } static void screen_opengl_views_setup(OGLRender *oglrender) @@ -192,10 +192,10 @@ static void screen_opengl_views_setup(OGLRender *oglrender) if (!is_multiview) { /* we only have one view when multiview is off */ - rv = rr->views.first; + rv = static_cast<RenderView *>(rr->views.first); - if (rv == NULL) { - rv = MEM_callocN(sizeof(RenderView), "new opengl render view"); + if (rv == nullptr) { + rv = MEM_cnew<RenderView>("new opengl render view"); BLI_addtail(&rr->views, rv); } @@ -224,9 +224,10 @@ static void screen_opengl_views_setup(OGLRender *oglrender) } /* remove all the views that are not needed */ - rv = rr->views.last; + rv = static_cast<RenderView *>(rr->views.last); while (rv) { - srv = BLI_findstring(&rd->views, rv->name, offsetof(SceneRenderView, name)); + srv = static_cast<SceneRenderView *>( + BLI_findstring(&rd->views, rv->name, offsetof(SceneRenderView, name))); if (BKE_scene_multiview_is_render_view_active(rd, srv)) { rv = rv->prev; } @@ -253,15 +254,16 @@ static void screen_opengl_views_setup(OGLRender *oglrender) } /* create all the views that are needed */ - for (srv = rd->views.first; srv; srv = srv->next) { + for (srv = static_cast<SceneRenderView *>(rd->views.first); srv; srv = srv->next) { if (BKE_scene_multiview_is_render_view_active(rd, srv) == false) { continue; } - rv = BLI_findstring(&rr->views, srv->name, offsetof(SceneRenderView, name)); + rv = static_cast<RenderView *>( + BLI_findstring(&rr->views, srv->name, offsetof(SceneRenderView, name))); - if (rv == NULL) { - rv = MEM_callocN(sizeof(RenderView), "new opengl render view"); + if (rv == nullptr) { + rv = MEM_cnew<RenderView>("new opengl render view"); BLI_strncpy(rv->name, srv->name, sizeof(rv->name)); BLI_addtail(&rr->views, rv); } @@ -291,19 +293,19 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R ARegion *region = oglrender->region; View3D *v3d = oglrender->v3d; RegionView3D *rv3d = oglrender->rv3d; - Object *camera = NULL; + Object *camera = nullptr; int sizex = oglrender->sizex; int sizey = oglrender->sizey; - const short view_context = (v3d != NULL); + const short view_context = (v3d != nullptr); bool draw_sky = (scene->r.alphamode == R_ADDSKY); - float *rectf = NULL; - uchar *rect = NULL; + float *rectf = nullptr; + uchar *rect = nullptr; const char *viewname = RE_GetActiveRenderView(oglrender->re); - ImBuf *ibuf_result = NULL; + ImBuf *ibuf_result = nullptr; if (oglrender->is_sequencer) { SpaceSeq *sseq = oglrender->sseq; - struct bGPdata *gpd = (sseq && (sseq->flag & SEQ_PREVIEW_SHOW_GPENCIL)) ? sseq->gpd : NULL; + struct bGPdata *gpd = (sseq && (sseq->flag & SEQ_PREVIEW_SHOW_GPENCIL)) ? sseq->gpd : nullptr; /* use pre-calculated ImBuf (avoids deadlock), see: */ ImBuf *ibuf = oglrender->seq_data.ibufs_arr[oglrender->view_id]; @@ -318,7 +320,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R * TODO(sergey): In the case of output to float container (EXR) * it actually makes sense to keep float buffer instead. */ - if (out->rect_float != NULL) { + if (out->rect_float != nullptr) { IMB_rect_from_float(out); imb_freerectfloatImBuf(out); } @@ -352,7 +354,8 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R ED_annotation_draw_ex(scene, gpd, sizex, sizey, scene->r.cfra, SPACE_SEQ); G.f &= ~G_FLAG_RENDER_VIEWPORT; - gp_rect = MEM_mallocN(sizeof(uchar[4]) * sizex * sizey, "offscreen rect"); + gp_rect = static_cast<uchar *>( + MEM_mallocN(sizeof(uchar[4]) * sizex * sizey, "offscreen rect")); GPU_offscreen_read_pixels(oglrender->ofs, GPU_DATA_UBYTE, gp_rect); for (i = 0; i < sizex * sizey * 4; i += 4) { @@ -372,7 +375,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R if (view_context) { ibuf_view = ED_view3d_draw_offscreen_imbuf(depsgraph, scene, - v3d->shading.type, + static_cast<eDrawType>(v3d->shading.type), v3d, region, sizex, @@ -392,7 +395,7 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R else { ibuf_view = ED_view3d_draw_offscreen_imbuf_simple(depsgraph, scene, - NULL, + nullptr, OB_SOLID, scene->camera, oglrender->sizex, @@ -420,9 +423,9 @@ static void screen_opengl_render_doit(const bContext *C, OGLRender *oglrender, R } } - if (ibuf_result != NULL) { + if (ibuf_result != nullptr) { if ((scene->r.stamp & R_STAMP_ALL) && (scene->r.stamp & R_STAMP_DRAW)) { - BKE_image_stamp_buf(scene, camera, NULL, rect, rectf, rr->rectx, rr->recty, 4); + BKE_image_stamp_buf(scene, camera, nullptr, rect, rectf, rr->rectx, rr->recty, 4); } RE_render_result_rect_from_ibuf(rr, &scene->r, ibuf_result, oglrender->view_id); IMB_freeImBuf(ibuf_result); @@ -445,7 +448,7 @@ static void screen_opengl_render_write(OGLRender *oglrender) &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, false, - NULL); + nullptr); /* write images as individual images or stereo */ BKE_render_result_stamp_info(scene, scene->camera, rr, false); @@ -506,7 +509,8 @@ static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender) } rr = RE_AcquireResultRead(oglrender->re); - for (rv = rr->views.first, view_id = 0; rv; rv = rv->next, view_id++) { + for (rv = static_cast<RenderView *>(rr->views.first), view_id = 0; rv; + rv = rv->next, view_id++) { BLI_assert(view_id < oglrender->views_len); RE_SetActiveRenderView(oglrender->re, rv->name); oglrender->view_id = view_id; @@ -530,7 +534,7 @@ static void screen_opengl_render_apply(const bContext *C, OGLRender *oglrender) static void gather_frames_to_render_for_adt(const OGLRender *oglrender, const AnimData *adt) { - if (adt == NULL || adt->action == NULL) { + if (adt == nullptr || adt->action == nullptr) { return; } @@ -539,7 +543,7 @@ static void gather_frames_to_render_for_adt(const OGLRender *oglrender, const An int frame_end = PEFRA; LISTBASE_FOREACH (FCurve *, fcu, &adt->action->curves) { - if (fcu->driver != NULL || fcu->fpt != NULL) { + if (fcu->driver != nullptr || fcu->fpt != nullptr) { /* Drivers have values for any point in time, so to get "the keyed frames" they are * useless. Same for baked FCurves, they also have keys for every frame, which is not * useful for rendering the keyed subset of the frames. */ @@ -568,7 +572,7 @@ static void gather_frames_to_render_for_adt(const OGLRender *oglrender, const An static void gather_frames_to_render_for_grease_pencil(const OGLRender *oglrender, const bGPdata *gp) { - if (gp == NULL) { + if (gp == nullptr) { return; } @@ -589,7 +593,7 @@ static void gather_frames_to_render_for_grease_pencil(const OGLRender *oglrender static int gather_frames_to_render_for_id(LibraryIDLinkCallbackData *cb_data) { ID **id_p = cb_data->id_pointer; - if (*id_p == NULL) { + if (*id_p == nullptr) { return IDWALK_RET_NOP; } ID *id = *id_p; @@ -602,7 +606,7 @@ static int gather_frames_to_render_for_id(LibraryIDLinkCallbackData *cb_data) return IDWALK_RET_STOP_RECURSION; } - OGLRender *oglrender = cb_data->user_data; + OGLRender *oglrender = static_cast<OGLRender *>(cb_data->user_data); /* Whitelist of datablocks to follow pointers into. */ const ID_Type id_type = GS(id->name); @@ -699,7 +703,7 @@ static void gather_frames_to_render(bContext *C, OGLRender *oglrender) /* Gather the frames from linked data-blocks (materials, shape-keys, etc.). */ BKE_library_foreach_ID_link( - NULL, id, gather_frames_to_render_for_id, oglrender, IDWALK_RECURSE); + nullptr, id, gather_frames_to_render_for_id, oglrender, IDWALK_RECURSE); } CTX_DATA_END; } @@ -722,8 +726,8 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) const bool is_render_keyed_only = RNA_boolean_get(op->ptr, "render_keyed_only"); const bool is_sequencer = RNA_boolean_get(op->ptr, "sequencer"); const bool is_write_still = RNA_boolean_get(op->ptr, "write_still"); - const eImageFormatDepth color_depth = (is_animation) ? scene->r.im_format.depth : - R_IMF_CHAN_DEPTH_32; + const eImageFormatDepth color_depth = static_cast<eImageFormatDepth>( + (is_animation) ? (eImageFormatDepth)scene->r.im_format.depth : R_IMF_CHAN_DEPTH_32); char err_out[256] = "unknown"; if (G.background) { @@ -747,7 +751,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) is_view_context = false; } - if (!is_view_context && scene->camera == NULL) { + if (!is_view_context && scene->camera == nullptr) { BKE_report(op->reports, RPT_ERROR, "Scene has no camera"); return false; } @@ -777,7 +781,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) } /* allocate opengl render */ - oglrender = MEM_callocN(sizeof(OGLRender), "OGLRender"); + oglrender = MEM_new<OGLRender>("OGLRender"); op->customdata = oglrender; oglrender->ofs = ofs; @@ -801,7 +805,8 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) oglrender->is_sequencer = is_sequencer; if (is_sequencer) { oglrender->sseq = CTX_wm_space_seq(C); - ImBuf **ibufs_arr = MEM_callocN(sizeof(*ibufs_arr) * oglrender->views_len, __func__); + ImBuf **ibufs_arr = static_cast<ImBuf **>( + MEM_callocN(sizeof(*ibufs_arr) * oglrender->views_len, __func__)); oglrender->seq_data.ibufs_arr = ibufs_arr; } @@ -812,7 +817,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) /* so quad view renders camera */ ED_view3d_context_user_region(C, &oglrender->v3d, &oglrender->region); - oglrender->rv3d = oglrender->region->regiondata; + oglrender->rv3d = static_cast<RegionView3D *>(oglrender->region->regiondata); /* MUST be cleared on exit */ memset(&oglrender->scene->customdata_mask_modal, @@ -832,13 +837,14 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) /* create image and image user */ oglrender->ima = BKE_image_ensure_viewer(oglrender->bmain, IMA_TYPE_R_RESULT, "Render Result"); - BKE_image_signal(oglrender->bmain, oglrender->ima, NULL, IMA_SIGNAL_FREE); + BKE_image_signal(oglrender->bmain, oglrender->ima, nullptr, IMA_SIGNAL_FREE); BKE_image_backup_render(oglrender->scene, oglrender->ima, true); oglrender->iuser.scene = scene; /* create render result */ - RE_InitState(oglrender->re, NULL, &scene->r, &scene->view_layers, NULL, sizex, sizey, NULL); + RE_InitState( + oglrender->re, nullptr, &scene->r, &scene->view_layers, nullptr, sizex, sizey, nullptr); /* create render views */ screen_opengl_views_setup(oglrender); @@ -848,8 +854,8 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) oglrender->win = win; oglrender->totvideos = 0; - oglrender->mh = NULL; - oglrender->movie_ctx_arr = NULL; + oglrender->mh = nullptr; + oglrender->movie_ctx_arr = nullptr; if (is_animation) { if (is_render_keyed_only) { @@ -866,7 +872,7 @@ static bool screen_opengl_render_init(bContext *C, wmOperator *op) BLI_spin_init(&oglrender->reports_lock); } else { - oglrender->task_pool = NULL; + oglrender->task_pool = nullptr; } oglrender->num_scheduled_frames = 0; BLI_mutex_init(&oglrender->task_mutex); @@ -954,12 +960,12 @@ static void screen_opengl_render_end(bContext *C, OGLRender *oglrender) CTX_wm_area_set(C, oglrender->prevsa); CTX_wm_region_set(C, oglrender->prevar); - MEM_freeN(oglrender); + MEM_delete(oglrender); } static void screen_opengl_render_cancel(bContext *C, wmOperator *op) { - screen_opengl_render_end(C, op->customdata); + screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata)); } /* share between invoke and exec */ @@ -969,7 +975,7 @@ static bool screen_opengl_render_anim_init(bContext *C, wmOperator *op) OGLRender *oglrender; Scene *scene; - oglrender = op->customdata; + oglrender = static_cast<OGLRender *>(op->customdata); scene = oglrender->scene; oglrender->totvideos = BKE_scene_multiview_num_videos_get(&scene->r); @@ -983,13 +989,14 @@ static bool screen_opengl_render_anim_init(bContext *C, wmOperator *op) &scene->r, oglrender->sizex, oglrender->sizey, &width, &height); oglrender->mh = BKE_movie_handle_get(scene->r.im_format.imtype); - if (oglrender->mh == NULL) { + if (oglrender->mh == nullptr) { BKE_report(oglrender->reports, RPT_ERROR, "Movie format unsupported"); screen_opengl_render_end(C, oglrender); return false; } - oglrender->movie_ctx_arr = MEM_mallocN(sizeof(void *) * oglrender->totvideos, "Movies"); + oglrender->movie_ctx_arr = static_cast<void **>( + MEM_mallocN(sizeof(void *) * oglrender->totvideos, "Movies")); for (i = 0; i < oglrender->totvideos; i++) { Scene *scene_eval = DEG_get_evaluated_scene(oglrender->depsgraph); @@ -1017,10 +1024,10 @@ static bool screen_opengl_render_anim_init(bContext *C, wmOperator *op) return true; } -typedef struct WriteTaskData { +struct WriteTaskData { RenderResult *rr; Scene tmp_scene; -} WriteTaskData; +}; static void write_result_func(TaskPool *__restrict pool, void *task_data_v) { @@ -1073,18 +1080,19 @@ static void write_result_func(TaskPool *__restrict pool, void *task_data_v) &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, - NULL); + nullptr); BKE_render_result_stamp_info(scene, scene->camera, rr, false); - ok = RE_WriteRenderViewsImage(NULL, rr, scene, true, name); + ok = RE_WriteRenderViewsImage(nullptr, rr, scene, true, name); if (!ok) { BKE_reportf(&reports, RPT_ERROR, "Write error: cannot save %s", name); } } - if (reports.list.first != NULL) { + if (reports.list.first != nullptr) { BLI_spin_lock(&oglrender->reports_lock); - for (Report *report = reports.list.first; report != NULL; report = report->next) { - BKE_report(oglrender->reports, report->type, report->message); + for (Report *report = static_cast<Report *>(reports.list.first); report != nullptr; + report = report->next) { + BKE_report(oglrender->reports, static_cast<eReportType>(report->type), report->message); } BLI_spin_unlock(&oglrender->reports_lock); } @@ -1105,27 +1113,27 @@ static bool schedule_write_result(OGLRender *oglrender, RenderResult *rr) return false; } Scene *scene = oglrender->scene; - WriteTaskData *task_data = MEM_mallocN(sizeof(WriteTaskData), "write task data"); + WriteTaskData *task_data = MEM_new<WriteTaskData>("write task data"); task_data->rr = rr; - task_data->tmp_scene = *scene; + memcpy(&task_data->tmp_scene, scene, sizeof(task_data->tmp_scene)); BLI_mutex_lock(&oglrender->task_mutex); oglrender->num_scheduled_frames++; if (oglrender->num_scheduled_frames > MAX_SCHEDULED_FRAMES) { BLI_condition_wait(&oglrender->task_condition, &oglrender->task_mutex); } BLI_mutex_unlock(&oglrender->task_mutex); - BLI_task_pool_push(oglrender->task_pool, write_result_func, task_data, true, NULL); + BLI_task_pool_push(oglrender->task_pool, write_result_func, task_data, true, nullptr); return true; } static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op) { - OGLRender *oglrender = op->customdata; + OGLRender *oglrender = static_cast<OGLRender *>(op->customdata); Scene *scene = oglrender->scene; Depsgraph *depsgraph = oglrender->depsgraph; char name[FILE_MAX]; bool ok = false; - const bool view_context = (oglrender->v3d != NULL); + const bool view_context = (oglrender->v3d != nullptr); bool is_movie; RenderResult *rr; @@ -1148,7 +1156,7 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op) &scene->r.im_format, (scene->r.scemode & R_EXTENSION) != 0, true, - NULL); + nullptr); if ((scene->r.mode & R_NO_OVERWRITE) && BLI_exists(name)) { BLI_spin_lock(&oglrender->reports_lock); @@ -1177,7 +1185,7 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op) BKE_scene_camera_switch_update(scene); } - if (oglrender->render_frames == NULL || + if (oglrender->render_frames == nullptr || BLI_BITMAP_TEST_BOOL(oglrender->render_frames, CFRA - PSFRA)) { /* render into offscreen buffer */ screen_opengl_render_apply(C, oglrender); @@ -1185,10 +1193,12 @@ static bool screen_opengl_render_anim_step(bContext *C, wmOperator *op) /* save to disk */ rr = RE_AcquireResultRead(oglrender->re); - RenderResult *new_rr = RE_DuplicateRenderResult(rr); - RE_ReleaseResult(oglrender->re); + { + RenderResult *new_rr = RE_DuplicateRenderResult(rr); + RE_ReleaseResult(oglrender->re); - ok = schedule_write_result(oglrender, new_rr); + ok = schedule_write_result(oglrender, new_rr); + } finally: /* Step the frame and bail early if needed */ @@ -1197,16 +1207,16 @@ finally: /* Step the frame and bail early if needed */ /* stop at the end or on error */ if (CFRA >= PEFRA || !ok) { - screen_opengl_render_end(C, op->customdata); - return 0; + screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata)); + return false; } - return 1; + return true; } static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent *event) { - OGLRender *oglrender = op->customdata; + OGLRender *oglrender = static_cast<OGLRender *>(op->customdata); const bool anim = RNA_boolean_get(op->ptr, "animation"); bool ret; @@ -1214,7 +1224,7 @@ static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent case EVT_ESCKEY: /* cancel */ oglrender->pool_ok = false; /* Flag pool for cancel. */ - screen_opengl_render_end(C, op->customdata); + screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata)); return OPERATOR_FINISHED; case TIMER: /* render frame? */ @@ -1231,8 +1241,8 @@ static int screen_opengl_render_modal(bContext *C, wmOperator *op, const wmEvent WM_event_add_notifier(C, NC_SCENE | ND_RENDER_RESULT, oglrender->scene); if (anim == 0) { - screen_opengl_render_apply(C, op->customdata); - screen_opengl_render_end(C, op->customdata); + screen_opengl_render_apply(C, static_cast<OGLRender *>(op->customdata)); + screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata)); return OPERATOR_FINISHED; } @@ -1261,7 +1271,7 @@ static int screen_opengl_render_invoke(bContext *C, wmOperator *op, const wmEven } } - oglrender = op->customdata; + oglrender = static_cast<OGLRender *>(op->customdata); render_view_open(C, event->xy[0], event->xy[1], op->reports); /* View may be changed above #USER_RENDER_DISPLAY_WINDOW. */ @@ -1284,8 +1294,8 @@ static int screen_opengl_render_exec(bContext *C, wmOperator *op) if (!is_animation) { /* same as invoke */ /* render image */ - screen_opengl_render_apply(C, op->customdata); - screen_opengl_render_end(C, op->customdata); + screen_opengl_render_apply(C, static_cast<OGLRender *>(op->customdata)); + screen_opengl_render_end(C, static_cast<OGLRender *>(op->customdata)); return OPERATOR_FINISHED; } @@ -1312,7 +1322,7 @@ static char *screen_opengl_render_description(struct bContext *UNUSED(C), struct PointerRNA *ptr) { if (!RNA_boolean_get(ptr, "animation")) { - return NULL; + return nullptr; } if (RNA_boolean_get(ptr, "render_keyed_only")) { @@ -1344,32 +1354,32 @@ void RENDER_OT_opengl(wmOperatorType *ot) prop = RNA_def_boolean(ot->srna, "animation", - 0, + false, "Animation", "Render files from the animation range of this scene"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); prop = RNA_def_boolean(ot->srna, "render_keyed_only", - 0, + false, "Render Keyframes Only", "Render only those frames where selected objects have a key in their " "animation data. Only used when rendering animation"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); prop = RNA_def_boolean( - ot->srna, "sequencer", 0, "Sequencer", "Render using the sequencer's OpenGL display"); + ot->srna, "sequencer", false, "Sequencer", "Render using the sequencer's OpenGL display"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); prop = RNA_def_boolean( ot->srna, "write_still", - 0, + false, "Write Image", "Save rendered the image to the output path (used only when animation is disabled)"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); prop = RNA_def_boolean(ot->srna, "view_context", - 1, + true, "View Context", "Use the current 3D view for rendering, else use scene settings"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); diff --git a/source/blender/editors/render/render_ops.c b/source/blender/editors/render/render_ops.cc index e0aa02b354d..0f10d186e6e 100644 --- a/source/blender/editors/render/render_ops.c +++ b/source/blender/editors/render/render_ops.cc @@ -21,7 +21,7 @@ * \ingroup edrend */ -#include <stdlib.h> +#include <cstdlib> #include "BLI_utildefines.h" @@ -29,11 +29,11 @@ #include "WM_api.h" -#include "render_intern.h" /* own include */ +#include "render_intern.hh" /* own include */ /***************************** render ***********************************/ -void ED_operatortypes_render(void) +void ED_operatortypes_render() { WM_operatortype_append(OBJECT_OT_material_slot_add); WM_operatortype_append(OBJECT_OT_material_slot_remove); diff --git a/source/blender/editors/render/render_preview.c b/source/blender/editors/render/render_preview.cc index e1121aa4b1e..79c3b2f7ac6 100644 --- a/source/blender/editors/render/render_preview.c +++ b/source/blender/editors/render/render_preview.cc @@ -23,9 +23,9 @@ /* global includes */ -#include <math.h> -#include <stdlib.h> -#include <string.h> +#include <cmath> +#include <cstdlib> +#include <cstring> #ifndef WIN32 # include <unistd.h> @@ -116,7 +116,7 @@ static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect); /** \name Local Structs * \{ */ -typedef struct ShaderPreview { +struct ShaderPreview { /* from wmJob */ void *owner; short *stop, *do_update; @@ -137,31 +137,32 @@ typedef struct ShaderPreview { int sizex, sizey; uint *pr_rect; - int pr_method; + ePreviewRenderMethod pr_method; bool own_id_copy; Main *bmain; Main *pr_main; -} ShaderPreview; +}; -typedef struct IconPreviewSize { +struct IconPreviewSize { struct IconPreviewSize *next, *prev; int sizex, sizey; uint *rect; -} IconPreviewSize; +}; -typedef struct IconPreview { +struct IconPreview { Main *bmain; - Depsgraph *depsgraph; /* May be NULL (see #WM_OT_previews_ensure). */ + Depsgraph *depsgraph; /* May be nullptr (see #WM_OT_previews_ensure). */ Scene *scene; void *owner; - ID *id, *id_copy; /* May be NULL! (see ICON_TYPE_PREVIEW case in #ui_icon_ensure_deferred()) */ + ID *id, + *id_copy; /* May be nullptr! (see ICON_TYPE_PREVIEW case in #ui_icon_ensure_deferred()) */ ListBase sizes; - /* May be NULL, is used for rendering IDs that require some other object for it to be applied on - * before the ID can be represented as an image, for example when rendering an Action. */ + /* May be nullptr, is used for rendering IDs that require some other object for it to be applied + * on before the ID can be represented as an image, for example when rendering an Action. */ struct Object *active_object; -} IconPreview; +}; /** \} */ @@ -169,18 +170,18 @@ typedef struct IconPreview { /** \name Preview for Buttons * \{ */ -static Main *G_pr_main = NULL; -static Main *G_pr_main_grease_pencil = NULL; +static Main *G_pr_main = nullptr; +static Main *G_pr_main_grease_pencil = nullptr; #ifndef WITH_HEADLESS static Main *load_main_from_memory(const void *blend, int blend_size) { const int fileflags = G.fileflags; - Main *bmain = NULL; + Main *bmain = nullptr; BlendFileData *bfd; G.fileflags |= G_FILE_NO_UI; - bfd = BLO_read_from_memory(blend, blend_size, BLO_READ_SKIP_NONE, NULL); + bfd = BLO_read_from_memory(blend, blend_size, BLO_READ_SKIP_NONE, nullptr); if (bfd) { bmain = bfd->main; @@ -192,7 +193,7 @@ static Main *load_main_from_memory(const void *blend, int blend_size) } #endif -void ED_preview_ensure_dbase(void) +void ED_preview_ensure_dbase() { #ifndef WITH_HEADLESS static bool base_initialized = false; @@ -212,12 +213,12 @@ static bool check_engine_supports_preview(Scene *scene) return (type->flag & RE_USE_PREVIEW) != 0; } -static bool preview_method_is_render(int pr_method) +static bool preview_method_is_render(const ePreviewRenderMethod pr_method) { - return ELEM(pr_method, PR_ICON_RENDER, PR_BUTS_RENDER, PR_NODE_RENDER); + return ELEM(pr_method, PR_ICON_RENDER, PR_BUTS_RENDER); } -void ED_preview_free_dbase(void) +void ED_preview_free_dbase() { if (G_pr_main) { BKE_main_free(G_pr_main); @@ -230,11 +231,11 @@ void ED_preview_free_dbase(void) static Scene *preview_get_scene(Main *pr_main) { - if (pr_main == NULL) { - return NULL; + if (pr_main == nullptr) { + return nullptr; } - return pr_main->scenes.first; + return static_cast<Scene *>(pr_main->scenes.first); } static const char *preview_collection_name(const ePreviewType pr_type) @@ -276,10 +277,10 @@ static bool render_engine_supports_ray_visibility(const Scene *sce) static void switch_preview_collection_visibilty(ViewLayer *view_layer, const ePreviewType pr_type) { /* Set appropriate layer as visible. */ - LayerCollection *lc = view_layer->layer_collections.first; + LayerCollection *lc = static_cast<LayerCollection *>(view_layer->layer_collections.first); const char *collection_name = preview_collection_name(pr_type); - for (lc = lc->layer_collections.first; lc; lc = lc->next) { + for (lc = static_cast<LayerCollection *>(lc->layer_collections.first); lc; lc = lc->next) { if (STREQ(lc->collection->id.name + 2, collection_name)) { lc->collection->flag &= ~COLLECTION_HIDE_RENDER; } @@ -308,7 +309,8 @@ static void switch_preview_floor_material(Main *pr_main, } const char *material_name = preview_floor_material_name(scene, pr_method); - Material *mat = BLI_findstring(&pr_main->materials, material_name, offsetof(ID, name) + 2); + Material *mat = static_cast<Material *>( + BLI_findstring(&pr_main->materials, material_name, offsetof(ID, name) + 2)); if (mat) { me->mat[0] = mat; } @@ -329,7 +331,8 @@ static void switch_preview_floor_visibility(Main *pr_main, } } if (base->object->type == OB_MESH) { - switch_preview_floor_material(pr_main, base->object->data, scene, pr_method); + switch_preview_floor_material( + pr_main, static_cast<Mesh *>(base->object->data), scene, pr_method); } } } @@ -348,16 +351,16 @@ static void set_preview_visibility(Main *pr_main, static World *preview_get_localized_world(ShaderPreview *sp, World *world) { - if (world == NULL) { - return NULL; + if (world == nullptr) { + return nullptr; } - if (sp->worldcopy != NULL) { + if (sp->worldcopy != nullptr) { return sp->worldcopy; } - ID *id_copy = BKE_id_copy_ex(NULL, + ID *id_copy = BKE_id_copy_ex(nullptr, &world->id, - NULL, + nullptr, LIB_ID_CREATE_LOCAL | LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA); sp->worldcopy = (World *)id_copy; @@ -367,9 +370,9 @@ static World *preview_get_localized_world(ShaderPreview *sp, World *world) static ID *duplicate_ids(ID *id, const bool allow_failure) { - if (id == NULL) { + if (id == nullptr) { /* Non-ID preview render. */ - return NULL; + return nullptr; } switch (GS(id->name)) { @@ -379,20 +382,23 @@ static ID *duplicate_ids(ID *id, const bool allow_failure) case ID_LA: case ID_WO: { BLI_assert(BKE_previewimg_id_supports_jobs(id)); - ID *id_copy = BKE_id_copy_ex( - NULL, id, NULL, LIB_ID_CREATE_LOCAL | LIB_ID_COPY_LOCALIZE | LIB_ID_COPY_NO_ANIMDATA); + ID *id_copy = BKE_id_copy_ex(nullptr, + id, + nullptr, + LIB_ID_CREATE_LOCAL | LIB_ID_COPY_LOCALIZE | + LIB_ID_COPY_NO_ANIMDATA); return id_copy; } /* These support threading, but don't need duplicating. */ case ID_IM: case ID_BR: BLI_assert(BKE_previewimg_id_supports_jobs(id)); - return NULL; + return nullptr; default: if (!allow_failure) { BLI_assert_msg(0, "ID type preview not supported."); } - return NULL; + return nullptr; } } @@ -404,8 +410,8 @@ static const char *preview_world_name(const Scene *sce, * material trick to show the floor in the reflections, but hide the floor for camera rays. For * Eevee we use a transparent world that has a projected grid. * - * In the future when Eevee supports vulkan raytracing we can re-evaluate and perhaps remove this - * approximation. + * In the future when Eevee supports VULKAN ray-tracing we can re-evaluate and perhaps remove + * this approximation. */ if (id_type == ID_MA && pr_method == PR_ICON_RENDER && !render_engine_supports_ray_visibility(sce)) { @@ -419,13 +425,14 @@ static World *preview_get_world(Main *pr_main, const ID_Type id_type, const ePreviewRenderMethod pr_method) { - World *result = NULL; + World *result = nullptr; const char *world_name = preview_world_name(sce, id_type, pr_method); - result = BLI_findstring(&pr_main->worlds, world_name, offsetof(ID, name) + 2); + result = static_cast<World *>( + BLI_findstring(&pr_main->worlds, world_name, offsetof(ID, name) + 2)); /* No world found return first world. */ - if (result == NULL) { - result = pr_main->worlds.first; + if (result == nullptr) { + result = static_cast<World *>(pr_main->worlds.first); } BLI_assert_msg(result, "Preview file has no world."); @@ -454,7 +461,7 @@ static World *preview_prepare_world(Main *pr_main, } /* call this with a pointer to initialize preview scene */ -/* call this with NULL to restore assigned ID pointers in preview scene */ +/* call this with nullptr to restore assigned ID pointers in preview scene */ static Scene *preview_prepare_scene( Main *bmain, Scene *scene, ID *id, int id_type, ShaderPreview *sp) { @@ -465,7 +472,7 @@ static Scene *preview_prepare_scene( sce = preview_get_scene(pr_main); if (sce) { - ViewLayer *view_layer = sce->view_layers.first; + ViewLayer *view_layer = static_cast<ViewLayer *>(sce->view_layers.first); /* Only enable the combined renderpass */ view_layer->passflag = SCE_PASS_COMBINED; @@ -491,7 +498,8 @@ static Scene *preview_prepare_scene( sce->r.cfra = scene->r.cfra; /* Setup the world. */ - sce->world = preview_prepare_world(pr_main, sce, scene->world, id_type, sp->pr_method); + sce->world = preview_prepare_world( + pr_main, sce, scene->world, static_cast<ID_Type>(id_type), sp->pr_method); if (id_type == ID_TE) { /* Texture is not actually rendered with engine, just set dummy value. */ @@ -499,13 +507,13 @@ static Scene *preview_prepare_scene( } if (id_type == ID_MA) { - Material *mat = NULL, *origmat = (Material *)id; + Material *mat = nullptr, *origmat = (Material *)id; if (origmat) { /* work on a copy */ - BLI_assert(sp->id_copy != NULL); + BLI_assert(sp->id_copy != nullptr); mat = sp->matcopy = (Material *)sp->id_copy; - sp->id_copy = NULL; + sp->id_copy = nullptr; BLI_addtail(&pr_main->materials, mat); /* Use current scene world for lighting. */ @@ -523,20 +531,11 @@ static Scene *preview_prepare_scene( } /* For grease pencil, always use sphere for icon renders. */ - const ePreviewType preview_type = (sp->pr_method == PR_ICON_RENDER && - sp->pr_main == G_pr_main_grease_pencil) ? - MA_SPHERE_A : - mat->pr_type; + const ePreviewType preview_type = static_cast<ePreviewType>( + (sp->pr_method == PR_ICON_RENDER && sp->pr_main == G_pr_main_grease_pencil) ? + MA_SPHERE_A : + (ePreviewType)mat->pr_type); set_preview_visibility(pr_main, sce, view_layer, preview_type, sp->pr_method); - - if (sp->pr_method != PR_ICON_RENDER) { - if (mat->nodetree && sp->pr_method == PR_NODE_RENDER) { - /* two previews, they get copied by wmJob */ - BKE_node_preview_init_tree(mat->nodetree, sp->sizex, sp->sizey, true); - /* WATCH: Accessing origmat is not safe! */ - BKE_node_preview_init_tree(origmat->nodetree, sp->sizex, sp->sizey, true); - } - } } else { sce->display.render_aa = SCE_DISPLAY_AA_OFF; @@ -564,30 +563,23 @@ static Scene *preview_prepare_scene( } } else if (id_type == ID_TE) { - Tex *tex = NULL, *origtex = (Tex *)id; + Tex *tex = nullptr, *origtex = (Tex *)id; if (origtex) { - BLI_assert(sp->id_copy != NULL); + BLI_assert(sp->id_copy != nullptr); tex = sp->texcopy = (Tex *)sp->id_copy; - sp->id_copy = NULL; + sp->id_copy = nullptr; BLI_addtail(&pr_main->textures, tex); } - - if (tex && tex->nodetree && sp->pr_method == PR_NODE_RENDER) { - /* two previews, they get copied by wmJob */ - BKE_node_preview_init_tree(tex->nodetree, sp->sizex, sp->sizey, true); - /* WATCH: Accessing origtex is not safe! */ - BKE_node_preview_init_tree(origtex->nodetree, sp->sizex, sp->sizey, true); - } } else if (id_type == ID_LA) { - Light *la = NULL, *origla = (Light *)id; + Light *la = nullptr, *origla = (Light *)id; /* work on a copy */ if (origla) { - BLI_assert(sp->id_copy != NULL); + BLI_assert(sp->id_copy != nullptr); la = sp->lampcopy = (Light *)sp->id_copy; - sp->id_copy = NULL; + sp->id_copy = nullptr; BLI_addtail(&pr_main->lights, la); } @@ -608,39 +600,25 @@ static Scene *preview_prepare_scene( } } } - - if (la && la->nodetree && sp->pr_method == PR_NODE_RENDER) { - /* two previews, they get copied by wmJob */ - BKE_node_preview_init_tree(la->nodetree, sp->sizex, sp->sizey, true); - /* WATCH: Accessing origla is not safe! */ - BKE_node_preview_init_tree(origla->nodetree, sp->sizex, sp->sizey, true); - } } else if (id_type == ID_WO) { - World *wrld = NULL, *origwrld = (World *)id; + World *wrld = nullptr, *origwrld = (World *)id; if (origwrld) { - BLI_assert(sp->id_copy != NULL); + BLI_assert(sp->id_copy != nullptr); wrld = sp->worldcopy = (World *)sp->id_copy; - sp->id_copy = NULL; + sp->id_copy = nullptr; BLI_addtail(&pr_main->worlds, wrld); } set_preview_visibility(pr_main, sce, view_layer, MA_SKY, sp->pr_method); sce->world = wrld; - - if (wrld && wrld->nodetree && sp->pr_method == PR_NODE_RENDER) { - /* two previews, they get copied by wmJob */ - BKE_node_preview_init_tree(wrld->nodetree, sp->sizex, sp->sizey, true); - /* WATCH: Accessing origwrld is not safe! */ - BKE_node_preview_init_tree(origwrld->nodetree, sp->sizex, sp->sizey, true); - } } return sce; } - return NULL; + return nullptr; } /* new UI convention: draw is in pixel space already. */ @@ -677,7 +655,7 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect /* test if something rendered ok */ re = RE_GetRender(name); - if (re == NULL) { + if (re == nullptr) { return false; } @@ -689,7 +667,7 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect } else { /* possible the job clears the views but we're still drawing T45496 */ - rv = NULL; + rv = nullptr; } if (rv && rv->rectf) { @@ -700,8 +678,8 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect newrect->ymax = max_ii(newrect->ymax, rect->ymin + rres.recty); if (rres.rectx && rres.recty) { - uchar *rect_byte = MEM_mallocN(rres.rectx * rres.recty * sizeof(int), - "ed_preview_draw_rect"); + uchar *rect_byte = static_cast<uchar *>( + MEM_mallocN(rres.rectx * rres.recty * sizeof(int), "ed_preview_draw_rect")); float fx = rect->xmin + offx; float fy = rect->ymin; @@ -709,12 +687,21 @@ static bool ed_preview_draw_rect(ScrArea *area, int split, int first, rcti *rect RE_AcquiredResultGet32(re, &rres, (uint *)rect_byte, 0); IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); - immDrawPixelsTex( - &state, fx, fy, rres.rectx, rres.recty, GPU_RGBA8, false, rect_byte, 1.0f, 1.0f, NULL); + immDrawPixelsTexTiled(&state, + fx, + fy, + rres.rectx, + rres.recty, + GPU_RGBA8, + false, + rect_byte, + 1.0f, + 1.0f, + nullptr); MEM_freeN(rect_byte); - ok = 1; + ok = true; } } } @@ -733,9 +720,9 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r ID *parent = (ID *)parentp; MTex *slot = (MTex *)slotp; SpaceProperties *sbuts = CTX_wm_space_properties(C); - ShaderPreview *sp = WM_jobs_customdata(wm, area); + ShaderPreview *sp = static_cast<ShaderPreview *>(WM_jobs_customdata(wm, area)); rcti newrect; - int ok; + bool ok; int newx = BLI_rcti_size_x(rect); int newy = BLI_rcti_size_y(rect); @@ -759,10 +746,10 @@ void ED_preview_draw(const bContext *C, void *idp, void *parentp, void *slotp, r /* start a new preview render job if signaled through sbuts->preview, * if no render result was found and no preview render job is running, * or if the job is running and the size of preview changed */ - if ((sbuts != NULL && sbuts->preview) || + if ((sbuts != nullptr && sbuts->preview) || (!ok && !WM_jobs_test(wm, area, WM_JOB_TYPE_RENDER_PREVIEW)) || (sp && (abs(sp->sizex - newx) >= 2 || abs(sp->sizey - newy) > 2))) { - if (sbuts != NULL) { + if (sbuts != nullptr) { sbuts->preview = 0; } ED_preview_shader_job(C, area, id, parent, slot, newx, newy, PR_BUTS_RENDER); @@ -826,11 +813,11 @@ static Scene *object_preview_scene_create(const struct ObjectPreviewData *previe * viewport displays. */ CFRA = preview_data->cfra; - ViewLayer *view_layer = scene->view_layers.first; + ViewLayer *view_layer = static_cast<ViewLayer *>(scene->view_layers.first); Depsgraph *depsgraph = DEG_graph_new( preview_data->pr_main, scene, view_layer, DAG_EVAL_VIEWPORT); - BLI_assert(preview_data->object != NULL); + BLI_assert(preview_data->object != nullptr); BLI_addtail(&preview_data->pr_main->objects, preview_data->object); BKE_collection_object_add(preview_data->pr_main, scene->master_collection, preview_data->object); @@ -861,26 +848,23 @@ static Scene *object_preview_scene_create(const struct ObjectPreviewData *previe static void object_preview_render(IconPreview *preview, IconPreviewSize *preview_sized) { Main *preview_main = BKE_main_new(); - const float pixelsize_old = U.pixelsize; char err_out[256] = "unknown"; BLI_assert(preview->id_copy && (preview->id_copy != preview->id)); - struct ObjectPreviewData preview_data = { - .pr_main = preview_main, - /* Act on a copy. */ - .object = (Object *)preview->id_copy, - .cfra = preview->scene->r.cfra, - .sizex = preview_sized->sizex, - .sizey = preview_sized->sizey, - }; + struct ObjectPreviewData preview_data = {}; + preview_data.pr_main = preview_main; + /* Act on a copy. */ + preview_data.object = (Object *)preview->id_copy; + preview_data.cfra = preview->scene->r.cfra; + preview_data.sizex = preview_sized->sizex; + preview_data.sizey = preview_sized->sizey; + Depsgraph *depsgraph; Scene *scene = object_preview_scene_create(&preview_data, &depsgraph); /* Ownership is now ours. */ - preview->id_copy = NULL; - - U.pixelsize = 2.0f; + preview->id_copy = nullptr; View3DShading shading; BKE_screen_view3d_shading_init(&shading); @@ -898,13 +882,11 @@ static void object_preview_render(IconPreview *preview, IconPreviewSize *preview IB_rect, V3D_OFSDRAW_OVERRIDE_SCENE_SETTINGS, R_ALPHAPREMUL, - NULL, - NULL, + nullptr, + nullptr, err_out); /* TODO: color-management? */ - U.pixelsize = pixelsize_old; - if (ibuf) { icon_copy_rect(ibuf, preview_sized->sizex, preview_sized->sizey, preview_sized->rect); IMB_freeImBuf(ibuf); @@ -923,15 +905,15 @@ static void object_preview_render(IconPreview *preview, IconPreviewSize *preview static struct PoseBackup *action_preview_render_prepare(IconPreview *preview) { Object *object = preview->active_object; - if (object == NULL) { + if (object == nullptr) { WM_report(RPT_WARNING, "No active object, unable to apply the Action before rendering"); - return NULL; + return nullptr; } - if (object->pose == NULL) { + if (object->pose == nullptr) { WM_reportf(RPT_WARNING, "Object %s has no pose, unable to apply the Action before rendering", object->id.name + 2); - return NULL; + return nullptr; } /* Create a backup of the current pose. */ @@ -952,7 +934,7 @@ static struct PoseBackup *action_preview_render_prepare(IconPreview *preview) static void action_preview_render_cleanup(IconPreview *preview, struct PoseBackup *pose_backup) { - if (pose_backup == NULL) { + if (pose_backup == nullptr) { return; } ED_pose_backup_restore(pose_backup); @@ -972,7 +954,7 @@ static void action_preview_render(IconPreview *preview, IconPreviewSize *preview /* Not all code paths that lead to this function actually provide a depsgraph. * The "Refresh Asset Preview" button (ED_OT_lib_id_generate_preview) does, * but WM_OT_previews_ensure does not. */ - BLI_assert(depsgraph != NULL); + BLI_assert(depsgraph != nullptr); BLI_assert(preview->scene == DEG_get_input_scene(depsgraph)); /* Apply the pose before getting the evaluated scene, so that the new pose is evaluated. */ @@ -980,7 +962,7 @@ static void action_preview_render(IconPreview *preview, IconPreviewSize *preview Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); Object *camera_eval = scene_eval->camera; - if (camera_eval == NULL) { + if (camera_eval == nullptr) { printf("Scene has no camera, unable to render preview of %s without it.\n", preview->id->name + 2); return; @@ -989,7 +971,7 @@ static void action_preview_render(IconPreview *preview, IconPreviewSize *preview /* This renders with the Workbench engine settings stored on the Scene. */ ImBuf *ibuf = ED_view3d_draw_offscreen_imbuf_simple(depsgraph, scene_eval, - NULL, + nullptr, OB_SOLID, camera_eval, preview_sized->sizex, @@ -997,8 +979,8 @@ static void action_preview_render(IconPreview *preview, IconPreviewSize *preview IB_rect, V3D_OFSDRAW_NONE, R_ADDSKY, - NULL, - NULL, + nullptr, + nullptr, err_out); action_preview_render_cleanup(preview, pose_backup); @@ -1024,7 +1006,7 @@ static void shader_preview_update(void *spv, RenderResult *UNUSED(rr), volatile struct rcti *UNUSED(rect)) { - ShaderPreview *sp = spv; + ShaderPreview *sp = static_cast<ShaderPreview *>(spv); *(sp->do_update) = true; } @@ -1032,46 +1014,13 @@ static void shader_preview_update(void *spv, /* called by renderer, checks job value */ static int shader_preview_break(void *spv) { - ShaderPreview *sp = spv; + ShaderPreview *sp = static_cast<ShaderPreview *>(spv); return *(sp->stop); } -/* outside thread, called before redraw notifiers, it moves finished preview over */ -static void shader_preview_updatejob(void *spv) +static void shader_preview_updatejob(void *UNUSED(spv)) { - ShaderPreview *sp = spv; - - if (sp->pr_method == PR_NODE_RENDER) { - if (GS(sp->id->name) == ID_MA) { - Material *mat = (Material *)sp->id; - - if (sp->matcopy && mat->nodetree && sp->matcopy->nodetree) { - ntreeLocalSync(sp->matcopy->nodetree, mat->nodetree); - } - } - else if (GS(sp->id->name) == ID_TE) { - Tex *tex = (Tex *)sp->id; - - if (sp->texcopy && tex->nodetree && sp->texcopy->nodetree) { - ntreeLocalSync(sp->texcopy->nodetree, tex->nodetree); - } - } - else if (GS(sp->id->name) == ID_WO) { - World *wrld = (World *)sp->id; - - if (sp->worldcopy && wrld->nodetree && sp->worldcopy->nodetree) { - ntreeLocalSync(sp->worldcopy->nodetree, wrld->nodetree); - } - } - else if (GS(sp->id->name) == ID_LA) { - Light *la = (Light *)sp->id; - - if (sp->lampcopy && la->nodetree && sp->lampcopy->nodetree) { - ntreeLocalSync(sp->lampcopy->nodetree, la->nodetree); - } - } - } } /* Renders texture directly to render buffer. */ @@ -1083,13 +1032,14 @@ static void shader_preview_texture(ShaderPreview *sp, Tex *tex, Scene *sce, Rend /* This is needed otherwise no RenderResult is created. */ sce->r.scemode &= ~R_BUTS_PREVIEW; - RE_InitState(re, NULL, &sce->r, &sce->view_layers, NULL, width, height, NULL); + RE_InitState(re, nullptr, &sce->r, &sce->view_layers, nullptr, width, height, nullptr); RE_SetScene(re, sce); /* Create buffer in empty RenderView created in the init step. */ RenderResult *rr = RE_AcquireResultWrite(re); RenderView *rv = (RenderView *)rr->views.first; - rv->rectf = MEM_callocN(sizeof(float[4]) * width * height, "texture render result"); + rv->rectf = static_cast<float *>( + MEM_callocN(sizeof(float[4]) * width * height, "texture render result")); RE_ReleaseResult(re); /* Get texture image pool (if any) */ @@ -1162,7 +1112,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs /* get the stuff from the builtin preview dbase */ sce = preview_prepare_scene(sp->bmain, sp->scene, id, idtype, sp); - if (sce == NULL) { + if (sce == nullptr) { return; } @@ -1175,7 +1125,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs re = RE_GetRender(name); /* full refreshed render from first tile */ - if (re == NULL) { + if (re == nullptr) { re = RE_NewRender(name); } @@ -1187,21 +1137,12 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs sce->r.scemode |= R_NO_IMAGE_LOAD; sce->display.render_aa = SCE_DISPLAY_AA_SAMPLES_8; } - else if (sp->pr_method == PR_NODE_RENDER) { - if (idtype == ID_MA) { - sce->r.scemode |= R_MATNODE_PREVIEW; - } - else if (idtype == ID_TE) { - sce->r.scemode |= R_TEXNODE_PREVIEW; - } - sce->display.render_aa = SCE_DISPLAY_AA_OFF; - } else { /* PR_BUTS_RENDER */ sce->display.render_aa = SCE_DISPLAY_AA_SAMPLES_8; } /* Callbacks are cleared on GetRender(). */ - if (ELEM(sp->pr_method, PR_BUTS_RENDER, PR_NODE_RENDER)) { + if (sp->pr_method == PR_BUTS_RENDER) { RE_display_update_cb(re, sp, shader_preview_update); } /* set this for all previews, default is react to G.is_break still */ @@ -1234,7 +1175,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs } /* unassign the pointers, reset vars */ - preview_prepare_scene(sp->bmain, sp->scene, NULL, GS(id->name), sp); + preview_prepare_scene(sp->bmain, sp->scene, nullptr, GS(id->name), sp); /* XXX bad exception, end-exec is not being called in render, because it uses local main. */ #if 0 @@ -1249,7 +1190,7 @@ static void shader_preview_render(ShaderPreview *sp, ID *id, int split, int firs /* runs inside thread for material and icons */ static void shader_preview_startjob(void *customdata, short *stop, short *do_update) { - ShaderPreview *sp = customdata; + ShaderPreview *sp = static_cast<ShaderPreview *>(customdata); sp->stop = stop; sp->do_update = do_update; @@ -1280,17 +1221,17 @@ static void preview_id_copy_free(ID *id) static void shader_preview_free(void *customdata) { - ShaderPreview *sp = customdata; + ShaderPreview *sp = static_cast<ShaderPreview *>(customdata); Main *pr_main = sp->pr_main; - ID *main_id_copy = NULL; - ID *sub_id_copy = NULL; + ID *main_id_copy = nullptr; + ID *sub_id_copy = nullptr; if (sp->matcopy) { main_id_copy = (ID *)sp->matcopy; BLI_remlink(&pr_main->materials, sp->matcopy); } if (sp->texcopy) { - BLI_assert(main_id_copy == NULL); + BLI_assert(main_id_copy == nullptr); main_id_copy = (ID *)sp->texcopy; BLI_remlink(&pr_main->textures, sp->texcopy); } @@ -1305,14 +1246,10 @@ static void shader_preview_free(void *customdata) BLI_remlink(&pr_main->worlds, sp->worldcopy); } if (sp->lampcopy) { - BLI_assert(main_id_copy == NULL); + BLI_assert(main_id_copy == nullptr); main_id_copy = (ID *)sp->lampcopy; BLI_remlink(&pr_main->lights, sp->lampcopy); } - if (main_id_copy || sp->id_copy) { - /* node previews */ - shader_preview_updatejob(sp); - } if (sp->own_id_copy) { if (sp->id_copy) { preview_id_copy_free(sp->id_copy); @@ -1351,7 +1288,7 @@ static ImBuf *icon_preview_imbuf_from_brush(Brush *brush) BLI_path_abs(path, ID_BLEND_PATH_FROM_GLOBAL(&brush->id)); /* Use default color-spaces for brushes. */ - brush->icon_imbuf = IMB_loadiffname(path, flags, NULL); + brush->icon_imbuf = IMB_loadiffname(path, flags, nullptr); /* otherwise lets try to find it in other directories */ if (!(brush->icon_imbuf)) { @@ -1362,7 +1299,7 @@ static ImBuf *icon_preview_imbuf_from_brush(Brush *brush) if (path[0]) { /* Use default color spaces. */ - brush->icon_imbuf = IMB_loadiffname(path, flags, NULL); + brush->icon_imbuf = IMB_loadiffname(path, flags, nullptr); } } @@ -1388,7 +1325,7 @@ static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect) short ex, ey, dx, dy; /* paranoia test */ - if (ibuf == NULL || (ibuf->rect == NULL && ibuf->rect_float == NULL)) { + if (ibuf == nullptr || (ibuf->rect == nullptr && ibuf->rect_float == nullptr)) { return; } @@ -1418,7 +1355,7 @@ static void icon_copy_rect(ImBuf *ibuf, uint w, uint h, uint *rect) IMB_scalefastImBuf(ima, ex, ey); /* if needed, convert to 32 bits */ - if (ima->rect == NULL) { + if (ima->rect == nullptr) { IMB_rect_from_float(ima); } @@ -1446,13 +1383,13 @@ static void set_alpha(char *cp, int sizex, int sizey, char alpha) static void icon_preview_startjob(void *customdata, short *stop, short *do_update) { - ShaderPreview *sp = customdata; + ShaderPreview *sp = static_cast<ShaderPreview *>(customdata); if (sp->pr_method == PR_ICON_DEFERRED) { - PreviewImage *prv = sp->owner; + PreviewImage *prv = static_cast<PreviewImage *>(sp->owner); ImBuf *thumb; - char *deferred_data = PRV_DEFERRED_DATA(prv); - int source = deferred_data[0]; + char *deferred_data = static_cast<char *>(PRV_DEFERRED_DATA(prv)); + ThumbSource source = static_cast<ThumbSource>(deferred_data[0]); char *path = &deferred_data[1]; // printf("generating deferred %d×%d preview for %s\n", sp->sizex, sp->sizey, path); @@ -1471,15 +1408,15 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat ID *id = sp->id; short idtype = GS(id->name); - BLI_assert(id != NULL); + BLI_assert(id != nullptr); if (idtype == ID_IM) { Image *ima = (Image *)id; - ImBuf *ibuf = NULL; + ImBuf *ibuf = nullptr; ImageUser iuser; BKE_imageuser_default(&iuser); - if (ima == NULL) { + if (ima == nullptr) { return; } @@ -1487,12 +1424,12 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat iuser.framenr = 1; iuser.scene = sp->scene; - /* elubie: this needs to be changed: here image is always loaded if not + /* NOTE(@elubie): this needs to be changed: here image is always loaded if not * 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 && ibuf->rect_float == NULL)) { - BKE_image_release_ibuf(ima, ibuf, NULL); + * only get existing `ibuf`. */ + ibuf = BKE_image_acquire_ibuf(ima, &iuser, nullptr); + if (ibuf == nullptr || (ibuf->rect == nullptr && ibuf->rect_float == nullptr)) { + BKE_image_release_ibuf(ima, ibuf, nullptr); return; } @@ -1500,7 +1437,7 @@ static void icon_preview_startjob(void *customdata, short *stop, short *do_updat *do_update = true; - BKE_image_release_ibuf(ima, ibuf, NULL); + BKE_image_release_ibuf(ima, ibuf, nullptr); } else if (idtype == ID_BR) { Brush *br = (Brush *)id; @@ -1544,7 +1481,7 @@ static void common_preview_startjob(void *customdata, short *do_update, float *UNUSED(progress)) { - ShaderPreview *sp = customdata; + ShaderPreview *sp = static_cast<ShaderPreview *>(customdata); if (ELEM(sp->pr_method, PR_ICON_RENDER, PR_ICON_DEFERRED)) { icon_preview_startjob(customdata, stop, do_update); @@ -1560,17 +1497,17 @@ static void common_preview_startjob(void *customdata, */ static void other_id_types_preview_render(IconPreview *ip, IconPreviewSize *cur_size, - const int pr_method, + const ePreviewRenderMethod pr_method, short *stop, short *do_update, float *progress) { - ShaderPreview *sp = MEM_callocN(sizeof(ShaderPreview), "Icon ShaderPreview"); + ShaderPreview *sp = MEM_cnew<ShaderPreview>("Icon ShaderPreview"); /* These types don't use the ShaderPreview mess, they have their own types and functions. */ BLI_assert(!ip->id || !ELEM(GS(ip->id->name), ID_OB)); - /* construct shader preview from image size and previewcustomdata */ + /* Construct shader preview from image size and preview custom-data. */ sp->scene = ip->scene; sp->owner = ip->owner; sp->sizex = cur_size->sizex; @@ -1581,7 +1518,7 @@ static void other_id_types_preview_render(IconPreview *ip, sp->id_copy = ip->id_copy; sp->bmain = ip->bmain; sp->own_id_copy = false; - Material *ma = NULL; + Material *ma = nullptr; if (sp->pr_method == PR_ICON_RENDER) { BLI_assert(ip->id); @@ -1591,7 +1528,7 @@ static void other_id_types_preview_render(IconPreview *ip, ma = (Material *)ip->id; } - if ((ma == NULL) || (ma->gp_style == NULL)) { + if ((ma == nullptr) || (ma->gp_style == nullptr)) { sp->pr_main = G_pr_main; } else { @@ -1629,10 +1566,12 @@ static void icon_preview_startjob_all_sizes(void *customdata, IconPreview *ip = (IconPreview *)customdata; IconPreviewSize *cur_size; - for (cur_size = ip->sizes.first; cur_size; cur_size = cur_size->next) { - PreviewImage *prv = ip->owner; + for (cur_size = static_cast<IconPreviewSize *>(ip->sizes.first); cur_size; + cur_size = cur_size->next) { + PreviewImage *prv = static_cast<PreviewImage *>(ip->owner); /* Is this a render job or a deferred loading job? */ - const int pr_method = (prv->tag & PRV_TAG_DEFFERED) ? PR_ICON_DEFERRED : PR_ICON_RENDER; + const ePreviewRenderMethod pr_method = (prv->tag & PRV_TAG_DEFFERED) ? PR_ICON_DEFERRED : + PR_ICON_RENDER; if (*stop) { break; @@ -1649,7 +1588,7 @@ static void icon_preview_startjob_all_sizes(void *customdata, * they can skip this test. */ /* TODO: Decouple the ID-type-specific render functions from this function, so that it's not * necessary to know here what happens inside lower-level functions. */ - const bool use_solid_render_mode = (ip->id != NULL) && ELEM(GS(ip->id->name), ID_OB, ID_AC); + const bool use_solid_render_mode = (ip->id != nullptr) && ELEM(GS(ip->id->name), ID_OB, ID_AC); if (!use_solid_render_mode && preview_method_is_render(pr_method) && !check_engine_supports_preview(ip->scene)) { continue; @@ -1662,7 +1601,7 @@ static void icon_preview_startjob_all_sizes(void *customdata, } #endif - if (ip->id != NULL) { + if (ip->id != nullptr) { switch (GS(ip->id->name)) { case ID_OB: if (object_preview_is_type_supported((Object *)ip->id)) { @@ -1675,7 +1614,7 @@ static void icon_preview_startjob_all_sizes(void *customdata, action_preview_render(ip, cur_size); continue; default: - /* Fall through to the same code as the `ip->id == NULL` case. */ + /* Fall through to the same code as the `ip->id == nullptr` case. */ break; } } @@ -1685,7 +1624,7 @@ static void icon_preview_startjob_all_sizes(void *customdata, static void icon_preview_add_size(IconPreview *ip, uint *rect, int sizex, int sizey) { - IconPreviewSize *cur_size = ip->sizes.first, *new_size; + IconPreviewSize *cur_size = static_cast<IconPreviewSize *>(ip->sizes.first); while (cur_size) { if (cur_size->sizex == sizex && cur_size->sizey == sizey) { @@ -1696,7 +1635,7 @@ static void icon_preview_add_size(IconPreview *ip, uint *rect, int sizex, int si cur_size = cur_size->next; } - new_size = MEM_callocN(sizeof(IconPreviewSize), "IconPreviewSize"); + IconPreviewSize *new_size = MEM_cnew<IconPreviewSize>("IconPreviewSize"); new_size->sizex = sizex; new_size->sizey = sizey; new_size->rect = rect; @@ -1706,7 +1645,7 @@ static void icon_preview_add_size(IconPreview *ip, uint *rect, int sizex, int si static void icon_preview_endjob(void *customdata) { - IconPreview *ip = customdata; + IconPreview *ip = static_cast<IconPreview *>(customdata); if (ip->id) { @@ -1723,7 +1662,7 @@ static void icon_preview_endjob(void *customdata) for (i = 0; i < NUM_ICON_SIZES; i++) { if (prv_img->gputexture[i]) { GPU_texture_free(prv_img->gputexture[i]); - prv_img->gputexture[i] = NULL; + prv_img->gputexture[i] = nullptr; WM_main_add_notifier(NC_MATERIAL | ND_SHADING_DRAW, ip->id); } } @@ -1732,7 +1671,7 @@ static void icon_preview_endjob(void *customdata) } if (ip->owner) { - PreviewImage *prv_img = ip->owner; + PreviewImage *prv_img = static_cast<PreviewImage *>(ip->owner); prv_img->tag &= ~PRV_TAG_DEFFERED_RENDERING; LISTBASE_FOREACH (IconPreviewSize *, icon_size, &ip->sizes) { @@ -1761,20 +1700,23 @@ static void icon_preview_free(void *customdata) bool ED_preview_id_is_supported(const ID *id) { - if (id == NULL) { + if (id == nullptr) { + return false; + } + if (GS(id->name) == ID_NT) { + /* Node groups don't support standard preview generation. */ return false; } - if (GS(id->name) == ID_OB) { return object_preview_is_type_supported((const Object *)id); } - return BKE_previewimg_id_get_p(id) != NULL; + return BKE_previewimg_id_get_p(id) != nullptr; } void ED_preview_icon_render( const bContext *C, Scene *scene, ID *id, uint *rect, int sizex, int sizey) { - IconPreview ip = {NULL}; + IconPreview ip = {nullptr}; short stop = false, update = false; float progress = 0.0f; @@ -1797,7 +1739,7 @@ void ED_preview_icon_render( icon_preview_endjob(&ip); BLI_freelistN(&ip.sizes); - if (ip.id_copy != NULL) { + if (ip.id_copy != nullptr) { preview_id_copy_free(ip.id_copy); } } @@ -1818,10 +1760,10 @@ void ED_preview_icon_job( WM_JOB_EXCL_RENDER, WM_JOB_TYPE_RENDER_PREVIEW); - ip = MEM_callocN(sizeof(IconPreview), "icon preview"); + ip = MEM_cnew<IconPreview>("icon preview"); /* render all resolutions from suspended job too */ - old_ip = WM_jobs_customdata_get(wm_job); + old_ip = static_cast<IconPreview *>(WM_jobs_customdata_get(wm_job)); if (old_ip) { BLI_movelisttolist(&ip->sizes, &old_ip->sizes); } @@ -1840,7 +1782,7 @@ void ED_preview_icon_job( /* Special threading hack: * warn main code that this preview is being rendered and cannot be freed... */ { - PreviewImage *prv_img = owner; + PreviewImage *prv_img = static_cast<PreviewImage *>(owner); if (prv_img->tag & PRV_TAG_DEFFERED) { prv_img->tag |= PRV_TAG_DEFFERED_RENDERING; } @@ -1853,7 +1795,8 @@ void ED_preview_icon_job( * Particularly important for heavy scenes and Eevee using OpenGL that blocks * the user interface drawing. */ WM_jobs_delay_start(wm_job, (delay) ? 2.0 : 0.0); - WM_jobs_callbacks(wm_job, icon_preview_startjob_all_sizes, NULL, NULL, icon_preview_endjob); + WM_jobs_callbacks( + wm_job, icon_preview_startjob_all_sizes, nullptr, nullptr, icon_preview_endjob); WM_jobs_start(CTX_wm_manager(C), wm_job); } @@ -1865,13 +1808,13 @@ void ED_preview_shader_job(const bContext *C, MTex *slot, int sizex, int sizey, - int method) + ePreviewRenderMethod method) { Object *ob = CTX_data_active_object(C); wmJob *wm_job; ShaderPreview *sp; Scene *scene = CTX_data_scene(C); - short id_type = GS(id->name); + const ID_Type id_type = GS(id->name); BLI_assert(BKE_previewimg_id_supports_jobs(id)); @@ -1882,11 +1825,6 @@ void ED_preview_shader_job(const bContext *C, return; } - /* Only texture node preview is supported with Cycles. */ - if (method == PR_NODE_RENDER && id_type != ID_TE) { - return; - } - ED_preview_ensure_dbase(); wm_job = WM_jobs_get(CTX_wm_manager(C), @@ -1895,7 +1833,7 @@ void ED_preview_shader_job(const bContext *C, "Shader Preview", WM_JOB_EXCL_RENDER, WM_JOB_TYPE_RENDER_PREVIEW); - sp = MEM_callocN(sizeof(ShaderPreview), "shader preview"); + sp = MEM_cnew<ShaderPreview>("shader preview"); /* customdata for preview thread */ sp->scene = scene; @@ -1909,17 +1847,17 @@ void ED_preview_shader_job(const bContext *C, sp->parent = parent; sp->slot = slot; sp->bmain = CTX_data_main(C); - Material *ma = NULL; + Material *ma = nullptr; /* hardcoded preview .blend for Eevee + Cycles, this should be solved * once with custom preview .blend path for external engines */ /* grease pencil use its own preview file */ - if (GS(id->name) == ID_MA) { + if (id_type == ID_MA) { ma = (Material *)id; } - if ((ma == NULL) || (ma->gp_style == NULL)) { + if ((ma == nullptr) || (ma->gp_style == nullptr)) { sp->pr_main = G_pr_main; } else { @@ -1936,7 +1874,7 @@ void ED_preview_shader_job(const bContext *C, /* setup job */ WM_jobs_customdata_set(wm_job, sp, shader_preview_free); WM_jobs_timer(wm_job, 0.1, NC_MATERIAL, NC_MATERIAL); - WM_jobs_callbacks(wm_job, common_preview_startjob, NULL, shader_preview_updatejob, NULL); + WM_jobs_callbacks(wm_job, common_preview_startjob, nullptr, shader_preview_updatejob, nullptr); WM_jobs_start(CTX_wm_manager(C), wm_job); } @@ -1946,28 +1884,28 @@ void ED_preview_kill_jobs(wmWindowManager *wm, Main *UNUSED(bmain)) if (wm) { /* This is called to stop all preview jobs before scene data changes, to * avoid invalid memory access. */ - WM_jobs_kill(wm, NULL, common_preview_startjob); - WM_jobs_kill(wm, NULL, icon_preview_startjob_all_sizes); + WM_jobs_kill(wm, nullptr, common_preview_startjob); + WM_jobs_kill(wm, nullptr, icon_preview_startjob_all_sizes); } } -typedef struct PreviewRestartQueueEntry { +struct PreviewRestartQueueEntry { struct PreviewRestartQueueEntry *next, *prev; enum eIconSizes size; ID *id; -} PreviewRestartQueueEntry; +}; static ListBase /* #PreviewRestartQueueEntry */ G_restart_previews_queue; -void ED_preview_restart_queue_free(void) +void ED_preview_restart_queue_free() { BLI_freelistN(&G_restart_previews_queue); } void ED_preview_restart_queue_add(ID *id, enum eIconSizes size) { - PreviewRestartQueueEntry *queue_entry = MEM_mallocN(sizeof(*queue_entry), __func__); + PreviewRestartQueueEntry *queue_entry = MEM_new<PreviewRestartQueueEntry>(__func__); queue_entry->size = size; queue_entry->id = id; BLI_addtail(&G_restart_previews_queue, queue_entry); @@ -1986,7 +1924,7 @@ void ED_preview_restart_queue_work(const bContext *C) } BKE_previewimg_clear_single(preview, queue_entry->size); - UI_icon_render_id(C, NULL, queue_entry->id, queue_entry->size, true); + UI_icon_render_id(C, nullptr, queue_entry->id, queue_entry->size, true); BLI_freelinkN(&G_restart_previews_queue, queue_entry); } diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.cc index 54ff25ede28..19ab6841e22 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.cc @@ -20,8 +20,8 @@ * \ingroup edrend */ -#include <stdlib.h> -#include <string.h> +#include <cstdlib> +#include <cstring> #include "MEM_guardedalloc.h" @@ -64,6 +64,8 @@ #include "BKE_workspace.h" #include "BKE_world.h" +#include "NOD_composite.h" + #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" @@ -96,7 +98,7 @@ #include "engines/eevee/eevee_lightcache.h" -#include "render_intern.h" /* own include */ +#include "render_intern.hh" /* own include */ static bool object_materials_supported_poll_ex(bContext *C, const Object *ob); @@ -106,7 +108,7 @@ static bool object_materials_supported_poll_ex(bContext *C, const Object *ob); static bool object_array_for_shading_edit_mode_enabled_filter(const Object *ob, void *user_data) { - bContext *C = user_data; + bContext *C = static_cast<bContext *>(user_data); if (object_materials_supported_poll_ex(C, ob)) { if (BKE_object_is_in_editmode(ob) == true) { return true; @@ -123,7 +125,7 @@ static Object **object_array_for_shading_edit_mode_enabled(bContext *C, uint *r_ static bool object_array_for_shading_edit_mode_disabled_filter(const Object *ob, void *user_data) { - bContext *C = user_data; + bContext *C = static_cast<bContext *>(user_data); if (object_materials_supported_poll_ex(C, ob)) { if (BKE_object_is_in_editmode(ob) == false) { return true; @@ -159,7 +161,7 @@ static bool object_materials_supported_poll_ex(bContext *C, const Object *ob) } /* Material linked to obdata. */ - const ID *data = ob->data; + const ID *data = static_cast<ID *>(ob->data); return (data && !ID_IS_LINKED(data) && !ID_IS_OVERRIDE_LIBRARY(data)); } @@ -188,8 +190,8 @@ static int material_slot_add_exec(bContext *C, wmOperator *UNUSED(op)) if (ob->mode & OB_MODE_TEXTURE_PAINT) { Scene *scene = CTX_data_scene(C); - ED_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL); - WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL); + ED_paint_proj_mesh_data_check(scene, ob, nullptr, nullptr, nullptr, nullptr); + WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, nullptr); } WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); @@ -238,8 +240,8 @@ static int material_slot_remove_exec(bContext *C, wmOperator *op) if (ob->mode & OB_MODE_TEXTURE_PAINT) { Scene *scene = CTX_data_scene(C); - ED_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL); - WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL); + ED_paint_proj_mesh_data_check(scene, ob, nullptr, nullptr, nullptr, nullptr); + WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, nullptr); } DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); @@ -277,7 +279,7 @@ static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op)) bool changed_multi = false; Object *obact = CTX_data_active_object(C); - const Material *mat_active = obact ? BKE_object_material_get(obact, obact->actcol) : NULL; + const Material *mat_active = obact ? BKE_object_material_get(obact, obact->actcol) : nullptr; uint objects_len = 0; Object **objects = object_array_for_shading_edit_mode_enabled(C, &objects_len); @@ -328,7 +330,7 @@ static int material_slot_assign_exec(bContext *C, wmOperator *UNUSED(op)) ListBase *nurbs = BKE_curve_editNurbs_get((Curve *)ob->data); if (nurbs) { - for (nu = nurbs->first; nu; nu = nu->next) { + for (nu = static_cast<Nurb *>(nurbs->first); nu; nu = nu->next) { if (ED_curve_nurb_select_check(v3d, nu)) { changed = true; nu->mat_nr = mat_nr_active; @@ -384,7 +386,7 @@ static int material_slot_de_select(bContext *C, bool select) { bool changed_multi = false; Object *obact = CTX_data_active_object(C); - const Material *mat_active = obact ? BKE_object_material_get(obact, obact->actcol) : NULL; + const Material *mat_active = obact ? BKE_object_material_get(obact, obact->actcol) : nullptr; uint objects_len = 0; Object **objects = object_array_for_shading_edit_mode_enabled(C, &objects_len); @@ -432,7 +434,7 @@ static int material_slot_de_select(bContext *C, bool select) int a; if (nurbs) { - for (nu = nurbs->first; nu; nu = nu->next) { + for (nu = static_cast<Nurb *>(nurbs->first); nu; nu = nu->next) { if (nu->mat_nr == mat_nr_active) { if (nu->bezt) { a = nu->pntsu; @@ -477,7 +479,7 @@ static int material_slot_de_select(bContext *C, bool select) if (changed) { changed_multi = true; - DEG_id_tag_update(ob->data, ID_RECALC_SELECT); + DEG_id_tag_update(static_cast<ID *>(ob->data), ID_RECALC_SELECT); WM_event_add_notifier(C, NC_GEOM | ND_SELECT, ob->data); } } @@ -545,7 +547,8 @@ static int material_slot_copy_exec(bContext *C, wmOperator *UNUSED(op)) Material ***matar_object = &ob->mat; - Material **matar = MEM_callocN(sizeof(*matar) * (size_t)ob->totcol, __func__); + Material **matar = static_cast<Material **>( + MEM_callocN(sizeof(*matar) * (size_t)ob->totcol, __func__)); for (int i = ob->totcol; i--;) { matar[i] = ob->matbits[i] ? (*matar_object)[i] : (*matar_obdata)[i]; } @@ -620,7 +623,7 @@ static int material_slot_move_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - slot_remap = MEM_mallocN(sizeof(uint) * ob->totcol, __func__); + slot_remap = static_cast<uint *>(MEM_mallocN(sizeof(uint) * ob->totcol, __func__)); range_vn_u(slot_remap, ob->totcol, 0); @@ -643,7 +646,7 @@ void OBJECT_OT_material_slot_move(wmOperatorType *ot) static const EnumPropertyItem material_slot_move[] = { {1, "UP", 0, "Up", ""}, {-1, "DOWN", 0, "Down", ""}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; /* identifiers */ @@ -715,8 +718,8 @@ static int material_slot_remove_unused_exec(bContext *C, wmOperator *op) if (ob_active->mode & OB_MODE_TEXTURE_PAINT) { Scene *scene = CTX_data_scene(C); - ED_paint_proj_mesh_data_check(scene, ob_active, NULL, NULL, NULL, NULL); - WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, NULL); + ED_paint_proj_mesh_data_check(scene, ob_active, nullptr, nullptr, nullptr, nullptr); + WM_event_add_notifier(C, NC_SCENE | ND_TOOLSETTINGS, nullptr); } WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob_active); @@ -749,7 +752,8 @@ void OBJECT_OT_material_slot_remove_unused(wmOperatorType *ot) static int new_material_exec(bContext *C, wmOperator *UNUSED(op)) { - Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data; + Material *ma = static_cast<Material *>( + CTX_data_pointer_get_type(C, "material", &RNA_Material).data); Main *bmain = CTX_data_main(C); PointerRNA ptr, idptr; PropertyRNA *prop; @@ -757,17 +761,18 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op)) /* hook into UI */ UI_context_active_but_prop_get_templateID(C, &ptr, &prop); - Object *ob = (prop && RNA_struct_is_a(ptr.type, &RNA_Object)) ? ptr.data : NULL; + Object *ob = static_cast<Object *>((prop && RNA_struct_is_a(ptr.type, &RNA_Object)) ? ptr.data : + nullptr); /* add or copy material */ if (ma) { Material *new_ma = (Material *)BKE_id_copy_ex( - bmain, &ma->id, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS); + bmain, &ma->id, nullptr, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS); ma = new_ma; } else { const char *name = DATA_("Material"); - if (!(ob != NULL && ob->type == OB_GPENCIL)) { + if (!(ob != nullptr && ob->type == OB_GPENCIL)) { ma = BKE_material_add(bmain, name); } else { @@ -778,10 +783,10 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op)) } if (prop) { - if (ob != NULL) { + if (ob != nullptr) { /* Add slot follows user-preferences for creating new slots, * RNA pointer assignment doesn't, see: T60014. */ - if (BKE_object_material_get_p(ob, ob->actcol) == NULL) { + if (BKE_object_material_get_p(ob, ob->actcol) == nullptr) { BKE_object_material_slot_add(bmain, ob); } } @@ -791,7 +796,7 @@ static int new_material_exec(bContext *C, wmOperator *UNUSED(op)) id_us_min(&ma->id); RNA_id_pointer_create(&ma->id, &idptr); - RNA_property_pointer_set(&ptr, prop, idptr, NULL); + RNA_property_pointer_set(&ptr, prop, idptr, nullptr); RNA_property_update(C, &ptr, prop); } @@ -823,7 +828,7 @@ void MATERIAL_OT_new(wmOperatorType *ot) static int new_texture_exec(bContext *C, wmOperator *UNUSED(op)) { - Tex *tex = CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data; + Tex *tex = static_cast<Tex *>(CTX_data_pointer_get_type(C, "texture", &RNA_Texture).data); Main *bmain = CTX_data_main(C); PointerRNA ptr, idptr; PropertyRNA *prop; @@ -845,7 +850,7 @@ static int new_texture_exec(bContext *C, wmOperator *UNUSED(op)) id_us_min(&tex->id); RNA_id_pointer_create(&tex->id, &idptr); - RNA_property_pointer_set(&ptr, prop, idptr, NULL); + RNA_property_pointer_set(&ptr, prop, idptr, nullptr); RNA_property_update(C, &ptr, prop); } @@ -876,7 +881,7 @@ void TEXTURE_OT_new(wmOperatorType *ot) static int new_world_exec(bContext *C, wmOperator *UNUSED(op)) { - World *wo = CTX_data_pointer_get_type(C, "world", &RNA_World).data; + World *wo = static_cast<World *>(CTX_data_pointer_get_type(C, "world", &RNA_World).data); Main *bmain = CTX_data_main(C); PointerRNA ptr, idptr; PropertyRNA *prop; @@ -884,7 +889,7 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op)) /* add or copy world */ if (wo) { World *new_wo = (World *)BKE_id_copy_ex( - bmain, &wo->id, NULL, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS); + bmain, &wo->id, nullptr, LIB_ID_COPY_DEFAULT | LIB_ID_COPY_ACTIONS); wo = new_wo; } else { @@ -902,7 +907,7 @@ static int new_world_exec(bContext *C, wmOperator *UNUSED(op)) id_us_min(&wo->id); RNA_id_pointer_create(&wo->id, &idptr); - RNA_property_pointer_set(&ptr, prop, idptr, NULL); + RNA_property_pointer_set(&ptr, prop, idptr, nullptr); RNA_property_update(C, &ptr, prop); } @@ -960,7 +965,7 @@ void SCENE_OT_view_layer_add(wmOperatorType *ot) 0, "Blank", "Add a new view layer with all collections disabled"}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; /* identifiers */ @@ -997,7 +1002,7 @@ static int view_layer_remove_exec(bContext *C, wmOperator *UNUSED(op)) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - if (!ED_scene_view_layer_delete(bmain, scene, view_layer, NULL)) { + if (!ED_scene_view_layer_delete(bmain, scene, view_layer, nullptr)) { return OPERATOR_CANCELLED; } @@ -1041,7 +1046,7 @@ static int view_layer_add_aov_exec(bContext *C, wmOperator *UNUSED(op)) BKE_view_layer_verify_aov(engine, scene, view_layer); } RE_engine_free(engine); - engine = NULL; + engine = nullptr; } if (scene->nodetree) { @@ -1080,7 +1085,7 @@ 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) { + if (view_layer->active_aov == nullptr) { return OPERATOR_FINISHED; } @@ -1093,7 +1098,7 @@ static int view_layer_remove_aov_exec(bContext *C, wmOperator *UNUSED(op)) BKE_view_layer_verify_aov(engine, scene, view_layer); } RE_engine_free(engine); - engine = NULL; + engine = nullptr; } if (scene->nodetree) { @@ -1135,7 +1140,7 @@ enum { static void light_cache_bake_tag_cache(Scene *scene, wmOperator *op) { - if (scene->eevee.light_cache_data != NULL) { + if (scene->eevee.light_cache_data != nullptr) { int subset = RNA_enum_get(op->ptr, "subset"); switch (subset) { case LIGHTCACHE_SUBSET_ALL: @@ -1261,7 +1266,7 @@ void SCENE_OT_light_cache_bake(wmOperatorType *ot) 0, "Cubemaps Only", "Try to only bake reflection cubemaps if irradiance grids are up to date"}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; /* identifiers */ @@ -1317,7 +1322,7 @@ static int light_cache_free_exec(bContext *C, wmOperator *UNUSED(op)) } EEVEE_lightcache_free(scene->eevee.light_cache_data); - scene->eevee.light_cache_data = NULL; + scene->eevee.light_cache_data = nullptr; EEVEE_lightcache_info_update(&scene->eevee); @@ -1358,7 +1363,7 @@ static int render_view_add_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - BKE_scene_add_render_view(scene, NULL); + BKE_scene_add_render_view(scene, nullptr); scene->r.actview = BLI_listbase_count(&scene->r.views) - 1; WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene); @@ -1389,7 +1394,8 @@ void SCENE_OT_render_view_add(wmOperatorType *ot) static int render_view_remove_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); - SceneRenderView *rv = BLI_findlink(&scene->r.views, scene->r.actview); + SceneRenderView *rv = static_cast<SceneRenderView *>( + BLI_findlink(&scene->r.views, scene->r.actview)); if (!BKE_scene_remove_render_view(scene, rv)) { return OPERATOR_CANCELLED; @@ -1444,9 +1450,9 @@ static bool freestyle_linestyle_check_report(FreestyleLineSet *lineset, ReportLi static bool freestyle_active_module_poll(bContext *C) { PointerRNA ptr = CTX_data_pointer_get_type(C, "freestyle_module", &RNA_FreestyleModuleSettings); - FreestyleModuleConfig *module = ptr.data; + FreestyleModuleConfig *module = static_cast<FreestyleModuleConfig *>(ptr.data); - return module != NULL; + return module != nullptr; } static int freestyle_module_add_exec(bContext *C, wmOperator *UNUSED(op)) @@ -1486,7 +1492,7 @@ static int freestyle_module_remove_exec(bContext *C, wmOperator *UNUSED(op)) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); PointerRNA ptr = CTX_data_pointer_get_type(C, "freestyle_module", &RNA_FreestyleModuleSettings); - FreestyleModuleConfig *module = ptr.data; + FreestyleModuleConfig *module = static_cast<FreestyleModuleConfig *>(ptr.data); BKE_freestyle_module_delete(&view_layer->freestyle_config, module); @@ -1516,7 +1522,7 @@ static int freestyle_module_move_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); PointerRNA ptr = CTX_data_pointer_get_type(C, "freestyle_module", &RNA_FreestyleModuleSettings); - FreestyleModuleConfig *module = ptr.data; + FreestyleModuleConfig *module = static_cast<FreestyleModuleConfig *>(ptr.data); int dir = RNA_enum_get(op->ptr, "direction"); if (BKE_freestyle_module_move(&view_layer->freestyle_config, module, dir)) { @@ -1538,7 +1544,7 @@ void SCENE_OT_freestyle_module_move(wmOperatorType *ot) static const EnumPropertyItem direction_items[] = { {-1, "UP", 0, "Up", ""}, {1, "DOWN", 0, "Down", ""}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; /* identifiers */ @@ -1574,7 +1580,7 @@ static int freestyle_lineset_add_exec(bContext *C, wmOperator *UNUSED(op)) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - BKE_freestyle_lineset_add(bmain, &view_layer->freestyle_config, NULL); + BKE_freestyle_lineset_add(bmain, &view_layer->freestyle_config, nullptr); DEG_id_tag_update(&scene->id, 0); WM_event_add_notifier(C, NC_SCENE | ND_RENDER_OPTIONS, scene); @@ -1610,7 +1616,7 @@ static bool freestyle_active_lineset_poll(bContext *C) return false; } - return BKE_freestyle_lineset_get_active(&view_layer->freestyle_config) != NULL; + return BKE_freestyle_lineset_get_active(&view_layer->freestyle_config) != nullptr; } static int freestyle_lineset_copy_exec(bContext *C, wmOperator *UNUSED(op)) @@ -1730,7 +1736,7 @@ void SCENE_OT_freestyle_lineset_move(wmOperatorType *ot) static const EnumPropertyItem direction_items[] = { {-1, "UP", 0, "Up", ""}, {1, "DOWN", 0, "Down", ""}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; /* identifiers */ @@ -1814,7 +1820,7 @@ static int freestyle_color_modifier_add_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - if (BKE_linestyle_color_modifier_add(lineset->linestyle, NULL, type) == NULL) { + if (BKE_linestyle_color_modifier_add(lineset->linestyle, nullptr, type) == nullptr) { BKE_report(op->reports, RPT_ERROR, "Unknown line color modifier type"); return OPERATOR_CANCELLED; } @@ -1861,7 +1867,7 @@ static int freestyle_alpha_modifier_add_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - if (BKE_linestyle_alpha_modifier_add(lineset->linestyle, NULL, type) == NULL) { + if (BKE_linestyle_alpha_modifier_add(lineset->linestyle, nullptr, type) == nullptr) { BKE_report(op->reports, RPT_ERROR, "Unknown alpha transparency modifier type"); return OPERATOR_CANCELLED; } @@ -1908,7 +1914,7 @@ static int freestyle_thickness_modifier_add_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - if (BKE_linestyle_thickness_modifier_add(lineset->linestyle, NULL, type) == NULL) { + if (BKE_linestyle_thickness_modifier_add(lineset->linestyle, nullptr, type) == nullptr) { BKE_report(op->reports, RPT_ERROR, "Unknown line thickness modifier type"); return OPERATOR_CANCELLED; } @@ -1955,7 +1961,7 @@ static int freestyle_geometry_modifier_add_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - if (BKE_linestyle_geometry_modifier_add(lineset->linestyle, NULL, type) == NULL) { + if (BKE_linestyle_geometry_modifier_add(lineset->linestyle, nullptr, type) == nullptr) { BKE_report(op->reports, RPT_ERROR, "Unknown stroke geometry modifier type"); return OPERATOR_CANCELLED; } @@ -2014,7 +2020,7 @@ static int freestyle_modifier_remove_exec(bContext *C, wmOperator *op) ViewLayer *view_layer = CTX_data_view_layer(C); FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config); PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier); - LineStyleModifier *modifier = ptr.data; + LineStyleModifier *modifier = static_cast<LineStyleModifier *>(ptr.data); if (!freestyle_linestyle_check_report(lineset, op->reports)) { return OPERATOR_CANCELLED; @@ -2070,7 +2076,7 @@ static int freestyle_modifier_copy_exec(bContext *C, wmOperator *op) ViewLayer *view_layer = CTX_data_view_layer(C); FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config); PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier); - LineStyleModifier *modifier = ptr.data; + LineStyleModifier *modifier = static_cast<LineStyleModifier *>(ptr.data); if (!freestyle_linestyle_check_report(lineset, op->reports)) { return OPERATOR_CANCELLED; @@ -2126,7 +2132,7 @@ static int freestyle_modifier_move_exec(bContext *C, wmOperator *op) ViewLayer *view_layer = CTX_data_view_layer(C); FreestyleLineSet *lineset = BKE_freestyle_lineset_get_active(&view_layer->freestyle_config); PointerRNA ptr = CTX_data_pointer_get_type(C, "modifier", &RNA_LineStyleModifier); - LineStyleModifier *modifier = ptr.data; + LineStyleModifier *modifier = static_cast<LineStyleModifier *>(ptr.data); int dir = RNA_enum_get(op->ptr, "direction"); bool changed = false; @@ -2166,7 +2172,7 @@ void SCENE_OT_freestyle_modifier_move(wmOperatorType *ot) static const EnumPropertyItem direction_items[] = { {-1, "UP", 0, "Up", ""}, {1, "DOWN", 0, "Down", ""}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; /* identifiers */ @@ -2252,9 +2258,12 @@ static int texture_slot_move_exec(bContext *C, wmOperator *op) mtex_ar[act] = mtex_ar[act - 1]; mtex_ar[act - 1] = mtexswap; - BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act - 1, -1, 0); - BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act, act - 1, 0); - BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, -1, act, 0); + BKE_animdata_fix_paths_rename( + id, adt, nullptr, "texture_slots", nullptr, nullptr, act - 1, -1, false); + BKE_animdata_fix_paths_rename( + id, adt, nullptr, "texture_slots", nullptr, nullptr, act, act - 1, false); + BKE_animdata_fix_paths_rename( + id, adt, nullptr, "texture_slots", nullptr, nullptr, -1, act, false); set_active_mtex(id, act - 1); } @@ -2265,9 +2274,12 @@ static int texture_slot_move_exec(bContext *C, wmOperator *op) mtex_ar[act] = mtex_ar[act + 1]; mtex_ar[act + 1] = mtexswap; - BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act + 1, -1, 0); - BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, act, act + 1, 0); - BKE_animdata_fix_paths_rename(id, adt, NULL, "texture_slots", NULL, NULL, -1, act, 0); + BKE_animdata_fix_paths_rename( + id, adt, nullptr, "texture_slots", nullptr, nullptr, act + 1, -1, false); + BKE_animdata_fix_paths_rename( + id, adt, nullptr, "texture_slots", nullptr, nullptr, act, act + 1, false); + BKE_animdata_fix_paths_rename( + id, adt, nullptr, "texture_slots", nullptr, nullptr, -1, act, false); set_active_mtex(id, act + 1); } @@ -2285,7 +2297,7 @@ void TEXTURE_OT_slot_move(wmOperatorType *ot) static const EnumPropertyItem slot_move[] = { {-1, "UP", 0, "Up", ""}, {1, "DOWN", 0, "Down", ""}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; /* identifiers */ @@ -2311,9 +2323,10 @@ void TEXTURE_OT_slot_move(wmOperatorType *ot) /* material copy/paste */ static int copy_material_exec(bContext *C, wmOperator *UNUSED(op)) { - Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data; + Material *ma = static_cast<Material *>( + CTX_data_pointer_get_type(C, "material", &RNA_Material).data); - if (ma == NULL) { + if (ma == nullptr) { return OPERATOR_CANCELLED; } @@ -2345,9 +2358,10 @@ void MATERIAL_OT_copy(wmOperatorType *ot) static int paste_material_exec(bContext *C, wmOperator *UNUSED(op)) { - Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data; + Material *ma = static_cast<Material *>( + CTX_data_pointer_get_type(C, "material", &RNA_Material).data); - if (ma == NULL) { + if (ma == nullptr) { return OPERATOR_CANCELLED; } @@ -2382,14 +2396,14 @@ void MATERIAL_OT_paste(wmOperatorType *ot) static short mtexcopied = 0; /* must be reset on file load */ static MTex mtexcopybuf; -void ED_render_clear_mtex_copybuf(void) +void ED_render_clear_mtex_copybuf() { /* use for file reload */ mtexcopied = 0; } static void copy_mtex_copybuf(ID *id) { - MTex **mtex = NULL; + MTex **mtex = nullptr; switch (GS(id->name)) { case ID_PA: @@ -2413,9 +2427,9 @@ static void copy_mtex_copybuf(ID *id) static void paste_mtex_copybuf(ID *id) { - MTex **mtex = NULL; + MTex **mtex = nullptr; - if (mtexcopied == 0 || mtexcopybuf.tex == NULL) { + if (mtexcopied == 0 || mtexcopybuf.tex == nullptr) { return; } @@ -2432,8 +2446,8 @@ static void paste_mtex_copybuf(ID *id) } if (mtex) { - if (*mtex == NULL) { - *mtex = MEM_mallocN(sizeof(MTex), "mtex copy"); + if (*mtex == nullptr) { + *mtex = MEM_new<MTex>("mtex copy"); } else if ((*mtex)->tex) { id_us_min(&(*mtex)->tex->id); @@ -2455,7 +2469,7 @@ static int copy_mtex_exec(bContext *C, wmOperator *UNUSED(op)) { ID *id = CTX_data_pointer_get_type(C, "texture_slot", &RNA_TextureSlot).owner_id; - if (id == NULL) { + if (id == nullptr) { /* copying empty slot */ ED_render_clear_mtex_copybuf(); return OPERATOR_CANCELLED; @@ -2470,7 +2484,7 @@ static bool copy_mtex_poll(bContext *C) { ID *id = CTX_data_pointer_get_type(C, "texture_slot", &RNA_TextureSlot).owner_id; - return (id != NULL); + return (id != nullptr); } void TEXTURE_OT_slot_copy(wmOperatorType *ot) @@ -2499,14 +2513,15 @@ static int paste_mtex_exec(bContext *C, wmOperator *UNUSED(op)) { ID *id = CTX_data_pointer_get_type(C, "texture_slot", &RNA_TextureSlot).owner_id; - if (id == NULL) { - Material *ma = CTX_data_pointer_get_type(C, "material", &RNA_Material).data; - Light *la = CTX_data_pointer_get_type(C, "light", &RNA_Light).data; - World *wo = CTX_data_pointer_get_type(C, "world", &RNA_World).data; - ParticleSystem *psys = - CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data; - FreestyleLineStyle *linestyle = - CTX_data_pointer_get_type(C, "line_style", &RNA_FreestyleLineStyle).data; + if (id == nullptr) { + Material *ma = static_cast<Material *>( + CTX_data_pointer_get_type(C, "material", &RNA_Material).data); + Light *la = static_cast<Light *>(CTX_data_pointer_get_type(C, "light", &RNA_Light).data); + World *wo = static_cast<World *>(CTX_data_pointer_get_type(C, "world", &RNA_World).data); + ParticleSystem *psys = static_cast<ParticleSystem *>( + CTX_data_pointer_get_type(C, "particle_system", &RNA_ParticleSystem).data); + FreestyleLineStyle *linestyle = static_cast<FreestyleLineStyle *>( + CTX_data_pointer_get_type(C, "line_style", &RNA_FreestyleLineStyle).data); if (ma) { id = &ma->id; @@ -2524,14 +2539,14 @@ static int paste_mtex_exec(bContext *C, wmOperator *UNUSED(op)) id = &linestyle->id; } - if (id == NULL) { + if (id == nullptr) { return OPERATOR_CANCELLED; } } paste_mtex_copybuf(id); - WM_event_add_notifier(C, NC_TEXTURE | ND_SHADING_LINKS, NULL); + WM_event_add_notifier(C, NC_TEXTURE | ND_SHADING_LINKS, nullptr); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.cc index e975eab4736..b1e8e3927ef 100644 --- a/source/blender/editors/render/render_update.c +++ b/source/blender/editors/render/render_update.cc @@ -20,8 +20,8 @@ * \ingroup edrend */ -#include <stdlib.h> -#include <string.h> +#include <cstdlib> +#include <cstring> #include "DNA_cachefile_types.h" #include "DNA_light_types.h" @@ -49,6 +49,8 @@ #include "BKE_paint.h" #include "BKE_scene.h" +#include "NOD_composite.h" + #include "RE_engine.h" #include "RE_pipeline.h" @@ -62,7 +64,7 @@ #include "WM_api.h" -#include <stdio.h> +#include <cstdio> /* -------------------------------------------------------------------- */ /** \name Render Engines @@ -82,8 +84,8 @@ void ED_render_view3d_update(Depsgraph *depsgraph, continue; } - View3D *v3d = area->spacedata.first; - RegionView3D *rv3d = region->regiondata; + View3D *v3d = static_cast<View3D *>(area->spacedata.first); + RegionView3D *rv3d = static_cast<RegionView3D *>(region->regiondata); RenderEngine *engine = rv3d->render_engine; /* call update if the scene changed, or if the render engine @@ -94,7 +96,7 @@ void ED_render_view3d_update(Depsgraph *depsgraph, bContext *C = CTX_create(); CTX_data_main_set(C, bmain); CTX_data_scene_set(C, scene); - CTX_wm_manager_set(C, bmain->wm.first); + CTX_wm_manager_set(C, static_cast<wmWindowManager *>(bmain->wm.first)); CTX_wm_window_set(C, window); CTX_wm_screen_set(C, WM_window_get_active_screen(window)); CTX_wm_area_set(C, area); @@ -111,15 +113,15 @@ void ED_render_view3d_update(Depsgraph *depsgraph, else { RenderEngineType *engine_type = ED_view3d_engine_type(scene, v3d->shading.type); if (updated) { - DRW_notify_view_update((&(DRWUpdateContext){ - .bmain = bmain, - .depsgraph = depsgraph, - .scene = scene, - .view_layer = view_layer, - .region = region, - .v3d = v3d, - .engine_type = engine_type, - })); + DRWUpdateContext drw_context = {nullptr}; + drw_context.bmain = bmain; + drw_context.depsgraph = depsgraph; + drw_context.scene = scene; + drw_context.view_layer = view_layer; + drw_context.region = region; + drw_context.v3d = v3d; + drw_context.engine_type = engine_type; + DRW_notify_view_update(&drw_context); } } } @@ -148,7 +150,7 @@ void ED_render_scene_update(const DEGEditorUpdateContext *update_ctx, const bool recursive_check = true; - wmWindowManager *wm = bmain->wm.first; + wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first); LISTBASE_FOREACH (wmWindow *, window, &wm->windows) { bScreen *screen = WM_window_get_active_screen(window); @@ -166,13 +168,13 @@ void ED_render_engine_area_exit(Main *bmain, ScrArea *area) { /* clear all render engines in this area */ ARegion *region; - wmWindowManager *wm = bmain->wm.first; + wmWindowManager *wm = static_cast<wmWindowManager *>(bmain->wm.first); if (area->spacetype != SPACE_VIEW3D) { return; } - for (region = area->regionbase.first; region; region = region->next) { + for (region = static_cast<ARegion *>(area->regionbase.first); region; region = region->next) { if (region->regiontype != RGN_TYPE_WINDOW || !(region->regiondata)) { continue; } @@ -183,16 +185,18 @@ void ED_render_engine_area_exit(Main *bmain, ScrArea *area) void ED_render_engine_changed(Main *bmain, const bool update_scene_data) { /* on changing the render engine type, clear all running render engines */ - for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { + for (bScreen *screen = static_cast<bScreen *>(bmain->screens.first); screen; + screen = static_cast<bScreen *>(screen->id.next)) { LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { ED_render_engine_area_exit(bmain, area); } } - RE_FreePersistentData(NULL); + RE_FreePersistentData(nullptr); /* Inform all render engines and draw managers. */ - DEGEditorUpdateContext update_ctx = {NULL}; + DEGEditorUpdateContext update_ctx = {nullptr}; update_ctx.bmain = bmain; - for (Scene *scene = bmain->scenes.first; scene; scene = scene->id.next) { + for (Scene *scene = static_cast<Scene *>(bmain->scenes.first); scene; + scene = static_cast<Scene *>(scene->id.next)) { update_ctx.scene = scene; LISTBASE_FOREACH (ViewLayer *, view_layer, &scene->view_layers) { /* TDODO(sergey): Iterate over depsgraphs instead? */ @@ -258,14 +262,16 @@ static void texture_changed(Main *bmain, Tex *tex) /* icons */ BKE_icon_changed(BKE_icon_id_ensure(&tex->id)); - for (scene = bmain->scenes.first; scene; scene = scene->id.next) { + for (scene = static_cast<Scene *>(bmain->scenes.first); scene; + scene = static_cast<Scene *>(scene->id.next)) { /* paint overlays */ - for (view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { + for (view_layer = static_cast<ViewLayer *>(scene->view_layers.first); view_layer; + view_layer = view_layer->next) { BKE_paint_invalidate_overlay_tex(scene, view_layer, tex); } /* find compositing nodes */ if (scene->use_nodes && scene->nodetree) { - for (node = scene->nodetree->nodes.first; node; node = node->next) { + for (node = static_cast<bNode *>(scene->nodetree->nodes.first); node; node = node->next) { if (node->id == &tex->id) { ED_node_tag_update_id(&scene->id); } @@ -288,7 +294,8 @@ static void image_changed(Main *bmain, Image *ima) BKE_icon_changed(BKE_icon_id_ensure(&ima->id)); /* textures */ - for (tex = bmain->textures.first; tex; tex = tex->id.next) { + for (tex = static_cast<Tex *>(bmain->textures.first); tex; + tex = static_cast<Tex *>(tex->id.next)) { if (tex->type == TEX_IMAGE && tex->ima == ima) { texture_changed(bmain, tex); } @@ -300,10 +307,11 @@ static void scene_changed(Main *bmain, Scene *scene) Object *ob; /* glsl */ - for (ob = bmain->objects.first; ob; ob = ob->id.next) { + for (ob = static_cast<Object *>(bmain->objects.first); ob; + ob = static_cast<Object *>(ob->id.next)) { if (ob->mode & OB_MODE_TEXTURE_PAINT) { BKE_texpaint_slots_refresh_object(scene, ob); - ED_paint_proj_mesh_data_check(scene, ob, NULL, NULL, NULL, NULL); + ED_paint_proj_mesh_data_check(scene, ob, nullptr, nullptr, nullptr, nullptr); } } } diff --git a/source/blender/editors/render/render_view.c b/source/blender/editors/render/render_view.cc index 9163718ffad..980cd899120 100644 --- a/source/blender/editors/render/render_view.c +++ b/source/blender/editors/render/render_view.cc @@ -21,8 +21,8 @@ * \ingroup edrend */ -#include <stddef.h> -#include <string.h> +#include <cstddef> +#include <cstring> #include "BLI_listbase.h" #include "BLI_utildefines.h" @@ -47,7 +47,7 @@ #include "wm_window.h" -#include "render_intern.h" +#include "render_intern.hh" /*********************** utilities for finding areas *************************/ @@ -59,11 +59,11 @@ static ScrArea *biggest_non_image_area(bContext *C) { bScreen *screen = CTX_wm_screen(C); - ScrArea *area, *big = NULL; + ScrArea *area, *big = nullptr; int size, maxsize = 0, bwmaxsize = 0; short foundwin = 0; - for (area = screen->areabase.first; area; area = area->next) { + for (area = static_cast<ScrArea *>(screen->areabase.first); area; area = area->next) { if (area->winx > 30 && area->winy > 30) { size = area->winx * area->winy; if (!area->full && area->spacetype == SPACE_PROPERTIES) { @@ -86,17 +86,17 @@ static ScrArea *biggest_non_image_area(bContext *C) static ScrArea *find_area_showing_r_result(bContext *C, Scene *scene, wmWindow **win) { wmWindowManager *wm = CTX_wm_manager(C); - ScrArea *area = NULL; + ScrArea *area = nullptr; SpaceImage *sima; /* find an imagewindow showing render result */ - for (*win = wm->windows.first; *win; *win = (*win)->next) { + for (*win = static_cast<wmWindow *>(wm->windows.first); *win; *win = (*win)->next) { if (WM_window_get_active_scene(*win) == scene) { const bScreen *screen = WM_window_get_active_screen(*win); - for (area = screen->areabase.first; area; area = area->next) { + for (area = static_cast<ScrArea *>(screen->areabase.first); area; area = area->next) { if (area->spacetype == SPACE_IMAGE) { - sima = area->spacedata.first; + sima = static_cast<SpaceImage *>(area->spacedata.first); if (sima->image && sima->image->type == IMA_TYPE_R_RESULT) { break; } @@ -118,9 +118,9 @@ static ScrArea *find_area_image_empty(bContext *C) SpaceImage *sima; /* find an imagewindow showing render result */ - for (area = screen->areabase.first; area; area = area->next) { + for (area = static_cast<ScrArea *>(screen->areabase.first); area; area = area->next) { if (area->spacetype == SPACE_IMAGE) { - sima = area->spacedata.first; + sima = static_cast<SpaceImage *>(area->spacedata.first); if ((sima->mode == SI_MODE_VIEW) && !sima->image) { break; } @@ -136,13 +136,13 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); - wmWindow *win = NULL; - ScrArea *area = NULL; + wmWindow *win = nullptr; + ScrArea *area = nullptr; SpaceImage *sima; bool area_was_image = false; if (U.render_display_type == USER_RENDER_DISPLAY_NONE) { - return NULL; + return nullptr; } if (U.render_display_type == USER_RENDER_DISPLAY_WINDOW) { @@ -168,14 +168,14 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports) true, false, true, - WIN_ALIGN_LOCATION_CENTER) == NULL) { + WIN_ALIGN_LOCATION_CENTER) == nullptr) { BKE_report(reports, RPT_ERROR, "Failed to open window!"); - return NULL; + return nullptr; } area = CTX_wm_area(C); if (BLI_listbase_is_single(&area->spacedata) == false) { - sima = area->spacedata.first; + sima = static_cast<SpaceImage *>(area->spacedata.first); sima->flag |= SI_PREVSPACE; } } @@ -185,7 +185,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports) /* If the active screen is already in full-screen mode, skip this and * unset the area, so that the full-screen area is just changed later. */ if (area && area->full) { - area = NULL; + area = nullptr; } else { if (area && area->spacetype == SPACE_IMAGE) { @@ -199,7 +199,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports) if (!area) { area = find_area_showing_r_result(C, scene, &win); - if (area == NULL) { + if (area == nullptr) { area = find_area_image_empty(C); } @@ -208,12 +208,12 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports) wm_window_raise(win); } - if (area == NULL) { + if (area == nullptr) { /* find largest open non-image area */ area = biggest_non_image_area(C); if (area) { ED_area_newspace(C, area, SPACE_IMAGE, true); - sima = area->spacedata.first; + sima = static_cast<SpaceImage *>(area->spacedata.first); /* Makes "Escape" go back to previous space. */ sima->flag |= SI_PREVSPACE; @@ -228,7 +228,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports) area = BKE_screen_find_big_area(CTX_wm_screen(C), SPACE_TYPE_ANY, 0); if (area->spacetype != SPACE_IMAGE) { // XXX newspace(area, SPACE_IMAGE); - sima = area->spacedata.first; + sima = static_cast<SpaceImage *>(area->spacedata.first); /* Makes "Escape" go back to previous space. */ sima->flag |= SI_PREVSPACE; @@ -236,7 +236,7 @@ ScrArea *render_view_open(bContext *C, int mx, int my, ReportList *reports) } } } - sima = area->spacedata.first; + sima = static_cast<SpaceImage *>(area->spacedata.first); sima->link_flag |= SPACE_FLAG_TYPE_TEMPORARY; /* get the correct image, and scale it */ @@ -272,7 +272,7 @@ static int render_view_cancel_exec(bContext *C, wmOperator *UNUSED(op)) { wmWindow *win = CTX_wm_window(C); ScrArea *area = CTX_wm_area(C); - SpaceImage *sima = area->spacedata.first; + SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first); /* ensure image editor full-screen and area full-screen states are in sync */ if ((sima->flag & SI_FULLWINDOW) && !area->full) { @@ -333,7 +333,7 @@ static int render_view_show_invoke(bContext *C, wmOperator *op, const wmEvent *e ScrArea *area = find_area_showing_r_result(C, CTX_data_scene(C), &winshow); /* is there another window on current scene showing result? */ - for (win = CTX_wm_manager(C)->windows.first; win; win = win->next) { + for (win = static_cast<wmWindow *>(CTX_wm_manager(C)->windows.first); win; win = win->next) { const bScreen *screen = WM_window_get_active_screen(win); if ((WM_window_is_temp_screen(win) && @@ -348,7 +348,7 @@ static int render_view_show_invoke(bContext *C, wmOperator *op, const wmEvent *e if (area) { /* but don't close it when rendering */ if (G.is_rendering == false) { - SpaceImage *sima = area->spacedata.first; + SpaceImage *sima = static_cast<SpaceImage *>(area->spacedata.first); if (sima->flag & SI_PREVSPACE) { sima->flag &= ~SI_PREVSPACE; diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index 5dc6fe88663..c6834c84794 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -1667,7 +1667,7 @@ static bool event_in_markers_region(const ARegion *region, const wmEvent *event) { rcti rect = region->winrct; rect.ymax = rect.ymin + UI_MARKER_MARGIN_Y; - return BLI_rcti_isect_pt(&rect, event->xy[0], event->xy[1]); + return BLI_rcti_isect_pt_v(&rect, event->xy); } /** @@ -1680,7 +1680,7 @@ static void ed_default_handlers( /* NOTE: add-handler checks if it already exists. */ - /* XXX it would be good to have boundbox checks for some of these... */ + /* XXX: it would be good to have bound-box checks for some of these. */ if (flag & ED_KEYMAP_UI) { wmKeyMap *keymap = WM_keymap_ensure(wm->defaultconf, "User Interface", 0, 0); WM_event_add_keymap_handler(handlers, keymap); diff --git a/source/blender/editors/screen/glutil.c b/source/blender/editors/screen/glutil.c index 5f523df18d1..63b7fbc14a7 100644 --- a/source/blender/editors/screen/glutil.c +++ b/source/blender/editors/screen/glutil.c @@ -64,7 +64,7 @@ IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin) state.shader = GPU_shader_get_builtin_shader(builtin); - /* Shader will be unbind by immUnbindProgram in immDrawPixelsTexScaled_clipping */ + /* Shader will be unbind by immUnbindProgram in a `immDrawPixelsTex` function. */ immBindBuiltinProgram(builtin); immUniform1i("image", 0); state.do_shader_unbind = true; @@ -72,23 +72,92 @@ IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin) return state; } -void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state, - float x, - float y, - int img_w, - int img_h, - eGPUTextureFormat gpu_format, - bool use_filter, - void *rect, - float scaleX, - float scaleY, - float clip_min_x, - float clip_min_y, - float clip_max_x, - float clip_max_y, - float xzoom, - float yzoom, - const float color[4]) +void immDrawPixelsTexScaledFullSize(const IMMDrawPixelsTexState *state, + const float x, + const float y, + const int img_w, + const int img_h, + const eGPUTextureFormat gpu_format, + const bool use_filter, + const void *rect, + const float scaleX, + const float scaleY, + const float xzoom, + const float yzoom, + const float color[4]) +{ + static const float white[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + const float draw_width = img_w * scaleX * xzoom; + const float draw_height = img_h * scaleY * yzoom; + /* Down-scaling with regular bi-linear interpolation (i.e. #GL_LINEAR) doesn't give good + * filtering results. Mipmaps can be used to get better results (i.e. #GL_LINEAR_MIPMAP_LINEAR), + * so always use mipmaps when filtering. */ + const bool use_mipmap = use_filter && ((draw_width < img_w) || (draw_height < img_h)); + + GPUTexture *tex = GPU_texture_create_2d("immDrawPixels", img_w, img_h, 1, gpu_format, NULL); + + const bool use_float_data = ELEM(gpu_format, GPU_RGBA16F, GPU_RGB16F, GPU_R16F); + eGPUDataFormat gpu_data_format = (use_float_data) ? GPU_DATA_FLOAT : GPU_DATA_UBYTE; + GPU_texture_update(tex, gpu_data_format, rect); + + GPU_texture_filter_mode(tex, use_filter); + if (use_mipmap) { + GPU_texture_generate_mipmap(tex); + GPU_texture_mipmap_mode(tex, true, true); + } + GPU_texture_wrap_mode(tex, false, true); + + GPU_texture_bind(tex, 0); + + /* optional */ + /* NOTE: Shader could be null for GLSL OCIO drawing, it is fine, since + * it does not need color. + */ + if (state->shader != NULL && GPU_shader_get_uniform(state->shader, "color") != -1) { + immUniformColor4fv((color) ? color : white); + } + + uint pos = state->pos, texco = state->texco; + + immBegin(GPU_PRIM_TRI_FAN, 4); + immAttr2f(texco, 0.0f, 0.0f); + immVertex2f(pos, x, y); + + immAttr2f(texco, 1.0f, 0.0f); + immVertex2f(pos, x + draw_width, y); + + immAttr2f(texco, 1.0f, 1.0f); + immVertex2f(pos, x + draw_width, y + draw_height); + + immAttr2f(texco, 0.0f, 1.0f); + immVertex2f(pos, x, y + draw_height); + immEnd(); + + if (state->do_shader_unbind) { + immUnbindProgram(); + } + + GPU_texture_unbind(tex); + GPU_texture_free(tex); +} + +void immDrawPixelsTexTiled_scaling_clipping(IMMDrawPixelsTexState *state, + float x, + float y, + int img_w, + int img_h, + eGPUTextureFormat gpu_format, + bool use_filter, + void *rect, + float scaleX, + float scaleY, + float clip_min_x, + float clip_min_y, + float clip_max_x, + float clip_max_y, + float xzoom, + float yzoom, + const float color[4]) { int subpart_x, subpart_y, tex_w = 256, tex_h = 256; int seamless, offset_x, offset_y, nsubparts_x, nsubparts_y; @@ -242,103 +311,103 @@ void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state, GPU_unpack_row_length_set(0); } -void immDrawPixelsTexScaled(IMMDrawPixelsTexState *state, - float x, - float y, - int img_w, - int img_h, - eGPUTextureFormat gpu_format, - bool use_filter, - void *rect, - float scaleX, - float scaleY, - float xzoom, - float yzoom, - const float color[4]) +void immDrawPixelsTexTiled_scaling(IMMDrawPixelsTexState *state, + float x, + float y, + int img_w, + int img_h, + eGPUTextureFormat gpu_format, + bool use_filter, + void *rect, + float scaleX, + float scaleY, + float xzoom, + float yzoom, + const float color[4]) { - immDrawPixelsTexScaled_clipping(state, - x, - y, - img_w, - img_h, - gpu_format, - use_filter, - rect, - scaleX, - scaleY, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - xzoom, - yzoom, - color); + immDrawPixelsTexTiled_scaling_clipping(state, + x, + y, + img_w, + img_h, + gpu_format, + use_filter, + rect, + scaleX, + scaleY, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + xzoom, + yzoom, + color); } -void immDrawPixelsTex(IMMDrawPixelsTexState *state, - float x, - float y, - int img_w, - int img_h, - eGPUTextureFormat gpu_format, - bool use_filter, - void *rect, - float xzoom, - float yzoom, - const float color[4]) +void immDrawPixelsTexTiled(IMMDrawPixelsTexState *state, + float x, + float y, + int img_w, + int img_h, + eGPUTextureFormat gpu_format, + bool use_filter, + void *rect, + float xzoom, + float yzoom, + const float color[4]) { - immDrawPixelsTexScaled_clipping(state, - x, - y, - img_w, - img_h, - gpu_format, - use_filter, - rect, - 1.0f, - 1.0f, - 0.0f, - 0.0f, - 0.0f, - 0.0f, - xzoom, - yzoom, - color); + immDrawPixelsTexTiled_scaling_clipping(state, + x, + y, + img_w, + img_h, + gpu_format, + use_filter, + rect, + 1.0f, + 1.0f, + 0.0f, + 0.0f, + 0.0f, + 0.0f, + xzoom, + yzoom, + color); } -void immDrawPixelsTex_clipping(IMMDrawPixelsTexState *state, - float x, - float y, - int img_w, - int img_h, - eGPUTextureFormat gpu_format, - bool use_filter, - void *rect, - float clip_min_x, - float clip_min_y, - float clip_max_x, - float clip_max_y, - float xzoom, - float yzoom, - const float color[4]) +void immDrawPixelsTexTiled_clipping(IMMDrawPixelsTexState *state, + float x, + float y, + int img_w, + int img_h, + eGPUTextureFormat gpu_format, + bool use_filter, + void *rect, + float clip_min_x, + float clip_min_y, + float clip_max_x, + float clip_max_y, + float xzoom, + float yzoom, + const float color[4]) { - immDrawPixelsTexScaled_clipping(state, - x, - y, - img_w, - img_h, - gpu_format, - use_filter, - rect, - 1.0f, - 1.0f, - clip_min_x, - clip_min_y, - clip_max_x, - clip_max_y, - xzoom, - yzoom, - color); + immDrawPixelsTexTiled_scaling_clipping(state, + x, + y, + img_w, + img_h, + gpu_format, + use_filter, + rect, + 1.0f, + 1.0f, + clip_min_x, + clip_min_y, + clip_max_x, + clip_max_y, + xzoom, + yzoom, + color); } /* **** Color management helper functions for GLSL display/transform ***** */ @@ -409,40 +478,40 @@ void ED_draw_imbuf_clipping(ImBuf *ibuf, } if (format != 0) { - immDrawPixelsTex_clipping(&state, - x, - y, - ibuf->x, - ibuf->y, - format, - use_filter, - ibuf->rect_float, - clip_min_x, - clip_min_y, - clip_max_x, - clip_max_y, - zoom_x, - zoom_y, - NULL); + immDrawPixelsTexTiled_clipping(&state, + x, + y, + ibuf->x, + ibuf->y, + format, + use_filter, + ibuf->rect_float, + clip_min_x, + clip_min_y, + clip_max_x, + clip_max_y, + zoom_x, + zoom_y, + NULL); } } else if (ibuf->rect) { /* ibuf->rect is always RGBA */ - immDrawPixelsTex_clipping(&state, - x, - y, - ibuf->x, - ibuf->y, - GPU_RGBA8, - use_filter, - ibuf->rect, - clip_min_x, - clip_min_y, - clip_max_x, - clip_max_y, - zoom_x, - zoom_y, - NULL); + immDrawPixelsTexTiled_clipping(&state, + x, + y, + ibuf->x, + ibuf->y, + GPU_RGBA8, + use_filter, + ibuf->rect, + clip_min_x, + clip_min_y, + clip_max_x, + clip_max_y, + zoom_x, + zoom_y, + NULL); } IMB_colormanagement_finish_glsl_draw(); @@ -461,21 +530,21 @@ void ED_draw_imbuf_clipping(ImBuf *ibuf, if (display_buffer) { IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); - immDrawPixelsTex_clipping(&state, - x, - y, - ibuf->x, - ibuf->y, - GPU_RGBA8, - use_filter, - display_buffer, - clip_min_x, - clip_min_y, - clip_max_x, - clip_max_y, - zoom_x, - zoom_y, - NULL); + immDrawPixelsTexTiled_clipping(&state, + x, + y, + ibuf->x, + ibuf->y, + GPU_RGBA8, + use_filter, + display_buffer, + clip_min_x, + clip_min_y, + clip_max_x, + clip_max_y, + zoom_x, + zoom_y, + NULL); } IMB_display_buffer_release(cache_handle); diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c index 304205d0cc4..04df90bf912 100644 --- a/source/blender/editors/screen/screen_context.c +++ b/source/blender/editors/screen/screen_context.c @@ -501,7 +501,7 @@ static eContextResult screen_ctx_active_pose_bone(const bContext *C, bContextDat Object *obact = view_layer->basact ? view_layer->basact->object : NULL; Object *obpose = BKE_object_pose_armature_get(obact); - bPoseChannel *pchan = BKE_pose_channel_active(obpose); + bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(obpose); if (pchan) { CTX_data_pointer_set(result, &obpose->id, &RNA_PoseBone, pchan); return CTX_RESULT_OK; diff --git a/source/blender/editors/screen/screen_draw.c b/source/blender/editors/screen/screen_draw.c index e720ae4b9d8..01730b3c9aa 100644 --- a/source/blender/editors/screen/screen_draw.c +++ b/source/blender/editors/screen/screen_draw.c @@ -144,7 +144,7 @@ static void drawscredge_area_draw( } GPUBatch *batch = batch_screen_edges_get(NULL); - GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_AREA_EDGES); + GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_AREA_BORDERS); GPU_batch_uniform_4fv(batch, "rect", (float *)&rect); GPU_batch_draw(batch); } @@ -212,7 +212,7 @@ void ED_screen_draw_edges(wmWindow *win) GPU_blend(GPU_BLEND_ALPHA); GPUBatch *batch = batch_screen_edges_get(&verts_per_corner); - GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_AREA_EDGES); + GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_AREA_BORDERS); GPU_batch_uniform_1i(batch, "cornerLen", verts_per_corner); GPU_batch_uniform_1f(batch, "scale", corner_scale); GPU_batch_uniform_4fv(batch, "color", col); diff --git a/source/blender/editors/screen/screen_intern.h b/source/blender/editors/screen/screen_intern.h index bc06e46ba96..e42c891b0ba 100644 --- a/source/blender/editors/screen/screen_intern.h +++ b/source/blender/editors/screen/screen_intern.h @@ -71,10 +71,10 @@ typedef enum eScreenAxis { /** * we swap spaces for fullscreen to keep all allocated data area vertices were set */ -void ED_area_data_copy(ScrArea *area_dst, ScrArea *area_src, const bool do_free); +void ED_area_data_copy(ScrArea *area_dst, ScrArea *area_src, bool do_free); void ED_area_data_swap(ScrArea *area_dst, ScrArea *area_src); /* for quick toggle, can skip fades */ -void region_toggle_hidden(struct bContext *C, ARegion *region, const bool do_fade); +void region_toggle_hidden(struct bContext *C, ARegion *region, bool do_fade); /* screen_draw.c */ @@ -85,7 +85,7 @@ void region_toggle_hidden(struct bContext *C, ARegion *region, const bool do_fad * \param sa2: Target area that will be replaced. */ void screen_draw_join_highlight(struct ScrArea *sa1, struct ScrArea *sa2); -void screen_draw_split_preview(struct ScrArea *area, const eScreenAxis dir_axis, const float fac); +void screen_draw_split_preview(struct ScrArea *area, eScreenAxis dir_axis, float fac); /* screen_edit.c */ @@ -111,9 +111,9 @@ void screen_change_prepare(bScreen *screen_old, ScrArea *area_split(const wmWindow *win, bScreen *screen, ScrArea *area, - const eScreenAxis dir_axis, - const float fac, - const bool merge); + eScreenAxis dir_axis, + float fac, + bool merge); /** * Join any two neighboring areas. Might involve complex changes. */ @@ -127,8 +127,7 @@ eScreenDir area_getorientation(ScrArea *sa_a, ScrArea *sa_b); /** * Get alignment offset of adjacent areas. 'dir' value is like #area_getorientation(). */ -void area_getoffsets( - ScrArea *sa_a, ScrArea *sa_b, const eScreenDir dir, int *r_offset1, int *r_offset2); +void area_getoffsets(ScrArea *sa_a, ScrArea *sa_b, eScreenDir dir, int *r_offset1, int *r_offset2); /** * Close a screen area, allowing most-aligned neighbor to take its place. */ @@ -150,15 +149,15 @@ bool screen_geom_edge_is_horizontal(ScrEdge *se); */ ScrEdge *screen_geom_area_map_find_active_scredge(const struct ScrAreaMap *area_map, const rcti *bounds_rect, - const int mx, - const int my); + int mx, + int my); /** * Need win size to make sure not to include edges along screen edge. */ ScrEdge *screen_geom_find_active_scredge(const wmWindow *win, const bScreen *screen, - const int mx, - const int my); + int mx, + int my); /** * \brief Main screen-layout calculation function. * @@ -172,7 +171,7 @@ void screen_geom_vertices_scale(const wmWindow *win, bScreen *screen); */ short screen_geom_find_area_split_point(const ScrArea *area, const rcti *window_rect, - const eScreenAxis dir_axis, + eScreenAxis dir_axis, float fac); /** * Select all edges that are directly or indirectly connected to \a edge. diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c index d017345b523..6581bffb6bd 100644 --- a/source/blender/editors/screen/screen_ops.c +++ b/source/blender/editors/screen/screen_ops.c @@ -1128,8 +1128,7 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event) AREAMAP_FROM_SCREEN(screen), &screen_rect, event->xy[0], event->xy[1]) == NULL)) { /* What area are we now in? */ - ScrArea *area = BKE_screen_find_area_xy( - screen, SPACE_TYPE_ANY, event->xy[0], event->xy[1]); + ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy); if (area == sad->sa1) { /* Same area, so possible split. */ @@ -1173,7 +1172,7 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event) /* gesture is large enough? */ if (is_gesture) { /* second area, for join when (sa1 != sa2) */ - sad->sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy[0], event->xy[1]); + sad->sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy); /* apply sends event */ actionzone_apply(C, op, sad->az->type); actionzone_exit(op); @@ -1241,12 +1240,16 @@ static ScrEdge *screen_area_edge_from_cursor(const bContext *C, int borderwidth = (4 * UI_DPI_FAC); ScrArea *sa1, *sa2; if (screen_geom_edge_is_horizontal(actedge)) { - sa1 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0], cursor[1] + borderwidth); - sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0], cursor[1] - borderwidth); + sa1 = BKE_screen_find_area_xy( + screen, SPACE_TYPE_ANY, (const int[2]){cursor[0], cursor[1] + borderwidth}); + sa2 = BKE_screen_find_area_xy( + screen, SPACE_TYPE_ANY, (const int[2]){cursor[0], cursor[1] - borderwidth}); } else { - sa1 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0] + borderwidth, cursor[1]); - sa2 = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, cursor[0] - borderwidth, cursor[1]); + sa1 = BKE_screen_find_area_xy( + screen, SPACE_TYPE_ANY, (const int[2]){cursor[0] + borderwidth, cursor[1]}); + sa2 = BKE_screen_find_area_xy( + screen, SPACE_TYPE_ANY, (const int[2]){cursor[0] - borderwidth, cursor[1]}); } bool isGlobal = ((sa1 && ED_area_is_global(sa1)) || (sa2 && ED_area_is_global(sa2))); if (!isGlobal) { @@ -1334,8 +1337,7 @@ static int area_swap_modal(bContext *C, wmOperator *op, const wmEvent *event) switch (event->type) { case MOUSEMOVE: /* second area, for join */ - sad->sa2 = BKE_screen_find_area_xy( - CTX_wm_screen(C), SPACE_TYPE_ANY, event->xy[0], event->xy[1]); + sad->sa2 = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, event->xy); break; case LEFTMOUSE: /* release LMB */ if (event->val == KM_RELEASE) { @@ -2081,15 +2083,31 @@ typedef struct sAreaSplitData { } sAreaSplitData; +static bool area_split_allowed(const ScrArea *area, const eScreenAxis dir_axis) +{ + if (!area || area->global) { + /* Must be a non-global area. */ + return false; + } + + if ((dir_axis == SCREEN_AXIS_V && area->winx <= 2 * AREAMINX) || + (dir_axis == SCREEN_AXIS_H && area->winy <= 2 * ED_area_headersize())) { + /* Must be at least double minimum sizes to split into two. */ + return false; + } + + return true; +} + static void area_split_draw_cb(const struct wmWindow *UNUSED(win), void *userdata) { const wmOperator *op = userdata; sAreaSplitData *sd = op->customdata; - if (sd->sarea) { - const eScreenAxis dir_axis = RNA_enum_get(op->ptr, "direction"); - float fac = RNA_float_get(op->ptr, "factor"); + const eScreenAxis dir_axis = RNA_enum_get(op->ptr, "direction"); + if (area_split_allowed(sd->sarea, dir_axis)) { + float fac = RNA_float_get(op->ptr, "factor"); screen_draw_split_preview(sd->sarea, dir_axis, fac); } } @@ -2119,18 +2137,6 @@ static bool area_split_init(bContext *C, wmOperator *op) /* required properties */ const eScreenAxis dir_axis = RNA_enum_get(op->ptr, "direction"); - /* minimal size */ - if (dir_axis == SCREEN_AXIS_V) { - if (area->winx < 2 * AREAMINX) { - return false; - } - } - else { - if (area->winy < 2 * ED_area_headersize()) { - return false; - } - } - /* custom data */ sAreaSplitData *sd = (sAreaSplitData *)MEM_callocN(sizeof(sAreaSplitData), "op_area_split"); op->customdata = sd; @@ -2187,6 +2193,10 @@ static bool area_split_apply(bContext *C, wmOperator *op) float fac = RNA_float_get(op->ptr, "factor"); const eScreenAxis dir_axis = RNA_enum_get(op->ptr, "direction"); + if (!area_split_allowed(sd->sarea, dir_axis)) { + return false; + } + sd->narea = area_split(win, screen, sd->sarea, dir_axis, fac, false); /* false = no merge */ if (sd->narea == NULL) { @@ -2252,9 +2262,15 @@ static void area_split_exit(bContext *C, wmOperator *op) static void area_split_preview_update_cursor(bContext *C, wmOperator *op) { - wmWindow *win = CTX_wm_window(C); + sAreaSplitData *sd = (sAreaSplitData *)op->customdata; const eScreenAxis dir_axis = RNA_enum_get(op->ptr, "direction"); - WM_cursor_set(win, (dir_axis == SCREEN_AXIS_H) ? WM_CURSOR_H_SPLIT : WM_CURSOR_V_SPLIT); + if (area_split_allowed(sd->sarea, dir_axis)) { + WM_cursor_set(CTX_wm_window(C), + (dir_axis == SCREEN_AXIS_H) ? WM_CURSOR_H_SPLIT : WM_CURSOR_V_SPLIT); + } + else { + WM_cursor_set(CTX_wm_window(C), WM_CURSOR_STOP); + } } /* UI callback, adds new handler */ @@ -2507,9 +2523,11 @@ static int area_split_modal(bContext *C, wmOperator *op, const wmEvent *event) if (sd->sarea) { ED_area_tag_redraw(sd->sarea); } + + area_split_preview_update_cursor(C, op); + /* area context not set */ - sd->sarea = BKE_screen_find_area_xy( - CTX_wm_screen(C), SPACE_TYPE_ANY, event->xy[0], event->xy[1]); + sd->sarea = BKE_screen_find_area_xy(CTX_wm_screen(C), SPACE_TYPE_ANY, event->xy); if (sd->sarea) { ScrArea *area = sd->sarea; @@ -3517,7 +3535,7 @@ static int area_join_modal(bContext *C, wmOperator *op, const wmEvent *event) switch (event->type) { case MOUSEMOVE: { - ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy[0], event->xy[1]); + ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy); jd->dir = area_getorientation(jd->sa1, jd->sa2); if (area == jd->sa1) { diff --git a/source/blender/editors/screen/screendump.c b/source/blender/editors/screen/screendump.c index 5c4ba67d72a..4bc9f1e2565 100644 --- a/source/blender/editors/screen/screendump.c +++ b/source/blender/editors/screen/screendump.c @@ -166,8 +166,7 @@ static int screenshot_invoke(bContext *C, wmOperator *op, const wmEvent *event) if (use_crop) { area = CTX_wm_area(C); bScreen *screen = CTX_wm_screen(C); - ScrArea *area_test = BKE_screen_find_area_xy( - screen, SPACE_TYPE_ANY, event->xy[0], event->xy[1]); + ScrArea *area_test = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->xy); if (area_test != NULL) { area = area_test; } @@ -180,8 +179,9 @@ static int screenshot_invoke(bContext *C, wmOperator *op, const wmEvent *event) /* extension is added by 'screenshot_check' after */ char filepath[FILE_MAX] = "//screen"; - if (G.relbase_valid) { - BLI_strncpy(filepath, BKE_main_blendfile_path_from_global(), sizeof(filepath)); + const char *blendfile_path = BKE_main_blendfile_path_from_global(); + if (blendfile_path[0] != '\0') { + BLI_strncpy(filepath, blendfile_path, sizeof(filepath)); BLI_path_extension_replace(filepath, sizeof(filepath), ""); /* strip '.blend' */ } RNA_string_set(op->ptr, "filepath", filepath); diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c index 125b345a1ed..6e69c82ba67 100644 --- a/source/blender/editors/screen/workspace_edit.c +++ b/source/blender/editors/screen/workspace_edit.c @@ -495,7 +495,7 @@ static void WORKSPACE_OT_reorder_to_back(wmOperatorType *ot) { /* identifiers */ ot->name = "Workspace Reorder to Back"; - ot->description = "Reorder workspace to be first in the list"; + ot->description = "Reorder workspace to be last in the list"; ot->idname = "WORKSPACE_OT_reorder_to_back"; /* api callbacks */ diff --git a/source/blender/editors/sculpt_paint/CMakeLists.txt b/source/blender/editors/sculpt_paint/CMakeLists.txt index b826ff8701d..b15b6784d34 100644 --- a/source/blender/editors/sculpt_paint/CMakeLists.txt +++ b/source/blender/editors/sculpt_paint/CMakeLists.txt @@ -27,6 +27,7 @@ set(INC ../../gpu ../../imbuf ../../makesdna + ../../nodes ../../makesrna ../../render ../../windowmanager @@ -59,6 +60,7 @@ set(SRC sculpt.c sculpt_automasking.c sculpt_boundary.c + sculpt_brush_types.c sculpt_cloth.c sculpt_detail.c sculpt_dyntopo.c @@ -71,6 +73,7 @@ set(SRC sculpt_mask_expand.c sculpt_mask_init.c sculpt_multiplane_scrape.c + sculpt_ops.c sculpt_paint_color.c sculpt_pose.c sculpt_smooth.c diff --git a/source/blender/editors/sculpt_paint/paint_cursor.c b/source/blender/editors/sculpt_paint/paint_cursor.c index 265746e27cd..4010b87a2ed 100644 --- a/source/blender/editors/sculpt_paint/paint_cursor.c +++ b/source/blender/editors/sculpt_paint/paint_cursor.c @@ -47,6 +47,8 @@ #include "BKE_object.h" #include "BKE_paint.h" +#include "NOD_texture.h" + #include "WM_api.h" #include "wm_cursors.h" diff --git a/source/blender/editors/sculpt_paint/paint_image.c b/source/blender/editors/sculpt_paint/paint_image.c index dc2eaacca0c..a912bb5cf3b 100644 --- a/source/blender/editors/sculpt_paint/paint_image.c +++ b/source/blender/editors/sculpt_paint/paint_image.c @@ -56,6 +56,8 @@ #include "BKE_paint.h" #include "BKE_undo_system.h" +#include "NOD_texture.h" + #include "DEG_depsgraph.h" #include "UI_interface.h" diff --git a/source/blender/editors/sculpt_paint/paint_image_proj.c b/source/blender/editors/sculpt_paint/paint_image_proj.c index 7df5848e068..ca012f20f01 100644 --- a/source/blender/editors/sculpt_paint/paint_image_proj.c +++ b/source/blender/editors/sculpt_paint/paint_image_proj.c @@ -414,6 +414,7 @@ typedef struct ProjPaintState { int totvert_eval; const MVert *mvert_eval; + const float (*vert_normals)[3]; const MEdge *medge_eval; const MPoly *mpoly_eval; const MLoop *mloop_eval; @@ -1718,10 +1719,10 @@ static float project_paint_uvpixel_mask(const ProjPaintState *ps, float no[3], angle_cos; if (mp->flag & ME_SMOOTH) { - const short *no1, *no2, *no3; - no1 = ps->mvert_eval[lt_vtri[0]].no; - no2 = ps->mvert_eval[lt_vtri[1]].no; - no3 = ps->mvert_eval[lt_vtri[2]].no; + const float *no1, *no2, *no3; + no1 = ps->vert_normals[lt_vtri[0]]; + no2 = ps->vert_normals[lt_vtri[1]]; + no3 = ps->vert_normals[lt_vtri[2]]; no[0] = w[0] * no1[0] + w[1] * no2[0] + w[2] * no3[0]; no[1] = w[0] * no1[1] + w[1] * no2[1] + w[2] * no3[1]; @@ -3871,7 +3872,6 @@ static void proj_paint_state_screen_coords_init(ProjPaintState *ps, const int di static void proj_paint_state_cavity_init(ProjPaintState *ps) { - const MVert *mv; const MEdge *me; float *cavities; int a; @@ -3891,13 +3891,11 @@ static void proj_paint_state_cavity_init(ProjPaintState *ps) sub_v3_v3(edges[me->v1], e); counter[me->v1]++; } - for (a = 0, mv = ps->mvert_eval; a < ps->totvert_eval; a++, mv++) { + for (a = 0; a < ps->totvert_eval; a++) { if (counter[a] > 0) { - float no[3]; mul_v3_fl(edges[a], 1.0f / counter[a]); - normal_short_to_float_v3(no, mv->no); /* Augment the difference. */ - cavities[a] = saacos(10.0f * dot_v3v3(no, edges[a])) * (float)M_1_PI; + cavities[a] = saacos(10.0f * dot_v3v3(ps->vert_normals[a], edges[a])) * (float)M_1_PI; } else { cavities[a] = 0.0; @@ -3964,7 +3962,7 @@ static void proj_paint_state_vert_flags_init(ProjPaintState *ps) ps->vertFlags = MEM_callocN(sizeof(char) * ps->totvert_eval, "paint-vertFlags"); for (a = 0, mv = ps->mvert_eval; a < ps->totvert_eval; a++, mv++) { - normal_short_to_float_v3(no, mv->no); + copy_v3_v3(no, ps->vert_normals[a]); if (UNLIKELY(ps->is_flip_object)) { negate_v3(no); } @@ -4064,6 +4062,7 @@ static bool proj_paint_state_mesh_eval_init(const bContext *C, ProjPaintState *p ps->mat_array[totmat - 1] = NULL; ps->mvert_eval = ps->me_eval->mvert; + ps->vert_normals = BKE_mesh_vertex_normals_ensure(ps->me_eval); if (ps->do_mask_cavity) { ps->medge_eval = ps->me_eval->medge; } @@ -6567,7 +6566,7 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op) nodeSetActive(ntree, imanode); - /* Connect to first available principled bsdf node. */ + /* Connect to first available principled BSDF node. */ bNode *in_node = ntreeFindType(ntree, SH_NODE_BSDF_PRINCIPLED); bNode *out_node = imanode; @@ -6623,7 +6622,7 @@ static bool proj_paint_add_slot(bContext *C, wmOperator *op) } } - ntreeUpdateTree(CTX_data_main(C), ntree); + ED_node_tree_propagate_change(C, bmain, ntree); /* In case we added more than one node, position them too. */ nodePositionPropagate(out_node); diff --git a/source/blender/editors/sculpt_paint/paint_intern.h b/source/blender/editors/sculpt_paint/paint_intern.h index 90887b9fc39..d31390bbb42 100644 --- a/source/blender/editors/sculpt_paint/paint_intern.h +++ b/source/blender/editors/sculpt_paint/paint_intern.h @@ -25,6 +25,8 @@ #include "BKE_paint.h" +#include "BLI_compiler_compat.h" +#include "BLI_math.h" #include "BLI_rect.h" #include "DNA_scene_types.h" @@ -150,10 +152,7 @@ unsigned int vpaint_get_current_col(struct Scene *scene, struct VPaint *vp, bool /** * \note weight-paint has an equivalent function: #ED_wpaint_blend_tool */ -unsigned int ED_vpaint_blend_tool(const int tool, - const uint col, - const uint paintcol, - const int alpha_i); +unsigned int ED_vpaint_blend_tool(int tool, uint col, uint paintcol, int alpha_i); /** * Apply callback to each vertex of the active vertex color layer. */ @@ -171,10 +170,7 @@ bool ED_vpaint_color_transform(struct Object *ob, * * \note vertex-paint has an equivalent function: #ED_vpaint_blend_tool */ -float ED_wpaint_blend_tool(const int tool, - const float weight, - const float paintval, - const float alpha); +float ED_wpaint_blend_tool(int tool, float weight, float paintval, float alpha); /* Utility for tools to ensure vertex groups exist before they begin. */ enum eWPaintFlag { WPAINT_ENSURE_MIRROR = (1 << 0), @@ -191,7 +187,7 @@ bool ED_wpaint_ensure_data(struct bContext *C, enum eWPaintFlag flag, struct WPaintVGroupIndex *vgroup_index); /** Return -1 when invalid. */ -int ED_wpaint_mirror_vgroup_ensure(struct Object *ob, const int vgroup_active); +int ED_wpaint_mirror_vgroup_ensure(struct Object *ob, int vgroup_active); /* paint_vertex_color_ops.c */ @@ -244,7 +240,7 @@ void paint_2d_stroke_done(void *ps); void paint_2d_stroke(void *ps, const float prev_mval[2], const float mval[2], - const bool eraser, + bool eraser, float pressure, float distance, float size); @@ -267,7 +263,7 @@ void paint_proj_stroke(const struct bContext *C, void *ps_handle_p, const float prev_pos[2], const float pos[2], - const bool eraser, + bool eraser, float pressure, float distance, float size); @@ -331,8 +327,8 @@ typedef struct CurveMaskCache { void paint_curve_mask_cache_free_data(CurveMaskCache *curve_mask_cache); void paint_curve_mask_cache_update(CurveMaskCache *curve_mask_cache, const struct Brush *brush, - const int diameter, - const float radius, + int diameter, + float radius, const float cursor_position[2]); /* sculpt_uv.c */ @@ -404,8 +400,61 @@ bool facemask_paint_poll(struct bContext *C); /** * Uses symm to selectively flip any axis of a coordinate. */ -void flip_v3_v3(float out[3], const float in[3], const enum ePaintSymmetryFlags symm); -void flip_qt_qt(float out[4], const float in[4], const enum ePaintSymmetryFlags symm); + +BLI_INLINE void flip_v3_v3(float out[3], const float in[3], const ePaintSymmetryFlags symm) +{ + if (symm & PAINT_SYMM_X) { + out[0] = -in[0]; + } + else { + out[0] = in[0]; + } + if (symm & PAINT_SYMM_Y) { + out[1] = -in[1]; + } + else { + out[1] = in[1]; + } + if (symm & PAINT_SYMM_Z) { + out[2] = -in[2]; + } + else { + out[2] = in[2]; + } +} + +BLI_INLINE void flip_qt_qt(float out[4], const float in[4], const ePaintSymmetryFlags symm) +{ + float axis[3], angle; + + quat_to_axis_angle(axis, &angle, in); + normalize_v3(axis); + + if (symm & PAINT_SYMM_X) { + axis[0] *= -1.0f; + angle *= -1.0f; + } + if (symm & PAINT_SYMM_Y) { + axis[1] *= -1.0f; + angle *= -1.0f; + } + if (symm & PAINT_SYMM_Z) { + axis[2] *= -1.0f; + angle *= -1.0f; + } + + axis_angle_normalized_to_quat(out, axis, angle); +} + +BLI_INLINE void flip_v3(float v[3], const ePaintSymmetryFlags symm) +{ + flip_v3_v3(v, v, symm); +} + +BLI_INLINE void flip_qt(float quat[4], const ePaintSymmetryFlags symm) +{ + flip_qt_qt(quat, quat, symm); +} /* stroke operator */ typedef enum BrushStrokeMode { diff --git a/source/blender/editors/sculpt_paint/paint_utils.c b/source/blender/editors/sculpt_paint/paint_utils.c index 541893f7957..95a0aba1ffb 100644 --- a/source/blender/editors/sculpt_paint/paint_utils.c +++ b/source/blender/editors/sculpt_paint/paint_utils.c @@ -397,51 +397,6 @@ static Image *imapaint_face_image(Object *ob, Mesh *me, int face_index) return ima; } -void flip_v3_v3(float out[3], const float in[3], const ePaintSymmetryFlags symm) -{ - if (symm & PAINT_SYMM_X) { - out[0] = -in[0]; - } - else { - out[0] = in[0]; - } - if (symm & PAINT_SYMM_Y) { - out[1] = -in[1]; - } - else { - out[1] = in[1]; - } - if (symm & PAINT_SYMM_Z) { - out[2] = -in[2]; - } - else { - out[2] = in[2]; - } -} - -void flip_qt_qt(float out[4], const float in[4], const ePaintSymmetryFlags symm) -{ - float axis[3], angle; - - quat_to_axis_angle(axis, &angle, in); - normalize_v3(axis); - - if (symm & PAINT_SYMM_X) { - axis[0] *= -1.0f; - angle *= -1.0f; - } - if (symm & PAINT_SYMM_Y) { - axis[1] *= -1.0f; - angle *= -1.0f; - } - if (symm & PAINT_SYMM_Z) { - axis[2] *= -1.0f; - angle *= -1.0f; - } - - axis_angle_normalized_to_quat(out, axis, angle); -} - void paint_sample_color( bContext *C, ARegion *region, int x, int y, bool texpaint_proj, bool use_palette) { diff --git a/source/blender/editors/sculpt_paint/paint_vertex.c b/source/blender/editors/sculpt_paint/paint_vertex.c index 23e03f3e576..75d4237d157 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex.c +++ b/source/blender/editors/sculpt_paint/paint_vertex.c @@ -32,6 +32,7 @@ #include "BLI_listbase.h" #include "BLI_math.h" #include "BLI_rect.h" +#include "BLI_string.h" #include "BLI_task.h" #include "DNA_brush_types.h" @@ -43,9 +44,11 @@ #include "RNA_access.h" #include "BKE_brush.h" +#include "BKE_colortools.h" #include "BKE_context.h" #include "BKE_deform.h" #include "BKE_layer.h" +#include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_mesh.h" #include "BKE_mesh_mapping.h" @@ -1470,14 +1473,48 @@ struct WPaintData { bool precomputed_weight_ready; }; +static void smooth_brush_toggle_on(const bContext *C, Paint *paint, StrokeCache *cache) +{ + Scene *scene = CTX_data_scene(C); + Brush *brush = paint->brush; + int cur_brush_size = BKE_brush_size_get(scene, brush); + + BLI_strncpy( + cache->saved_active_brush_name, brush->id.name + 2, sizeof(cache->saved_active_brush_name)); + + /* Switch to the blur (smooth) brush. */ + brush = BKE_paint_toolslots_brush_get(paint, WPAINT_TOOL_BLUR); + if (brush) { + BKE_paint_brush_set(paint, brush); + cache->saved_smooth_size = BKE_brush_size_get(scene, brush); + BKE_brush_size_set(scene, brush, cur_brush_size); + BKE_curvemapping_init(brush->curve); + } +} + +static void smooth_brush_toggle_off(const bContext *C, Paint *paint, StrokeCache *cache) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + Brush *brush = BKE_paint_brush(paint); + /* The current brush should match with what we have stored in the cache. */ + BLI_assert(brush == cache->brush); + + /* Try to switch back to the saved/previous brush. */ + BKE_brush_size_set(scene, brush, cache->saved_smooth_size); + brush = (Brush *)BKE_libblock_find_name(bmain, ID_BR, cache->saved_active_brush_name); + if (brush) { + BKE_paint_brush_set(paint, brush); + } +} + /* Initialize the stroke cache invariants from operator properties */ static void vwpaint_update_cache_invariants( - bContext *C, const VPaint *vp, SculptSession *ss, wmOperator *op, const float mouse[2]) + bContext *C, VPaint *vp, SculptSession *ss, wmOperator *op, const float mouse[2]) { StrokeCache *cache; Scene *scene = CTX_data_scene(C); UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; - const Brush *brush = vp->paint.brush; ViewContext *vc = paint_stroke_view_context(op->customdata); Object *ob = CTX_data_active_object(C); float mat[3][3]; @@ -1513,7 +1550,12 @@ static void vwpaint_update_cache_invariants( ups->draw_inverted = false; } + if (cache->alt_smooth) { + smooth_brush_toggle_on(C, &vp->paint, cache); + } + copy_v2_v2(cache->mouse, cache->initial_mouse); + Brush *brush = vp->paint.brush; /* Truly temporary data that isn't stored in properties */ cache->vc = vc; cache->brush = brush; @@ -1715,15 +1757,15 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo wpd->mirror.lock = tmpflags; } - if (ELEM(vp->paint.brush->weightpaint_tool, WPAINT_TOOL_SMEAR, WPAINT_TOOL_BLUR)) { - wpd->precomputed_weight = MEM_mallocN(sizeof(float) * me->totvert, __func__); - } - /* If not previously created, create vertex/weight paint mode session data */ vertex_paint_init_stroke(depsgraph, ob); vwpaint_update_cache_invariants(C, vp, ss, op, mouse); vertex_paint_init_session_data(ts, ob); + if (ELEM(vp->paint.brush->weightpaint_tool, WPAINT_TOOL_SMEAR, WPAINT_TOOL_BLUR)) { + wpd->precomputed_weight = MEM_mallocN(sizeof(float) * me->totvert, __func__); + } + if (ob->sculpt->mode.wpaint.dvert_prev != NULL) { MDeformVert *dv = ob->sculpt->mode.wpaint.dvert_prev; for (int i = 0; i < me->totvert; i++, dv++) { @@ -1735,13 +1777,6 @@ static bool wpaint_stroke_test_start(bContext *C, wmOperator *op, const float mo return true; } -static float dot_vf3vs3(const float brushNormal[3], const short vertexNormal[3]) -{ - float normal[3]; - normal_short_to_float_v3(normal, vertexNormal); - return dot_v3v3(brushNormal, normal); -} - static void get_brush_alpha_data(const Scene *scene, const SculptSession *ss, const Brush *brush, @@ -1868,7 +1903,7 @@ static void do_wpaint_brush_blur_task_cb_ex(void *__restrict userdata, if (total_hit_loops != 0) { float brush_strength = cache->bstrength; const float angle_cos = (use_normal && vd.no) ? - dot_vf3vs3(sculpt_normal_frontface, vd.no) : + dot_v3v3(sculpt_normal_frontface, vd.no) : 1.0f; if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) && ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 || @@ -1948,7 +1983,7 @@ static void do_wpaint_brush_smear_task_cb_ex(void *__restrict userdata, if (!(use_face_sel || use_vert_sel) || mv_curr->flag & SELECT) { float brush_strength = cache->bstrength; const float angle_cos = (use_normal && vd.no) ? - dot_vf3vs3(sculpt_normal_frontface, vd.no) : + dot_v3v3(sculpt_normal_frontface, vd.no) : 1.0f; if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) && ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 || @@ -2054,9 +2089,8 @@ static void do_wpaint_brush_draw_task_cb_ex(void *__restrict userdata, /* If the vertex is selected */ if (!(use_face_sel || use_vert_sel) || v_flag & SELECT) { float brush_strength = cache->bstrength; - const float angle_cos = (use_normal && vd.no) ? - dot_vf3vs3(sculpt_normal_frontface, vd.no) : - 1.0f; + const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) : + 1.0f; if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) && ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 || view_angle_limits_apply_falloff( @@ -2111,7 +2145,7 @@ static void do_wpaint_brush_calc_average_weight_cb_ex( BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { /* Test to see if the vertex coordinates are within the spherical brush region. */ if (sculpt_brush_test_sq_fn(&test, vd.co)) { - const float angle_cos = (use_normal && vd.no) ? dot_vf3vs3(sculpt_normal_frontface, vd.no) : + const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) : 1.0f; if (angle_cos > 0.0 && BKE_brush_curve_strength(data->brush, sqrtf(test.dist), cache->radius) > 0.0) { @@ -2403,7 +2437,7 @@ static void wpaint_stroke_update_step(bContext *C, struct PaintStroke *stroke, P wpi.vgroup_validmap = wpd->vgroup_validmap; wpi.vgroup_locked = wpd->vgroup_locked; wpi.vgroup_unlocked = wpd->vgroup_unlocked; - wpi.do_flip = RNA_boolean_get(itemptr, "pen_flip"); + wpi.do_flip = RNA_boolean_get(itemptr, "pen_flip") || ss->cache->invert; wpi.do_multipaint = wpd->do_multipaint; wpi.do_auto_normalize = ((ts->auto_normalize != 0) && (wpi.vgroup_validmap != NULL) && (wpi.do_multipaint || wpi.vgroup_validmap[wpi.active.index])); @@ -2488,6 +2522,14 @@ static void wpaint_stroke_done(const bContext *C, struct PaintStroke *stroke) MEM_freeN(wpd); } + SculptSession *ss = ob->sculpt; + + if (ss->cache->alt_smooth) { + ToolSettings *ts = CTX_data_tool_settings(C); + VPaint *vp = ts->wpaint; + smooth_brush_toggle_off(C, &vp->paint, ss->cache); + } + /* and particles too */ if (ob->particlesystem.first) { ParticleSystem *psys; @@ -2895,9 +2937,8 @@ static void do_vpaint_brush_draw_task_cb_ex(void *__restrict userdata, /* Calc the dot prod. between ray norm on surf and current vert * (ie splash prevention factor), and only paint front facing verts. */ float brush_strength = cache->bstrength; - const float angle_cos = (use_normal && vd.no) ? - dot_vf3vs3(sculpt_normal_frontface, vd.no) : - 1.0f; + const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) : + 1.0f; if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) && ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 || view_angle_limits_apply_falloff( @@ -2990,9 +3031,8 @@ static void do_vpaint_brush_blur_task_cb_ex(void *__restrict userdata, /* If the vertex is selected for painting. */ if (!use_vert_sel || mv->flag & SELECT) { float brush_strength = cache->bstrength; - const float angle_cos = (use_normal && vd.no) ? - dot_vf3vs3(sculpt_normal_frontface, vd.no) : - 1.0f; + const float angle_cos = (use_normal && vd.no) ? dot_v3v3(sculpt_normal_frontface, vd.no) : + 1.0f; if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) && ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 || view_angle_limits_apply_falloff( @@ -3116,7 +3156,7 @@ static void do_vpaint_brush_smear_task_cb_ex(void *__restrict userdata, * (ie splash prevention factor), and only paint front facing verts. */ float brush_strength = cache->bstrength; const float angle_cos = (use_normal && vd.no) ? - dot_vf3vs3(sculpt_normal_frontface, vd.no) : + dot_v3v3(sculpt_normal_frontface, vd.no) : 1.0f; if (((brush->flag & BRUSH_FRONTFACE) == 0 || (angle_cos > 0.0f)) && ((brush->flag & BRUSH_FRONTFACE_FALLOFF) == 0 || @@ -3443,6 +3483,14 @@ static void vpaint_stroke_done(const bContext *C, struct PaintStroke *stroke) MEM_freeN(vpd->smear.color_curr); } + SculptSession *ss = ob->sculpt; + + if (ss->cache->alt_smooth) { + ToolSettings *ts = CTX_data_tool_settings(C); + VPaint *vp = ts->vpaint; + smooth_brush_toggle_off(C, &vp->paint, ss->cache); + } + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); MEM_freeN(vpd); diff --git a/source/blender/editors/sculpt_paint/paint_vertex_proj.c b/source/blender/editors/sculpt_paint/paint_vertex_proj.c index 85cd211367a..9d5fffdcfcc 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_proj.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_proj.c @@ -72,8 +72,10 @@ struct VertProjUpdate { /* -------------------------------------------------------------------- */ /* Internal Init */ -static void vpaint_proj_dm_map_cosnos_init__map_cb( - void *userData, int index, const float co[3], const float no_f[3], const short no_s[3]) +static void vpaint_proj_dm_map_cosnos_init__map_cb(void *userData, + int index, + const float co[3], + const float no[3]) { struct VertProjHandle *vp_handle = userData; CoNo *co_no = &vp_handle->vcosnos[index]; @@ -86,12 +88,7 @@ static void vpaint_proj_dm_map_cosnos_init__map_cb( } copy_v3_v3(co_no->co, co); - if (no_f) { - copy_v3_v3(co_no->no, no_f); - } - else { - normal_short_to_float_v3(co_no->no, no_s); - } + copy_v3_v3(co_no->no, no); } static void vpaint_proj_dm_map_cosnos_init(struct Depsgraph *depsgraph, @@ -116,8 +113,10 @@ static void vpaint_proj_dm_map_cosnos_init(struct Depsgraph *depsgraph, /* Same as init but take mouse location into account */ -static void vpaint_proj_dm_map_cosnos_update__map_cb( - void *userData, int index, const float co[3], const float no_f[3], const short no_s[3]) +static void vpaint_proj_dm_map_cosnos_update__map_cb(void *userData, + int index, + const float co[3], + const float no[3]) { struct VertProjUpdate *vp_update = userData; struct VertProjHandle *vp_handle = vp_update->vp_handle; @@ -148,12 +147,7 @@ static void vpaint_proj_dm_map_cosnos_update__map_cb( /* continue with regular functionality */ copy_v3_v3(co_no->co, co); - if (no_f) { - copy_v3_v3(co_no->no, no_f); - } - else { - normal_short_to_float_v3(co_no->no, no_s); - } + copy_v3_v3(co_no->no, no); } static void vpaint_proj_dm_map_cosnos_update(struct Depsgraph *depsgraph, diff --git a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c index d10a56be866..1dfc4db6ac3 100644 --- a/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c +++ b/source/blender/editors/sculpt_paint/paint_vertex_weight_ops.c @@ -665,8 +665,7 @@ static void gradientVert_update(WPGradient_userData *grad_data, int index) static void gradientVertUpdate__mapFunc(void *userData, int index, const float UNUSED(co[3]), - const float UNUSED(no_f[3]), - const short UNUSED(no_s[3])) + const float UNUSED(no[3])) { WPGradient_userData *grad_data = userData; WPGradient_vertStore *vs = &grad_data->vert_cache->elem[index]; @@ -681,8 +680,7 @@ static void gradientVertUpdate__mapFunc(void *userData, static void gradientVertInit__mapFunc(void *userData, int index, const float co[3], - const float UNUSED(no_f[3]), - const short UNUSED(no_s[3])) + const float UNUSED(no[3])) { WPGradient_userData *grad_data = userData; Mesh *me = grad_data->me; diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index aeeed094aab..2725fc1eae4 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -73,6 +73,8 @@ #include "BKE_subdiv_ccg.h" #include "BKE_subsurf.h" +#include "NOD_texture.h" + #include "DEG_depsgraph.h" #include "IMB_colormanagement.h" @@ -177,11 +179,11 @@ void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3]) switch (BKE_pbvh_type(ss->pbvh)) { case PBVH_FACES: { if (ss->shapekey_active || ss->deform_modifiers_active) { - const MVert *mverts = BKE_pbvh_get_verts(ss->pbvh); - normal_short_to_float_v3(no, mverts[index].no); + const float(*vert_normals)[3] = BKE_pbvh_get_vert_normals(ss->pbvh); + copy_v3_v3(no, vert_normals[index]); } else { - normal_short_to_float_v3(no, ss->mvert[index].no); + copy_v3_v3(no, ss->vert_normals[index]); } break; } @@ -1329,103 +1331,6 @@ static void sculpt_rake_data_update(struct SculptRakeData *srd, const float co[3 } } -static void sculpt_rake_rotate(const SculptSession *ss, - const float sculpt_co[3], - const float v_co[3], - float factor, - float r_delta[3]) -{ - float vec_rot[3]; - -#if 0 - /* lerp */ - sub_v3_v3v3(vec_rot, v_co, sculpt_co); - mul_qt_v3(ss->cache->rake_rotation_symmetry, vec_rot); - add_v3_v3(vec_rot, sculpt_co); - sub_v3_v3v3(r_delta, vec_rot, v_co); - mul_v3_fl(r_delta, factor); -#else - /* slerp */ - float q_interp[4]; - sub_v3_v3v3(vec_rot, v_co, sculpt_co); - - copy_qt_qt(q_interp, ss->cache->rake_rotation_symmetry); - pow_qt_fl_normalized(q_interp, factor); - mul_qt_v3(q_interp, vec_rot); - - add_v3_v3(vec_rot, sculpt_co); - sub_v3_v3v3(r_delta, vec_rot, v_co); -#endif -} - -/** - * Align the grab delta to the brush normal. - * - * \param grab_delta: Typically from `ss->cache->grab_delta_symmetry`. - */ -static void sculpt_project_v3_normal_align(SculptSession *ss, - const float normal_weight, - float grab_delta[3]) -{ - /* Signed to support grabbing in (to make a hole) as well as out. */ - const float len_signed = dot_v3v3(ss->cache->sculpt_normal_symm, grab_delta); - - /* This scale effectively projects the offset so dragging follows the cursor, - * as the normal points towards the view, the scale increases. */ - float len_view_scale; - { - float view_aligned_normal[3]; - project_plane_v3_v3v3( - view_aligned_normal, ss->cache->sculpt_normal_symm, ss->cache->view_normal); - len_view_scale = fabsf(dot_v3v3(view_aligned_normal, ss->cache->sculpt_normal_symm)); - len_view_scale = (len_view_scale > FLT_EPSILON) ? 1.0f / len_view_scale : 1.0f; - } - - mul_v3_fl(grab_delta, 1.0f - normal_weight); - madd_v3_v3fl( - grab_delta, ss->cache->sculpt_normal_symm, (len_signed * normal_weight) * len_view_scale); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name SculptProjectVector - * - * Fast-path for #project_plane_v3_v3v3 - * \{ */ - -typedef struct SculptProjectVector { - float plane[3]; - float len_sq; - float len_sq_inv_neg; - bool is_valid; - -} SculptProjectVector; - -/** - * \param plane: Direction, can be any length. - */ -static void sculpt_project_v3_cache_init(SculptProjectVector *spvc, const float plane[3]) -{ - copy_v3_v3(spvc->plane, plane); - spvc->len_sq = len_squared_v3(spvc->plane); - spvc->is_valid = (spvc->len_sq > FLT_EPSILON); - spvc->len_sq_inv_neg = (spvc->is_valid) ? -1.0f / spvc->len_sq : 0.0f; -} - -/** - * Calculate the projection. - */ -static void sculpt_project_v3(const SculptProjectVector *spvc, const float vec[3], float r_vec[3]) -{ -#if 0 - project_plane_v3_v3v3(r_vec, vec, spvc->plane); -#else - /* inline the projection, cache `-1.0 / dot_v3_v3(v_proj, v_proj)` */ - madd_v3_v3fl(r_vec, spvc->plane, dot_v3v3(vec, spvc->plane) * spvc->len_sq_inv_neg); -#endif -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -1484,10 +1389,10 @@ static void paint_mesh_restore_co_task_cb(void *__restrict userdata, if (orig_data.unode->type == SCULPT_UNDO_COORDS) { copy_v3_v3(vd.co, orig_data.co); if (vd.no) { - copy_v3_v3_short(vd.no, orig_data.no); + copy_v3_v3(vd.no, orig_data.no); } else { - normal_short_to_float_v3(vd.fno, orig_data.no); + copy_v3_v3(vd.fno, orig_data.no); } } else if (orig_data.unode->type == SCULPT_UNDO_MASK) { @@ -1786,7 +1691,7 @@ const float *SCULPT_brush_frontface_normal_from_falloff_shape(SculptSession *ss, static float frontface(const Brush *br, const float sculpt_normal[3], - const short no[3], + const float no[3], const float fno[3]) { if (!(br->flag & BRUSH_FRONTFACE)) { @@ -1795,10 +1700,7 @@ static float frontface(const Brush *br, float dot; if (no) { - float tmp[3]; - - normal_short_to_float_v3(tmp, no); - dot = dot_v3v3(tmp, sculpt_normal); + dot = dot_v3v3(no, sculpt_normal); } else { dot = dot_v3v3(fno, sculpt_normal); @@ -1835,15 +1737,6 @@ static bool sculpt_brush_test_cyl(SculptBrushTest *test, /* ===== Sculpting ===== */ -static void flip_v3(float v[3], const ePaintSymmetryFlags symm) -{ - flip_v3_v3(v, v, symm); -} - -static void flip_qt(float quat[4], const ePaintSymmetryFlags symm) -{ - flip_qt_qt(quat, quat, symm); -} static float calc_overlap(StrokeCache *cache, const char symm, const char axis, const float angle) { @@ -1913,9 +1806,9 @@ static float calc_symmetry_feather(Sculpt *sd, StrokeCache *cache) * (optionally using original coordinates). * * Functions are: - * - #calc_area_center - * - #calc_area_normal - * - #calc_area_normal_and_center + * - #SCULPT_calc_area_center + * - #SCULPT_calc_area_normal + * - #SCULPT_calc_area_normal_and_center * * \note These are all _very_ similar, when changing one, check others. * \{ */ @@ -2044,19 +1937,19 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata, float co[3]; /* For bm_vert only. */ - short no_s[3]; + float no_s[3]; if (use_original) { if (unode->bm_entry) { const float *temp_co; - const short *temp_no_s; + const float *temp_no_s; BM_log_original_vert_data(ss->bm_log, vd.bm_vert, &temp_co, &temp_no_s); copy_v3_v3(co, temp_co); - copy_v3_v3_short(no_s, temp_no_s); + copy_v3_v3(no_s, temp_no_s); } else { copy_v3_v3(co, unode->co[vd.i]); - copy_v3_v3_short(no_s, unode->no[vd.i]); + copy_v3_v3(no_s, unode->no[vd.i]); } } else { @@ -2076,11 +1969,11 @@ static void calc_area_normal_and_center_task_cb(void *__restrict userdata, data->any_vertex_sampled = true; if (use_original) { - normal_short_to_float_v3(no, no_s); + copy_v3_v3(no, no_s); } else { if (vd.no) { - normal_short_to_float_v3(no, vd.no); + copy_v3_v3(no, vd.no); } else { copy_v3_v3(no, vd.fno); @@ -2137,7 +2030,7 @@ static void calc_area_normal_and_center_reduce(const void *__restrict UNUSED(use add_v2_v2_int(join->count_co, anctd->count_co); } -static void calc_area_center( +void SCULPT_calc_area_center( Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_co[3]) { const Brush *brush = BKE_paint_brush(&sd->paint); @@ -2234,11 +2127,7 @@ bool SCULPT_pbvh_calc_area_normal(const Brush *brush, return data.any_vertex_sampled; } -/** - * This calculates flatten center and area normal together, - * amortizing the memory bandwidth and loop overhead to calculate both at the same time. - */ -static void calc_area_normal_and_center( +void SCULPT_calc_area_normal_and_center( Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3]) { const Brush *brush = BKE_paint_brush(&sd->paint); @@ -2460,7 +2349,7 @@ float SCULPT_brush_strength_factor(SculptSession *ss, const Brush *br, const float brush_point[3], const float len, - const short vno[3], + const float vno[3], const float fno[3], const float mask, const int vertex_index, @@ -2633,9 +2522,23 @@ void SCULPT_clip(Sculpt *sd, SculptSession *ss, float co[3], const float val[3]) continue; } - if (ss->cache && (ss->cache->flag & (CLIP_X << i)) && - (fabsf(co[i]) <= ss->cache->clip_tolerance[i])) { - co[i] = 0.0f; + bool do_clip = false; + float co_clip[3]; + if (ss->cache && (ss->cache->flag & (CLIP_X << i))) { + /* Take possible mirror object into account. */ + mul_v3_m4v3(co_clip, ss->cache->clip_mirror_mtx, co); + + if (fabsf(co_clip[i]) <= ss->cache->clip_tolerance[i]) { + co_clip[i] = 0.0f; + float imtx[4][4]; + invert_m4_m4(imtx, ss->cache->clip_mirror_mtx); + mul_m4_v3(imtx, co_clip); + do_clip = true; + } + } + + if (do_clip) { + co[i] = co_clip[i]; } else { co[i] = val[i]; @@ -2856,10 +2759,6 @@ static void update_brush_local_mat(Sculpt *sd, Object *ob) /** \} */ -/* -------------------------------------------------------------------- */ -/** \name Sculpt Topology Rake (Shared Utility) - * \{ */ - typedef struct { SculptSession *ss; const float *ray_start; @@ -2885,1295 +2784,6 @@ typedef struct { bool original; } SculptFindNearestToRayData; -static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - Sculpt *sd = data->sd; - const Brush *brush = data->brush; - - float direction[3]; - copy_v3_v3(direction, ss->cache->grab_delta_symmetry); - - float tmp[3]; - mul_v3_v3fl( - tmp, ss->cache->sculpt_normal_symm, dot_v3v3(ss->cache->sculpt_normal_symm, direction)); - sub_v3_v3(direction, tmp); - normalize_v3(direction); - - /* Cancel if there's no grab data. */ - if (is_zero_v3(direction)) { - return; - } - - const float bstrength = clamp_f(data->strength, 0.0f, 1.0f); - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - const float fade = - bstrength * - SCULPT_brush_strength_factor( - ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, *vd.mask, vd.index, thread_id) * - ss->cache->pressure; - - float avg[3], val[3]; - - SCULPT_bmesh_four_neighbor_average(avg, direction, vd.bm_vert); - - sub_v3_v3v3(val, avg, vd.co); - - madd_v3_v3v3fl(val, vd.co, val, fade); - - SCULPT_clip(sd, ss, vd.co, val); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void bmesh_topology_rake( - Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, float bstrength) -{ - Brush *brush = BKE_paint_brush(&sd->paint); - const float strength = clamp_f(bstrength, 0.0f, 1.0f); - - /* Interactions increase both strength and quality. */ - const int iterations = 3; - - int iteration; - const int count = iterations * strength + 1; - const float factor = iterations * strength / count; - - for (iteration = 0; iteration <= count; iteration++) { - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .strength = factor, - }; - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - - BLI_task_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings); - } -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Sculpt Mask Brush - * \{ */ - -static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float bstrength = ss->cache->bstrength; - - PBVHVertexIter vd; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - - const float fade = SCULPT_brush_strength_factor( - ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id); - - if (bstrength > 0.0f) { - (*vd.mask) += fade * bstrength * (1.0f - *vd.mask); - } - else { - (*vd.mask) += fade * bstrength * (*vd.mask); - } - *vd.mask = clamp_f(*vd.mask, 0.0f, 1.0f); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - BKE_pbvh_vertex_iter_end; - } -} - -static void do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - Brush *brush = BKE_paint_brush(&sd->paint); - - /* Threaded loop over nodes. */ - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings); -} - -static void do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - - switch ((BrushMaskTool)brush->mask_tool) { - case BRUSH_MASK_DRAW: - do_mask_brush_draw(sd, ob, nodes, totnode); - break; - case BRUSH_MASK_SMOOTH: - SCULPT_smooth(sd, ob, nodes, totnode, ss->cache->bstrength, true); - break; - } -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Sculpt Multires Displacement Eraser Brush - * \{ */ - -static void do_displacement_eraser_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f); - - float(*proxy)[3] = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - float limit_co[3]; - float disp[3]; - SCULPT_vertex_limit_surface_get(ss, vd.index, limit_co); - sub_v3_v3v3(disp, limit_co, vd.co); - mul_v3_v3fl(proxy[vd.i], disp, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_displacement_eraser_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - Brush *brush = BKE_paint_brush(&sd->paint); - BKE_curvemapping_init(brush->curve); - - /* Threaded loop over nodes. */ - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_displacement_eraser_brush_task_cb_ex, &settings); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Sculpt Multires Displacement Smear Brush - * \{ */ - -static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f); - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - float current_disp[3]; - float current_disp_norm[3]; - float interp_limit_surface_disp[3]; - - copy_v3_v3(interp_limit_surface_disp, ss->cache->prev_displacement[vd.index]); - - switch (brush->smear_deform_type) { - case BRUSH_SMEAR_DEFORM_DRAG: - sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location); - break; - case BRUSH_SMEAR_DEFORM_PINCH: - sub_v3_v3v3(current_disp, ss->cache->location, vd.co); - break; - case BRUSH_SMEAR_DEFORM_EXPAND: - sub_v3_v3v3(current_disp, vd.co, ss->cache->location); - break; - } - - normalize_v3_v3(current_disp_norm, current_disp); - mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength); - - float weights_accum = 1.0f; - - SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) { - float vertex_disp[3]; - float vertex_disp_norm[3]; - float neighbor_limit_co[3]; - SCULPT_vertex_limit_surface_get(ss, ni.index, neighbor_limit_co); - sub_v3_v3v3(vertex_disp, - ss->cache->limit_surface_co[ni.index], - ss->cache->limit_surface_co[vd.index]); - const float *neighbor_limit_surface_disp = ss->cache->prev_displacement[ni.index]; - normalize_v3_v3(vertex_disp_norm, vertex_disp); - - if (dot_v3v3(current_disp_norm, vertex_disp_norm) >= 0.0f) { - continue; - } - - const float disp_interp = clamp_f( - -dot_v3v3(current_disp_norm, vertex_disp_norm), 0.0f, 1.0f); - madd_v3_v3fl(interp_limit_surface_disp, neighbor_limit_surface_disp, disp_interp); - weights_accum += disp_interp; - } - SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); - - mul_v3_fl(interp_limit_surface_disp, 1.0f / weights_accum); - - float new_co[3]; - add_v3_v3v3(new_co, ss->cache->limit_surface_co[vd.index], interp_limit_surface_disp); - interp_v3_v3v3(vd.co, vd.co, new_co, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_displacement_smear_store_prev_disp_task_cb_ex( - void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls)) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - - PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - sub_v3_v3v3(ss->cache->prev_displacement[vd.index], - SCULPT_vertex_co_get(ss, vd.index), - ss->cache->limit_surface_co[vd.index]); - } - BKE_pbvh_vertex_iter_end; -} - -static void do_displacement_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - Brush *brush = BKE_paint_brush(&sd->paint); - SculptSession *ss = ob->sculpt; - - BKE_curvemapping_init(brush->curve); - - const int totvert = SCULPT_vertex_count_get(ss); - if (!ss->cache->prev_displacement) { - ss->cache->prev_displacement = MEM_malloc_arrayN( - totvert, sizeof(float[3]), "prev displacement"); - ss->cache->limit_surface_co = MEM_malloc_arrayN(totvert, sizeof(float[3]), "limit surface co"); - for (int i = 0; i < totvert; i++) { - SCULPT_vertex_limit_surface_get(ss, i, ss->cache->limit_surface_co[i]); - sub_v3_v3v3(ss->cache->prev_displacement[i], - SCULPT_vertex_co_get(ss, i), - ss->cache->limit_surface_co[i]); - } - } - /* Threaded loop over nodes. */ - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range( - 0, totnode, &data, do_displacement_smear_store_prev_disp_task_cb_ex, &settings); - BLI_task_parallel_range(0, totnode, &data, do_displacement_smear_brush_task_cb_ex, &settings); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Sculpt Draw Brush - * \{ */ - -static void do_draw_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float *offset = data->offset; - - PBVHVertexIter vd; - float(*proxy)[3]; - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - /* Offset vertex. */ - const float fade = SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - mul_v3_v3fl(proxy[vd.i], offset, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - float offset[3]; - const float bstrength = ss->cache->bstrength; - - /* Offset with as much as possible factored in already. */ - float effective_normal[3]; - SCULPT_tilt_effective_normal_get(ss, brush, effective_normal); - mul_v3_v3fl(offset, effective_normal, ss->cache->radius); - mul_v3_v3(offset, ss->cache->scale); - mul_v3_fl(offset, bstrength); - - /* XXX: this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise - * initialize before threads so they can do curve mapping. */ - BKE_curvemapping_init(brush->curve); - - /* Threaded loop over nodes. */ - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .offset = offset, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings); -} - -static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float *offset = data->offset; - - PBVHVertexIter vd; - SculptOrigVertData orig_data; - float(*proxy)[3]; - - SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - SCULPT_orig_vert_data_update(&orig_data, &vd); - if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { - continue; - } - /* Offset vertex. */ - const float fade = SCULPT_brush_strength_factor(ss, - brush, - orig_data.co, - sqrtf(test.dist), - orig_data.no, - NULL, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - mul_v3_v3fl(proxy[vd.i], offset, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_draw_sharp_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - float offset[3]; - const float bstrength = ss->cache->bstrength; - - /* Offset with as much as possible factored in already. */ - float effective_normal[3]; - SCULPT_tilt_effective_normal_get(ss, brush, effective_normal); - mul_v3_v3fl(offset, effective_normal, ss->cache->radius); - mul_v3_v3(offset, ss->cache->scale); - mul_v3_fl(offset, bstrength); - - /* XXX: this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise - * initialize before threads so they can do curve mapping. */ - BKE_curvemapping_init(brush->curve); - - /* Threaded loop over nodes. */ - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .offset = offset, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Sculpt Topology Brush - * \{ */ - -static void do_topology_slide_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - - PBVHVertexIter vd; - SculptOrigVertData orig_data; - float(*proxy)[3]; - - SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - SCULPT_orig_vert_data_update(&orig_data, &vd); - if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { - continue; - } - const float fade = SCULPT_brush_strength_factor(ss, - brush, - orig_data.co, - sqrtf(test.dist), - orig_data.no, - NULL, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - float current_disp[3]; - float current_disp_norm[3]; - float final_disp[3] = {0.0f, 0.0f, 0.0f}; - - switch (brush->slide_deform_type) { - case BRUSH_SLIDE_DEFORM_DRAG: - sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location); - break; - case BRUSH_SLIDE_DEFORM_PINCH: - sub_v3_v3v3(current_disp, ss->cache->location, vd.co); - break; - case BRUSH_SLIDE_DEFORM_EXPAND: - sub_v3_v3v3(current_disp, vd.co, ss->cache->location); - break; - } - - normalize_v3_v3(current_disp_norm, current_disp); - mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength); - - SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) { - float vertex_disp[3]; - float vertex_disp_norm[3]; - sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.index), vd.co); - normalize_v3_v3(vertex_disp_norm, vertex_disp); - if (dot_v3v3(current_disp_norm, vertex_disp_norm) > 0.0f) { - madd_v3_v3fl(final_disp, vertex_disp_norm, dot_v3v3(current_disp, vertex_disp)); - } - } - SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); - - mul_v3_v3fl(proxy[vd.i], final_disp, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -void SCULPT_relax_vertex(SculptSession *ss, - PBVHVertexIter *vd, - float factor, - bool filter_boundary_face_sets, - float *r_final_pos) -{ - float smooth_pos[3]; - float final_disp[3]; - float boundary_normal[3]; - int avg_count = 0; - int neighbor_count = 0; - zero_v3(smooth_pos); - zero_v3(boundary_normal); - const bool is_boundary = SCULPT_vertex_is_boundary(ss, vd->index); - - SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->index, ni) { - neighbor_count++; - if (!filter_boundary_face_sets || - (filter_boundary_face_sets && !SCULPT_vertex_has_unique_face_set(ss, ni.index))) { - - /* When the vertex to relax is boundary, use only connected boundary vertices for the average - * position. */ - if (is_boundary) { - if (!SCULPT_vertex_is_boundary(ss, ni.index)) { - continue; - } - add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index)); - avg_count++; - - /* Calculate a normal for the constraint plane using the edges of the boundary. */ - float to_neighbor[3]; - sub_v3_v3v3(to_neighbor, SCULPT_vertex_co_get(ss, ni.index), vd->co); - normalize_v3(to_neighbor); - add_v3_v3(boundary_normal, to_neighbor); - } - else { - add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index)); - avg_count++; - } - } - } - SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); - - /* Don't modify corner vertices. */ - if (neighbor_count <= 2) { - copy_v3_v3(r_final_pos, vd->co); - return; - } - - if (avg_count > 0) { - mul_v3_fl(smooth_pos, 1.0f / avg_count); - } - else { - copy_v3_v3(r_final_pos, vd->co); - return; - } - - float plane[4]; - float smooth_closest_plane[3]; - float vno[3]; - - if (is_boundary && avg_count == 2) { - normalize_v3_v3(vno, boundary_normal); - } - else { - SCULPT_vertex_normal_get(ss, vd->index, vno); - } - - if (is_zero_v3(vno)) { - copy_v3_v3(r_final_pos, vd->co); - return; - } - - plane_from_point_normal_v3(plane, vd->co, vno); - closest_to_plane_v3(smooth_closest_plane, plane, smooth_pos); - sub_v3_v3v3(final_disp, smooth_closest_plane, vd->co); - - mul_v3_fl(final_disp, factor); - add_v3_v3v3(r_final_pos, vd->co, final_disp); -} - -static void do_topology_relax_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float bstrength = ss->cache->bstrength; - - PBVHVertexIter vd; - SculptOrigVertData orig_data; - - SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); - - BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n]); - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - SCULPT_orig_vert_data_update(&orig_data, &vd); - if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { - continue; - } - const float fade = SCULPT_brush_strength_factor(ss, - brush, - orig_data.co, - sqrtf(test.dist), - orig_data.no, - NULL, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - SCULPT_relax_vertex(ss, &vd, fade * bstrength, false, vd.co); - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_slide_relax_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - - if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) { - return; - } - - BKE_curvemapping_init(brush->curve); - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - if (ss->cache->alt_smooth) { - SCULPT_boundary_info_ensure(ob); - for (int i = 0; i < 4; i++) { - BLI_task_parallel_range(0, totnode, &data, do_topology_relax_task_cb_ex, &settings); - } - } - else { - BLI_task_parallel_range(0, totnode, &data, do_topology_slide_task_cb_ex, &settings); - } -} - -static void calc_sculpt_plane( - Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3]) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - - if (SCULPT_stroke_is_main_symmetry_pass(ss->cache) && - (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache) || - !(brush->flag & BRUSH_ORIGINAL_PLANE) || !(brush->flag & BRUSH_ORIGINAL_NORMAL))) { - switch (brush->sculpt_plane) { - case SCULPT_DISP_DIR_VIEW: - copy_v3_v3(r_area_no, ss->cache->true_view_normal); - break; - - case SCULPT_DISP_DIR_X: - ARRAY_SET_ITEMS(r_area_no, 1.0f, 0.0f, 0.0f); - break; - - case SCULPT_DISP_DIR_Y: - ARRAY_SET_ITEMS(r_area_no, 0.0f, 1.0f, 0.0f); - break; - - case SCULPT_DISP_DIR_Z: - ARRAY_SET_ITEMS(r_area_no, 0.0f, 0.0f, 1.0f); - break; - - case SCULPT_DISP_DIR_AREA: - calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co); - if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { - project_plane_v3_v3v3(r_area_no, r_area_no, ss->cache->view_normal); - normalize_v3(r_area_no); - } - break; - - default: - break; - } - - /* For flatten center. */ - /* Flatten center has not been calculated yet if we are not using the area normal. */ - if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA) { - calc_area_center(sd, ob, nodes, totnode, r_area_co); - } - - /* For area normal. */ - if ((!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) && - (brush->flag & BRUSH_ORIGINAL_NORMAL)) { - copy_v3_v3(r_area_no, ss->cache->sculpt_normal); - } - else { - copy_v3_v3(ss->cache->sculpt_normal, r_area_no); - } - - /* For flatten center. */ - if ((!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) && - (brush->flag & BRUSH_ORIGINAL_PLANE)) { - copy_v3_v3(r_area_co, ss->cache->last_center); - } - else { - copy_v3_v3(ss->cache->last_center, r_area_co); - } - } - else { - /* For area normal. */ - copy_v3_v3(r_area_no, ss->cache->sculpt_normal); - - /* For flatten center. */ - copy_v3_v3(r_area_co, ss->cache->last_center); - - /* For area normal. */ - flip_v3(r_area_no, ss->cache->mirror_symmetry_pass); - - /* For flatten center. */ - flip_v3(r_area_co, ss->cache->mirror_symmetry_pass); - - /* For area normal. */ - mul_m4_v3(ss->cache->symm_rot_mat, r_area_no); - - /* For flatten center. */ - mul_m4_v3(ss->cache->symm_rot_mat, r_area_co); - - /* Shift the plane for the current tile. */ - add_v3_v3(r_area_co, ss->cache->plane_offset); - } -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Sculpt Crease & Blob Brush - * \{ */ - -/** - * Used for 'SCULPT_TOOL_CREASE' and 'SCULPT_TOOL_BLOB' - */ -static void do_crease_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - SculptProjectVector *spvc = data->spvc; - const float flippedbstrength = data->flippedbstrength; - const float *offset = data->offset; - - PBVHVertexIter vd; - float(*proxy)[3]; - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - /* Offset vertex. */ - const float fade = SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - float val1[3]; - float val2[3]; - - /* First we pinch. */ - sub_v3_v3v3(val1, test.location, vd.co); - if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { - project_plane_v3_v3v3(val1, val1, ss->cache->view_normal); - } - - mul_v3_fl(val1, fade * flippedbstrength); - - sculpt_project_v3(spvc, val1, val1); - - /* Then we draw. */ - mul_v3_v3fl(val2, offset, fade); - - add_v3_v3v3(proxy[vd.i], val1, val2); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - const Scene *scene = ss->cache->vc->scene; - Brush *brush = BKE_paint_brush(&sd->paint); - float offset[3]; - float bstrength = ss->cache->bstrength; - float flippedbstrength, crease_correction; - float brush_alpha; - - SculptProjectVector spvc; - - /* Offset with as much as possible factored in already. */ - mul_v3_v3fl(offset, ss->cache->sculpt_normal_symm, ss->cache->radius); - mul_v3_v3(offset, ss->cache->scale); - mul_v3_fl(offset, bstrength); - - /* We divide out the squared alpha and multiply by the squared crease - * to give us the pinch strength. */ - crease_correction = brush->crease_pinch_factor * brush->crease_pinch_factor; - brush_alpha = BKE_brush_alpha_get(scene, brush); - if (brush_alpha > 0.0f) { - crease_correction /= brush_alpha * brush_alpha; - } - - /* We always want crease to pinch or blob to relax even when draw is negative. */ - flippedbstrength = (bstrength < 0.0f) ? -crease_correction * bstrength : - crease_correction * bstrength; - - if (brush->sculpt_tool == SCULPT_TOOL_BLOB) { - flippedbstrength *= -1.0f; - } - - /* Use surface normal for 'spvc', so the vertices are pinched towards a line instead of a single - * point. Without this we get a 'flat' surface surrounding the pinch. */ - sculpt_project_v3_cache_init(&spvc, ss->cache->sculpt_normal_symm); - - /* Threaded loop over nodes. */ - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .spvc = &spvc, - .offset = offset, - .flippedbstrength = flippedbstrength, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings); -} - -static void do_pinch_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - float(*stroke_xz)[3] = data->stroke_xz; - - PBVHVertexIter vd; - float(*proxy)[3]; - const float bstrength = ss->cache->bstrength; - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - float x_object_space[3]; - float z_object_space[3]; - copy_v3_v3(x_object_space, stroke_xz[0]); - copy_v3_v3(z_object_space, stroke_xz[1]); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - float disp_center[3]; - float x_disp[3]; - float z_disp[3]; - /* Calculate displacement from the vertex to the brush center. */ - sub_v3_v3v3(disp_center, test.location, vd.co); - - /* Project the displacement into the X vector (aligned to the stroke). */ - mul_v3_v3fl(x_disp, x_object_space, dot_v3v3(disp_center, x_object_space)); - - /* Project the displacement into the Z vector (aligned to the surface normal). */ - mul_v3_v3fl(z_disp, z_object_space, dot_v3v3(disp_center, z_object_space)); - - /* Add the two projected vectors to calculate the final displacement. - * The Y component is removed. */ - add_v3_v3v3(disp_center, x_disp, z_disp); - - if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { - project_plane_v3_v3v3(disp_center, disp_center, ss->cache->view_normal); - } - mul_v3_v3fl(proxy[vd.i], disp_center, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - - float area_no[3]; - float area_co[3]; - - float mat[4][4]; - calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co); - - /* delay the first daub because grab delta is not setup */ - if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) { - return; - } - - if (is_zero_v3(ss->cache->grab_delta_symmetry)) { - return; - } - - /* Initialize `mat`. */ - cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry); - mat[0][3] = 0.0f; - cross_v3_v3v3(mat[1], area_no, mat[0]); - mat[1][3] = 0.0f; - copy_v3_v3(mat[2], area_no); - mat[2][3] = 0.0f; - copy_v3_v3(mat[3], ss->cache->location); - mat[3][3] = 1.0f; - normalize_m4(mat); - - float stroke_xz[2][3]; - normalize_v3_v3(stroke_xz[0], mat[0]); - normalize_v3_v3(stroke_xz[1], mat[2]); - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .stroke_xz = stroke_xz, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings); -} - -static void do_grab_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float *grab_delta = data->grab_delta; - - PBVHVertexIter vd; - SculptOrigVertData orig_data; - float(*proxy)[3]; - const float bstrength = ss->cache->bstrength; - - SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - const bool grab_silhouette = brush->flag2 & BRUSH_GRAB_SILHOUETTE; - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - SCULPT_orig_vert_data_update(&orig_data, &vd); - - if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { - continue; - } - float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - orig_data.co, - sqrtf(test.dist), - orig_data.no, - NULL, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - if (grab_silhouette) { - float silhouette_test_dir[3]; - normalize_v3_v3(silhouette_test_dir, grab_delta); - if (dot_v3v3(ss->cache->initial_normal, ss->cache->grab_delta_symmetry) < 0.0f) { - mul_v3_fl(silhouette_test_dir, -1.0f); - } - float vno[3]; - normal_short_to_float_v3(vno, orig_data.no); - fade *= max_ff(dot_v3v3(vno, silhouette_test_dir), 0.0f); - } - - mul_v3_v3fl(proxy[vd.i], grab_delta, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - float grab_delta[3]; - - copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry); - - if (ss->cache->normal_weight > 0.0f) { - sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta); - } - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .grab_delta = grab_delta, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings); -} - -static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict UNUSED(tls)) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float *grab_delta = data->grab_delta; - const float *location = ss->cache->location; - - PBVHVertexIter vd; - SculptOrigVertData orig_data; - float(*proxy)[3]; - - const float bstrength = ss->cache->bstrength; - - SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - float dir; - if (ss->cache->mouse[0] > ss->cache->initial_mouse[0]) { - dir = 1.0f; - } - else { - dir = -1.0f; - } - - if (brush->elastic_deform_type == BRUSH_ELASTIC_DEFORM_TWIST) { - int symm = ss->cache->mirror_symmetry_pass; - if (ELEM(symm, 1, 2, 4, 7)) { - dir = -dir; - } - } - - KelvinletParams params; - float force = len_v3(grab_delta) * dir * bstrength; - BKE_kelvinlet_init_params( - ¶ms, ss->cache->radius, force, 1.0f, brush->elastic_deform_volume_preservation); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - SCULPT_orig_vert_data_update(&orig_data, &vd); - float final_disp[3]; - switch (brush->elastic_deform_type) { - case BRUSH_ELASTIC_DEFORM_GRAB: - BKE_kelvinlet_grab(final_disp, ¶ms, orig_data.co, location, grab_delta); - mul_v3_fl(final_disp, bstrength * 20.0f); - break; - case BRUSH_ELASTIC_DEFORM_GRAB_BISCALE: { - BKE_kelvinlet_grab_biscale(final_disp, ¶ms, orig_data.co, location, grab_delta); - mul_v3_fl(final_disp, bstrength * 20.0f); - break; - } - case BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE: { - BKE_kelvinlet_grab_triscale(final_disp, ¶ms, orig_data.co, location, grab_delta); - mul_v3_fl(final_disp, bstrength * 20.0f); - break; - } - case BRUSH_ELASTIC_DEFORM_SCALE: - BKE_kelvinlet_scale( - final_disp, ¶ms, orig_data.co, location, ss->cache->sculpt_normal_symm); - break; - case BRUSH_ELASTIC_DEFORM_TWIST: - BKE_kelvinlet_twist( - final_disp, ¶ms, orig_data.co, location, ss->cache->sculpt_normal_symm); - break; - } - - if (vd.mask) { - mul_v3_fl(final_disp, 1.0f - *vd.mask); - } - - mul_v3_fl(final_disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index)); - - copy_v3_v3(proxy[vd.i], final_disp); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - float grab_delta[3]; - - copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry); - - if (ss->cache->normal_weight > 0.0f) { - sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta); - } - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .grab_delta = grab_delta, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings); -} - ePaintSymmetryAreas SCULPT_get_vertex_symm_area(const float co[3]) { ePaintSymmetryAreas symm_area = PAINT_SYMM_AREA_DEFAULT; @@ -4257,7 +2867,7 @@ void SCULPT_calc_brush_plane( break; case SCULPT_DISP_DIR_AREA: - calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co); + SCULPT_calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co); if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { project_plane_v3_v3v3(r_area_no, r_area_no, ss->cache->view_normal); normalize_v3(r_area_no); @@ -4271,7 +2881,7 @@ void SCULPT_calc_brush_plane( /* For flatten center. */ /* Flatten center has not been calculated yet if we are not using the area normal. */ if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA) { - calc_area_center(sd, ob, nodes, totnode, r_area_co); + SCULPT_calc_area_center(sd, ob, nodes, totnode, r_area_co); } /* For area normal. */ @@ -4316,564 +2926,12 @@ void SCULPT_calc_brush_plane( } } -static void do_nudge_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float *cono = data->cono; - - PBVHVertexIter vd; - float(*proxy)[3]; - const float bstrength = ss->cache->bstrength; - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - mul_v3_v3fl(proxy[vd.i], cono, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - float grab_delta[3]; - float tmp[3], cono[3]; - - copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry); - - cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta); - cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm); - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .cono = cono, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings); -} - -static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - SculptProjectVector *spvc = data->spvc; - const float *grab_delta = data->grab_delta; - - PBVHVertexIter vd; - float(*proxy)[3]; - const float bstrength = ss->cache->bstrength; - const bool do_rake_rotation = ss->cache->is_rake_rotation_valid; - const bool do_pinch = (brush->crease_pinch_factor != 0.5f); - const float pinch = do_pinch ? (2.0f * (0.5f - brush->crease_pinch_factor) * - (len_v3(grab_delta) / ss->cache->radius)) : - 0.0f; - - const bool do_elastic = brush->snake_hook_deform_type == BRUSH_SNAKE_HOOK_DEFORM_ELASTIC; - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - KelvinletParams params; - BKE_kelvinlet_init_params(¶ms, ss->cache->radius, bstrength, 1.0f, 0.4f); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!do_elastic && !sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - - float fade; - if (do_elastic) { - fade = 1.0f; - } - else { - fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - } - - mul_v3_v3fl(proxy[vd.i], grab_delta, fade); - - /* Negative pinch will inflate, helps maintain volume. */ - if (do_pinch) { - float delta_pinch_init[3], delta_pinch[3]; - - sub_v3_v3v3(delta_pinch, vd.co, test.location); - if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { - project_plane_v3_v3v3(delta_pinch, delta_pinch, ss->cache->true_view_normal); - } - - /* Important to calculate based on the grabbed location - * (intentionally ignore fade here). */ - add_v3_v3(delta_pinch, grab_delta); - - sculpt_project_v3(spvc, delta_pinch, delta_pinch); - - copy_v3_v3(delta_pinch_init, delta_pinch); - - float pinch_fade = pinch * fade; - /* When reducing, scale reduction back by how close to the center we are, - * so we don't pinch into nothingness. */ - if (pinch > 0.0f) { - /* Square to have even less impact for close vertices. */ - pinch_fade *= pow2f(min_ff(1.0f, len_v3(delta_pinch) / ss->cache->radius)); - } - mul_v3_fl(delta_pinch, 1.0f + pinch_fade); - sub_v3_v3v3(delta_pinch, delta_pinch_init, delta_pinch); - add_v3_v3(proxy[vd.i], delta_pinch); - } - - if (do_rake_rotation) { - float delta_rotate[3]; - sculpt_rake_rotate(ss, test.location, vd.co, fade, delta_rotate); - add_v3_v3(proxy[vd.i], delta_rotate); - } - - if (do_elastic) { - float disp[3]; - BKE_kelvinlet_grab_triscale(disp, ¶ms, vd.co, ss->cache->location, proxy[vd.i]); - mul_v3_fl(disp, bstrength * 20.0f); - if (vd.mask) { - mul_v3_fl(disp, 1.0f - *vd.mask); - } - mul_v3_fl(disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index)); - copy_v3_v3(proxy[vd.i], disp); - } - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - const float bstrength = ss->cache->bstrength; - float grab_delta[3]; - - SculptProjectVector spvc; - - copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry); - - if (bstrength < 0.0f) { - negate_v3(grab_delta); - } - - if (ss->cache->normal_weight > 0.0f) { - sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta); - } - - /* Optionally pinch while painting. */ - if (brush->crease_pinch_factor != 0.5f) { - sculpt_project_v3_cache_init(&spvc, grab_delta); - } - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .spvc = &spvc, - .grab_delta = grab_delta, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings); -} - -static void do_thumb_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float *cono = data->cono; - - PBVHVertexIter vd; - SculptOrigVertData orig_data; - float(*proxy)[3]; - const float bstrength = ss->cache->bstrength; - - SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - SCULPT_orig_vert_data_update(&orig_data, &vd); - - if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { - continue; - } - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - orig_data.co, - sqrtf(test.dist), - orig_data.no, - NULL, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - mul_v3_v3fl(proxy[vd.i], cono, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - float grab_delta[3]; - float tmp[3], cono[3]; - - copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry); - - cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta); - cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm); - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .cono = cono, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings); -} - -static void do_rotate_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float angle = data->angle; - - PBVHVertexIter vd; - SculptOrigVertData orig_data; - float(*proxy)[3]; - const float bstrength = ss->cache->bstrength; - - SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - SCULPT_orig_vert_data_update(&orig_data, &vd); - - if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { - continue; - } - float vec[3], rot[3][3]; - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - orig_data.co, - sqrtf(test.dist), - orig_data.no, - NULL, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - sub_v3_v3v3(vec, orig_data.co, ss->cache->location); - axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade); - mul_v3_m3v3(proxy[vd.i], rot, vec); - add_v3_v3(proxy[vd.i], ss->cache->location); - sub_v3_v3(proxy[vd.i], orig_data.co); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - - static const int flip[8] = {1, -1, -1, 1, -1, 1, 1, -1}; - const float angle = ss->cache->vertex_rotation * flip[ss->cache->mirror_symmetry_pass]; - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .angle = angle, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings); -} - -static void do_layer_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - Sculpt *sd = data->sd; - const Brush *brush = data->brush; - - const bool use_persistent_base = ss->persistent_base && brush->flag & BRUSH_PERSISTENT; - - PBVHVertexIter vd; - SculptOrigVertData orig_data; - const float bstrength = ss->cache->bstrength; - SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - SCULPT_orig_vert_data_update(&orig_data, &vd); - - if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { - continue; - } - const float fade = SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - const int vi = vd.index; - float *disp_factor; - if (use_persistent_base) { - disp_factor = &ss->persistent_base[vi].disp; - } - else { - disp_factor = &ss->cache->layer_displacement_factor[vi]; - } - - /* When using persistent base, the layer brush (holding Control) invert mode resets the - * height of the layer to 0. This makes possible to clean edges of previously added layers - * on top of the base. */ - /* The main direction of the layers is inverted using the regular brush strength with the - * brush direction property. */ - if (use_persistent_base && ss->cache->invert) { - (*disp_factor) += fabsf(fade * bstrength * (*disp_factor)) * - ((*disp_factor) > 0.0f ? -1.0f : 1.0f); - } - else { - (*disp_factor) += fade * bstrength * (1.05f - fabsf(*disp_factor)); - } - if (vd.mask) { - const float clamp_mask = 1.0f - *vd.mask; - *disp_factor = clamp_f(*disp_factor, -clamp_mask, clamp_mask); - } - else { - *disp_factor = clamp_f(*disp_factor, -1.0f, 1.0f); - } - - float final_co[3]; - float normal[3]; - - if (use_persistent_base) { - SCULPT_vertex_persistent_normal_get(ss, vi, normal); - mul_v3_fl(normal, brush->height); - madd_v3_v3v3fl(final_co, SCULPT_vertex_persistent_co_get(ss, vi), normal, *disp_factor); - } - else { - normal_short_to_float_v3(normal, orig_data.no); - mul_v3_fl(normal, brush->height); - madd_v3_v3v3fl(final_co, orig_data.co, normal, *disp_factor); - } - - float vdisp[3]; - sub_v3_v3v3(vdisp, final_co, vd.co); - mul_v3_fl(vdisp, fabsf(fade)); - add_v3_v3v3(final_co, vd.co, vdisp); - - SCULPT_clip(sd, ss, vd.co, final_co); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - - if (ss->cache->layer_displacement_factor == NULL) { - ss->cache->layer_displacement_factor = MEM_callocN(sizeof(float) * SCULPT_vertex_count_get(ss), - "layer displacement factor"); - } - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings); -} - -static void do_inflate_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - - PBVHVertexIter vd; - float(*proxy)[3]; - const float bstrength = ss->cache->bstrength; - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - float val[3]; - - if (vd.fno) { - copy_v3_v3(val, vd.fno); - } - else { - normal_short_to_float_v3(val, vd.no); - } - - mul_v3_fl(val, fade * ss->cache->radius); - mul_v3_v3v3(proxy[vd.i], val, ss->cache->scale); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - Brush *brush = BKE_paint_brush(&sd->paint); - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings); -} - int SCULPT_plane_trim(const StrokeCache *cache, const Brush *brush, const float val[3]) { return (!(brush->flag & BRUSH_PLANE_TRIM) || ((dot_v3v3(val, val) <= cache->radius_squared * cache->plane_trim_squared))); } -static bool plane_point_side_flip(const float co[3], const float plane[4], const bool flip) -{ - float d = plane_point_side_v3(plane, co); - if (flip) { - d = -d; - } - return d <= 0.0f; -} - int SCULPT_plane_point_side(const float co[3], const float plane[4]) { float d = plane_point_side_v3(plane, co); @@ -4893,807 +2951,6 @@ float SCULPT_brush_plane_offset_get(Sculpt *sd, SculptSession *ss) return rv; } -static void do_flatten_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float *area_no = data->area_no; - const float *area_co = data->area_co; - - PBVHVertexIter vd; - float(*proxy)[3]; - const float bstrength = ss->cache->bstrength; - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - plane_from_point_normal_v3(test.plane_tool, area_co, area_no); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - float intr[3]; - float val[3]; - - closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co); - - sub_v3_v3v3(val, intr, vd.co); - - if (SCULPT_plane_trim(ss->cache, brush, val)) { - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - mul_v3_v3fl(proxy[vd.i], val, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - - const float radius = ss->cache->radius; - - float area_no[3]; - float area_co[3]; - - float offset = SCULPT_brush_plane_offset_get(sd, ss); - float displace; - float temp[3]; - - SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co); - - SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor); - - displace = radius * offset; - - mul_v3_v3v3(temp, area_no, ss->cache->scale); - mul_v3_fl(temp, displace); - add_v3_v3(area_co, temp); - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .area_no = area_no, - .area_co = area_co, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Sculpt Clay Brush - * \{ */ - -typedef struct ClaySampleData { - float plane_dist[2]; -} ClaySampleData; - -static void calc_clay_surface_task_cb(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - ClaySampleData *csd = tls->userdata_chunk; - const float *area_no = data->area_no; - const float *area_co = data->area_co; - float plane[4]; - - PBVHVertexIter vd; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, brush->falloff_shape); - - /* Apply the brush normal radius to the test before sampling. */ - float test_radius = sqrtf(test.radius_squared); - test_radius *= brush->normal_radius_factor; - test.radius_squared = test_radius * test_radius; - plane_from_point_normal_v3(plane, area_co, area_no); - - if (is_zero_v4(plane)) { - return; - } - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - - float plane_dist = dist_signed_to_plane_v3(vd.co, plane); - float plane_dist_abs = fabsf(plane_dist); - if (plane_dist > 0.0f) { - csd->plane_dist[0] = MIN2(csd->plane_dist[0], plane_dist_abs); - } - else { - csd->plane_dist[1] = MIN2(csd->plane_dist[1], plane_dist_abs); - } - BKE_pbvh_vertex_iter_end; - } -} - -static void calc_clay_surface_reduce(const void *__restrict UNUSED(userdata), - void *__restrict chunk_join, - void *__restrict chunk) -{ - ClaySampleData *join = chunk_join; - ClaySampleData *csd = chunk; - join->plane_dist[0] = MIN2(csd->plane_dist[0], join->plane_dist[0]); - join->plane_dist[1] = MIN2(csd->plane_dist[1], join->plane_dist[1]); -} - -static void do_clay_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float *area_no = data->area_no; - const float *area_co = data->area_co; - - PBVHVertexIter vd; - float(*proxy)[3]; - const float bstrength = fabsf(ss->cache->bstrength); - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - plane_from_point_normal_v3(test.plane_tool, area_co, area_no); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - - float intr[3]; - float val[3]; - closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co); - - sub_v3_v3v3(val, intr, vd.co); - - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - mul_v3_v3fl(proxy[vd.i], val, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - - const float radius = fabsf(ss->cache->radius); - const float initial_radius = fabsf(ss->cache->initial_radius); - bool flip = ss->cache->bstrength < 0.0f; - - float offset = SCULPT_brush_plane_offset_get(sd, ss); - float displace; - - float area_no[3]; - float area_co[3]; - float temp[3]; - - SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co); - - SculptThreadedTaskData sample_data = { - .sd = NULL, - .ob = ob, - .brush = brush, - .nodes = nodes, - .totnode = totnode, - .area_no = area_no, - .area_co = ss->cache->location, - }; - - ClaySampleData csd = {{0}}; - - TaskParallelSettings sample_settings; - BKE_pbvh_parallel_range_settings(&sample_settings, true, totnode); - sample_settings.func_reduce = calc_clay_surface_reduce; - sample_settings.userdata_chunk = &csd; - sample_settings.userdata_chunk_size = sizeof(ClaySampleData); - - BLI_task_parallel_range(0, totnode, &sample_data, calc_clay_surface_task_cb, &sample_settings); - - float d_offset = (csd.plane_dist[0] + csd.plane_dist[1]); - d_offset = min_ff(radius, d_offset); - d_offset = d_offset / radius; - d_offset = 1.0f - d_offset; - displace = fabsf(initial_radius * (0.25f + offset + (d_offset * 0.15f))); - if (flip) { - displace = -displace; - } - - mul_v3_v3v3(temp, area_no, ss->cache->scale); - mul_v3_fl(temp, displace); - copy_v3_v3(area_co, ss->cache->location); - add_v3_v3(area_co, temp); - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .area_no = area_no, - .area_co = area_co, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings); -} - -static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - float(*mat)[4] = data->mat; - const float *area_no_sp = data->area_no_sp; - const float *area_co = data->area_co; - - PBVHVertexIter vd; - SculptBrushTest test; - float(*proxy)[3]; - const bool flip = (ss->cache->bstrength < 0.0f); - const float bstrength = flip ? -ss->cache->bstrength : ss->cache->bstrength; - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SCULPT_brush_test_init(ss, &test); - plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp); - const int thread_id = BLI_task_parallel_thread_id(tls); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!SCULPT_brush_test_cube(&test, vd.co, mat, brush->tip_roundness)) { - continue; - } - - if (!plane_point_side_flip(vd.co, test.plane_tool, flip)) { - continue; - } - - float intr[3]; - float val[3]; - closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co); - sub_v3_v3v3(val, intr, vd.co); - - if (!SCULPT_plane_trim(ss->cache, brush, val)) { - continue; - } - /* The normal from the vertices is ignored, it causes glitch with planes, see: T44390. */ - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - ss->cache->radius * test.dist, - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - mul_v3_v3fl(proxy[vd.i], val, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - - const bool flip = (ss->cache->bstrength < 0.0f); - const float radius = flip ? -ss->cache->radius : ss->cache->radius; - const float offset = SCULPT_brush_plane_offset_get(sd, ss); - const float displace = radius * (0.18f + offset); - - /* The sculpt-plane normal (whatever its set to). */ - float area_no_sp[3]; - - /* Geometry normal */ - float area_no[3]; - float area_co[3]; - - float temp[3]; - float mat[4][4]; - float scale[4][4]; - float tmat[4][4]; - - SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no_sp, area_co); - SCULPT_tilt_apply_to_normal(area_no_sp, ss->cache, brush->tilt_strength_factor); - - if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL)) { - SCULPT_calc_area_normal(sd, ob, nodes, totnode, area_no); - } - else { - copy_v3_v3(area_no, area_no_sp); - } - - /* Delay the first daub because grab delta is not setup. */ - if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) { - return; - } - - if (is_zero_v3(ss->cache->grab_delta_symmetry)) { - return; - } - - mul_v3_v3v3(temp, area_no_sp, ss->cache->scale); - mul_v3_fl(temp, displace); - add_v3_v3(area_co, temp); - - /* Clay Strips uses a cube test with falloff in the XY axis (not in Z) and a plane to deform the - * vertices. When in Add mode, vertices that are below the plane and inside the cube are move - * towards the plane. In this situation, there may be cases where a vertex is outside the cube - * but below the plane, so won't be deformed, causing artifacts. In order to prevent these - * artifacts, this displaces the test cube space in relation to the plane in order to - * deform more vertices that may be below it. */ - /* The 0.7 and 1.25 factors are arbitrary and don't have any relation between them, they were set - * by doing multiple tests using the default "Clay Strips" brush preset. */ - float area_co_displaced[3]; - madd_v3_v3v3fl(area_co_displaced, area_co, area_no, -radius * 0.7f); - - /* Initialize brush local-space matrix. */ - cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry); - mat[0][3] = 0.0f; - cross_v3_v3v3(mat[1], area_no, mat[0]); - mat[1][3] = 0.0f; - copy_v3_v3(mat[2], area_no); - mat[2][3] = 0.0f; - copy_v3_v3(mat[3], area_co_displaced); - mat[3][3] = 1.0f; - normalize_m4(mat); - - /* Scale brush local space matrix. */ - scale_m4_fl(scale, ss->cache->radius); - mul_m4_m4m4(tmat, mat, scale); - - /* Deform the local space in Z to scale the test cube. As the test cube does not have falloff in - * Z this does not produce artifacts in the falloff cube and allows to deform extra vertices - * during big deformation while keeping the surface as uniform as possible. */ - mul_v3_fl(tmat[2], 1.25f); - - invert_m4_m4(mat, tmat); - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .area_no_sp = area_no_sp, - .area_co = area_co, - .mat = mat, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings); -} - -static void do_fill_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float *area_no = data->area_no; - const float *area_co = data->area_co; - - PBVHVertexIter vd; - float(*proxy)[3]; - const float bstrength = ss->cache->bstrength; - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - plane_from_point_normal_v3(test.plane_tool, area_co, area_no); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - - if (!SCULPT_plane_point_side(vd.co, test.plane_tool)) { - continue; - } - - float intr[3]; - float val[3]; - closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co); - sub_v3_v3v3(val, intr, vd.co); - - if (!SCULPT_plane_trim(ss->cache, brush, val)) { - continue; - } - - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - mul_v3_v3fl(proxy[vd.i], val, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - - const float radius = ss->cache->radius; - - float area_no[3]; - float area_co[3]; - float offset = SCULPT_brush_plane_offset_get(sd, ss); - - float displace; - - float temp[3]; - - SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co); - - SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor); - - displace = radius * offset; - - mul_v3_v3v3(temp, area_no, ss->cache->scale); - mul_v3_fl(temp, displace); - add_v3_v3(area_co, temp); - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .area_no = area_no, - .area_co = area_co, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings); -} - -static void do_scrape_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - const float *area_no = data->area_no; - const float *area_co = data->area_co; - - PBVHVertexIter vd; - float(*proxy)[3]; - const float bstrength = ss->cache->bstrength; - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - plane_from_point_normal_v3(test.plane_tool, area_co, area_no); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - - if (SCULPT_plane_point_side(vd.co, test.plane_tool)) { - continue; - } - - float intr[3]; - float val[3]; - closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co); - sub_v3_v3v3(val, intr, vd.co); - - if (!SCULPT_plane_trim(ss->cache, brush, val)) { - continue; - } - - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - mul_v3_v3fl(proxy[vd.i], val, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static void do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - - const float radius = ss->cache->radius; - - float area_no[3]; - float area_co[3]; - float offset = SCULPT_brush_plane_offset_get(sd, ss); - - float displace; - - float temp[3]; - - SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co); - - SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor); - - displace = -radius * offset; - - mul_v3_v3v3(temp, area_no, ss->cache->scale); - mul_v3_fl(temp, displace); - add_v3_v3(area_co, temp); - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .area_no = area_no, - .area_co = area_co, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings); -} - -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Sculpt Clay Thumb Brush - * \{ */ - -static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict tls) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - const Brush *brush = data->brush; - float(*mat)[4] = data->mat; - const float *area_no_sp = data->area_no_sp; - const float *area_co = data->area_co; - - PBVHVertexIter vd; - float(*proxy)[3]; - const float bstrength = data->clay_strength; - - proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; - - SculptBrushTest test; - SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( - ss, &test, data->brush->falloff_shape); - const int thread_id = BLI_task_parallel_thread_id(tls); - - float plane_tilt[4]; - float normal_tilt[3]; - float imat[4][4]; - - invert_m4_m4(imat, mat); - rotate_v3_v3v3fl(normal_tilt, area_no_sp, imat[0], DEG2RADF(-ss->cache->clay_thumb_front_angle)); - - /* Plane aligned to the geometry normal (back part of the brush). */ - plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp); - /* Tilted plane (front part of the brush). */ - plane_from_point_normal_v3(plane_tilt, area_co, normal_tilt); - - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - if (!sculpt_brush_test_sq_fn(&test, vd.co)) { - continue; - } - float local_co[3]; - mul_v3_m4v3(local_co, mat, vd.co); - float intr[3], intr_tilt[3]; - float val[3]; - - closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co); - closest_to_plane_normalized_v3(intr_tilt, plane_tilt, vd.co); - - /* Mix the deformation of the aligned and the tilted plane based on the brush space vertex - * coordinates. */ - /* We can also control the mix with a curve if it produces noticeable artifacts in the center - * of the brush. */ - const float tilt_mix = local_co[1] > 0.0f ? 0.0f : 1.0f; - interp_v3_v3v3(intr, intr, intr_tilt, tilt_mix); - sub_v3_v3v3(val, intr_tilt, vd.co); - - const float fade = bstrength * SCULPT_brush_strength_factor(ss, - brush, - vd.co, - sqrtf(test.dist), - vd.no, - vd.fno, - vd.mask ? *vd.mask : 0.0f, - vd.index, - thread_id); - - mul_v3_v3fl(proxy[vd.i], val, fade); - - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; -} - -static float sculpt_clay_thumb_get_stabilized_pressure(StrokeCache *cache) -{ - float final_pressure = 0.0f; - for (int i = 0; i < SCULPT_CLAY_STABILIZER_LEN; i++) { - final_pressure += cache->clay_pressure_stabilizer[i]; - } - return final_pressure / SCULPT_CLAY_STABILIZER_LEN; -} - -static void do_clay_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) -{ - SculptSession *ss = ob->sculpt; - Brush *brush = BKE_paint_brush(&sd->paint); - - const float radius = ss->cache->radius; - const float offset = SCULPT_brush_plane_offset_get(sd, ss); - const float displace = radius * (0.25f + offset); - - /* Sampled geometry normal and area center. */ - float area_no_sp[3]; - float area_no[3]; - float area_co[3]; - - float temp[3]; - float mat[4][4]; - float scale[4][4]; - float tmat[4][4]; - - SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no_sp, area_co); - - if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL)) { - SCULPT_calc_area_normal(sd, ob, nodes, totnode, area_no); - } - else { - copy_v3_v3(area_no, area_no_sp); - } - - /* Delay the first daub because grab delta is not setup. */ - if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) { - ss->cache->clay_thumb_front_angle = 0.0f; - return; - } - - /* Simulate the clay accumulation by increasing the plane angle as more samples are added to the - * stroke. */ - if (SCULPT_stroke_is_main_symmetry_pass(ss->cache)) { - ss->cache->clay_thumb_front_angle += 0.8f; - ss->cache->clay_thumb_front_angle = clamp_f(ss->cache->clay_thumb_front_angle, 0.0f, 60.0f); - } - - if (is_zero_v3(ss->cache->grab_delta_symmetry)) { - return; - } - - /* Displace the brush planes. */ - copy_v3_v3(area_co, ss->cache->location); - mul_v3_v3v3(temp, area_no_sp, ss->cache->scale); - mul_v3_fl(temp, displace); - add_v3_v3(area_co, temp); - - /* Initialize brush local-space matrix. */ - cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry); - mat[0][3] = 0.0f; - cross_v3_v3v3(mat[1], area_no, mat[0]); - mat[1][3] = 0.0f; - copy_v3_v3(mat[2], area_no); - mat[2][3] = 0.0f; - copy_v3_v3(mat[3], ss->cache->location); - mat[3][3] = 1.0f; - normalize_m4(mat); - - /* Scale brush local space matrix. */ - scale_m4_fl(scale, ss->cache->radius); - mul_m4_m4m4(tmat, mat, scale); - invert_m4_m4(mat, tmat); - - float clay_strength = ss->cache->bstrength * - sculpt_clay_thumb_get_stabilized_pressure(ss->cache); - - SculptThreadedTaskData data = { - .sd = sd, - .ob = ob, - .brush = brush, - .nodes = nodes, - .area_no_sp = area_no_sp, - .area_co = ss->cache->location, - .mat = mat, - .clay_strength = clay_strength, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_clay_thumb_brush_task_cb_ex, &settings); -} - /** \} */ /* -------------------------------------------------------------------- */ @@ -5773,7 +3030,7 @@ static void do_gravity(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, fl /** \} */ /* -------------------------------------------------------------------- */ -/** \name Sculpt Prush Utilities +/** \name Sculpt Brush Utilities * \{ */ void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3]) @@ -5980,14 +3237,22 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe } } - /* Initialize automasking cache. For anchored brushes with spherical falloff, we start off with - * zero radius, thus we have no pbvh nodes on the first brush step. */ + /* For anchored brushes with spherical falloff, we start off with zero radius, thus we have no + * PBVH nodes on the first brush step. */ if (totnode || ((brush->falloff_shape == PAINT_FALLOFF_SHAPE_SPHERE) && (brush->flag & BRUSH_ANCHORED))) { if (SCULPT_stroke_is_first_brush_step(ss->cache)) { + /* Initialize auto-masking cache. */ if (SCULPT_is_automasking_enabled(sd, ss, brush)) { ss->cache->automasking = SCULPT_automasking_cache_init(sd, brush, ob); } + /* Initialize surface smooth cache. */ + if ((brush->sculpt_tool == SCULPT_TOOL_SMOOTH) && + (brush->smooth_deform_type == BRUSH_SMOOTH_DEFORM_SURFACE)) { + BLI_assert(ss->cache->surface_smooth_laplacian_disp == NULL); + ss->cache->surface_smooth_laplacian_disp = MEM_callocN( + sizeof(float[3]) * SCULPT_vertex_count_get(ss), "HC smooth laplacian b"); + } } } @@ -6036,7 +3301,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe /* Apply one type of brush action. */ switch (brush->sculpt_tool) { case SCULPT_TOOL_DRAW: - do_draw_brush(sd, ob, nodes, totnode); + SCULPT_do_draw_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_SMOOTH: if (brush->smooth_deform_type == BRUSH_SMOOTH_DEFORM_LAPLACIAN) { @@ -6047,80 +3312,80 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe } break; case SCULPT_TOOL_CREASE: - do_crease_brush(sd, ob, nodes, totnode); + SCULPT_do_crease_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_BLOB: - do_crease_brush(sd, ob, nodes, totnode); + SCULPT_do_crease_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_PINCH: - do_pinch_brush(sd, ob, nodes, totnode); + SCULPT_do_pinch_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_INFLATE: - do_inflate_brush(sd, ob, nodes, totnode); + SCULPT_do_inflate_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_GRAB: - do_grab_brush(sd, ob, nodes, totnode); + SCULPT_do_grab_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_ROTATE: - do_rotate_brush(sd, ob, nodes, totnode); + SCULPT_do_rotate_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_SNAKE_HOOK: - do_snake_hook_brush(sd, ob, nodes, totnode); + SCULPT_do_snake_hook_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_NUDGE: - do_nudge_brush(sd, ob, nodes, totnode); + SCULPT_do_nudge_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_THUMB: - do_thumb_brush(sd, ob, nodes, totnode); + SCULPT_do_thumb_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_LAYER: - do_layer_brush(sd, ob, nodes, totnode); + SCULPT_do_layer_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_FLATTEN: - do_flatten_brush(sd, ob, nodes, totnode); + SCULPT_do_flatten_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_CLAY: - do_clay_brush(sd, ob, nodes, totnode); + SCULPT_do_clay_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_CLAY_STRIPS: - do_clay_strips_brush(sd, ob, nodes, totnode); + SCULPT_do_clay_strips_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_MULTIPLANE_SCRAPE: SCULPT_do_multiplane_scrape_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_CLAY_THUMB: - do_clay_thumb_brush(sd, ob, nodes, totnode); + SCULPT_do_clay_thumb_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_FILL: if (invert && brush->flag & BRUSH_INVERT_TO_SCRAPE_FILL) { - do_scrape_brush(sd, ob, nodes, totnode); + SCULPT_do_scrape_brush(sd, ob, nodes, totnode); } else { - do_fill_brush(sd, ob, nodes, totnode); + SCULPT_do_fill_brush(sd, ob, nodes, totnode); } break; case SCULPT_TOOL_SCRAPE: if (invert && brush->flag & BRUSH_INVERT_TO_SCRAPE_FILL) { - do_fill_brush(sd, ob, nodes, totnode); + SCULPT_do_fill_brush(sd, ob, nodes, totnode); } else { - do_scrape_brush(sd, ob, nodes, totnode); + SCULPT_do_scrape_brush(sd, ob, nodes, totnode); } break; case SCULPT_TOOL_MASK: - do_mask_brush(sd, ob, nodes, totnode); + SCULPT_do_mask_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_POSE: SCULPT_do_pose_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_DRAW_SHARP: - do_draw_sharp_brush(sd, ob, nodes, totnode); + SCULPT_do_draw_sharp_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_ELASTIC_DEFORM: - do_elastic_deform_brush(sd, ob, nodes, totnode); + SCULPT_do_elastic_deform_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_SLIDE_RELAX: - do_slide_relax_brush(sd, ob, nodes, totnode); + SCULPT_do_slide_relax_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_BOUNDARY: SCULPT_do_boundary_brush(sd, ob, nodes, totnode); @@ -6132,10 +3397,10 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe SCULPT_do_draw_face_sets_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_DISPLACEMENT_ERASER: - do_displacement_eraser_brush(sd, ob, nodes, totnode); + SCULPT_do_displacement_eraser_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_DISPLACEMENT_SMEAR: - do_displacement_smear_brush(sd, ob, nodes, totnode); + SCULPT_do_displacement_smear_brush(sd, ob, nodes, totnode); break; case SCULPT_TOOL_PAINT: SCULPT_do_paint_brush(sd, ob, nodes, totnode); @@ -6157,7 +3422,7 @@ static void do_brush_action(Sculpt *sd, Object *ob, Brush *brush, UnifiedPaintSe } if (sculpt_brush_use_topology_rake(ss, brush)) { - bmesh_topology_rake(sd, ob, nodes, totnode, brush->topology_rake_factor); + SCULPT_bmesh_topology_rake(sd, ob, nodes, totnode, brush->topology_rake_factor); } /* The cloth brush adds the gravity as a regular force and it is processed in the solver. */ @@ -6386,11 +3651,6 @@ void SCULPT_flush_stroke_deform(Sculpt *sd, Object *ob, bool is_proxy_used) } MEM_SAFE_FREE(nodes); - - /* Modifiers could depend on mesh normals, so we should update them. - * NOTE: then if sculpting happens on locked key, normals should be re-calculate after applying - * coords from key-block on base mesh. */ - BKE_mesh_calc_normals(me); } else if (ss->shapekey_active) { sculpt_update_keyblock(ob); @@ -6701,8 +3961,7 @@ static const char *sculpt_tool_name(Sculpt *sd) return "Sculpting"; } -/** - * Operator for applying a stroke (various attributes including mouse path) +/* Operator for applying a stroke (various attributes including mouse path) * using the current brush. */ void SCULPT_cache_free(StrokeCache *cache) @@ -6737,6 +3996,8 @@ static void sculpt_init_mirror_clipping(Object *ob, SculptSession *ss) { ModifierData *md; + unit_m4(ss->cache->clip_mirror_mtx); + for (md = ob->modifiers.first; md; md = md->next) { if (!(md->type == eModifierType_Mirror && (md->mode & eModifierMode_Realtime))) { continue; @@ -6758,6 +4019,73 @@ static void sculpt_init_mirror_clipping(Object *ob, SculptSession *ss) if (mmd->tolerance > ss->cache->clip_tolerance[i]) { ss->cache->clip_tolerance[i] = mmd->tolerance; } + + /* Store matrix for mirror object clipping. */ + if (mmd->mirror_ob) { + float imtx_mirror_ob[4][4]; + invert_m4_m4(imtx_mirror_ob, mmd->mirror_ob->obmat); + mul_m4_m4m4(ss->cache->clip_mirror_mtx, imtx_mirror_ob, ob->obmat); + } + } + } +} + +static void smooth_brush_toggle_on(const bContext *C, Paint *paint, StrokeCache *cache) +{ + Scene *scene = CTX_data_scene(C); + Brush *brush = paint->brush; + + if (brush->sculpt_tool == SCULPT_TOOL_MASK) { + cache->saved_mask_brush_tool = brush->mask_tool; + brush->mask_tool = BRUSH_MASK_SMOOTH; + } + else if (ELEM(brush->sculpt_tool, + SCULPT_TOOL_SLIDE_RELAX, + SCULPT_TOOL_DRAW_FACE_SETS, + SCULPT_TOOL_PAINT, + SCULPT_TOOL_SMEAR)) { + /* Do nothing, this tool has its own smooth mode. */ + } + else { + int cur_brush_size = BKE_brush_size_get(scene, brush); + + BLI_strncpy(cache->saved_active_brush_name, + brush->id.name + 2, + sizeof(cache->saved_active_brush_name)); + + /* Switch to the smooth brush. */ + brush = BKE_paint_toolslots_brush_get(paint, SCULPT_TOOL_SMOOTH); + if (brush) { + BKE_paint_brush_set(paint, brush); + cache->saved_smooth_size = BKE_brush_size_get(scene, brush); + BKE_brush_size_set(scene, brush, cur_brush_size); + BKE_curvemapping_init(brush->curve); + } + } +} + +static void smooth_brush_toggle_off(const bContext *C, Paint *paint, StrokeCache *cache) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + Brush *brush = BKE_paint_brush(paint); + + if (brush->sculpt_tool == SCULPT_TOOL_MASK) { + brush->mask_tool = cache->saved_mask_brush_tool; + } + else if (ELEM(brush->sculpt_tool, + SCULPT_TOOL_SLIDE_RELAX, + SCULPT_TOOL_DRAW_FACE_SETS, + SCULPT_TOOL_PAINT, + SCULPT_TOOL_SMEAR)) { + /* Do nothing. */ + } + else { + /* Try to switch back to the saved/previous brush. */ + BKE_brush_size_set(scene, brush, cache->saved_smooth_size); + brush = (Brush *)BKE_libblock_find_name(bmain, ID_BR, cache->saved_active_brush_name); + if (brush) { + BKE_paint_brush_set(paint, brush); } } } @@ -6767,8 +4095,6 @@ static void sculpt_update_cache_invariants( bContext *C, Sculpt *sd, SculptSession *ss, wmOperator *op, const float mouse[2]) { StrokeCache *cache = MEM_callocN(sizeof(StrokeCache), "stroke cache"); - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); UnifiedPaintSettings *ups = &CTX_data_tool_settings(C)->unified_paint_settings; Brush *brush = BKE_paint_brush(&sd->paint); ViewContext *vc = paint_stroke_view_context(op->customdata); @@ -6833,35 +4159,9 @@ static void sculpt_update_cache_invariants( /* Alt-Smooth. */ if (cache->alt_smooth) { - if (brush->sculpt_tool == SCULPT_TOOL_MASK) { - cache->saved_mask_brush_tool = brush->mask_tool; - brush->mask_tool = BRUSH_MASK_SMOOTH; - } - else if (ELEM(brush->sculpt_tool, - SCULPT_TOOL_SLIDE_RELAX, - SCULPT_TOOL_DRAW_FACE_SETS, - SCULPT_TOOL_PAINT, - SCULPT_TOOL_SMEAR)) { - /* Do nothing, this tool has its own smooth mode. */ - } - else { - Paint *p = &sd->paint; - Brush *br; - int size = BKE_brush_size_get(scene, brush); - - BLI_strncpy(cache->saved_active_brush_name, - brush->id.name + 2, - sizeof(cache->saved_active_brush_name)); - - br = (Brush *)BKE_libblock_find_name(bmain, ID_BR, "Smooth"); - if (br) { - BKE_paint_brush_set(p, br); - brush = br; - cache->saved_smooth_size = BKE_brush_size_get(scene, brush); - BKE_brush_size_set(scene, brush, size); - BKE_curvemapping_init(brush->curve); - } - } + smooth_brush_toggle_on(C, &sd->paint, cache); + /* Refresh the brush pointer in case we switched brush in the toggle function. */ + brush = BKE_paint_brush(&sd->paint); } copy_v2_v2(cache->mouse, cache->initial_mouse); @@ -6869,9 +4169,7 @@ static void sculpt_update_cache_invariants( copy_v2_v2(ups->tex_mouse, cache->initial_mouse); /* Truly temporary data that isn't stored in properties. */ - cache->vc = vc; - cache->brush = brush; /* Cache projection matrix. */ @@ -6946,7 +4244,7 @@ static float sculpt_brush_dynamic_size_get(Brush *brush, StrokeCache *cache, flo case SCULPT_TOOL_CLAY_STRIPS: return max_ff(initial_size * 0.30f, initial_size * powf(cache->pressure, 1.5f)); case SCULPT_TOOL_CLAY_THUMB: { - float clay_stabilized_pressure = sculpt_clay_thumb_get_stabilized_pressure(cache); + float clay_stabilized_pressure = SCULPT_clay_thumb_get_stabilized_pressure(cache); return initial_size * clay_stabilized_pressure; } default: @@ -7989,9 +5287,7 @@ static void sculpt_brush_exit_tex(Sculpt *sd) static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(stroke)) { - Main *bmain = CTX_data_main(C); Object *ob = CTX_data_active_object(C); - Scene *scene = CTX_data_scene(C); SculptSession *ss = ob->sculpt; Sculpt *sd = CTX_data_tool_settings(C)->sculpt; @@ -8009,23 +5305,9 @@ static void sculpt_stroke_done(const bContext *C, struct PaintStroke *UNUSED(str /* Alt-Smooth. */ if (ss->cache->alt_smooth) { - if (brush->sculpt_tool == SCULPT_TOOL_MASK) { - brush->mask_tool = ss->cache->saved_mask_brush_tool; - } - else if (ELEM(brush->sculpt_tool, - SCULPT_TOOL_SLIDE_RELAX, - SCULPT_TOOL_DRAW_FACE_SETS, - SCULPT_TOOL_PAINT, - SCULPT_TOOL_SMEAR)) { - /* Do nothing. */ - } - else { - BKE_brush_size_set(scene, brush, ss->cache->saved_smooth_size); - brush = (Brush *)BKE_libblock_find_name(bmain, ID_BR, ss->cache->saved_active_brush_name); - if (brush) { - BKE_paint_brush_set(&sd->paint, brush); - } - } + smooth_brush_toggle_off(C, &sd->paint, ss->cache); + /* Refresh the brush pointer in case we switched brush in the toggle function. */ + brush = BKE_paint_brush(&sd->paint); } if (SCULPT_is_automasking_enabled(sd, ss, brush)) { @@ -8131,7 +5413,7 @@ static void sculpt_brush_stroke_cancel(bContext *C, wmOperator *op) sculpt_brush_exit_tex(sd); } -static void SCULPT_OT_brush_stroke(wmOperatorType *ot) +void SCULPT_OT_brush_stroke(wmOperatorType *ot) { /* Identifiers. */ ot->name = "Sculpt"; @@ -8159,677 +5441,6 @@ static void SCULPT_OT_brush_stroke(wmOperatorType *ot) "Clicks on the background do not start the stroke"); } -/* Reset the copy of the mesh that is being sculpted on (currently just for the layer brush). */ - -static int sculpt_set_persistent_base_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); - Object *ob = CTX_data_active_object(C); - SculptSession *ss = ob->sculpt; - - if (!ss) { - return OPERATOR_FINISHED; - } - SCULPT_vertex_random_access_ensure(ss); - BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false); - - MEM_SAFE_FREE(ss->persistent_base); - - const int totvert = SCULPT_vertex_count_get(ss); - ss->persistent_base = MEM_mallocN(sizeof(SculptPersistentBase) * totvert, - "layer persistent base"); - - for (int i = 0; i < totvert; i++) { - copy_v3_v3(ss->persistent_base[i].co, SCULPT_vertex_co_get(ss, i)); - SCULPT_vertex_normal_get(ss, i, ss->persistent_base[i].no); - ss->persistent_base[i].disp = 0.0f; - } - - return OPERATOR_FINISHED; -} - -static void SCULPT_OT_set_persistent_base(wmOperatorType *ot) -{ - /* Identifiers. */ - ot->name = "Set Persistent Base"; - ot->idname = "SCULPT_OT_set_persistent_base"; - ot->description = "Reset the copy of the mesh that is being sculpted on"; - - /* API callbacks. */ - ot->exec = sculpt_set_persistent_base_exec; - ot->poll = SCULPT_mode_poll; - - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -/************************* SCULPT_OT_optimize *************************/ - -static int sculpt_optimize_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *ob = CTX_data_active_object(C); - - SCULPT_pbvh_clear(ob); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - - return OPERATOR_FINISHED; -} - -/* The BVH gets less optimal more quickly with dynamic topology than - * regular sculpting. There is no doubt more clever stuff we can do to - * optimize it on the fly, but for now this gives the user a nicer way - * to recalculate it than toggling modes. */ -static void SCULPT_OT_optimize(wmOperatorType *ot) -{ - /* Identifiers. */ - ot->name = "Rebuild BVH"; - ot->idname = "SCULPT_OT_optimize"; - ot->description = "Recalculate the sculpt BVH to improve performance"; - - /* API callbacks. */ - ot->exec = sculpt_optimize_exec; - ot->poll = SCULPT_mode_poll; - - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -/********************* Dynamic topology symmetrize ********************/ - -static bool sculpt_no_multires_poll(bContext *C) -{ - Object *ob = CTX_data_active_object(C); - if (SCULPT_mode_poll(C) && ob->sculpt && ob->sculpt->pbvh) { - return BKE_pbvh_type(ob->sculpt->pbvh) != PBVH_GRIDS; - } - return false; -} - -static int sculpt_symmetrize_exec(bContext *C, wmOperator *op) -{ - Main *bmain = CTX_data_main(C); - Object *ob = CTX_data_active_object(C); - const Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - SculptSession *ss = ob->sculpt; - PBVH *pbvh = ss->pbvh; - const float dist = RNA_float_get(op->ptr, "merge_tolerance"); - - if (!pbvh) { - return OPERATOR_CANCELLED; - } - - switch (BKE_pbvh_type(pbvh)) { - case PBVH_BMESH: - /* Dyntopo Symmetrize. */ - - /* To simplify undo for symmetrize, all BMesh elements are logged - * as deleted, then after symmetrize operation all BMesh elements - * are logged as added (as opposed to attempting to store just the - * parts that symmetrize modifies). */ - SCULPT_undo_push_begin(ob, "Dynamic topology symmetrize"); - SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE); - BM_log_before_all_removed(ss->bm, ss->bm_log); - - BM_mesh_toolflags_set(ss->bm, true); - - /* Symmetrize and re-triangulate. */ - BMO_op_callf(ss->bm, - (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), - "symmetrize input=%avef direction=%i dist=%f use_shapekey=%b", - sd->symmetrize_direction, - dist, - true); - SCULPT_dynamic_topology_triangulate(ss->bm); - - /* Bisect operator flags edges (keep tags clean for edge queue). */ - BM_mesh_elem_hflag_disable_all(ss->bm, BM_EDGE, BM_ELEM_TAG, false); - - BM_mesh_toolflags_set(ss->bm, false); - - /* Finish undo. */ - BM_log_all_added(ss->bm, ss->bm_log); - SCULPT_undo_push_end(); - - break; - case PBVH_FACES: - /* Mesh Symmetrize. */ - ED_sculpt_undo_geometry_begin(ob, "mesh symmetrize"); - Mesh *mesh = ob->data; - - BKE_mesh_mirror_apply_mirror_on_axis(bmain, mesh, sd->symmetrize_direction, dist); - - ED_sculpt_undo_geometry_end(ob); - BKE_mesh_calc_normals(ob->data); - BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL); - - break; - case PBVH_GRIDS: - return OPERATOR_CANCELLED; - } - - /* Redraw. */ - SCULPT_pbvh_clear(ob); - WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); - - return OPERATOR_FINISHED; -} - -static void SCULPT_OT_symmetrize(wmOperatorType *ot) -{ - /* Identifiers. */ - ot->name = "Symmetrize"; - ot->idname = "SCULPT_OT_symmetrize"; - ot->description = "Symmetrize the topology modifications"; - - /* API callbacks. */ - ot->exec = sculpt_symmetrize_exec; - ot->poll = sculpt_no_multires_poll; - - RNA_def_float(ot->srna, - "merge_tolerance", - 0.001f, - 0.0f, - FLT_MAX, - "Merge Distance", - "Distance within which symmetrical vertices are merged", - 0.0f, - 1.0f); -} - -/**** Toggle operator for turning sculpt mode on or off ****/ - -static void sculpt_init_session(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob) -{ - /* Create persistent sculpt mode data. */ - BKE_sculpt_toolsettings_data_ensure(scene); - - /* Create sculpt mode session data. */ - if (ob->sculpt != NULL) { - BKE_sculptsession_free(ob); - } - ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session"); - ob->sculpt->mode_type = OB_MODE_SCULPT; - - BKE_sculpt_ensure_orig_mesh_data(scene, ob); - - BKE_scene_graph_evaluated_ensure(depsgraph, bmain); - - /* This function expects a fully evaluated depsgraph. */ - BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false); - - /* Here we can detect geometry that was just added to Sculpt Mode as it has the - * SCULPT_FACE_SET_NONE assigned, so we can create a new Face Set for it. */ - /* In sculpt mode all geometry that is assigned to SCULPT_FACE_SET_NONE is considered as not - * initialized, which is used is some operators that modify the mesh topology to perform certain - * actions in the new polys. After these operations are finished, all polys should have a valid - * face set ID assigned (different from SCULPT_FACE_SET_NONE) to manage their visibility - * correctly. */ - /* TODO(pablodp606): Based on this we can improve the UX in future tools for creating new - * objects, like moving the transform pivot position to the new area or masking existing - * geometry. */ - SculptSession *ss = ob->sculpt; - const int new_face_set = SCULPT_face_set_next_available_get(ss); - for (int i = 0; i < ss->totfaces; i++) { - if (ss->face_sets[i] == SCULPT_FACE_SET_NONE) { - ss->face_sets[i] = new_face_set; - } - } -} - -void ED_object_sculptmode_enter_ex(Main *bmain, - Depsgraph *depsgraph, - Scene *scene, - Object *ob, - const bool force_dyntopo, - ReportList *reports) -{ - const int mode_flag = OB_MODE_SCULPT; - Mesh *me = BKE_mesh_from_object(ob); - - /* Enter sculpt mode. */ - ob->mode |= mode_flag; - - sculpt_init_session(bmain, depsgraph, scene, ob); - - if (!(fabsf(ob->scale[0] - ob->scale[1]) < 1e-4f && - fabsf(ob->scale[1] - ob->scale[2]) < 1e-4f)) { - BKE_report( - reports, RPT_WARNING, "Object has non-uniform scale, sculpting may be unpredictable"); - } - else if (is_negative_m4(ob->obmat)) { - BKE_report(reports, RPT_WARNING, "Object has negative scale, sculpting may be unpredictable"); - } - - Paint *paint = BKE_paint_get_active_from_paintmode(scene, PAINT_MODE_SCULPT); - BKE_paint_init(bmain, scene, PAINT_MODE_SCULPT, PAINT_CURSOR_SCULPT); - - paint_cursor_start(paint, SCULPT_mode_poll_view3d); - - /* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes, - * As long as no data was added that is not supported. */ - if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) { - MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob); - - const char *message_unsupported = NULL; - if (me->totloop != me->totpoly * 3) { - message_unsupported = TIP_("non-triangle face"); - } - else if (mmd != NULL) { - message_unsupported = TIP_("multi-res modifier"); - } - else { - enum eDynTopoWarnFlag flag = SCULPT_dynamic_topology_check(scene, ob); - if (flag == 0) { - /* pass */ - } - else if (flag & DYNTOPO_WARN_VDATA) { - message_unsupported = TIP_("vertex data"); - } - else if (flag & DYNTOPO_WARN_EDATA) { - message_unsupported = TIP_("edge data"); - } - else if (flag & DYNTOPO_WARN_LDATA) { - message_unsupported = TIP_("face data"); - } - else if (flag & DYNTOPO_WARN_MODIFIER) { - message_unsupported = TIP_("constructive modifier"); - } - else { - BLI_assert(0); - } - } - - if ((message_unsupported == NULL) || force_dyntopo) { - /* Needed because we may be entering this mode before the undo system loads. */ - wmWindowManager *wm = bmain->wm.first; - bool has_undo = wm->undo_stack != NULL; - /* Undo push is needed to prevent memory leak. */ - if (has_undo) { - SCULPT_undo_push_begin(ob, "Dynamic topology enable"); - } - SCULPT_dynamic_topology_enable_ex(bmain, depsgraph, scene, ob); - if (has_undo) { - SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN); - SCULPT_undo_push_end(); - } - } - else { - BKE_reportf( - reports, RPT_WARNING, "Dynamic Topology found: %s, disabled", message_unsupported); - me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY; - } - } - - /* Flush object mode. */ - DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); -} - -void ED_object_sculptmode_enter(struct bContext *C, Depsgraph *depsgraph, ReportList *reports) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *ob = OBACT(view_layer); - ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, reports); -} - -void ED_object_sculptmode_exit_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob) -{ - const int mode_flag = OB_MODE_SCULPT; - Mesh *me = BKE_mesh_from_object(ob); - - multires_flush_sculpt_updates(ob); - - /* Not needed for now. */ -#if 0 - MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob); - const int flush_recalc = ed_object_sculptmode_flush_recalc_flag(scene, ob, mmd); -#endif - - /* Always for now, so leaving sculpt mode always ensures scene is in - * a consistent state. */ - if (true || /* flush_recalc || */ (ob->sculpt && ob->sculpt->bm)) { - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - } - - if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) { - /* Dynamic topology must be disabled before exiting sculpt - * mode to ensure the undo stack stays in a consistent - * state. */ - sculpt_dynamic_topology_disable_with_undo(bmain, depsgraph, scene, ob); - - /* Store so we know to re-enable when entering sculpt mode. */ - me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY; - } - - /* Leave sculpt mode. */ - ob->mode &= ~mode_flag; - - BKE_sculptsession_free(ob); - - paint_cursor_delete_textures(); - - /* Never leave derived meshes behind. */ - BKE_object_free_derived_caches(ob); - - /* Flush object mode. */ - DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); -} - -void ED_object_sculptmode_exit(bContext *C, Depsgraph *depsgraph) -{ - Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *ob = OBACT(view_layer); - ED_object_sculptmode_exit_ex(bmain, depsgraph, scene, ob); -} - -static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op) -{ - struct wmMsgBus *mbus = CTX_wm_message_bus(C); - Main *bmain = CTX_data_main(C); - Depsgraph *depsgraph = CTX_data_depsgraph_on_load(C); - Scene *scene = CTX_data_scene(C); - ToolSettings *ts = scene->toolsettings; - ViewLayer *view_layer = CTX_data_view_layer(C); - Object *ob = OBACT(view_layer); - const int mode_flag = OB_MODE_SCULPT; - const bool is_mode_set = (ob->mode & mode_flag) != 0; - - if (!is_mode_set) { - if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { - return OPERATOR_CANCELLED; - } - } - - if (is_mode_set) { - ED_object_sculptmode_exit_ex(bmain, depsgraph, scene, ob); - } - else { - if (depsgraph) { - depsgraph = CTX_data_ensure_evaluated_depsgraph(C); - } - ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, op->reports); - BKE_paint_toolslots_brush_validate(bmain, &ts->sculpt->paint); - - if (ob->mode & mode_flag) { - Mesh *me = ob->data; - /* Dyntopo adds its own undo step. */ - if ((me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) == 0) { - /* Without this the memfile undo step is used, - * while it works it causes lag when undoing the first undo step, see T71564. */ - wmWindowManager *wm = CTX_wm_manager(C); - if (wm->op_undo_depth <= 1) { - SCULPT_undo_push_begin(ob, op->type->name); - } - } - } - } - - WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene); - - WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode); - - WM_toolsystem_update_from_context_view3d(C); - - return OPERATOR_FINISHED; -} - -static void SCULPT_OT_sculptmode_toggle(wmOperatorType *ot) -{ - /* Identifiers. */ - ot->name = "Sculpt Mode"; - ot->idname = "SCULPT_OT_sculptmode_toggle"; - ot->description = "Toggle sculpt mode in 3D view"; - - /* API callbacks. */ - ot->exec = sculpt_mode_toggle_exec; - ot->poll = ED_operator_object_active_editable_mesh; - - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float radius) -{ - Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); - Object *ob = CTX_data_active_object(C); - - ss->preview_vert_index_count = 0; - int totpoints = 0; - - /* This function is called from the cursor drawing code, so the PBVH may not be build yet. */ - if (!ss->pbvh) { - return; - } - - if (!ss->deform_modifiers_active) { - return; - } - - if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { - return; - } - - BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); - - if (!ss->pmap) { - return; - } - - float brush_co[3]; - copy_v3_v3(brush_co, SCULPT_active_vertex_co_get(ss)); - - BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(SCULPT_vertex_count_get(ss), "visited_vertices"); - - /* Assuming an average of 6 edges per vertex in a triangulated mesh. */ - const int max_preview_vertices = SCULPT_vertex_count_get(ss) * 3 * 2; - - if (ss->preview_vert_index_list == NULL) { - ss->preview_vert_index_list = MEM_callocN(max_preview_vertices * sizeof(int), "preview lines"); - } - - GSQueue *not_visited_vertices = BLI_gsqueue_new(sizeof(int)); - int active_v = SCULPT_active_vertex_get(ss); - BLI_gsqueue_push(not_visited_vertices, &active_v); - - while (!BLI_gsqueue_is_empty(not_visited_vertices)) { - int from_v; - BLI_gsqueue_pop(not_visited_vertices, &from_v); - SculptVertexNeighborIter ni; - SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) { - if (totpoints + (ni.size * 2) < max_preview_vertices) { - int to_v = ni.index; - ss->preview_vert_index_list[totpoints] = from_v; - totpoints++; - ss->preview_vert_index_list[totpoints] = to_v; - totpoints++; - if (BLI_BITMAP_TEST(visited_vertices, to_v)) { - continue; - } - BLI_BITMAP_ENABLE(visited_vertices, to_v); - const float *co = SCULPT_vertex_co_for_grab_active_get(ss, to_v); - if (len_squared_v3v3(brush_co, co) < radius * radius) { - BLI_gsqueue_push(not_visited_vertices, &to_v); - } - } - } - SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); - } - - BLI_gsqueue_free(not_visited_vertices); - - MEM_freeN(visited_vertices); - - ss->preview_vert_index_count = totpoints; -} - -static int vertex_to_loop_colors_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *ob = CTX_data_active_object(C); - - ID *data; - data = ob->data; - if (data && ID_IS_LINKED(data)) { - return OPERATOR_CANCELLED; - } - - if (ob->type != OB_MESH) { - return OPERATOR_CANCELLED; - } - - Mesh *mesh = ob->data; - - const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_MLOOPCOL); - if (mloopcol_layer_n == -1) { - return OPERATOR_CANCELLED; - } - MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPCOL, mloopcol_layer_n); - - const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR); - if (MPropCol_layer_n == -1) { - return OPERATOR_CANCELLED; - } - MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n); - - MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP); - MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY); - - for (int i = 0; i < mesh->totpoly; i++) { - MPoly *c_poly = &polys[i]; - for (int j = 0; j < c_poly->totloop; j++) { - int loop_index = c_poly->loopstart + j; - MLoop *c_loop = &loops[c_poly->loopstart + j]; - float srgb_color[4]; - linearrgb_to_srgb_v4(srgb_color, vertcols[c_loop->v].color); - loopcols[loop_index].r = (char)(srgb_color[0] * 255); - loopcols[loop_index].g = (char)(srgb_color[1] * 255); - loopcols[loop_index].b = (char)(srgb_color[2] * 255); - loopcols[loop_index].a = (char)(srgb_color[3] * 255); - } - } - - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); - - return OPERATOR_FINISHED; -} - -static void SCULPT_OT_vertex_to_loop_colors(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Sculpt Vertex Color to Vertex Color"; - ot->description = "Copy the Sculpt Vertex Color to a regular color layer"; - ot->idname = "SCULPT_OT_vertex_to_loop_colors"; - - /* api callbacks */ - ot->poll = SCULPT_vertex_colors_poll; - ot->exec = vertex_to_loop_colors_exec; - - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -static int loop_to_vertex_colors_exec(bContext *C, wmOperator *UNUSED(op)) -{ - Object *ob = CTX_data_active_object(C); - - ID *data; - data = ob->data; - if (data && ID_IS_LINKED(data)) { - return OPERATOR_CANCELLED; - } - - if (ob->type != OB_MESH) { - return OPERATOR_CANCELLED; - } - - Mesh *mesh = ob->data; - - const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_MLOOPCOL); - if (mloopcol_layer_n == -1) { - return OPERATOR_CANCELLED; - } - MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPCOL, mloopcol_layer_n); - - const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR); - if (MPropCol_layer_n == -1) { - return OPERATOR_CANCELLED; - } - MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n); - - MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP); - MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY); - - for (int i = 0; i < mesh->totpoly; i++) { - MPoly *c_poly = &polys[i]; - for (int j = 0; j < c_poly->totloop; j++) { - int loop_index = c_poly->loopstart + j; - MLoop *c_loop = &loops[c_poly->loopstart + j]; - vertcols[c_loop->v].color[0] = (loopcols[loop_index].r / 255.0f); - vertcols[c_loop->v].color[1] = (loopcols[loop_index].g / 255.0f); - vertcols[c_loop->v].color[2] = (loopcols[loop_index].b / 255.0f); - vertcols[c_loop->v].color[3] = (loopcols[loop_index].a / 255.0f); - srgb_to_linearrgb_v4(vertcols[c_loop->v].color, vertcols[c_loop->v].color); - } - } - - DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); - - return OPERATOR_FINISHED; -} - -static void SCULPT_OT_loop_to_vertex_colors(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Vertex Color to Sculpt Vertex Color"; - ot->description = "Copy the active loop color layer to the vertex color"; - ot->idname = "SCULPT_OT_loop_to_vertex_colors"; - - /* api callbacks */ - ot->poll = SCULPT_vertex_colors_poll; - ot->exec = loop_to_vertex_colors_exec; - - ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; -} - -static int sculpt_sample_color_invoke(bContext *C, - wmOperator *UNUSED(op), - const wmEvent *UNUSED(e)) -{ - Sculpt *sd = CTX_data_tool_settings(C)->sculpt; - Scene *scene = CTX_data_scene(C); - Object *ob = CTX_data_active_object(C); - Brush *brush = BKE_paint_brush(&sd->paint); - SculptSession *ss = ob->sculpt; - int active_vertex = SCULPT_active_vertex_get(ss); - const float *active_vertex_color = SCULPT_vertex_color_get(ss, active_vertex); - if (!active_vertex_color) { - return OPERATOR_CANCELLED; - } - - float color_srgb[3]; - copy_v3_v3(color_srgb, active_vertex_color); - IMB_colormanagement_scene_linear_to_srgb_v3(color_srgb); - BKE_brush_color_set(scene, brush, color_srgb); - - WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush); - - return OPERATOR_FINISHED; -} - -static void SCULPT_OT_sample_color(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Sample Color"; - ot->idname = "SCULPT_OT_sample_color"; - ot->description = "Sample the vertex color of the active vertex"; - - /* api callbacks */ - ot->invoke = sculpt_sample_color_invoke; - ot->poll = SCULPT_vertex_colors_poll; - - ot->flag = OPTYPE_REGISTER; -} - /* Fake Neighbors. */ /* This allows the sculpt tools to work on meshes with multiple connected components as they had * only one connected component. When initialized and enabled, the sculpt API will return extra @@ -9105,356 +5716,10 @@ void SCULPT_fake_neighbors_free(Object *ob) sculpt_pose_fake_neighbors_free(ss); } -/** - * #sculpt_mask_by_color_delta_get returns values in the (0,1) range that are used to generate the - * mask based on the difference between two colors (the active color and the color of any other - * vertex). Ideally, a threshold of 0 should mask only the colors that are equal to the active - * color and threshold of 1 should mask all colors. In order to avoid artifacts and produce softer - * falloffs in the mask, the MASK_BY_COLOR_SLOPE defines the size of the transition values between - * masked and unmasked vertices. The smaller this value is, the sharper the generated mask is going - * to be. - */ -#define MASK_BY_COLOR_SLOPE 0.25f - -static float sculpt_mask_by_color_delta_get(const float *color_a, - const float *color_b, - const float threshold, - const bool invert) -{ - float len = len_v3v3(color_a, color_b); - /* Normalize len to the (0, 1) range. */ - len = len / M_SQRT3; - - if (len < threshold - MASK_BY_COLOR_SLOPE) { - len = 1.0f; - } - else if (len >= threshold) { - len = 0.0f; - } - else { - len = (-len + threshold) / MASK_BY_COLOR_SLOPE; - } - - if (invert) { - return 1.0f - len; - } - return len; -} - -static float sculpt_mask_by_color_final_mask_get(const float current_mask, - const float new_mask, - const bool invert, - const bool preserve_mask) -{ - if (preserve_mask) { - if (invert) { - return min_ff(current_mask, new_mask); - } - return max_ff(current_mask, new_mask); - } - return new_mask; -} - -typedef struct MaskByColorContiguousFloodFillData { - float threshold; - bool invert; - float *new_mask; - float initial_color[3]; -} MaskByColorContiguousFloodFillData; - -static void do_mask_by_color_contiguous_update_nodes_cb( - void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls)) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - - SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_MASK); - bool update_node = false; - - const bool invert = data->mask_by_color_invert; - const bool preserve_mask = data->mask_by_color_preserve_mask; - - PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - const float current_mask = *vd.mask; - const float new_mask = data->mask_by_color_floodfill[vd.index]; - *vd.mask = sculpt_mask_by_color_final_mask_get(current_mask, new_mask, invert, preserve_mask); - if (current_mask == *vd.mask) { - continue; - } - update_node = true; - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; - if (update_node) { - BKE_pbvh_node_mark_redraw(data->nodes[n]); - } -} - -static bool sculpt_mask_by_color_contiguous_floodfill_cb( - SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata) -{ - MaskByColorContiguousFloodFillData *data = userdata; - const float *current_color = SCULPT_vertex_color_get(ss, to_v); - float new_vertex_mask = sculpt_mask_by_color_delta_get( - current_color, data->initial_color, data->threshold, data->invert); - data->new_mask[to_v] = new_vertex_mask; - - if (is_duplicate) { - data->new_mask[to_v] = data->new_mask[from_v]; - } - - float len = len_v3v3(current_color, data->initial_color); - len = len / M_SQRT3; - return len <= data->threshold; -} - -static void sculpt_mask_by_color_contiguous(Object *object, - const int vertex, - const float threshold, - const bool invert, - const bool preserve_mask) -{ - SculptSession *ss = object->sculpt; - const int totvert = SCULPT_vertex_count_get(ss); - - float *new_mask = MEM_calloc_arrayN(totvert, sizeof(float), "new mask"); - - if (invert) { - for (int i = 0; i < totvert; i++) { - new_mask[i] = 1.0f; - } - } - - SculptFloodFill flood; - SCULPT_floodfill_init(ss, &flood); - SCULPT_floodfill_add_initial(&flood, vertex); - - MaskByColorContiguousFloodFillData ffd; - ffd.threshold = threshold; - ffd.invert = invert; - ffd.new_mask = new_mask; - copy_v3_v3(ffd.initial_color, SCULPT_vertex_color_get(ss, vertex)); - - SCULPT_floodfill_execute(ss, &flood, sculpt_mask_by_color_contiguous_floodfill_cb, &ffd); - SCULPT_floodfill_free(&flood); - - int totnode; - PBVHNode **nodes; - BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); - - SculptThreadedTaskData data = { - .ob = object, - .nodes = nodes, - .mask_by_color_floodfill = new_mask, - .mask_by_color_vertex = vertex, - .mask_by_color_threshold = threshold, - .mask_by_color_invert = invert, - .mask_by_color_preserve_mask = preserve_mask, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range( - 0, totnode, &data, do_mask_by_color_contiguous_update_nodes_cb, &settings); - - MEM_SAFE_FREE(nodes); - - MEM_freeN(new_mask); -} - -static void do_mask_by_color_task_cb(void *__restrict userdata, - const int n, - const TaskParallelTLS *__restrict UNUSED(tls)) -{ - SculptThreadedTaskData *data = userdata; - SculptSession *ss = data->ob->sculpt; - - SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_MASK); - bool update_node = false; - - const float threshold = data->mask_by_color_threshold; - const bool invert = data->mask_by_color_invert; - const bool preserve_mask = data->mask_by_color_preserve_mask; - const float *active_color = SCULPT_vertex_color_get(ss, data->mask_by_color_vertex); - - PBVHVertexIter vd; - BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { - const float current_mask = *vd.mask; - const float new_mask = sculpt_mask_by_color_delta_get(active_color, vd.col, threshold, invert); - *vd.mask = sculpt_mask_by_color_final_mask_get(current_mask, new_mask, invert, preserve_mask); - - if (current_mask == *vd.mask) { - continue; - } - update_node = true; - if (vd.mvert) { - vd.mvert->flag |= ME_VERT_PBVH_UPDATE; - } - } - BKE_pbvh_vertex_iter_end; - if (update_node) { - BKE_pbvh_node_mark_redraw(data->nodes[n]); - } -} - -static void sculpt_mask_by_color_full_mesh(Object *object, - const int vertex, - const float threshold, - const bool invert, - const bool preserve_mask) -{ - SculptSession *ss = object->sculpt; - - int totnode; - PBVHNode **nodes; - BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); - - SculptThreadedTaskData data = { - .ob = object, - .nodes = nodes, - .mask_by_color_vertex = vertex, - .mask_by_color_threshold = threshold, - .mask_by_color_invert = invert, - .mask_by_color_preserve_mask = preserve_mask, - }; - - TaskParallelSettings settings; - BKE_pbvh_parallel_range_settings(&settings, true, totnode); - BLI_task_parallel_range(0, totnode, &data, do_mask_by_color_task_cb, &settings); - - MEM_SAFE_FREE(nodes); -} - -static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEvent *event) -{ - Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); - Object *ob = CTX_data_active_object(C); - SculptSession *ss = ob->sculpt; - - BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); - - /* Color data is not available in Multires. */ - if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) { - return OPERATOR_CANCELLED; - } - - if (!ss->vcol) { - return OPERATOR_CANCELLED; - } - - SCULPT_vertex_random_access_ensure(ss); - - /* Tools that are not brushes do not have the brush gizmo to update the vertex as the mouse move, - * so it needs to be updated here. */ - SculptCursorGeometryInfo sgi; - float mouse[2]; - mouse[0] = event->mval[0]; - mouse[1] = event->mval[1]; - SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false); - - SCULPT_undo_push_begin(ob, "Mask by color"); - - const int active_vertex = SCULPT_active_vertex_get(ss); - const float threshold = RNA_float_get(op->ptr, "threshold"); - const bool invert = RNA_boolean_get(op->ptr, "invert"); - const bool preserve_mask = RNA_boolean_get(op->ptr, "preserve_previous_mask"); - - if (RNA_boolean_get(op->ptr, "contiguous")) { - sculpt_mask_by_color_contiguous(ob, active_vertex, threshold, invert, preserve_mask); - } - else { - sculpt_mask_by_color_full_mesh(ob, active_vertex, threshold, invert, preserve_mask); - } - - BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask); - SCULPT_undo_push_end(); - - SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK); - - return OPERATOR_FINISHED; -} - -static void SCULPT_OT_mask_by_color(wmOperatorType *ot) -{ - /* identifiers */ - ot->name = "Mask by Color"; - ot->idname = "SCULPT_OT_mask_by_color"; - ot->description = "Creates a mask based on the sculpt vertex colors"; - - /* api callbacks */ - ot->invoke = sculpt_mask_by_color_invoke; - ot->poll = SCULPT_vertex_colors_poll; - - ot->flag = OPTYPE_REGISTER; - - ot->prop = RNA_def_boolean( - ot->srna, "contiguous", false, "Contiguous", "Mask only contiguous color areas"); - - ot->prop = RNA_def_boolean(ot->srna, "invert", false, "Invert", "Invert the generated mask"); - ot->prop = RNA_def_boolean( - ot->srna, - "preserve_previous_mask", - false, - "Preserve Previous Mask", - "Preserve the previous mask and add or subtract the new one generated by the colors"); - - RNA_def_float(ot->srna, - "threshold", - 0.35f, - 0.0f, - 1.0f, - "Threshold", - "How much changes in color affect the mask generation", - 0.0f, - 1.0f); -} - /** \} */ /* -------------------------------------------------------------------- */ /** \name Operator Registration * \{ */ -void ED_operatortypes_sculpt(void) -{ - WM_operatortype_append(SCULPT_OT_brush_stroke); - WM_operatortype_append(SCULPT_OT_sculptmode_toggle); - WM_operatortype_append(SCULPT_OT_set_persistent_base); - WM_operatortype_append(SCULPT_OT_dynamic_topology_toggle); - WM_operatortype_append(SCULPT_OT_optimize); - WM_operatortype_append(SCULPT_OT_symmetrize); - WM_operatortype_append(SCULPT_OT_detail_flood_fill); - WM_operatortype_append(SCULPT_OT_sample_detail_size); - WM_operatortype_append(SCULPT_OT_set_detail_size); - WM_operatortype_append(SCULPT_OT_mesh_filter); - WM_operatortype_append(SCULPT_OT_mask_filter); - WM_operatortype_append(SCULPT_OT_dirty_mask); - WM_operatortype_append(SCULPT_OT_mask_expand); - WM_operatortype_append(SCULPT_OT_set_pivot_position); - WM_operatortype_append(SCULPT_OT_face_sets_create); - WM_operatortype_append(SCULPT_OT_face_sets_change_visibility); - WM_operatortype_append(SCULPT_OT_face_sets_randomize_colors); - WM_operatortype_append(SCULPT_OT_face_sets_init); - WM_operatortype_append(SCULPT_OT_cloth_filter); - WM_operatortype_append(SCULPT_OT_face_sets_edit); - WM_operatortype_append(SCULPT_OT_face_set_lasso_gesture); - WM_operatortype_append(SCULPT_OT_face_set_box_gesture); - WM_operatortype_append(SCULPT_OT_trim_box_gesture); - WM_operatortype_append(SCULPT_OT_trim_lasso_gesture); - WM_operatortype_append(SCULPT_OT_project_line_gesture); - - WM_operatortype_append(SCULPT_OT_sample_color); - WM_operatortype_append(SCULPT_OT_loop_to_vertex_colors); - WM_operatortype_append(SCULPT_OT_vertex_to_loop_colors); - WM_operatortype_append(SCULPT_OT_color_filter); - WM_operatortype_append(SCULPT_OT_mask_by_color); - WM_operatortype_append(SCULPT_OT_dyntopo_detail_size_edit); - WM_operatortype_append(SCULPT_OT_mask_init); - - WM_operatortype_append(SCULPT_OT_expand); -} - /** \} */ diff --git a/source/blender/editors/sculpt_paint/sculpt_boundary.c b/source/blender/editors/sculpt_paint/sculpt_boundary.c index e238fafb063..1e41c5cdbdf 100644 --- a/source/blender/editors/sculpt_paint/sculpt_boundary.c +++ b/source/blender/editors/sculpt_paint/sculpt_boundary.c @@ -772,12 +772,10 @@ static void do_boundary_brush_inflate_task_cb_ex(void *__restrict userdata, const float mask = vd.mask ? 1.0f - *vd.mask : 1.0f; const float automask = SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index); - float normal[3]; - normal_short_to_float_v3(normal, orig_data.no); float *target_co = SCULPT_brush_deform_target_vertex_co_get(ss, brush->deform_target, &vd); madd_v3_v3v3fl(target_co, orig_data.co, - normal, + orig_data.no, boundary->edit_info[vd.index].strength_factor * disp * mask * automask * strength); diff --git a/source/blender/editors/sculpt_paint/sculpt_brush_types.c b/source/blender/editors/sculpt_paint/sculpt_brush_types.c new file mode 100644 index 00000000000..c2acc361a79 --- /dev/null +++ b/source/blender/editors/sculpt_paint/sculpt_brush_types.c @@ -0,0 +1,2847 @@ +/* + * 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) 2006 by Nicholas Bishop + * All rights reserved. + * Implements the Sculpt Mode tools + */ + +/** \file + * \ingroup edsculpt + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_blenlib.h" +#include "BLI_dial_2d.h" +#include "BLI_ghash.h" +#include "BLI_gsqueue.h" +#include "BLI_hash.h" +#include "BLI_math.h" +#include "BLI_math_color.h" +#include "BLI_math_color_blend.h" +#include "BLI_task.h" +#include "BLI_utildefines.h" + +#include "BLT_translation.h" + +#include "PIL_time.h" + +#include "DNA_brush_types.h" +#include "DNA_customdata_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_node_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_brush.h" +#include "BKE_ccg.h" +#include "BKE_colortools.h" +#include "BKE_context.h" +#include "BKE_image.h" +#include "BKE_kelvinlet.h" +#include "BKE_key.h" +#include "BKE_lib_id.h" +#include "BKE_main.h" +#include "BKE_mesh.h" +#include "BKE_mesh_mapping.h" +#include "BKE_mesh_mirror.h" +#include "BKE_modifier.h" +#include "BKE_multires.h" +#include "BKE_node.h" +#include "BKE_object.h" +#include "BKE_paint.h" +#include "BKE_particle.h" +#include "BKE_pbvh.h" +#include "BKE_pointcache.h" +#include "BKE_report.h" +#include "BKE_scene.h" +#include "BKE_screen.h" +#include "BKE_subdiv_ccg.h" +#include "BKE_subsurf.h" + +#include "DEG_depsgraph.h" + +#include "IMB_colormanagement.h" + +#include "WM_api.h" +#include "WM_message.h" +#include "WM_toolsystem.h" +#include "WM_types.h" + +#include "ED_object.h" +#include "ED_screen.h" +#include "ED_sculpt.h" +#include "ED_view3d.h" + +#include "paint_intern.h" +#include "sculpt_intern.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "bmesh.h" +#include "bmesh_tools.h" + +#include <math.h> +#include <stdlib.h> +#include <string.h> + +/* -------------------------------------------------------------------- */ +/** \name SculptProjectVector + * + * Fast-path for #project_plane_v3_v3v3 + * \{ */ + +typedef struct SculptProjectVector { + float plane[3]; + float len_sq; + float len_sq_inv_neg; + bool is_valid; + +} SculptProjectVector; + +static bool plane_point_side_flip(const float co[3], const float plane[4], const bool flip) +{ + float d = plane_point_side_v3(plane, co); + if (flip) { + d = -d; + } + return d <= 0.0f; +} + +/** + * \param plane: Direction, can be any length. + */ +static void sculpt_project_v3_cache_init(SculptProjectVector *spvc, const float plane[3]) +{ + copy_v3_v3(spvc->plane, plane); + spvc->len_sq = len_squared_v3(spvc->plane); + spvc->is_valid = (spvc->len_sq > FLT_EPSILON); + spvc->len_sq_inv_neg = (spvc->is_valid) ? -1.0f / spvc->len_sq : 0.0f; +} + +/** + * Calculate the projection. + */ +static void sculpt_project_v3(const SculptProjectVector *spvc, const float vec[3], float r_vec[3]) +{ +#if 0 + project_plane_v3_v3v3(r_vec, vec, spvc->plane); +#else + /* inline the projection, cache `-1.0 / dot_v3_v3(v_proj, v_proj)` */ + madd_v3_v3fl(r_vec, spvc->plane, dot_v3v3(vec, spvc->plane) * spvc->len_sq_inv_neg); +#endif +} + +static void calc_sculpt_plane( + Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3]) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + + if (SCULPT_stroke_is_main_symmetry_pass(ss->cache) && + (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache) || + !(brush->flag & BRUSH_ORIGINAL_PLANE) || !(brush->flag & BRUSH_ORIGINAL_NORMAL))) { + switch (brush->sculpt_plane) { + case SCULPT_DISP_DIR_VIEW: + copy_v3_v3(r_area_no, ss->cache->true_view_normal); + break; + + case SCULPT_DISP_DIR_X: + ARRAY_SET_ITEMS(r_area_no, 1.0f, 0.0f, 0.0f); + break; + + case SCULPT_DISP_DIR_Y: + ARRAY_SET_ITEMS(r_area_no, 0.0f, 1.0f, 0.0f); + break; + + case SCULPT_DISP_DIR_Z: + ARRAY_SET_ITEMS(r_area_no, 0.0f, 0.0f, 1.0f); + break; + + case SCULPT_DISP_DIR_AREA: + SCULPT_calc_area_normal_and_center(sd, ob, nodes, totnode, r_area_no, r_area_co); + if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { + project_plane_v3_v3v3(r_area_no, r_area_no, ss->cache->view_normal); + normalize_v3(r_area_no); + } + break; + + default: + break; + } + + /* For flatten center. */ + /* Flatten center has not been calculated yet if we are not using the area normal. */ + if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA) { + SCULPT_calc_area_center(sd, ob, nodes, totnode, r_area_co); + } + + /* For area normal. */ + if ((!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) && + (brush->flag & BRUSH_ORIGINAL_NORMAL)) { + copy_v3_v3(r_area_no, ss->cache->sculpt_normal); + } + else { + copy_v3_v3(ss->cache->sculpt_normal, r_area_no); + } + + /* For flatten center. */ + if ((!SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) && + (brush->flag & BRUSH_ORIGINAL_PLANE)) { + copy_v3_v3(r_area_co, ss->cache->last_center); + } + else { + copy_v3_v3(ss->cache->last_center, r_area_co); + } + } + else { + /* For area normal. */ + copy_v3_v3(r_area_no, ss->cache->sculpt_normal); + + /* For flatten center. */ + copy_v3_v3(r_area_co, ss->cache->last_center); + + /* For area normal. */ + flip_v3(r_area_no, ss->cache->mirror_symmetry_pass); + + /* For flatten center. */ + flip_v3(r_area_co, ss->cache->mirror_symmetry_pass); + + /* For area normal. */ + mul_m4_v3(ss->cache->symm_rot_mat, r_area_no); + + /* For flatten center. */ + mul_m4_v3(ss->cache->symm_rot_mat, r_area_co); + + /* Shift the plane for the current tile. */ + add_v3_v3(r_area_co, ss->cache->plane_offset); + } +} + +static void sculpt_rake_rotate(const SculptSession *ss, + const float sculpt_co[3], + const float v_co[3], + float factor, + float r_delta[3]) +{ + float vec_rot[3]; + +#if 0 + /* lerp */ + sub_v3_v3v3(vec_rot, v_co, sculpt_co); + mul_qt_v3(ss->cache->rake_rotation_symmetry, vec_rot); + add_v3_v3(vec_rot, sculpt_co); + sub_v3_v3v3(r_delta, vec_rot, v_co); + mul_v3_fl(r_delta, factor); +#else + /* slerp */ + float q_interp[4]; + sub_v3_v3v3(vec_rot, v_co, sculpt_co); + + copy_qt_qt(q_interp, ss->cache->rake_rotation_symmetry); + pow_qt_fl_normalized(q_interp, factor); + mul_qt_v3(q_interp, vec_rot); + + add_v3_v3(vec_rot, sculpt_co); + sub_v3_v3v3(r_delta, vec_rot, v_co); +#endif +} + +/** + * Align the grab delta to the brush normal. + * + * \param grab_delta: Typically from `ss->cache->grab_delta_symmetry`. + */ +static void sculpt_project_v3_normal_align(SculptSession *ss, + const float normal_weight, + float grab_delta[3]) +{ + /* Signed to support grabbing in (to make a hole) as well as out. */ + const float len_signed = dot_v3v3(ss->cache->sculpt_normal_symm, grab_delta); + + /* This scale effectively projects the offset so dragging follows the cursor, + * as the normal points towards the view, the scale increases. */ + float len_view_scale; + { + float view_aligned_normal[3]; + project_plane_v3_v3v3( + view_aligned_normal, ss->cache->sculpt_normal_symm, ss->cache->view_normal); + len_view_scale = fabsf(dot_v3v3(view_aligned_normal, ss->cache->sculpt_normal_symm)); + len_view_scale = (len_view_scale > FLT_EPSILON) ? 1.0f / len_view_scale : 1.0f; + } + + mul_v3_fl(grab_delta, 1.0f - normal_weight); + madd_v3_v3fl( + grab_delta, ss->cache->sculpt_normal_symm, (len_signed * normal_weight) * len_view_scale); +} + +/* -------------------------------------------------------------------- */ +/** \name Sculpt Draw Brush + * \{ */ + +static void do_draw_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float *offset = data->offset; + + PBVHVertexIter vd; + float(*proxy)[3]; + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + /* Offset vertex. */ + const float fade = SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + mul_v3_v3fl(proxy[vd.i], offset, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_draw_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + float offset[3]; + const float bstrength = ss->cache->bstrength; + + /* Offset with as much as possible factored in already. */ + float effective_normal[3]; + SCULPT_tilt_effective_normal_get(ss, brush, effective_normal); + mul_v3_v3fl(offset, effective_normal, ss->cache->radius); + mul_v3_v3(offset, ss->cache->scale); + mul_v3_fl(offset, bstrength); + + /* XXX: this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise + * initialize before threads so they can do curve mapping. */ + BKE_curvemapping_init(brush->curve); + + /* Threaded loop over nodes. */ + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .offset = offset, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_draw_brush_task_cb_ex, &settings); +} + +/** \} */ + +static void do_fill_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float *area_no = data->area_no; + const float *area_co = data->area_co; + + PBVHVertexIter vd; + float(*proxy)[3]; + const float bstrength = ss->cache->bstrength; + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + plane_from_point_normal_v3(test.plane_tool, area_co, area_no); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + + if (!SCULPT_plane_point_side(vd.co, test.plane_tool)) { + continue; + } + + float intr[3]; + float val[3]; + closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co); + sub_v3_v3v3(val, intr, vd.co); + + if (!SCULPT_plane_trim(ss->cache, brush, val)) { + continue; + } + + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + mul_v3_v3fl(proxy[vd.i], val, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_fill_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + + const float radius = ss->cache->radius; + + float area_no[3]; + float area_co[3]; + float offset = SCULPT_brush_plane_offset_get(sd, ss); + + float displace; + + float temp[3]; + + SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co); + + SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor); + + displace = radius * offset; + + mul_v3_v3v3(temp, area_no, ss->cache->scale); + mul_v3_fl(temp, displace); + add_v3_v3(area_co, temp); + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .area_no = area_no, + .area_co = area_co, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_fill_brush_task_cb_ex, &settings); +} + +static void do_scrape_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float *area_no = data->area_no; + const float *area_co = data->area_co; + + PBVHVertexIter vd; + float(*proxy)[3]; + const float bstrength = ss->cache->bstrength; + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + plane_from_point_normal_v3(test.plane_tool, area_co, area_no); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + + if (SCULPT_plane_point_side(vd.co, test.plane_tool)) { + continue; + } + + float intr[3]; + float val[3]; + closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co); + sub_v3_v3v3(val, intr, vd.co); + + if (!SCULPT_plane_trim(ss->cache, brush, val)) { + continue; + } + + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + mul_v3_v3fl(proxy[vd.i], val, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + + const float radius = ss->cache->radius; + + float area_no[3]; + float area_co[3]; + float offset = SCULPT_brush_plane_offset_get(sd, ss); + + float displace; + + float temp[3]; + + SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co); + + SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor); + + displace = -radius * offset; + + mul_v3_v3v3(temp, area_no, ss->cache->scale); + mul_v3_fl(temp, displace); + add_v3_v3(area_co, temp); + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .area_no = area_no, + .area_co = area_co, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_scrape_brush_task_cb_ex, &settings); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sculpt Clay Thumb Brush + * \{ */ + +static void do_clay_thumb_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + float(*mat)[4] = data->mat; + const float *area_no_sp = data->area_no_sp; + const float *area_co = data->area_co; + + PBVHVertexIter vd; + float(*proxy)[3]; + const float bstrength = data->clay_strength; + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + float plane_tilt[4]; + float normal_tilt[3]; + float imat[4][4]; + + invert_m4_m4(imat, mat); + rotate_v3_v3v3fl(normal_tilt, area_no_sp, imat[0], DEG2RADF(-ss->cache->clay_thumb_front_angle)); + + /* Plane aligned to the geometry normal (back part of the brush). */ + plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp); + /* Tilted plane (front part of the brush). */ + plane_from_point_normal_v3(plane_tilt, area_co, normal_tilt); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + float local_co[3]; + mul_v3_m4v3(local_co, mat, vd.co); + float intr[3], intr_tilt[3]; + float val[3]; + + closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co); + closest_to_plane_normalized_v3(intr_tilt, plane_tilt, vd.co); + + /* Mix the deformation of the aligned and the tilted plane based on the brush space vertex + * coordinates. */ + /* We can also control the mix with a curve if it produces noticeable artifacts in the center + * of the brush. */ + const float tilt_mix = local_co[1] > 0.0f ? 0.0f : 1.0f; + interp_v3_v3v3(intr, intr, intr_tilt, tilt_mix); + sub_v3_v3v3(val, intr_tilt, vd.co); + + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + mul_v3_v3fl(proxy[vd.i], val, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +float SCULPT_clay_thumb_get_stabilized_pressure(StrokeCache *cache) +{ + float final_pressure = 0.0f; + for (int i = 0; i < SCULPT_CLAY_STABILIZER_LEN; i++) { + final_pressure += cache->clay_pressure_stabilizer[i]; + } + return final_pressure / SCULPT_CLAY_STABILIZER_LEN; +} + +void SCULPT_do_clay_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + + const float radius = ss->cache->radius; + const float offset = SCULPT_brush_plane_offset_get(sd, ss); + const float displace = radius * (0.25f + offset); + + /* Sampled geometry normal and area center. */ + float area_no_sp[3]; + float area_no[3]; + float area_co[3]; + + float temp[3]; + float mat[4][4]; + float scale[4][4]; + float tmat[4][4]; + + SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no_sp, area_co); + + if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL)) { + SCULPT_calc_area_normal(sd, ob, nodes, totnode, area_no); + } + else { + copy_v3_v3(area_no, area_no_sp); + } + + /* Delay the first daub because grab delta is not setup. */ + if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) { + ss->cache->clay_thumb_front_angle = 0.0f; + return; + } + + /* Simulate the clay accumulation by increasing the plane angle as more samples are added to the + * stroke. */ + if (SCULPT_stroke_is_main_symmetry_pass(ss->cache)) { + ss->cache->clay_thumb_front_angle += 0.8f; + ss->cache->clay_thumb_front_angle = clamp_f(ss->cache->clay_thumb_front_angle, 0.0f, 60.0f); + } + + if (is_zero_v3(ss->cache->grab_delta_symmetry)) { + return; + } + + /* Displace the brush planes. */ + copy_v3_v3(area_co, ss->cache->location); + mul_v3_v3v3(temp, area_no_sp, ss->cache->scale); + mul_v3_fl(temp, displace); + add_v3_v3(area_co, temp); + + /* Initialize brush local-space matrix. */ + cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry); + mat[0][3] = 0.0f; + cross_v3_v3v3(mat[1], area_no, mat[0]); + mat[1][3] = 0.0f; + copy_v3_v3(mat[2], area_no); + mat[2][3] = 0.0f; + copy_v3_v3(mat[3], ss->cache->location); + mat[3][3] = 1.0f; + normalize_m4(mat); + + /* Scale brush local space matrix. */ + scale_m4_fl(scale, ss->cache->radius); + mul_m4_m4m4(tmat, mat, scale); + invert_m4_m4(mat, tmat); + + float clay_strength = ss->cache->bstrength * + SCULPT_clay_thumb_get_stabilized_pressure(ss->cache); + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .area_no_sp = area_no_sp, + .area_co = ss->cache->location, + .mat = mat, + .clay_strength = clay_strength, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_clay_thumb_brush_task_cb_ex, &settings); +} + +/** \} */ + +static void do_flatten_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float *area_no = data->area_no; + const float *area_co = data->area_co; + + PBVHVertexIter vd; + float(*proxy)[3]; + const float bstrength = ss->cache->bstrength; + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + plane_from_point_normal_v3(test.plane_tool, area_co, area_no); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + float intr[3]; + float val[3]; + + closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co); + + sub_v3_v3v3(val, intr, vd.co); + + if (SCULPT_plane_trim(ss->cache, brush, val)) { + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + mul_v3_v3fl(proxy[vd.i], val, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_flatten_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + + const float radius = ss->cache->radius; + + float area_no[3]; + float area_co[3]; + + float offset = SCULPT_brush_plane_offset_get(sd, ss); + float displace; + float temp[3]; + + SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co); + + SCULPT_tilt_apply_to_normal(area_no, ss->cache, brush->tilt_strength_factor); + + displace = radius * offset; + + mul_v3_v3v3(temp, area_no, ss->cache->scale); + mul_v3_fl(temp, displace); + add_v3_v3(area_co, temp); + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .area_no = area_no, + .area_co = area_co, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_flatten_brush_task_cb_ex, &settings); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sculpt Clay Brush + * \{ */ + +typedef struct ClaySampleData { + float plane_dist[2]; +} ClaySampleData; + +static void calc_clay_surface_task_cb(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + ClaySampleData *csd = tls->userdata_chunk; + const float *area_no = data->area_no; + const float *area_co = data->area_co; + float plane[4]; + + PBVHVertexIter vd; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, brush->falloff_shape); + + /* Apply the brush normal radius to the test before sampling. */ + float test_radius = sqrtf(test.radius_squared); + test_radius *= brush->normal_radius_factor; + test.radius_squared = test_radius * test_radius; + plane_from_point_normal_v3(plane, area_co, area_no); + + if (is_zero_v4(plane)) { + return; + } + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + + float plane_dist = dist_signed_to_plane_v3(vd.co, plane); + float plane_dist_abs = fabsf(plane_dist); + if (plane_dist > 0.0f) { + csd->plane_dist[0] = MIN2(csd->plane_dist[0], plane_dist_abs); + } + else { + csd->plane_dist[1] = MIN2(csd->plane_dist[1], plane_dist_abs); + } + BKE_pbvh_vertex_iter_end; + } +} + +static void calc_clay_surface_reduce(const void *__restrict UNUSED(userdata), + void *__restrict chunk_join, + void *__restrict chunk) +{ + ClaySampleData *join = chunk_join; + ClaySampleData *csd = chunk; + join->plane_dist[0] = MIN2(csd->plane_dist[0], join->plane_dist[0]); + join->plane_dist[1] = MIN2(csd->plane_dist[1], join->plane_dist[1]); +} + +static void do_clay_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float *area_no = data->area_no; + const float *area_co = data->area_co; + + PBVHVertexIter vd; + float(*proxy)[3]; + const float bstrength = fabsf(ss->cache->bstrength); + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + plane_from_point_normal_v3(test.plane_tool, area_co, area_no); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + + float intr[3]; + float val[3]; + closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co); + + sub_v3_v3v3(val, intr, vd.co); + + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + mul_v3_v3fl(proxy[vd.i], val, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_clay_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + + const float radius = fabsf(ss->cache->radius); + const float initial_radius = fabsf(ss->cache->initial_radius); + bool flip = ss->cache->bstrength < 0.0f; + + float offset = SCULPT_brush_plane_offset_get(sd, ss); + float displace; + + float area_no[3]; + float area_co[3]; + float temp[3]; + + SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no, area_co); + + SculptThreadedTaskData sample_data = { + .sd = NULL, + .ob = ob, + .brush = brush, + .nodes = nodes, + .totnode = totnode, + .area_no = area_no, + .area_co = ss->cache->location, + }; + + ClaySampleData csd = {{0}}; + + TaskParallelSettings sample_settings; + BKE_pbvh_parallel_range_settings(&sample_settings, true, totnode); + sample_settings.func_reduce = calc_clay_surface_reduce; + sample_settings.userdata_chunk = &csd; + sample_settings.userdata_chunk_size = sizeof(ClaySampleData); + + BLI_task_parallel_range(0, totnode, &sample_data, calc_clay_surface_task_cb, &sample_settings); + + float d_offset = (csd.plane_dist[0] + csd.plane_dist[1]); + d_offset = min_ff(radius, d_offset); + d_offset = d_offset / radius; + d_offset = 1.0f - d_offset; + displace = fabsf(initial_radius * (0.25f + offset + (d_offset * 0.15f))); + if (flip) { + displace = -displace; + } + + mul_v3_v3v3(temp, area_no, ss->cache->scale); + mul_v3_fl(temp, displace); + copy_v3_v3(area_co, ss->cache->location); + add_v3_v3(area_co, temp); + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .area_no = area_no, + .area_co = area_co, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_clay_brush_task_cb_ex, &settings); +} + +static void do_clay_strips_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + float(*mat)[4] = data->mat; + const float *area_no_sp = data->area_no_sp; + const float *area_co = data->area_co; + + PBVHVertexIter vd; + SculptBrushTest test; + float(*proxy)[3]; + const bool flip = (ss->cache->bstrength < 0.0f); + const float bstrength = flip ? -ss->cache->bstrength : ss->cache->bstrength; + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SCULPT_brush_test_init(ss, &test); + plane_from_point_normal_v3(test.plane_tool, area_co, area_no_sp); + const int thread_id = BLI_task_parallel_thread_id(tls); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!SCULPT_brush_test_cube(&test, vd.co, mat, brush->tip_roundness)) { + continue; + } + + if (!plane_point_side_flip(vd.co, test.plane_tool, flip)) { + continue; + } + + float intr[3]; + float val[3]; + closest_to_plane_normalized_v3(intr, test.plane_tool, vd.co); + sub_v3_v3v3(val, intr, vd.co); + + if (!SCULPT_plane_trim(ss->cache, brush, val)) { + continue; + } + /* The normal from the vertices is ignored, it causes glitch with planes, see: T44390. */ + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + ss->cache->radius * test.dist, + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + mul_v3_v3fl(proxy[vd.i], val, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_clay_strips_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + + const bool flip = (ss->cache->bstrength < 0.0f); + const float radius = flip ? -ss->cache->radius : ss->cache->radius; + const float offset = SCULPT_brush_plane_offset_get(sd, ss); + const float displace = radius * (0.18f + offset); + + /* The sculpt-plane normal (whatever its set to). */ + float area_no_sp[3]; + + /* Geometry normal */ + float area_no[3]; + float area_co[3]; + + float temp[3]; + float mat[4][4]; + float scale[4][4]; + float tmat[4][4]; + + SCULPT_calc_brush_plane(sd, ob, nodes, totnode, area_no_sp, area_co); + SCULPT_tilt_apply_to_normal(area_no_sp, ss->cache, brush->tilt_strength_factor); + + if (brush->sculpt_plane != SCULPT_DISP_DIR_AREA || (brush->flag & BRUSH_ORIGINAL_NORMAL)) { + SCULPT_calc_area_normal(sd, ob, nodes, totnode, area_no); + } + else { + copy_v3_v3(area_no, area_no_sp); + } + + /* Delay the first daub because grab delta is not setup. */ + if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) { + return; + } + + if (is_zero_v3(ss->cache->grab_delta_symmetry)) { + return; + } + + mul_v3_v3v3(temp, area_no_sp, ss->cache->scale); + mul_v3_fl(temp, displace); + add_v3_v3(area_co, temp); + + /* Clay Strips uses a cube test with falloff in the XY axis (not in Z) and a plane to deform the + * vertices. When in Add mode, vertices that are below the plane and inside the cube are move + * towards the plane. In this situation, there may be cases where a vertex is outside the cube + * but below the plane, so won't be deformed, causing artifacts. In order to prevent these + * artifacts, this displaces the test cube space in relation to the plane in order to + * deform more vertices that may be below it. */ + /* The 0.7 and 1.25 factors are arbitrary and don't have any relation between them, they were set + * by doing multiple tests using the default "Clay Strips" brush preset. */ + float area_co_displaced[3]; + madd_v3_v3v3fl(area_co_displaced, area_co, area_no, -radius * 0.7f); + + /* Initialize brush local-space matrix. */ + cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry); + mat[0][3] = 0.0f; + cross_v3_v3v3(mat[1], area_no, mat[0]); + mat[1][3] = 0.0f; + copy_v3_v3(mat[2], area_no); + mat[2][3] = 0.0f; + copy_v3_v3(mat[3], area_co_displaced); + mat[3][3] = 1.0f; + normalize_m4(mat); + + /* Scale brush local space matrix. */ + scale_m4_fl(scale, ss->cache->radius); + mul_m4_m4m4(tmat, mat, scale); + + /* Deform the local space in Z to scale the test cube. As the test cube does not have falloff in + * Z this does not produce artifacts in the falloff cube and allows to deform extra vertices + * during big deformation while keeping the surface as uniform as possible. */ + mul_v3_fl(tmat[2], 1.25f); + + invert_m4_m4(mat, tmat); + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .area_no_sp = area_no_sp, + .area_co = area_co, + .mat = mat, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_clay_strips_brush_task_cb_ex, &settings); +} + +static void do_snake_hook_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + SculptProjectVector *spvc = data->spvc; + const float *grab_delta = data->grab_delta; + + PBVHVertexIter vd; + float(*proxy)[3]; + const float bstrength = ss->cache->bstrength; + const bool do_rake_rotation = ss->cache->is_rake_rotation_valid; + const bool do_pinch = (brush->crease_pinch_factor != 0.5f); + const float pinch = do_pinch ? (2.0f * (0.5f - brush->crease_pinch_factor) * + (len_v3(grab_delta) / ss->cache->radius)) : + 0.0f; + + const bool do_elastic = brush->snake_hook_deform_type == BRUSH_SNAKE_HOOK_DEFORM_ELASTIC; + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + KelvinletParams params; + BKE_kelvinlet_init_params(¶ms, ss->cache->radius, bstrength, 1.0f, 0.4f); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!do_elastic && !sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + + float fade; + if (do_elastic) { + fade = 1.0f; + } + else { + fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + } + + mul_v3_v3fl(proxy[vd.i], grab_delta, fade); + + /* Negative pinch will inflate, helps maintain volume. */ + if (do_pinch) { + float delta_pinch_init[3], delta_pinch[3]; + + sub_v3_v3v3(delta_pinch, vd.co, test.location); + if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { + project_plane_v3_v3v3(delta_pinch, delta_pinch, ss->cache->true_view_normal); + } + + /* Important to calculate based on the grabbed location + * (intentionally ignore fade here). */ + add_v3_v3(delta_pinch, grab_delta); + + sculpt_project_v3(spvc, delta_pinch, delta_pinch); + + copy_v3_v3(delta_pinch_init, delta_pinch); + + float pinch_fade = pinch * fade; + /* When reducing, scale reduction back by how close to the center we are, + * so we don't pinch into nothingness. */ + if (pinch > 0.0f) { + /* Square to have even less impact for close vertices. */ + pinch_fade *= pow2f(min_ff(1.0f, len_v3(delta_pinch) / ss->cache->radius)); + } + mul_v3_fl(delta_pinch, 1.0f + pinch_fade); + sub_v3_v3v3(delta_pinch, delta_pinch_init, delta_pinch); + add_v3_v3(proxy[vd.i], delta_pinch); + } + + if (do_rake_rotation) { + float delta_rotate[3]; + sculpt_rake_rotate(ss, test.location, vd.co, fade, delta_rotate); + add_v3_v3(proxy[vd.i], delta_rotate); + } + + if (do_elastic) { + float disp[3]; + BKE_kelvinlet_grab_triscale(disp, ¶ms, vd.co, ss->cache->location, proxy[vd.i]); + mul_v3_fl(disp, bstrength * 20.0f); + if (vd.mask) { + mul_v3_fl(disp, 1.0f - *vd.mask); + } + mul_v3_fl(disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index)); + copy_v3_v3(proxy[vd.i], disp); + } + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_snake_hook_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + const float bstrength = ss->cache->bstrength; + float grab_delta[3]; + + SculptProjectVector spvc; + + copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry); + + if (bstrength < 0.0f) { + negate_v3(grab_delta); + } + + if (ss->cache->normal_weight > 0.0f) { + sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta); + } + + /* Optionally pinch while painting. */ + if (brush->crease_pinch_factor != 0.5f) { + sculpt_project_v3_cache_init(&spvc, grab_delta); + } + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .spvc = &spvc, + .grab_delta = grab_delta, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_snake_hook_brush_task_cb_ex, &settings); +} + +static void do_thumb_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float *cono = data->cono; + + PBVHVertexIter vd; + SculptOrigVertData orig_data; + float(*proxy)[3]; + const float bstrength = ss->cache->bstrength; + + SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + SCULPT_orig_vert_data_update(&orig_data, &vd); + + if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { + continue; + } + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + orig_data.co, + sqrtf(test.dist), + orig_data.no, + NULL, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + mul_v3_v3fl(proxy[vd.i], cono, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_thumb_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + float grab_delta[3]; + float tmp[3], cono[3]; + + copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry); + + cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta); + cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm); + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .cono = cono, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_thumb_brush_task_cb_ex, &settings); +} + +static void do_rotate_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float angle = data->angle; + + PBVHVertexIter vd; + SculptOrigVertData orig_data; + float(*proxy)[3]; + const float bstrength = ss->cache->bstrength; + + SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + SCULPT_orig_vert_data_update(&orig_data, &vd); + + if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { + continue; + } + float vec[3], rot[3][3]; + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + orig_data.co, + sqrtf(test.dist), + orig_data.no, + NULL, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + sub_v3_v3v3(vec, orig_data.co, ss->cache->location); + axis_angle_normalized_to_mat3(rot, ss->cache->sculpt_normal_symm, angle * fade); + mul_v3_m3v3(proxy[vd.i], rot, vec); + add_v3_v3(proxy[vd.i], ss->cache->location); + sub_v3_v3(proxy[vd.i], orig_data.co); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_rotate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + + static const int flip[8] = {1, -1, -1, 1, -1, 1, 1, -1}; + const float angle = ss->cache->vertex_rotation * flip[ss->cache->mirror_symmetry_pass]; + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .angle = angle, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_rotate_brush_task_cb_ex, &settings); +} + +static void do_layer_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + Sculpt *sd = data->sd; + const Brush *brush = data->brush; + + const bool use_persistent_base = ss->persistent_base && brush->flag & BRUSH_PERSISTENT; + + PBVHVertexIter vd; + SculptOrigVertData orig_data; + const float bstrength = ss->cache->bstrength; + SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + SCULPT_orig_vert_data_update(&orig_data, &vd); + + if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { + continue; + } + const float fade = SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + const int vi = vd.index; + float *disp_factor; + if (use_persistent_base) { + disp_factor = &ss->persistent_base[vi].disp; + } + else { + disp_factor = &ss->cache->layer_displacement_factor[vi]; + } + + /* When using persistent base, the layer brush (holding Control) invert mode resets the + * height of the layer to 0. This makes possible to clean edges of previously added layers + * on top of the base. */ + /* The main direction of the layers is inverted using the regular brush strength with the + * brush direction property. */ + if (use_persistent_base && ss->cache->invert) { + (*disp_factor) += fabsf(fade * bstrength * (*disp_factor)) * + ((*disp_factor) > 0.0f ? -1.0f : 1.0f); + } + else { + (*disp_factor) += fade * bstrength * (1.05f - fabsf(*disp_factor)); + } + if (vd.mask) { + const float clamp_mask = 1.0f - *vd.mask; + *disp_factor = clamp_f(*disp_factor, -clamp_mask, clamp_mask); + } + else { + *disp_factor = clamp_f(*disp_factor, -1.0f, 1.0f); + } + + float final_co[3]; + float normal[3]; + + if (use_persistent_base) { + SCULPT_vertex_persistent_normal_get(ss, vi, normal); + mul_v3_fl(normal, brush->height); + madd_v3_v3v3fl(final_co, SCULPT_vertex_persistent_co_get(ss, vi), normal, *disp_factor); + } + else { + copy_v3_v3(normal, orig_data.no); + mul_v3_fl(normal, brush->height); + madd_v3_v3v3fl(final_co, orig_data.co, normal, *disp_factor); + } + + float vdisp[3]; + sub_v3_v3v3(vdisp, final_co, vd.co); + mul_v3_fl(vdisp, fabsf(fade)); + add_v3_v3v3(final_co, vd.co, vdisp); + + SCULPT_clip(sd, ss, vd.co, final_co); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_layer_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + + if (ss->cache->layer_displacement_factor == NULL) { + ss->cache->layer_displacement_factor = MEM_callocN(sizeof(float) * SCULPT_vertex_count_get(ss), + "layer displacement factor"); + } + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_layer_brush_task_cb_ex, &settings); +} + +static void do_inflate_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + + PBVHVertexIter vd; + float(*proxy)[3]; + const float bstrength = ss->cache->bstrength; + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + float val[3]; + + if (vd.fno) { + copy_v3_v3(val, vd.fno); + } + else { + copy_v3_v3(val, vd.no); + } + + mul_v3_fl(val, fade * ss->cache->radius); + mul_v3_v3v3(proxy[vd.i], val, ss->cache->scale); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_inflate_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + Brush *brush = BKE_paint_brush(&sd->paint); + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_inflate_brush_task_cb_ex, &settings); +} + +static void do_nudge_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float *cono = data->cono; + + PBVHVertexIter vd; + float(*proxy)[3]; + const float bstrength = ss->cache->bstrength; + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + mul_v3_v3fl(proxy[vd.i], cono, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_nudge_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + float grab_delta[3]; + float tmp[3], cono[3]; + + copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry); + + cross_v3_v3v3(tmp, ss->cache->sculpt_normal_symm, grab_delta); + cross_v3_v3v3(cono, tmp, ss->cache->sculpt_normal_symm); + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .cono = cono, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_nudge_brush_task_cb_ex, &settings); +} + +/* -------------------------------------------------------------------- */ +/** \name Sculpt Crease & Blob Brush + * \{ */ + +/** + * Used for 'SCULPT_TOOL_CREASE' and 'SCULPT_TOOL_BLOB' + */ +static void do_crease_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + SculptProjectVector *spvc = data->spvc; + const float flippedbstrength = data->flippedbstrength; + const float *offset = data->offset; + + PBVHVertexIter vd; + float(*proxy)[3]; + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + /* Offset vertex. */ + const float fade = SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + float val1[3]; + float val2[3]; + + /* First we pinch. */ + sub_v3_v3v3(val1, test.location, vd.co); + if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { + project_plane_v3_v3v3(val1, val1, ss->cache->view_normal); + } + + mul_v3_fl(val1, fade * flippedbstrength); + + sculpt_project_v3(spvc, val1, val1); + + /* Then we draw. */ + mul_v3_v3fl(val2, offset, fade); + + add_v3_v3v3(proxy[vd.i], val1, val2); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_crease_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + const Scene *scene = ss->cache->vc->scene; + Brush *brush = BKE_paint_brush(&sd->paint); + float offset[3]; + float bstrength = ss->cache->bstrength; + float flippedbstrength, crease_correction; + float brush_alpha; + + SculptProjectVector spvc; + + /* Offset with as much as possible factored in already. */ + mul_v3_v3fl(offset, ss->cache->sculpt_normal_symm, ss->cache->radius); + mul_v3_v3(offset, ss->cache->scale); + mul_v3_fl(offset, bstrength); + + /* We divide out the squared alpha and multiply by the squared crease + * to give us the pinch strength. */ + crease_correction = brush->crease_pinch_factor * brush->crease_pinch_factor; + brush_alpha = BKE_brush_alpha_get(scene, brush); + if (brush_alpha > 0.0f) { + crease_correction /= brush_alpha * brush_alpha; + } + + /* We always want crease to pinch or blob to relax even when draw is negative. */ + flippedbstrength = (bstrength < 0.0f) ? -crease_correction * bstrength : + crease_correction * bstrength; + + if (brush->sculpt_tool == SCULPT_TOOL_BLOB) { + flippedbstrength *= -1.0f; + } + + /* Use surface normal for 'spvc', so the vertices are pinched towards a line instead of a single + * point. Without this we get a 'flat' surface surrounding the pinch. */ + sculpt_project_v3_cache_init(&spvc, ss->cache->sculpt_normal_symm); + + /* Threaded loop over nodes. */ + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .spvc = &spvc, + .offset = offset, + .flippedbstrength = flippedbstrength, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_crease_brush_task_cb_ex, &settings); +} + +static void do_pinch_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + float(*stroke_xz)[3] = data->stroke_xz; + + PBVHVertexIter vd; + float(*proxy)[3]; + const float bstrength = ss->cache->bstrength; + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + float x_object_space[3]; + float z_object_space[3]; + copy_v3_v3(x_object_space, stroke_xz[0]); + copy_v3_v3(z_object_space, stroke_xz[1]); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + float disp_center[3]; + float x_disp[3]; + float z_disp[3]; + /* Calculate displacement from the vertex to the brush center. */ + sub_v3_v3v3(disp_center, test.location, vd.co); + + /* Project the displacement into the X vector (aligned to the stroke). */ + mul_v3_v3fl(x_disp, x_object_space, dot_v3v3(disp_center, x_object_space)); + + /* Project the displacement into the Z vector (aligned to the surface normal). */ + mul_v3_v3fl(z_disp, z_object_space, dot_v3v3(disp_center, z_object_space)); + + /* Add the two projected vectors to calculate the final displacement. + * The Y component is removed. */ + add_v3_v3v3(disp_center, x_disp, z_disp); + + if (brush->falloff_shape == PAINT_FALLOFF_SHAPE_TUBE) { + project_plane_v3_v3v3(disp_center, disp_center, ss->cache->view_normal); + } + mul_v3_v3fl(proxy[vd.i], disp_center, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_pinch_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + + float area_no[3]; + float area_co[3]; + + float mat[4][4]; + calc_sculpt_plane(sd, ob, nodes, totnode, area_no, area_co); + + /* delay the first daub because grab delta is not setup */ + if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) { + return; + } + + if (is_zero_v3(ss->cache->grab_delta_symmetry)) { + return; + } + + /* Initialize `mat`. */ + cross_v3_v3v3(mat[0], area_no, ss->cache->grab_delta_symmetry); + mat[0][3] = 0.0f; + cross_v3_v3v3(mat[1], area_no, mat[0]); + mat[1][3] = 0.0f; + copy_v3_v3(mat[2], area_no); + mat[2][3] = 0.0f; + copy_v3_v3(mat[3], ss->cache->location); + mat[3][3] = 1.0f; + normalize_m4(mat); + + float stroke_xz[2][3]; + normalize_v3_v3(stroke_xz[0], mat[0]); + normalize_v3_v3(stroke_xz[1], mat[2]); + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .stroke_xz = stroke_xz, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_pinch_brush_task_cb_ex, &settings); +} + +static void do_grab_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float *grab_delta = data->grab_delta; + + PBVHVertexIter vd; + SculptOrigVertData orig_data; + float(*proxy)[3]; + const float bstrength = ss->cache->bstrength; + + SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + const bool grab_silhouette = brush->flag2 & BRUSH_GRAB_SILHOUETTE; + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + SCULPT_orig_vert_data_update(&orig_data, &vd); + + if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { + continue; + } + float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + orig_data.co, + sqrtf(test.dist), + orig_data.no, + NULL, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + if (grab_silhouette) { + float silhouette_test_dir[3]; + normalize_v3_v3(silhouette_test_dir, grab_delta); + if (dot_v3v3(ss->cache->initial_normal, ss->cache->grab_delta_symmetry) < 0.0f) { + mul_v3_fl(silhouette_test_dir, -1.0f); + } + float vno[3]; + copy_v3_v3(vno, orig_data.no); + fade *= max_ff(dot_v3v3(vno, silhouette_test_dir), 0.0f); + } + + mul_v3_v3fl(proxy[vd.i], grab_delta, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_grab_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + float grab_delta[3]; + + copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry); + + if (ss->cache->normal_weight > 0.0f) { + sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta); + } + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .grab_delta = grab_delta, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_grab_brush_task_cb_ex, &settings); +} + +static void do_elastic_deform_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float *grab_delta = data->grab_delta; + const float *location = ss->cache->location; + + PBVHVertexIter vd; + SculptOrigVertData orig_data; + float(*proxy)[3]; + + const float bstrength = ss->cache->bstrength; + + SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + float dir; + if (ss->cache->mouse[0] > ss->cache->initial_mouse[0]) { + dir = 1.0f; + } + else { + dir = -1.0f; + } + + if (brush->elastic_deform_type == BRUSH_ELASTIC_DEFORM_TWIST) { + int symm = ss->cache->mirror_symmetry_pass; + if (ELEM(symm, 1, 2, 4, 7)) { + dir = -dir; + } + } + + KelvinletParams params; + float force = len_v3(grab_delta) * dir * bstrength; + BKE_kelvinlet_init_params( + ¶ms, ss->cache->radius, force, 1.0f, brush->elastic_deform_volume_preservation); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + SCULPT_orig_vert_data_update(&orig_data, &vd); + float final_disp[3]; + switch (brush->elastic_deform_type) { + case BRUSH_ELASTIC_DEFORM_GRAB: + BKE_kelvinlet_grab(final_disp, ¶ms, orig_data.co, location, grab_delta); + mul_v3_fl(final_disp, bstrength * 20.0f); + break; + case BRUSH_ELASTIC_DEFORM_GRAB_BISCALE: { + BKE_kelvinlet_grab_biscale(final_disp, ¶ms, orig_data.co, location, grab_delta); + mul_v3_fl(final_disp, bstrength * 20.0f); + break; + } + case BRUSH_ELASTIC_DEFORM_GRAB_TRISCALE: { + BKE_kelvinlet_grab_triscale(final_disp, ¶ms, orig_data.co, location, grab_delta); + mul_v3_fl(final_disp, bstrength * 20.0f); + break; + } + case BRUSH_ELASTIC_DEFORM_SCALE: + BKE_kelvinlet_scale( + final_disp, ¶ms, orig_data.co, location, ss->cache->sculpt_normal_symm); + break; + case BRUSH_ELASTIC_DEFORM_TWIST: + BKE_kelvinlet_twist( + final_disp, ¶ms, orig_data.co, location, ss->cache->sculpt_normal_symm); + break; + } + + if (vd.mask) { + mul_v3_fl(final_disp, 1.0f - *vd.mask); + } + + mul_v3_fl(final_disp, SCULPT_automasking_factor_get(ss->cache->automasking, ss, vd.index)); + + copy_v3_v3(proxy[vd.i], final_disp); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_elastic_deform_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + float grab_delta[3]; + + copy_v3_v3(grab_delta, ss->cache->grab_delta_symmetry); + + if (ss->cache->normal_weight > 0.0f) { + sculpt_project_v3_normal_align(ss, ss->cache->normal_weight, grab_delta); + } + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .grab_delta = grab_delta, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_elastic_deform_brush_task_cb_ex, &settings); +} +/** \} */ + +static void do_draw_sharp_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float *offset = data->offset; + + PBVHVertexIter vd; + SculptOrigVertData orig_data; + float(*proxy)[3]; + + SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + SCULPT_orig_vert_data_update(&orig_data, &vd); + if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { + continue; + } + /* Offset vertex. */ + const float fade = SCULPT_brush_strength_factor(ss, + brush, + orig_data.co, + sqrtf(test.dist), + orig_data.no, + NULL, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + mul_v3_v3fl(proxy[vd.i], offset, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_draw_sharp_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + float offset[3]; + const float bstrength = ss->cache->bstrength; + + /* Offset with as much as possible factored in already. */ + float effective_normal[3]; + SCULPT_tilt_effective_normal_get(ss, brush, effective_normal); + mul_v3_v3fl(offset, effective_normal, ss->cache->radius); + mul_v3_v3(offset, ss->cache->scale); + mul_v3_fl(offset, bstrength); + + /* XXX: this shouldn't be necessary, but sculpting crashes in blender2.8 otherwise + * initialize before threads so they can do curve mapping. */ + BKE_curvemapping_init(brush->curve); + + /* Threaded loop over nodes. */ + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .offset = offset, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_draw_sharp_brush_task_cb_ex, &settings); +} + +/* -------------------------------------------------------------------- */ +/** \name Sculpt Topology Brush + * \{ */ + +static void do_topology_slide_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + + PBVHVertexIter vd; + SculptOrigVertData orig_data; + float(*proxy)[3]; + + SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); + + proxy = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + SCULPT_orig_vert_data_update(&orig_data, &vd); + if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { + continue; + } + const float fade = SCULPT_brush_strength_factor(ss, + brush, + orig_data.co, + sqrtf(test.dist), + orig_data.no, + NULL, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + float current_disp[3]; + float current_disp_norm[3]; + float final_disp[3] = {0.0f, 0.0f, 0.0f}; + + switch (brush->slide_deform_type) { + case BRUSH_SLIDE_DEFORM_DRAG: + sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location); + break; + case BRUSH_SLIDE_DEFORM_PINCH: + sub_v3_v3v3(current_disp, ss->cache->location, vd.co); + break; + case BRUSH_SLIDE_DEFORM_EXPAND: + sub_v3_v3v3(current_disp, vd.co, ss->cache->location); + break; + } + + normalize_v3_v3(current_disp_norm, current_disp); + mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength); + + SculptVertexNeighborIter ni; + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) { + float vertex_disp[3]; + float vertex_disp_norm[3]; + sub_v3_v3v3(vertex_disp, SCULPT_vertex_co_get(ss, ni.index), vd.co); + normalize_v3_v3(vertex_disp_norm, vertex_disp); + if (dot_v3v3(current_disp_norm, vertex_disp_norm) > 0.0f) { + madd_v3_v3fl(final_disp, vertex_disp_norm, dot_v3v3(current_disp, vertex_disp)); + } + } + SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); + + mul_v3_v3fl(proxy[vd.i], final_disp, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_relax_vertex(SculptSession *ss, + PBVHVertexIter *vd, + float factor, + bool filter_boundary_face_sets, + float *r_final_pos) +{ + float smooth_pos[3]; + float final_disp[3]; + float boundary_normal[3]; + int avg_count = 0; + int neighbor_count = 0; + zero_v3(smooth_pos); + zero_v3(boundary_normal); + const bool is_boundary = SCULPT_vertex_is_boundary(ss, vd->index); + + SculptVertexNeighborIter ni; + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd->index, ni) { + neighbor_count++; + if (!filter_boundary_face_sets || + (filter_boundary_face_sets && !SCULPT_vertex_has_unique_face_set(ss, ni.index))) { + + /* When the vertex to relax is boundary, use only connected boundary vertices for the average + * position. */ + if (is_boundary) { + if (!SCULPT_vertex_is_boundary(ss, ni.index)) { + continue; + } + add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index)); + avg_count++; + + /* Calculate a normal for the constraint plane using the edges of the boundary. */ + float to_neighbor[3]; + sub_v3_v3v3(to_neighbor, SCULPT_vertex_co_get(ss, ni.index), vd->co); + normalize_v3(to_neighbor); + add_v3_v3(boundary_normal, to_neighbor); + } + else { + add_v3_v3(smooth_pos, SCULPT_vertex_co_get(ss, ni.index)); + avg_count++; + } + } + } + SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); + + /* Don't modify corner vertices. */ + if (neighbor_count <= 2) { + copy_v3_v3(r_final_pos, vd->co); + return; + } + + if (avg_count > 0) { + mul_v3_fl(smooth_pos, 1.0f / avg_count); + } + else { + copy_v3_v3(r_final_pos, vd->co); + return; + } + + float plane[4]; + float smooth_closest_plane[3]; + float vno[3]; + + if (is_boundary && avg_count == 2) { + normalize_v3_v3(vno, boundary_normal); + } + else { + SCULPT_vertex_normal_get(ss, vd->index, vno); + } + + if (is_zero_v3(vno)) { + copy_v3_v3(r_final_pos, vd->co); + return; + } + + plane_from_point_normal_v3(plane, vd->co, vno); + closest_to_plane_v3(smooth_closest_plane, plane, smooth_pos); + sub_v3_v3v3(final_disp, smooth_closest_plane, vd->co); + + mul_v3_fl(final_disp, factor); + add_v3_v3v3(r_final_pos, vd->co, final_disp); +} + +static void do_topology_relax_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float bstrength = ss->cache->bstrength; + + PBVHVertexIter vd; + SculptOrigVertData orig_data; + + SCULPT_orig_vert_data_init(&orig_data, data->ob, data->nodes[n]); + + BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n]); + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + SCULPT_orig_vert_data_update(&orig_data, &vd); + if (!sculpt_brush_test_sq_fn(&test, orig_data.co)) { + continue; + } + const float fade = SCULPT_brush_strength_factor(ss, + brush, + orig_data.co, + sqrtf(test.dist), + orig_data.no, + NULL, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + SCULPT_relax_vertex(ss, &vd, fade * bstrength, false, vd.co); + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_slide_relax_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + + if (SCULPT_stroke_is_first_brush_step_of_symmetry_pass(ss->cache)) { + return; + } + + BKE_curvemapping_init(brush->curve); + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + if (ss->cache->alt_smooth) { + SCULPT_boundary_info_ensure(ob); + for (int i = 0; i < 4; i++) { + BLI_task_parallel_range(0, totnode, &data, do_topology_relax_task_cb_ex, &settings); + } + } + else { + BLI_task_parallel_range(0, totnode, &data, do_topology_slide_task_cb_ex, &settings); + } +} +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sculpt Multires Displacement Eraser Brush + * \{ */ + +static void do_displacement_eraser_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f); + + float(*proxy)[3] = BKE_pbvh_node_add_proxy(ss->pbvh, data->nodes[n])->co; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + float limit_co[3]; + float disp[3]; + SCULPT_vertex_limit_surface_get(ss, vd.index, limit_co); + sub_v3_v3v3(disp, limit_co, vd.co); + mul_v3_v3fl(proxy[vd.i], disp, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_displacement_eraser_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + Brush *brush = BKE_paint_brush(&sd->paint); + BKE_curvemapping_init(brush->curve); + + /* Threaded loop over nodes. */ + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_displacement_eraser_brush_task_cb_ex, &settings); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sculpt Multires Displacement Smear Brush + * \{ */ + +static void do_displacement_smear_brush_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float bstrength = clamp_f(ss->cache->bstrength, 0.0f, 1.0f); + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + const float fade = bstrength * SCULPT_brush_strength_factor(ss, + brush, + vd.co, + sqrtf(test.dist), + vd.no, + vd.fno, + vd.mask ? *vd.mask : 0.0f, + vd.index, + thread_id); + + float current_disp[3]; + float current_disp_norm[3]; + float interp_limit_surface_disp[3]; + + copy_v3_v3(interp_limit_surface_disp, ss->cache->prev_displacement[vd.index]); + + switch (brush->smear_deform_type) { + case BRUSH_SMEAR_DEFORM_DRAG: + sub_v3_v3v3(current_disp, ss->cache->location, ss->cache->last_location); + break; + case BRUSH_SMEAR_DEFORM_PINCH: + sub_v3_v3v3(current_disp, ss->cache->location, vd.co); + break; + case BRUSH_SMEAR_DEFORM_EXPAND: + sub_v3_v3v3(current_disp, vd.co, ss->cache->location); + break; + } + + normalize_v3_v3(current_disp_norm, current_disp); + mul_v3_v3fl(current_disp, current_disp_norm, ss->cache->bstrength); + + float weights_accum = 1.0f; + + SculptVertexNeighborIter ni; + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, vd.index, ni) { + float vertex_disp[3]; + float vertex_disp_norm[3]; + float neighbor_limit_co[3]; + SCULPT_vertex_limit_surface_get(ss, ni.index, neighbor_limit_co); + sub_v3_v3v3(vertex_disp, + ss->cache->limit_surface_co[ni.index], + ss->cache->limit_surface_co[vd.index]); + const float *neighbor_limit_surface_disp = ss->cache->prev_displacement[ni.index]; + normalize_v3_v3(vertex_disp_norm, vertex_disp); + + if (dot_v3v3(current_disp_norm, vertex_disp_norm) >= 0.0f) { + continue; + } + + const float disp_interp = clamp_f( + -dot_v3v3(current_disp_norm, vertex_disp_norm), 0.0f, 1.0f); + madd_v3_v3fl(interp_limit_surface_disp, neighbor_limit_surface_disp, disp_interp); + weights_accum += disp_interp; + } + SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); + + mul_v3_fl(interp_limit_surface_disp, 1.0f / weights_accum); + + float new_co[3]; + add_v3_v3v3(new_co, ss->cache->limit_surface_co[vd.index], interp_limit_surface_disp); + interp_v3_v3v3(vd.co, vd.co, new_co, fade); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +static void do_displacement_smear_store_prev_disp_task_cb_ex( + void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + sub_v3_v3v3(ss->cache->prev_displacement[vd.index], + SCULPT_vertex_co_get(ss, vd.index), + ss->cache->limit_surface_co[vd.index]); + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_do_displacement_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + Brush *brush = BKE_paint_brush(&sd->paint); + SculptSession *ss = ob->sculpt; + + BKE_curvemapping_init(brush->curve); + + const int totvert = SCULPT_vertex_count_get(ss); + if (!ss->cache->prev_displacement) { + ss->cache->prev_displacement = MEM_malloc_arrayN( + totvert, sizeof(float[3]), "prev displacement"); + ss->cache->limit_surface_co = MEM_malloc_arrayN(totvert, sizeof(float[3]), "limit surface co"); + for (int i = 0; i < totvert; i++) { + SCULPT_vertex_limit_surface_get(ss, i, ss->cache->limit_surface_co[i]); + sub_v3_v3v3(ss->cache->prev_displacement[i], + SCULPT_vertex_co_get(ss, i), + ss->cache->limit_surface_co[i]); + } + } + /* Threaded loop over nodes. */ + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range( + 0, totnode, &data, do_displacement_smear_store_prev_disp_task_cb_ex, &settings); + BLI_task_parallel_range(0, totnode, &data, do_displacement_smear_brush_task_cb_ex, &settings); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sculpt Topology Rake (Shared Utility) + * \{ */ + +static void do_topology_rake_bmesh_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + Sculpt *sd = data->sd; + const Brush *brush = data->brush; + + float direction[3]; + copy_v3_v3(direction, ss->cache->grab_delta_symmetry); + + float tmp[3]; + mul_v3_v3fl( + tmp, ss->cache->sculpt_normal_symm, dot_v3v3(ss->cache->sculpt_normal_symm, direction)); + sub_v3_v3(direction, tmp); + normalize_v3(direction); + + /* Cancel if there's no grab data. */ + if (is_zero_v3(direction)) { + return; + } + + const float bstrength = clamp_f(data->strength, 0.0f, 1.0f); + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + const float fade = + bstrength * + SCULPT_brush_strength_factor( + ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, *vd.mask, vd.index, thread_id) * + ss->cache->pressure; + + float avg[3], val[3]; + + SCULPT_bmesh_four_neighbor_average(avg, direction, vd.bm_vert); + + sub_v3_v3v3(val, avg, vd.co); + + madd_v3_v3v3fl(val, vd.co, val, fade); + + SCULPT_clip(sd, ss, vd.co, val); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; +} + +void SCULPT_bmesh_topology_rake( + Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, float bstrength) +{ + Brush *brush = BKE_paint_brush(&sd->paint); + const float strength = clamp_f(bstrength, 0.0f, 1.0f); + + /* Interactions increase both strength and quality. */ + const int iterations = 3; + + int iteration; + const int count = iterations * strength + 1; + const float factor = iterations * strength / count; + + for (iteration = 0; iteration <= count; iteration++) { + + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + .strength = factor, + }; + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + + BLI_task_parallel_range(0, totnode, &data, do_topology_rake_bmesh_task_cb_ex, &settings); + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sculpt Mask Brush + * \{ */ + +static void do_mask_brush_draw_task_cb_ex(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict tls) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + const Brush *brush = data->brush; + const float bstrength = ss->cache->bstrength; + + PBVHVertexIter vd; + + SculptBrushTest test; + SculptBrushTestFn sculpt_brush_test_sq_fn = SCULPT_brush_test_init_with_falloff_shape( + ss, &test, data->brush->falloff_shape); + const int thread_id = BLI_task_parallel_thread_id(tls); + + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + if (!sculpt_brush_test_sq_fn(&test, vd.co)) { + continue; + } + + const float fade = SCULPT_brush_strength_factor( + ss, brush, vd.co, sqrtf(test.dist), vd.no, vd.fno, 0.0f, vd.index, thread_id); + + if (bstrength > 0.0f) { + (*vd.mask) += fade * bstrength * (1.0f - *vd.mask); + } + else { + (*vd.mask) += fade * bstrength * (*vd.mask); + } + *vd.mask = clamp_f(*vd.mask, 0.0f, 1.0f); + + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + BKE_pbvh_vertex_iter_end; + } +} + +void SCULPT_do_mask_brush_draw(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + Brush *brush = BKE_paint_brush(&sd->paint); + + /* Threaded loop over nodes. */ + SculptThreadedTaskData data = { + .sd = sd, + .ob = ob, + .brush = brush, + .nodes = nodes, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_mask_brush_draw_task_cb_ex, &settings); +} + +void SCULPT_do_mask_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) +{ + SculptSession *ss = ob->sculpt; + Brush *brush = BKE_paint_brush(&sd->paint); + + switch ((BrushMaskTool)brush->mask_tool) { + case BRUSH_MASK_DRAW: + SCULPT_do_mask_brush_draw(sd, ob, nodes, totnode); + break; + case BRUSH_MASK_SMOOTH: + SCULPT_smooth(sd, ob, nodes, totnode, ss->cache->bstrength, true); + break; + } +} + +/** \} */ diff --git a/source/blender/editors/sculpt_paint/sculpt_cloth.c b/source/blender/editors/sculpt_paint/sculpt_cloth.c index dcfd7f7bcdc..3ac57d73d37 100644 --- a/source/blender/editors/sculpt_paint/sculpt_cloth.c +++ b/source/blender/editors/sculpt_paint/sculpt_cloth.c @@ -560,13 +560,6 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata, thread_id); float brush_disp[3]; - float normal[3]; - if (vd.no) { - normal_short_to_float_v3(normal, vd.no); - } - else { - copy_v3_v3(normal, vd.fno); - } switch (brush->cloth_deform_type) { case BRUSH_CLOTH_DEFORM_DRAG: @@ -621,7 +614,7 @@ static void do_cloth_brush_apply_forces_task_cb_ex(void *__restrict userdata, mul_v3_v3fl(force, disp_center, fade); } break; case BRUSH_CLOTH_DEFORM_INFLATE: - mul_v3_v3fl(force, normal, fade); + mul_v3_v3fl(force, vd.no ? vd.no : vd.fno, fade); break; case BRUSH_CLOTH_DEFORM_EXPAND: cloth_sim->length_constraint_tweak[vd.index] += fade * 0.1f; diff --git a/source/blender/editors/sculpt_paint/sculpt_detail.c b/source/blender/editors/sculpt_paint/sculpt_detail.c index 9082408b8dd..f00b24d690a 100644 --- a/source/blender/editors/sculpt_paint/sculpt_detail.c +++ b/source/blender/editors/sculpt_paint/sculpt_detail.c @@ -248,8 +248,10 @@ static int sample_detail(bContext *C, int mx, int my, int mode) { /* Find 3D view to pick from. */ bScreen *screen = CTX_wm_screen(C); - ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, mx, my); - ARegion *region = (area) ? BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, mx, my) : NULL; + ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_VIEW3D, (const int[2]){mx, my}); + ARegion *region = (area) ? + BKE_area_find_region_xy(area, RGN_TYPE_WINDOW, (const int[2]){mx, my}) : + NULL; if (region == NULL) { return OPERATOR_CANCELLED; } diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c index 10f141e2311..cf45e25142b 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mask.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mask.c @@ -334,14 +334,7 @@ static float neighbor_dirty_mask(SculptSession *ss, PBVHVertexIter *vd) if (total > 0) { mul_v3_fl(avg, 1.0f / total); - float normal[3]; - if (vd->no) { - normal_short_to_float_v3(normal, vd->no); - } - else { - copy_v3_v3(normal, vd->fno); - } - float dot = dot_v3v3(avg, normal); + float dot = dot_v3v3(avg, vd->no ? vd->no : vd->fno); float angle = max_ff(saacosf(dot), 0.0f); return angle; } diff --git a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c index ff1a8935ba0..2d8bdc4e4ac 100644 --- a/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c +++ b/source/blender/editors/sculpt_paint/sculpt_filter_mesh.c @@ -303,7 +303,7 @@ static void mesh_filter_task_cb(void *__restrict userdata, PBVHVertexIter vd; BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); - float orig_co[3], val[3], avg[3], normal[3], disp[3], disp2[3], transform[3][3], final_pos[3]; + float orig_co[3], val[3], avg[3], disp[3], disp2[3], transform[3][3], final_pos[3]; float fade = vd.mask ? *vd.mask : 0.0f; fade = 1.0f - fade; fade *= data->filter_strength; @@ -339,8 +339,7 @@ static void mesh_filter_task_cb(void *__restrict userdata, sub_v3_v3v3(disp, val, orig_co); break; case MESH_FILTER_INFLATE: - normal_short_to_float_v3(normal, orig_data.no); - mul_v3_v3fl(disp, normal, fade); + mul_v3_v3fl(disp, orig_data.no, fade); break; case MESH_FILTER_SCALE: unit_m3(transform); @@ -372,7 +371,8 @@ static void mesh_filter_task_cb(void *__restrict userdata, mid_v3_v3v3(disp, disp, disp2); break; case MESH_FILTER_RANDOM: { - normal_short_to_float_v3(normal, orig_data.no); + float normal[3]; + copy_v3_v3(normal, orig_data.no); /* Index is not unique for multires, so hash by vertex coordinates. */ const uint *hash_co = (const uint *)orig_co; const uint hash = BLI_hash_int_2d(hash_co[0], hash_co[1]) ^ @@ -432,7 +432,6 @@ static void mesh_filter_task_cb(void *__restrict userdata, /* Intensify details. */ if (ss->filter_cache->sharpen_intensify_detail_strength > 0.0f) { float detail_strength[3]; - normal_short_to_float_v3(detail_strength, orig_data.no); copy_v3_v3(detail_strength, ss->filter_cache->detail_directions[vd.index]); madd_v3_v3fl(disp, detail_strength, diff --git a/source/blender/editors/sculpt_paint/sculpt_intern.h b/source/blender/editors/sculpt_paint/sculpt_intern.h index 4dd2a786922..8de9fa3763b 100644 --- a/source/blender/editors/sculpt_paint/sculpt_intern.h +++ b/source/blender/editors/sculpt_paint/sculpt_intern.h @@ -29,13 +29,13 @@ #include "DNA_meshdata_types.h" #include "DNA_vec_types.h" +#include "BKE_paint.h" +#include "BKE_pbvh.h" #include "BLI_bitmap.h" +#include "BLI_compiler_compat.h" #include "BLI_gsqueue.h" #include "BLI_threads.h" -#include "BKE_paint.h" -#include "BKE_pbvh.h" - struct AutomaskingCache; struct KeyBlock; struct Object; @@ -44,18 +44,12 @@ struct bContext; enum ePaintSymmetryFlags; -bool SCULPT_mode_poll(struct bContext *C); -bool SCULPT_mode_poll_view3d(struct bContext *C); -/** - * Checks for a brush, not just sculpt mode. - */ -bool SCULPT_poll(struct bContext *C); -bool SCULPT_poll_view3d(struct bContext *C); - -bool SCULPT_vertex_colors_poll(struct bContext *C); - /* Updates */ +/* -------------------------------------------------------------------- */ +/** \name Sculpt Types + * \{ */ + typedef enum SculptUpdateType { SCULPT_UPDATE_COORDS = 1 << 0, SCULPT_UPDATE_MASK = 1 << 1, @@ -63,86 +57,14 @@ typedef enum SculptUpdateType { SCULPT_UPDATE_COLOR = 1 << 3, } SculptUpdateType; -void SCULPT_flush_update_step(bContext *C, SculptUpdateType update_flags); -void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType update_flags); -/** - * Flush displacement from deformed PBVH to original layer. - */ -void SCULPT_flush_stroke_deform(struct Sculpt *sd, Object *ob, bool is_proxy_used); - -/** - * Should be used after modifying the mask or Face Sets IDs. - */ -void SCULPT_tag_update_overlays(bContext *C); - -/* Stroke */ - typedef struct SculptCursorGeometryInfo { float location[3]; float normal[3]; float active_vertex_co[3]; } SculptCursorGeometryInfo; -/** - * Do a ray-cast in the tree to find the 3d brush location - * (This allows us to ignore the GL depth buffer) - * Returns 0 if the ray doesn't hit the mesh, non-zero otherwise. - */ -bool SCULPT_stroke_get_location(struct bContext *C, float out[3], const float mouse[2]); -/** - * Gets the normal, location and active vertex location of the geometry under the cursor. This also - * updates the active vertex and cursor related data of the SculptSession using the mouse position - */ -bool SCULPT_cursor_geometry_info_update(bContext *C, - SculptCursorGeometryInfo *out, - const float mouse[2], - bool use_sampled_normal); -void SCULPT_geometry_preview_lines_update(bContext *C, struct SculptSession *ss, float radius); - -void SCULPT_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush); -float SCULPT_raycast_init(struct ViewContext *vc, - const float mouse[2], - float ray_start[3], - float ray_end[3], - float ray_normal[3], - bool original); - -/* Symmetry */ -char SCULPT_mesh_symmetry_xyz_get(Object *object); - -/* Sculpt PBVH abstraction API */ - -void SCULPT_vertex_random_access_ensure(struct SculptSession *ss); - -int SCULPT_vertex_count_get(struct SculptSession *ss); -const float *SCULPT_vertex_co_get(struct SculptSession *ss, int index); -void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3]); -float SCULPT_vertex_mask_get(struct SculptSession *ss, int index); -const float *SCULPT_vertex_color_get(SculptSession *ss, int index); - -const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, int index); -void SCULPT_vertex_persistent_normal_get(SculptSession *ss, int index, float no[3]); - -/** - * Coordinates used for manipulating the base mesh when Grab Active Vertex is enabled. - */ -const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, int index); - -/** - * Returns the info of the limit surface when multi-res is available, - * otherwise it returns the current coordinate of the vertex. - */ -void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3]); - -/** - * Returns the pointer to the coordinates that should be edited from a brush tool iterator - * depending on the given deformation target. - */ -float *SCULPT_brush_deform_target_vertex_co_get(SculptSession *ss, - const int deform_target, - PBVHVertexIter *iter); - #define SCULPT_VERTEX_NEIGHBOR_FIXED_CAPACITY 256 + typedef struct SculptVertexNeighborIter { /* Storage */ int *neighbors; @@ -159,531 +81,33 @@ typedef struct SculptVertexNeighborIter { bool is_duplicate; } SculptVertexNeighborIter; -void SCULPT_vertex_neighbors_get(struct SculptSession *ss, - const int index, - const bool include_duplicates, - SculptVertexNeighborIter *iter); - -/* Iterator over neighboring vertices. */ -#define SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN(ss, v_index, neighbor_iterator) \ - SCULPT_vertex_neighbors_get(ss, v_index, false, &neighbor_iterator); \ - for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \ - neighbor_iterator.i++) { \ - neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i]; - -/* Iterate over neighboring and duplicate vertices (for PBVH_GRIDS). Duplicates come - * first since they are nearest for floodfill. */ -#define SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN(ss, v_index, neighbor_iterator) \ - SCULPT_vertex_neighbors_get(ss, v_index, true, &neighbor_iterator); \ - for (neighbor_iterator.i = neighbor_iterator.size - 1; neighbor_iterator.i >= 0; \ - neighbor_iterator.i--) { \ - neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i]; \ - neighbor_iterator.is_duplicate = (neighbor_iterator.i >= \ - neighbor_iterator.size - neighbor_iterator.num_duplicates); - -#define SCULPT_VERTEX_NEIGHBORS_ITER_END(neighbor_iterator) \ - } \ - if (neighbor_iterator.neighbors != neighbor_iterator.neighbors_fixed) { \ - MEM_freeN(neighbor_iterator.neighbors); \ - } \ - ((void)0) - -int SCULPT_active_vertex_get(SculptSession *ss); -const float *SCULPT_active_vertex_co_get(SculptSession *ss); -void SCULPT_active_vertex_normal_get(SculptSession *ss, float normal[3]); - -/* Returns PBVH deformed vertices array if shape keys or deform modifiers are used, otherwise - * returns mesh original vertices array. */ -struct MVert *SCULPT_mesh_deformed_mverts_get(SculptSession *ss); - -/* Fake Neighbors */ - -#define FAKE_NEIGHBOR_NONE -1 - -void SCULPT_fake_neighbors_ensure(struct Sculpt *sd, Object *ob, const float max_dist); -void SCULPT_fake_neighbors_enable(Object *ob); -void SCULPT_fake_neighbors_disable(Object *ob); -void SCULPT_fake_neighbors_free(struct Object *ob); - -/* Vertex Info. */ -void SCULPT_boundary_info_ensure(Object *object); -/* Boundary Info needs to be initialized in order to use this function. */ -bool SCULPT_vertex_is_boundary(const SculptSession *ss, const int index); - -void SCULPT_connected_components_ensure(Object *ob); - -/* Sculpt Visibility API */ - -void SCULPT_vertex_visible_set(SculptSession *ss, int index, bool visible); -bool SCULPT_vertex_visible_get(SculptSession *ss, int index); - -void SCULPT_visibility_sync_all_face_sets_to_vertices(struct Object *ob); -void SCULPT_visibility_sync_all_vertex_to_face_sets(struct SculptSession *ss); - -/* Face Sets API */ - -int SCULPT_active_face_set_get(SculptSession *ss); -int SCULPT_vertex_face_set_get(SculptSession *ss, int index); -void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set); - -bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_set); -bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, int index); - -int SCULPT_face_set_next_available_get(SculptSession *ss); - -void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool visible); -bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, int index); -bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index); - -void SCULPT_face_sets_visibility_invert(SculptSession *ss); -void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible); - -/** - * Returns true when the step belongs to the stroke that is directly performed by the brush and - * not by one of the symmetry passes. - */ -bool SCULPT_stroke_is_main_symmetry_pass(struct StrokeCache *cache); -/** - * Return true only once per stroke on the first symmetry pass, regardless of the symmetry passes - * enabled. - * - * This should be used for functionality that needs to be computed once per stroke of a particular - * tool (allocating memory, updating random seeds...). - */ -bool SCULPT_stroke_is_first_brush_step(struct StrokeCache *cache); -/** - * Returns true on the first brush step of each symmetry pass. - */ -bool SCULPT_stroke_is_first_brush_step_of_symmetry_pass(struct StrokeCache *cache); - /* Sculpt Original Data */ typedef struct { struct BMLog *bm_log; struct SculptUndoNode *unode; float (*coords)[3]; - short (*normals)[3]; + float (*normals)[3]; const float *vmasks; float (*colors)[4]; /* Original coordinate, normal, and mask. */ const float *co; - const short *no; + const float *no; float mask; const float *col; } SculptOrigVertData; -/** - * Initialize a #SculptOrigVertData for accessing original vertex data; - * handles #BMesh, #Mesh, and multi-resolution. - */ -void SCULPT_orig_vert_data_init(SculptOrigVertData *data, Object *ob, PBVHNode *node); -/** - * Update a #SculptOrigVertData for a particular vertex from the PBVH iterator. - */ -void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter *iter); -/** - * Initialize a #SculptOrigVertData for accessing original vertex data; - * handles #BMesh, #Mesh, and multi-resolution. - */ -void SCULPT_orig_vert_data_unode_init(SculptOrigVertData *data, - Object *ob, - struct SculptUndoNode *unode); - -/* Utils. */ -void SCULPT_calc_brush_plane(struct Sculpt *sd, - struct Object *ob, - struct PBVHNode **nodes, - int totnode, - float r_area_no[3], - float r_area_co[3]); - -void SCULPT_calc_area_normal( - Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3]); - -int SCULPT_nearest_vertex_get(struct Sculpt *sd, - struct Object *ob, - const float co[3], - float max_distance, - bool use_original); - -int SCULPT_plane_point_side(const float co[3], const float plane[4]); -int SCULPT_plane_trim(const struct StrokeCache *cache, - const struct Brush *brush, - const float val[3]); -/** - * Handles clipping against a mirror modifier and #SCULPT_LOCK_X/Y/Z axis flags. - */ -void SCULPT_clip(Sculpt *sd, SculptSession *ss, float co[3], const float val[3]); - -float SCULPT_brush_plane_offset_get(Sculpt *sd, SculptSession *ss); - -ePaintSymmetryAreas SCULPT_get_vertex_symm_area(const float co[3]); -bool SCULPT_check_vertex_pivot_symmetry(const float vco[3], const float pco[3], const char symm); -/** - * Checks if a vertex is inside the brush radius from any of its mirrored axis. - */ -bool SCULPT_is_vertex_inside_brush_radius_symm(const float vertex[3], - const float br_co[3], - float radius, - char symm); -bool SCULPT_is_symmetry_iteration_valid(char i, char symm); -void SCULPT_flip_v3_by_symm_area(float v[3], - const ePaintSymmetryFlags symm, - const ePaintSymmetryAreas symmarea, - const float pivot[3]); -void SCULPT_flip_quat_by_symm_area(float quat[4], - const ePaintSymmetryFlags symm, - const ePaintSymmetryAreas symmarea, - const float pivot[3]); - /* Flood Fill. */ typedef struct { GSQueue *queue; BLI_bitmap *visited_vertices; } SculptFloodFill; -void SCULPT_floodfill_init(struct SculptSession *ss, SculptFloodFill *flood); -void SCULPT_floodfill_add_active(struct Sculpt *sd, - struct Object *ob, - struct SculptSession *ss, - SculptFloodFill *flood, - float radius); -void SCULPT_floodfill_add_initial_with_symmetry(struct Sculpt *sd, - struct Object *ob, - struct SculptSession *ss, - SculptFloodFill *flood, - int index, - float radius); -void SCULPT_floodfill_add_initial(SculptFloodFill *flood, int index); -void SCULPT_floodfill_add_and_skip_initial(SculptFloodFill *flood, int index); -void SCULPT_floodfill_execute( - struct SculptSession *ss, - SculptFloodFill *flood, - bool (*func)(SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata), - void *userdata); -void SCULPT_floodfill_free(SculptFloodFill *flood); - -/* Dynamic topology */ - -enum eDynTopoWarnFlag { - DYNTOPO_WARN_VDATA = (1 << 0), - DYNTOPO_WARN_EDATA = (1 << 1), - DYNTOPO_WARN_LDATA = (1 << 2), - DYNTOPO_WARN_MODIFIER = (1 << 3), -}; - -void SCULPT_dynamic_topology_enable_ex(struct Main *bmain, - struct Depsgraph *depsgraph, - Scene *scene, - Object *ob); -void SCULPT_dynamic_topology_disable(bContext *C, struct SculptUndoNode *unode); -void sculpt_dynamic_topology_disable_with_undo(struct Main *bmain, - struct Depsgraph *depsgraph, - Scene *scene, - Object *ob); - -/** - * Returns true if the stroke will use dynamic topology, false - * otherwise. - * - * Factors: some brushes like grab cannot do dynamic topology. - * Others, like smooth, are better without. - * Same goes for alt-key smoothing. - */ -bool SCULPT_stroke_is_dynamic_topology(const SculptSession *ss, const Brush *brush); - -void SCULPT_dynamic_topology_triangulate(struct BMesh *bm); -void SCULPT_dyntopo_node_layers_add(struct SculptSession *ss); - -enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob); - -void SCULPT_pbvh_clear(Object *ob); - -/* Auto-masking. */ -float SCULPT_automasking_factor_get(struct AutomaskingCache *automasking, - SculptSession *ss, - int vert); - -/* Returns the automasking cache depending on the active tool. Used for code that can run both for - * brushes and filter. */ -struct AutomaskingCache *SCULPT_automasking_active_cache_get(SculptSession *ss); - -struct AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object *ob); -void SCULPT_automasking_cache_free(struct AutomaskingCache *automasking); - -bool SCULPT_is_automasking_mode_enabled(const Sculpt *sd, - const Brush *br, - const eAutomasking_flag mode); -bool SCULPT_is_automasking_enabled(const Sculpt *sd, const SculptSession *ss, const Brush *br); - typedef enum eBoundaryAutomaskMode { AUTOMASK_INIT_BOUNDARY_EDGES = 1, AUTOMASK_INIT_BOUNDARY_FACE_SETS = 2, } eBoundaryAutomaskMode; -float *SCULPT_boundary_automasking_init(Object *ob, - eBoundaryAutomaskMode mode, - int propagation_steps, - float *automask_factor); - -/* Geodesic distances. */ - -/** - * Returns an array indexed by vertex index containing the geodesic distance to the closest vertex - * in the initial vertex set. The caller is responsible for freeing the array. - * Geodesic distances will only work when used with PBVH_FACES, for other types of PBVH it will - * fallback to euclidean distances to one of the initial vertices in the set. - */ -float *SCULPT_geodesic_distances_create(struct Object *ob, - struct GSet *initial_vertices, - const float limit_radius); -float *SCULPT_geodesic_from_vertex_and_symm(struct Sculpt *sd, - struct Object *ob, - const int vertex, - const float limit_radius); -float *SCULPT_geodesic_from_vertex(Object *ob, const int vertex, const float limit_radius); - -/* Filters. */ -void SCULPT_filter_cache_init(struct bContext *C, Object *ob, Sculpt *sd, const int undo_type); -void SCULPT_filter_cache_free(SculptSession *ss); - -void SCULPT_mask_filter_smooth_apply( - Sculpt *sd, Object *ob, PBVHNode **nodes, const int totnode, const int smooth_iterations); - -/* Brushes. */ - -/* Cloth Brush. */ - -/** - * Main Brush Function. - */ -void SCULPT_do_cloth_brush(struct Sculpt *sd, - struct Object *ob, - struct PBVHNode **nodes, - int totnode); - -void SCULPT_cloth_simulation_free(struct SculptClothSimulation *cloth_sim); - -/* Public functions. */ - -struct SculptClothSimulation *SCULPT_cloth_brush_simulation_create( - struct SculptSession *ss, - const float cloth_mass, - const float cloth_damping, - const float cloth_softbody_strength, - const bool use_collisions, - const bool needs_deform_coords); -void SCULPT_cloth_brush_simulation_init(struct SculptSession *ss, - struct SculptClothSimulation *cloth_sim); - -void SCULPT_cloth_sim_activate_nodes(struct SculptClothSimulation *cloth_sim, - PBVHNode **nodes, - int totnode); - -void SCULPT_cloth_brush_store_simulation_state(struct SculptSession *ss, - struct SculptClothSimulation *cloth_sim); - -void SCULPT_cloth_brush_do_simulation_step(struct Sculpt *sd, - struct Object *ob, - struct SculptClothSimulation *cloth_sim, - struct PBVHNode **nodes, - int totnode); - -void SCULPT_cloth_brush_ensure_nodes_constraints(struct Sculpt *sd, - struct Object *ob, - struct PBVHNode **nodes, - int totnode, - struct SculptClothSimulation *cloth_sim, - float initial_location[3], - const float radius); - -/** - * Cursor drawing function. - */ -void SCULPT_cloth_simulation_limits_draw(const uint gpuattr, - const struct Brush *brush, - const float location[3], - const float normal[3], - const float rds, - const float line_width, - const float outline_col[3], - const float alpha); -void SCULPT_cloth_plane_falloff_preview_draw(const uint gpuattr, - struct SculptSession *ss, - const float outline_col[3], - float outline_alpha); - -PBVHNode **SCULPT_cloth_brush_affected_nodes_gather(SculptSession *ss, - Brush *brush, - int *r_totnode); - -BLI_INLINE bool SCULPT_is_cloth_deform_brush(const Brush *brush) -{ - return (brush->sculpt_tool == SCULPT_TOOL_CLOTH && ELEM(brush->cloth_deform_type, - BRUSH_CLOTH_DEFORM_GRAB, - BRUSH_CLOTH_DEFORM_SNAKE_HOOK)) || - /* All brushes that are not the cloth brush deform the simulation using softbody - * constraints instead of applying forces. */ - (brush->sculpt_tool != SCULPT_TOOL_CLOTH && - brush->deform_target == BRUSH_DEFORM_TARGET_CLOTH_SIM); -} - -BLI_INLINE bool SCULPT_tool_needs_all_pbvh_nodes(const Brush *brush) -{ - if (brush->sculpt_tool == SCULPT_TOOL_ELASTIC_DEFORM) { - /* Elastic deformations in any brush need all nodes to avoid artifacts as the effect - * of the Kelvinlet is not constrained by the radius. */ - return true; - } - - if (brush->sculpt_tool == SCULPT_TOOL_POSE) { - /* Pose needs all nodes because it applies all symmetry iterations at the same time - * and the IK chain can grow to any area of the model. */ - /* TODO: This can be optimized by filtering the nodes after calculating the chain. */ - return true; - } - - if (brush->sculpt_tool == SCULPT_TOOL_BOUNDARY) { - /* Boundary needs all nodes because it is not possible to know where the boundary - * deformation is going to be propagated before calculating it. */ - /* TODO: after calculating the boundary info in the first iteration, it should be - * possible to get the nodes that have vertices included in any boundary deformation - * and cache them. */ - return true; - } - - if (brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK && - brush->snake_hook_deform_type == BRUSH_SNAKE_HOOK_DEFORM_ELASTIC) { - /* Snake hook in elastic deform type has same requirements as the elastic deform tool. */ - return true; - } - return false; -} - -/* Pose Brush. */ - -/** - * Main Brush Function. - */ -void SCULPT_do_pose_brush(struct Sculpt *sd, - struct Object *ob, - struct PBVHNode **nodes, - int totnode); -/** - * Calculate the pose origin and (Optionally the pose factor) - * that is used when using the pose brush. - * - * \param r_pose_origin: Must be a valid pointer. - * \param r_pose_factor: Optional, when set to NULL it won't be calculated. - */ -void SCULPT_pose_calc_pose_data(struct Sculpt *sd, - struct Object *ob, - struct SculptSession *ss, - float initial_location[3], - float radius, - float pose_offset, - float *r_pose_origin, - float *r_pose_factor); -void SCULPT_pose_brush_init(struct Sculpt *sd, - struct Object *ob, - struct SculptSession *ss, - struct Brush *br); -struct SculptPoseIKChain *SCULPT_pose_ik_chain_init(struct Sculpt *sd, - struct Object *ob, - struct SculptSession *ss, - struct Brush *br, - const float initial_location[3], - const float radius); -void SCULPT_pose_ik_chain_free(struct SculptPoseIKChain *ik_chain); - -/* Boundary Brush. */ - -/** - * Main function to get #SculptBoundary data both for brush deformation and viewport preview. - * Can return NULL if there is no boundary from the given vertex using the given radius. - */ -struct SculptBoundary *SCULPT_boundary_data_init(Object *object, - Brush *brush, - const int initial_vertex, - const float radius); -void SCULPT_boundary_data_free(struct SculptBoundary *boundary); -/* Main Brush Function. */ -void SCULPT_do_boundary_brush(struct Sculpt *sd, - struct Object *ob, - struct PBVHNode **nodes, - int totnode); - -void SCULPT_boundary_edges_preview_draw(const uint gpuattr, - struct SculptSession *ss, - const float outline_col[3], - const float outline_alpha); -void SCULPT_boundary_pivot_line_preview_draw(const uint gpuattr, struct SculptSession *ss); - -/* Multi-plane Scrape Brush. */ -/* Main Brush Function. */ -void SCULPT_do_multiplane_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode); -void SCULPT_multiplane_scrape_preview_draw(const uint gpuattr, - Brush *brush, - SculptSession *ss, - const float outline_col[3], - const float outline_alpha); -/* Draw Face Sets Brush. */ -void SCULPT_do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode); - -/* Paint Brush. */ -void SCULPT_do_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode); - -/* Smear Brush. */ -void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode); - -/* Smooth Brush. */ - -/** - * For bmesh: Average surrounding verts based on an orthogonality measure. - * Naturally converges to a quad-like structure. - */ -void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], struct BMVert *v); - -void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int index); -float SCULPT_neighbor_mask_average(SculptSession *ss, int index); -void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], int index); - -/** - * Mask the mesh boundaries smoothing only the mesh surface without using auto-masking. - */ -void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3], int index); - -void SCULPT_smooth(Sculpt *sd, - Object *ob, - PBVHNode **nodes, - const int totnode, - float bstrength, - const bool smooth_mask); -void SCULPT_do_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode); - -/* Surface Smooth Brush. */ - -void SCULPT_surface_smooth_laplacian_step(SculptSession *ss, - float *disp, - const float co[3], - float (*laplacian_disp)[3], - const int v_index, - const float origco[3], - const float alpha); -void SCULPT_surface_smooth_displace_step(SculptSession *ss, - float *co, - float (*laplacian_disp)[3], - const int v_index, - const float beta, - const float fade); -void SCULPT_do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode); - -/* Slide/Relax */ -void SCULPT_relax_vertex(struct SculptSession *ss, - struct PBVHVertexIter *vd, - float factor, - bool filter_boundary_face_sets, - float *r_final_pos); /* Undo */ @@ -726,7 +150,7 @@ typedef struct SculptUndoNode { float (*co)[3]; float (*orig_co)[3]; - short (*no)[3]; + float (*no)[3]; float (*col)[4]; float *mask; int totvert; @@ -782,7 +206,13 @@ struct SculptRakeData { float follow_co[3]; }; -/* Single struct used by all BLI_task threaded callbacks, let's avoid adding 10's of those... */ +/* +Generic thread data. The size of this struct +has gotten a little out of hand; normally we would +split it up, but it might be better to see if we can't +eliminate it altogether after moving to C++ (where +we'll be able to use lambdas). +*/ typedef struct SculptThreadedTaskData { struct bContext *C; struct Sculpt *sd; @@ -939,70 +369,12 @@ typedef struct { struct DistRayAABB_Precalc *dist_ray_to_aabb_precalc; } SculptSearchCircleData; -void SCULPT_brush_test_init(struct SculptSession *ss, SculptBrushTest *test); -bool SCULPT_brush_test_sphere(SculptBrushTest *test, const float co[3]); -bool SCULPT_brush_test_sphere_sq(SculptBrushTest *test, const float co[3]); -bool SCULPT_brush_test_sphere_fast(const SculptBrushTest *test, const float co[3]); -bool SCULPT_brush_test_cube(SculptBrushTest *test, - const float co[3], - const float local[4][4], - const float roundness); -bool SCULPT_brush_test_circle_sq(SculptBrushTest *test, const float co[3]); -/** - * Test AABB against sphere. - */ -bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v); -/** - * 2D projection (distance to line). - */ -bool SCULPT_search_circle_cb(PBVHNode *node, void *data_v); - -SculptBrushTestFn SCULPT_brush_test_init_with_falloff_shape(SculptSession *ss, - SculptBrushTest *test, - char falloff_shape); -const float *SCULPT_brush_frontface_normal_from_falloff_shape(SculptSession *ss, - char falloff_shape); - -/** - * Return a multiplier for brush strength on a particular vertex. - */ -float SCULPT_brush_strength_factor(struct SculptSession *ss, - const struct Brush *br, - const float point[3], - const float len, - const short vno[3], - const float fno[3], - const float mask, - const int vertex_index, - const int thread_id); - -/** - * Tilts a normal by the x and y tilt values using the view axis. - */ -void SCULPT_tilt_apply_to_normal(float r_normal[3], - struct StrokeCache *cache, - const float tilt_strength); - -/** - * Get effective surface normal with pen tilt and tilt strength applied to it. - */ -void SCULPT_tilt_effective_normal_get(const SculptSession *ss, const Brush *brush, float r_no[3]); - -/** - * Expose 'calc_area_normal' externally (just for vertex paint). - */ -bool SCULPT_pbvh_calc_area_normal(const struct Brush *brush, - Object *ob, - PBVHNode **nodes, - int totnode, - bool use_threading, - float r_area_no[3]); - -/* Cache stroke properties. Used because - * RNA property lookup isn't particularly fast. - * - * For descriptions of these settings, check the operator properties. - */ +/* Sculpt Filters */ +typedef enum SculptFilterOrientation { + SCULPT_FILTER_ORIENTATION_LOCAL = 0, + SCULPT_FILTER_ORIENTATION_WORLD = 1, + SCULPT_FILTER_ORIENTATION_VIEW = 2, +} SculptFilterOrientation; #define SCULPT_CLAY_STABILIZER_LEN 10 @@ -1019,12 +391,74 @@ typedef struct AutomaskingCache { float *factor; } AutomaskingCache; +typedef struct FilterCache { + bool enabled_axis[3]; + bool enabled_force_axis[3]; + int random_seed; + + /* Used for alternating between filter operations in filters that need to apply different ones to + * achieve certain effects. */ + int iteration_count; + + /* Stores the displacement produced by the laplacian step of HC smooth. */ + float (*surface_smooth_laplacian_disp)[3]; + float surface_smooth_shape_preservation; + float surface_smooth_current_vertex; + + /* Sharpen mesh filter. */ + float sharpen_smooth_ratio; + float sharpen_intensify_detail_strength; + int sharpen_curvature_smooth_iterations; + float *sharpen_factor; + float (*detail_directions)[3]; + + /* Filter orientation. */ + SculptFilterOrientation orientation; + float obmat[4][4]; + float obmat_inv[4][4]; + float viewmat[4][4]; + float viewmat_inv[4][4]; + + /* Displacement eraser. */ + float (*limit_surface_co)[3]; + + /* unmasked nodes */ + PBVHNode **nodes; + int totnode; + + /* Cloth filter. */ + SculptClothSimulation *cloth_sim; + float cloth_sim_pinch_point[3]; + + /* mask expand iteration caches */ + int mask_update_current_it; + int mask_update_last_it; + int *mask_update_it; + float *normal_factor; + float *edge_factor; + float *prev_mask; + float mask_expand_initial_co[3]; + + int new_face_set; + int *prev_face_set; + + int active_face_set; + + /* Auto-masking. */ + AutomaskingCache *automasking; +} FilterCache; + +/** + * This structure contains all the temporary data + * needed for individual brush strokes. + */ typedef struct StrokeCache { /* Invariants */ float initial_radius; float scale[3]; int flag; float clip_tolerance[3]; + float clip_mirror_mtx[4][4]; float initial_mouse[2]; /* Variants */ @@ -1181,27 +615,10 @@ typedef struct StrokeCache { } StrokeCache; -/* Sculpt Filters */ -typedef enum SculptFilterOrientation { - SCULPT_FILTER_ORIENTATION_LOCAL = 0, - SCULPT_FILTER_ORIENTATION_WORLD = 1, - SCULPT_FILTER_ORIENTATION_VIEW = 2, -} SculptFilterOrientation; - -/* Defines how transform tools are going to apply its displacement. */ -typedef enum SculptTransformDisplacementMode { - /* Displaces the elements from their original coordinates. */ - SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL = 0, - /* Displaces the elements incrementally from their previous position. */ - SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL = 1, -} SculptTransformDisplacementMode; +/* -------------------------------------------------------------------- */ +/** \name Sculpt Expand + * \{ */ -/* Filter orientation utils. */ -void SCULPT_filter_to_orientation_space(float r_v[3], struct FilterCache *filter_cache); -void SCULPT_filter_to_object_space(float r_v[3], struct FilterCache *filter_cache); -void SCULPT_filter_zero_disabled_axis_components(float r_v[3], struct FilterCache *filter_cache); - -/* Sculpt Expand. */ typedef enum eSculptExpandFalloffType { SCULPT_EXPAND_FALLOFF_GEODESIC, SCULPT_EXPAND_FALLOFF_TOPOLOGY, @@ -1349,83 +766,676 @@ typedef struct ExpandCache { int *original_face_sets; float (*original_colors)[4]; } ExpandCache; +/** \} */ -typedef struct FilterCache { - bool enabled_axis[3]; - bool enabled_force_axis[3]; - int random_seed; +/** \} */ - /* Used for alternating between filter operations in filters that need to apply different ones to - * achieve certain effects. */ - int iteration_count; +/* -------------------------------------------------------------------- */ +/** \name Sculpt Poll Functions + * \{ */ - /* Stores the displacement produced by the laplacian step of HC smooth. */ - float (*surface_smooth_laplacian_disp)[3]; - float surface_smooth_shape_preservation; - float surface_smooth_current_vertex; +bool SCULPT_mode_poll(struct bContext *C); +bool SCULPT_mode_poll_view3d(struct bContext *C); +/** + * Checks for a brush, not just sculpt mode. + */ +bool SCULPT_poll(struct bContext *C); +bool SCULPT_poll_view3d(struct bContext *C); - /* Sharpen mesh filter. */ - float sharpen_smooth_ratio; - float sharpen_intensify_detail_strength; - int sharpen_curvature_smooth_iterations; - float *sharpen_factor; - float (*detail_directions)[3]; +bool SCULPT_vertex_colors_poll(struct bContext *C); - /* Filter orientation. */ - SculptFilterOrientation orientation; - float obmat[4][4]; - float obmat_inv[4][4]; - float viewmat[4][4]; - float viewmat_inv[4][4]; +/** \} */ - /* Displacement eraser. */ - float (*limit_surface_co)[3]; +/* -------------------------------------------------------------------- */ +/** \name Sculpt Update Functions + * \{ */ - /* unmasked nodes */ - PBVHNode **nodes; - int totnode; +void SCULPT_flush_update_step(bContext *C, SculptUpdateType update_flags); +void SCULPT_flush_update_done(const bContext *C, Object *ob, SculptUpdateType update_flags); - /* Cloth filter. */ - SculptClothSimulation *cloth_sim; - float cloth_sim_pinch_point[3]; +void SCULPT_pbvh_clear(Object *ob); - /* mask expand iteration caches */ - int mask_update_current_it; - int mask_update_last_it; - int *mask_update_it; - float *normal_factor; - float *edge_factor; - float *prev_mask; - float mask_expand_initial_co[3]; +/** + * Flush displacement from deformed PBVH to original layer. + */ +void SCULPT_flush_stroke_deform(struct Sculpt *sd, Object *ob, bool is_proxy_used); - int new_face_set; - int *prev_face_set; +/** + * Should be used after modifying the mask or Face Sets IDs. + */ +void SCULPT_tag_update_overlays(bContext *C); +/** \} */ - int active_face_set; +/* -------------------------------------------------------------------- */ +/** \name Stroke Functions + * \{ */ - /* Transform. */ - SculptTransformDisplacementMode transform_displacement_mode; +/* Stroke */ - /* Auto-masking. */ - AutomaskingCache *automasking; -} FilterCache; +/** + * Do a ray-cast in the tree to find the 3d brush location + * (This allows us to ignore the GL depth buffer) + * Returns 0 if the ray doesn't hit the mesh, non-zero otherwise. + */ +bool SCULPT_stroke_get_location(struct bContext *C, float out[3], const float mouse[2]); +/** + * Gets the normal, location and active vertex location of the geometry under the cursor. This also + * updates the active vertex and cursor related data of the SculptSession using the mouse position + */ +bool SCULPT_cursor_geometry_info_update(bContext *C, + SculptCursorGeometryInfo *out, + const float mouse[2], + bool use_sampled_normal); +void SCULPT_geometry_preview_lines_update(bContext *C, struct SculptSession *ss, float radius); + +void SCULPT_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush); +float SCULPT_raycast_init(struct ViewContext *vc, + const float mouse[2], + float ray_start[3], + float ray_end[3], + float ray_normal[3], + bool original); + +/* Symmetry */ +char SCULPT_mesh_symmetry_xyz_get(Object *object); + +/** + * Returns true when the step belongs to the stroke that is directly performed by the brush and + * not by one of the symmetry passes. + */ +bool SCULPT_stroke_is_main_symmetry_pass(struct StrokeCache *cache); +/** + * Return true only once per stroke on the first symmetry pass, regardless of the symmetry passes + * enabled. + * + * This should be used for functionality that needs to be computed once per stroke of a particular + * tool (allocating memory, updating random seeds...). + */ +bool SCULPT_stroke_is_first_brush_step(struct StrokeCache *cache); +/** + * Returns true on the first brush step of each symmetry pass. + */ +bool SCULPT_stroke_is_first_brush_step_of_symmetry_pass(struct StrokeCache *cache); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sculpt mesh accessor API + * \{ */ + +/** Ensure random access; required for PBVH_BMESH */ +void SCULPT_vertex_random_access_ensure(struct SculptSession *ss); + +int SCULPT_vertex_count_get(struct SculptSession *ss); +const float *SCULPT_vertex_co_get(struct SculptSession *ss, int index); + +/** Get the normal for a given sculpt vertex; do not modify the result */ +void SCULPT_vertex_normal_get(SculptSession *ss, int index, float no[3]); + +float SCULPT_vertex_mask_get(struct SculptSession *ss, int index); +const float *SCULPT_vertex_color_get(SculptSession *ss, int index); + +const float *SCULPT_vertex_persistent_co_get(SculptSession *ss, int index); +void SCULPT_vertex_persistent_normal_get(SculptSession *ss, int index, float no[3]); + +/** + * Coordinates used for manipulating the base mesh when Grab Active Vertex is enabled. + */ +const float *SCULPT_vertex_co_for_grab_active_get(SculptSession *ss, int index); + +/** + * Returns the info of the limit surface when multi-res is available, + * otherwise it returns the current coordinate of the vertex. + */ +void SCULPT_vertex_limit_surface_get(SculptSession *ss, int index, float r_co[3]); + +/** + * Returns the pointer to the coordinates that should be edited from a brush tool iterator + * depending on the given deformation target. + */ +float *SCULPT_brush_deform_target_vertex_co_get(SculptSession *ss, + int deform_target, + PBVHVertexIter *iter); + +void SCULPT_vertex_neighbors_get(struct SculptSession *ss, + int index, + bool include_duplicates, + SculptVertexNeighborIter *iter); + +/** Iterator over neighboring vertices. */ +#define SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN(ss, v_index, neighbor_iterator) \ + SCULPT_vertex_neighbors_get(ss, v_index, false, &neighbor_iterator); \ + for (neighbor_iterator.i = 0; neighbor_iterator.i < neighbor_iterator.size; \ + neighbor_iterator.i++) { \ + neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i]; + +/** Iterate over neighboring and duplicate vertices (for PBVH_GRIDS). Duplicates come + * first since they are nearest for floodfill. */ +#define SCULPT_VERTEX_DUPLICATES_AND_NEIGHBORS_ITER_BEGIN(ss, v_index, neighbor_iterator) \ + SCULPT_vertex_neighbors_get(ss, v_index, true, &neighbor_iterator); \ + for (neighbor_iterator.i = neighbor_iterator.size - 1; neighbor_iterator.i >= 0; \ + neighbor_iterator.i--) { \ + neighbor_iterator.index = neighbor_iterator.neighbors[neighbor_iterator.i]; \ + neighbor_iterator.is_duplicate = (neighbor_iterator.i >= \ + neighbor_iterator.size - neighbor_iterator.num_duplicates); + +#define SCULPT_VERTEX_NEIGHBORS_ITER_END(neighbor_iterator) \ + } \ + if (neighbor_iterator.neighbors != neighbor_iterator.neighbors_fixed) { \ + MEM_freeN(neighbor_iterator.neighbors); \ + } \ + ((void)0) + +int SCULPT_active_vertex_get(SculptSession *ss); +const float *SCULPT_active_vertex_co_get(SculptSession *ss); +void SCULPT_active_vertex_normal_get(SculptSession *ss, float normal[3]); + +/* Returns PBVH deformed vertices array if shape keys or deform modifiers are used, otherwise + * returns mesh original vertices array. */ +struct MVert *SCULPT_mesh_deformed_mverts_get(SculptSession *ss); + +/* Fake Neighbors */ + +#define FAKE_NEIGHBOR_NONE -1 + +void SCULPT_fake_neighbors_ensure(struct Sculpt *sd, Object *ob, float max_dist); +void SCULPT_fake_neighbors_enable(Object *ob); +void SCULPT_fake_neighbors_disable(Object *ob); +void SCULPT_fake_neighbors_free(struct Object *ob); + +/* Vertex Info. */ +void SCULPT_boundary_info_ensure(Object *object); +/* Boundary Info needs to be initialized in order to use this function. */ +bool SCULPT_vertex_is_boundary(const SculptSession *ss, int index); + +void SCULPT_connected_components_ensure(Object *ob); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Sculpt Visibility API + * \{ */ + +void SCULPT_vertex_visible_set(SculptSession *ss, int index, bool visible); +bool SCULPT_vertex_visible_get(SculptSession *ss, int index); + +void SCULPT_visibility_sync_all_face_sets_to_vertices(struct Object *ob); +void SCULPT_visibility_sync_all_vertex_to_face_sets(struct SculptSession *ss); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Face Sets API + * \{ */ + +int SCULPT_active_face_set_get(SculptSession *ss); +int SCULPT_vertex_face_set_get(SculptSession *ss, int index); +void SCULPT_vertex_face_set_set(SculptSession *ss, int index, int face_set); + +bool SCULPT_vertex_has_face_set(SculptSession *ss, int index, int face_set); +bool SCULPT_vertex_has_unique_face_set(SculptSession *ss, int index); + +int SCULPT_face_set_next_available_get(SculptSession *ss); + +void SCULPT_face_set_visibility_set(SculptSession *ss, int face_set, bool visible); +bool SCULPT_vertex_all_face_sets_visible_get(const SculptSession *ss, int index); +bool SCULPT_vertex_any_face_set_visible_get(SculptSession *ss, int index); + +void SCULPT_face_sets_visibility_invert(SculptSession *ss); +void SCULPT_face_sets_visibility_all_set(SculptSession *ss, bool visible); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Original Data API + * \{ */ + +/** + * Initialize a #SculptOrigVertData for accessing original vertex data; + * handles #BMesh, #Mesh, and multi-resolution. + */ +void SCULPT_orig_vert_data_init(SculptOrigVertData *data, Object *ob, PBVHNode *node); +/** + * Update a #SculptOrigVertData for a particular vertex from the PBVH iterator. + */ +void SCULPT_orig_vert_data_update(SculptOrigVertData *orig_data, PBVHVertexIter *iter); +/** + * Initialize a #SculptOrigVertData for accessing original vertex data; + * handles #BMesh, #Mesh, and multi-resolution. + */ +void SCULPT_orig_vert_data_unode_init(SculptOrigVertData *data, + Object *ob, + struct SculptUndoNode *unode); +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Brush Utilities. + * \{ */ + +BLI_INLINE bool SCULPT_tool_needs_all_pbvh_nodes(const Brush *brush) +{ + if (brush->sculpt_tool == SCULPT_TOOL_ELASTIC_DEFORM) { + /* Elastic deformations in any brush need all nodes to avoid artifacts as the effect + * of the Kelvinlet is not constrained by the radius. */ + return true; + } + + if (brush->sculpt_tool == SCULPT_TOOL_POSE) { + /* Pose needs all nodes because it applies all symmetry iterations at the same time + * and the IK chain can grow to any area of the model. */ + /* TODO: This can be optimized by filtering the nodes after calculating the chain. */ + return true; + } + + if (brush->sculpt_tool == SCULPT_TOOL_BOUNDARY) { + /* Boundary needs all nodes because it is not possible to know where the boundary + * deformation is going to be propagated before calculating it. */ + /* TODO: after calculating the boundary info in the first iteration, it should be + * possible to get the nodes that have vertices included in any boundary deformation + * and cache them. */ + return true; + } + + if (brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK && + brush->snake_hook_deform_type == BRUSH_SNAKE_HOOK_DEFORM_ELASTIC) { + /* Snake hook in elastic deform type has same requirements as the elastic deform tool. */ + return true; + } + return false; +} + +void SCULPT_calc_brush_plane(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode, + float r_area_no[3], + float r_area_co[3]); + +void SCULPT_calc_area_normal( + Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3]); +/** + * This calculates flatten center and area normal together, + * amortizing the memory bandwidth and loop overhead to calculate both at the same time. + */ +void SCULPT_calc_area_normal_and_center( + Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_no[3], float r_area_co[3]); +void SCULPT_calc_area_center( + Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float r_area_co[3]); + +int SCULPT_nearest_vertex_get(struct Sculpt *sd, + struct Object *ob, + const float co[3], + float max_distance, + bool use_original); + +int SCULPT_plane_point_side(const float co[3], const float plane[4]); +int SCULPT_plane_trim(const struct StrokeCache *cache, + const struct Brush *brush, + const float val[3]); +/** + * Handles clipping against a mirror modifier and #SCULPT_LOCK_X/Y/Z axis flags. + */ +void SCULPT_clip(Sculpt *sd, SculptSession *ss, float co[3], const float val[3]); + +float SCULPT_brush_plane_offset_get(Sculpt *sd, SculptSession *ss); + +ePaintSymmetryAreas SCULPT_get_vertex_symm_area(const float co[3]); +bool SCULPT_check_vertex_pivot_symmetry(const float vco[3], const float pco[3], char symm); +/** + * Checks if a vertex is inside the brush radius from any of its mirrored axis. + */ +bool SCULPT_is_vertex_inside_brush_radius_symm(const float vertex[3], + const float br_co[3], + float radius, + char symm); +bool SCULPT_is_symmetry_iteration_valid(char i, char symm); +void SCULPT_flip_v3_by_symm_area(float v[3], + ePaintSymmetryFlags symm, + ePaintSymmetryAreas symmarea, + const float pivot[3]); +void SCULPT_flip_quat_by_symm_area(float quat[4], + ePaintSymmetryFlags symm, + ePaintSymmetryAreas symmarea, + const float pivot[3]); + +/** + * Initialize a point-in-brush test + */ +void SCULPT_brush_test_init(struct SculptSession *ss, SculptBrushTest *test); + +bool SCULPT_brush_test_sphere(SculptBrushTest *test, const float co[3]); +bool SCULPT_brush_test_sphere_sq(SculptBrushTest *test, const float co[3]); +bool SCULPT_brush_test_sphere_fast(const SculptBrushTest *test, const float co[3]); +bool SCULPT_brush_test_cube(SculptBrushTest *test, + const float co[3], + const float local[4][4], + float roundness); +bool SCULPT_brush_test_circle_sq(SculptBrushTest *test, const float co[3]); +/** + * Test AABB against sphere. + */ +bool SCULPT_search_sphere_cb(PBVHNode *node, void *data_v); +/** + * 2D projection (distance to line). + */ +bool SCULPT_search_circle_cb(PBVHNode *node, void *data_v); + +/** + * Initialize a point-in-brush test with a given falloff shape + * + * \param falloff_shape PAINT_FALLOFF_SHAPE_SPHERE or PAINT_FALLOFF_SHAPE_TUBE + * \return The brush falloff function + */ +SculptBrushTestFn SCULPT_brush_test_init_with_falloff_shape(SculptSession *ss, + SculptBrushTest *test, + char falloff_shape); +const float *SCULPT_brush_frontface_normal_from_falloff_shape(SculptSession *ss, + char falloff_shape); + +/** + * Return a multiplier for brush strength on a particular vertex. + */ +float SCULPT_brush_strength_factor(struct SculptSession *ss, + const struct Brush *br, + const float point[3], + float len, + const float vno[3], + const float fno[3], + float mask, + int vertex_index, + int thread_id); + +/** + * Tilts a normal by the x and y tilt values using the view axis. + */ +void SCULPT_tilt_apply_to_normal(float r_normal[3], + struct StrokeCache *cache, + float tilt_strength); + +/** + * Get effective surface normal with pen tilt and tilt strength applied to it. + */ +void SCULPT_tilt_effective_normal_get(const SculptSession *ss, const Brush *brush, float r_no[3]); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Flood Fill + * \{ */ + +void SCULPT_floodfill_init(struct SculptSession *ss, SculptFloodFill *flood); +void SCULPT_floodfill_add_active(struct Sculpt *sd, + struct Object *ob, + struct SculptSession *ss, + SculptFloodFill *flood, + float radius); +void SCULPT_floodfill_add_initial_with_symmetry(struct Sculpt *sd, + struct Object *ob, + struct SculptSession *ss, + SculptFloodFill *flood, + int index, + float radius); +void SCULPT_floodfill_add_initial(SculptFloodFill *flood, int index); +void SCULPT_floodfill_add_and_skip_initial(SculptFloodFill *flood, int index); +void SCULPT_floodfill_execute( + struct SculptSession *ss, + SculptFloodFill *flood, + bool (*func)(SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata), + void *userdata); +void SCULPT_floodfill_free(SculptFloodFill *flood); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Dynamic topology + * \{ */ + +enum eDynTopoWarnFlag { + DYNTOPO_WARN_VDATA = (1 << 0), + DYNTOPO_WARN_EDATA = (1 << 1), + DYNTOPO_WARN_LDATA = (1 << 2), + DYNTOPO_WARN_MODIFIER = (1 << 3), +}; + +/** Enable dynamic topology; mesh will be triangulated */ +void SCULPT_dynamic_topology_enable_ex(struct Main *bmain, + struct Depsgraph *depsgraph, + Scene *scene, + Object *ob); +void SCULPT_dynamic_topology_disable(bContext *C, struct SculptUndoNode *unode); +void sculpt_dynamic_topology_disable_with_undo(struct Main *bmain, + struct Depsgraph *depsgraph, + Scene *scene, + Object *ob); + +/** + * Returns true if the stroke will use dynamic topology, false + * otherwise. + * + * Factors: some brushes like grab cannot do dynamic topology. + * Others, like smooth, are better without. + * Same goes for alt-key smoothing. + */ +bool SCULPT_stroke_is_dynamic_topology(const SculptSession *ss, const Brush *brush); + +void SCULPT_dynamic_topology_triangulate(struct BMesh *bm); +void SCULPT_dyntopo_node_layers_add(struct SculptSession *ss); + +enum eDynTopoWarnFlag SCULPT_dynamic_topology_check(Scene *scene, Object *ob); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Auto-masking. + * \{ */ + +float SCULPT_automasking_factor_get(struct AutomaskingCache *automasking, + SculptSession *ss, + int vert); + +/* Returns the automasking cache depending on the active tool. Used for code that can run both for + * brushes and filter. */ +struct AutomaskingCache *SCULPT_automasking_active_cache_get(SculptSession *ss); + +struct AutomaskingCache *SCULPT_automasking_cache_init(Sculpt *sd, Brush *brush, Object *ob); +void SCULPT_automasking_cache_free(struct AutomaskingCache *automasking); + +bool SCULPT_is_automasking_mode_enabled(const Sculpt *sd, const Brush *br, eAutomasking_flag mode); +bool SCULPT_is_automasking_enabled(const Sculpt *sd, const SculptSession *ss, const Brush *br); + +float *SCULPT_boundary_automasking_init(Object *ob, + eBoundaryAutomaskMode mode, + int propagation_steps, + float *automask_factor); +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Geodesic distances. + * \{ */ + +/** + * Returns an array indexed by vertex index containing the geodesic distance to the closest vertex + * in the initial vertex set. The caller is responsible for freeing the array. + * Geodesic distances will only work when used with PBVH_FACES, for other types of PBVH it will + * fallback to euclidean distances to one of the initial vertices in the set. + */ +float *SCULPT_geodesic_distances_create(struct Object *ob, + struct GSet *initial_vertices, + float limit_radius); +float *SCULPT_geodesic_from_vertex_and_symm(struct Sculpt *sd, + struct Object *ob, + int vertex, + float limit_radius); +float *SCULPT_geodesic_from_vertex(Object *ob, int vertex, float limit_radius); +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Filter API + * \{ */ + +void SCULPT_filter_cache_init(struct bContext *C, Object *ob, Sculpt *sd, int undo_type); +void SCULPT_filter_cache_free(SculptSession *ss); + +void SCULPT_mask_filter_smooth_apply( + Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, int smooth_iterations); + +/* Filter orientation utils. */ +void SCULPT_filter_to_orientation_space(float r_v[3], struct FilterCache *filter_cache); +void SCULPT_filter_to_object_space(float r_v[3], struct FilterCache *filter_cache); +void SCULPT_filter_zero_disabled_axis_components(float r_v[3], struct FilterCache *filter_cache); + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Cloth Simulation. + * \{ */ + +/* Main cloth brush function */ +void SCULPT_do_cloth_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); + +void SCULPT_cloth_simulation_free(struct SculptClothSimulation *cloth_sim); + +/* Public functions. */ + +struct SculptClothSimulation *SCULPT_cloth_brush_simulation_create(struct SculptSession *ss, + float cloth_mass, + float cloth_damping, + float cloth_softbody_strength, + bool use_collisions, + bool needs_deform_coords); +void SCULPT_cloth_brush_simulation_init(struct SculptSession *ss, + struct SculptClothSimulation *cloth_sim); + +void SCULPT_cloth_sim_activate_nodes(struct SculptClothSimulation *cloth_sim, + PBVHNode **nodes, + int totnode); + +void SCULPT_cloth_brush_store_simulation_state(struct SculptSession *ss, + struct SculptClothSimulation *cloth_sim); + +void SCULPT_cloth_brush_do_simulation_step(struct Sculpt *sd, + struct Object *ob, + struct SculptClothSimulation *cloth_sim, + struct PBVHNode **nodes, + int totnode); + +void SCULPT_cloth_brush_ensure_nodes_constraints(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode, + struct SculptClothSimulation *cloth_sim, + float initial_location[3], + float radius); + +/** + * Cursor drawing function. + */ +void SCULPT_cloth_simulation_limits_draw(uint gpuattr, + const struct Brush *brush, + const float location[3], + const float normal[3], + float rds, + float line_width, + const float outline_col[3], + float alpha); +void SCULPT_cloth_plane_falloff_preview_draw(uint gpuattr, + struct SculptSession *ss, + const float outline_col[3], + float outline_alpha); + +PBVHNode **SCULPT_cloth_brush_affected_nodes_gather(SculptSession *ss, + Brush *brush, + int *r_totnode); + +BLI_INLINE bool SCULPT_is_cloth_deform_brush(const Brush *brush) +{ + return (brush->sculpt_tool == SCULPT_TOOL_CLOTH && ELEM(brush->cloth_deform_type, + BRUSH_CLOTH_DEFORM_GRAB, + BRUSH_CLOTH_DEFORM_SNAKE_HOOK)) || + /* All brushes that are not the cloth brush deform the simulation using softbody + * constraints instead of applying forces. */ + (brush->sculpt_tool != SCULPT_TOOL_CLOTH && + brush->deform_target == BRUSH_DEFORM_TARGET_CLOTH_SIM); +} +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Smoothing API + * \{ */ + +/** + * For bmesh: Average surrounding verts based on an orthogonality measure. + * Naturally converges to a quad-like structure. + */ +void SCULPT_bmesh_four_neighbor_average(float avg[3], float direction[3], struct BMVert *v); + +void SCULPT_neighbor_coords_average(SculptSession *ss, float result[3], int index); +float SCULPT_neighbor_mask_average(SculptSession *ss, int index); +void SCULPT_neighbor_color_average(SculptSession *ss, float result[4], int index); + +/** + * Mask the mesh boundaries smoothing only the mesh surface without using auto-masking. + */ +void SCULPT_neighbor_coords_average_interior(SculptSession *ss, float result[3], int index); + +void SCULPT_smooth( + Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode, float bstrength, bool smooth_mask); +void SCULPT_do_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode); + +/* Surface Smooth Brush. */ + +void SCULPT_surface_smooth_laplacian_step(SculptSession *ss, + float *disp, + const float co[3], + float (*laplacian_disp)[3], + int v_index, + const float origco[3], + float alpha); +void SCULPT_surface_smooth_displace_step( + SculptSession *ss, float *co, float (*laplacian_disp)[3], int v_index, float beta, float fade); +void SCULPT_do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode); + +/* Slide/Relax */ +void SCULPT_relax_vertex(struct SculptSession *ss, + struct PBVHVertexIter *vd, + float factor, + bool filter_boundary_face_sets, + float *r_final_pos); + +/** \} */ + +/** + * Expose 'calc_area_normal' externally (just for vertex paint). + */ +bool SCULPT_pbvh_calc_area_normal(const struct Brush *brush, + Object *ob, + PBVHNode **nodes, + int totnode, + bool use_threading, + float r_area_no[3]); /** * Flip all the edit-data across the axis/axes specified by \a symm. * Used to calculate multiple modifications to the mesh when symmetry is enabled. */ -void SCULPT_cache_calc_brushdata_symm(StrokeCache *cache, - const char symm, - const char axis, - const float angle); +void SCULPT_cache_calc_brushdata_symm(StrokeCache *cache, char symm, char axis, float angle); void SCULPT_cache_free(StrokeCache *cache); +/* -------------------------------------------------------------------- */ +/** \name Sculpt Undo + * \{ */ + SculptUndoNode *SCULPT_undo_push_node(Object *ob, PBVHNode *node, SculptUndoType type); SculptUndoNode *SCULPT_undo_get_node(PBVHNode *node); SculptUndoNode *SCULPT_undo_get_first_node(void); void SCULPT_undo_push_begin(struct Object *ob, const char *name); void SCULPT_undo_push_end(void); -void SCULPT_undo_push_end_ex(const bool use_nested_undo); +void SCULPT_undo_push_end_ex(bool use_nested_undo); + +/** \} */ void SCULPT_vertcos_to_key(Object *ob, KeyBlock *kb, const float (*vertCos)[3]); @@ -1444,12 +1454,17 @@ bool SCULPT_get_redraw_rect(struct ARegion *region, /* Operators. */ -/* Expand. */ +/* -------------------------------------------------------------------- */ +/** \name Expand Operator + * \{ */ void SCULPT_OT_expand(struct wmOperatorType *ot); void sculpt_expand_modal_keymap(struct wmKeyConfig *keyconf); +/** \} */ -/* Gestures. */ +/* -------------------------------------------------------------------- */ +/** \name Gesture Operators + * \{ */ void SCULPT_OT_face_set_lasso_gesture(struct wmOperatorType *ot); void SCULPT_OT_face_set_box_gesture(struct wmOperatorType *ot); @@ -1458,8 +1473,11 @@ void SCULPT_OT_trim_lasso_gesture(struct wmOperatorType *ot); void SCULPT_OT_trim_box_gesture(struct wmOperatorType *ot); void SCULPT_OT_project_line_gesture(struct wmOperatorType *ot); +/** \} */ -/* Face Sets. */ +/* -------------------------------------------------------------------- */ +/** \name Face Set Operators + * \{ */ void SCULPT_OT_face_sets_randomize_colors(struct wmOperatorType *ot); void SCULPT_OT_face_sets_change_visibility(struct wmOperatorType *ot); @@ -1467,9 +1485,18 @@ void SCULPT_OT_face_sets_init(struct wmOperatorType *ot); void SCULPT_OT_face_sets_create(struct wmOperatorType *ot); void SCULPT_OT_face_sets_edit(struct wmOperatorType *ot); -/* Transform. */ +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Transform Operators + * \{ */ void SCULPT_OT_set_pivot_position(struct wmOperatorType *ot); +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Filter Operators + * \{ */ /* Mesh Filter. */ @@ -1483,6 +1510,12 @@ void SCULPT_OT_cloth_filter(struct wmOperatorType *ot); void SCULPT_OT_color_filter(struct wmOperatorType *ot); +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Interactive Mask Operators + * \{ */ + /* Mask filter and Dirty Mask. */ void SCULPT_OT_mask_filter(struct wmOperatorType *ot); @@ -1495,14 +1528,210 @@ void SCULPT_OT_mask_expand(struct wmOperatorType *ot); /* Mask Init. */ void SCULPT_OT_mask_init(struct wmOperatorType *ot); +/** \} */ /* Detail size. */ +/* -------------------------------------------------------------------- */ +/** \name Dyntopo/Retopology Operators + * \{ */ + 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); + +/* sculpt_brush_types.c */ + +/* -------------------------------------------------------------------- */ +/** \name Brushes + * \{ */ + +/* Pose Brush. */ + +/** + * Main Brush Function. + */ +void SCULPT_do_pose_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +/** + * Calculate the pose origin and (Optionally the pose factor) + * that is used when using the pose brush. + * + * \param r_pose_origin: Must be a valid pointer. + * \param r_pose_factor: Optional, when set to NULL it won't be calculated. + */ +void SCULPT_pose_calc_pose_data(struct Sculpt *sd, + struct Object *ob, + struct SculptSession *ss, + float initial_location[3], + float radius, + float pose_offset, + float *r_pose_origin, + float *r_pose_factor); +void SCULPT_pose_brush_init(struct Sculpt *sd, + struct Object *ob, + struct SculptSession *ss, + struct Brush *br); +struct SculptPoseIKChain *SCULPT_pose_ik_chain_init(struct Sculpt *sd, + struct Object *ob, + struct SculptSession *ss, + struct Brush *br, + const float initial_location[3], + float radius); +void SCULPT_pose_ik_chain_free(struct SculptPoseIKChain *ik_chain); + +/* Boundary Brush. */ + +/** + * Main function to get #SculptBoundary data both for brush deformation and viewport preview. + * Can return NULL if there is no boundary from the given vertex using the given radius. + */ +struct SculptBoundary *SCULPT_boundary_data_init(Object *object, + Brush *brush, + int initial_vertex, + float radius); +void SCULPT_boundary_data_free(struct SculptBoundary *boundary); +/* Main Brush Function. */ +void SCULPT_do_boundary_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); + +void SCULPT_boundary_edges_preview_draw(uint gpuattr, + struct SculptSession *ss, + const float outline_col[3], + float outline_alpha); +void SCULPT_boundary_pivot_line_preview_draw(uint gpuattr, struct SculptSession *ss); + +/* Multi-plane Scrape Brush. */ +/* Main Brush Function. */ +void SCULPT_do_multiplane_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode); +void SCULPT_multiplane_scrape_preview_draw(uint gpuattr, + Brush *brush, + SculptSession *ss, + const float outline_col[3], + float outline_alpha); +/* Draw Face Sets Brush. */ +void SCULPT_do_draw_face_sets_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode); + +/* Paint Brush. */ +void SCULPT_do_paint_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode); + +/* Smear Brush. */ +void SCULPT_do_smear_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode); + +float SCULPT_clay_thumb_get_stabilized_pressure(struct StrokeCache *cache); + +void SCULPT_do_draw_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); + +void SCULPT_do_fill_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_scrape_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_clay_thumb_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_flatten_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_clay_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_clay_strips_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_snake_hook_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_thumb_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_rotate_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_layer_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_inflate_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_nudge_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_crease_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_pinch_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_grab_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_elastic_deform_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_draw_sharp_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_slide_relax_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); + +void SCULPT_do_displacement_smear_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_displacement_eraser_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_mask_brush_draw(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +void SCULPT_do_mask_brush(struct Sculpt *sd, + struct Object *ob, + struct PBVHNode **nodes, + int totnode); +/** \} */ + +void SCULPT_bmesh_topology_rake( + struct Sculpt *sd, struct Object *ob, struct PBVHNode **nodes, int totnode, float bstrength); + +/* end sculpt_brush_types.c */ + +/* sculpt_ops.c */ +void SCULPT_OT_brush_stroke(struct wmOperatorType *ot); + +/* end sculpt_ops.c */ diff --git a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c index 05db799cb00..0fec7a9c4bd 100644 --- a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c +++ b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c @@ -92,12 +92,7 @@ static void calc_multiplane_scrape_surface_task_cb(void *__restrict userdata, } float local_co[3]; float normal[3]; - if (vd.no) { - normal_short_to_float_v3(normal, vd.no); - } - else { - copy_v3_v3(normal, vd.fno); - } + copy_v3_v3(normal, vd.no ? vd.no : vd.fno); mul_v3_m4v3(local_co, mat, vd.co); /* Use the brush falloff to weight the sampled normals. */ const float fade = SCULPT_brush_strength_factor(ss, diff --git a/source/blender/editors/sculpt_paint/sculpt_ops.c b/source/blender/editors/sculpt_paint/sculpt_ops.c new file mode 100644 index 00000000000..119d246a770 --- /dev/null +++ b/source/blender/editors/sculpt_paint/sculpt_ops.c @@ -0,0 +1,1141 @@ +/* + * 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) 2006 by Nicholas Bishop + * All rights reserved. + * Implements the Sculpt Mode tools + */ + +/** \file + * \ingroup edsculpt + */ + +#include "MEM_guardedalloc.h" + +#include "BLI_array.h" +#include "BLI_blenlib.h" +#include "BLI_dial_2d.h" +#include "BLI_ghash.h" +#include "BLI_gsqueue.h" +#include "BLI_hash.h" +#include "BLI_link_utils.h" +#include "BLI_linklist.h" +#include "BLI_linklist_stack.h" +#include "BLI_listbase.h" +#include "BLI_math.h" +#include "BLI_math_color_blend.h" +#include "BLI_memarena.h" +#include "BLI_rand.h" +#include "BLI_task.h" +#include "BLI_utildefines.h" +#include "atomic_ops.h" + +#include "BLT_translation.h" + +#include "PIL_time.h" + +#include "DNA_brush_types.h" +#include "DNA_customdata_types.h" +#include "DNA_listBase.h" +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" +#include "DNA_node_types.h" +#include "DNA_object_types.h" +#include "DNA_scene_types.h" + +#include "BKE_attribute.h" +#include "BKE_brush.h" +#include "BKE_ccg.h" +#include "BKE_colortools.h" +#include "BKE_context.h" +#include "BKE_image.h" +#include "BKE_kelvinlet.h" +#include "BKE_key.h" +#include "BKE_lib_id.h" +#include "BKE_main.h" +#include "BKE_mesh.h" +#include "BKE_mesh_fair.h" +#include "BKE_mesh_mapping.h" +#include "BKE_mesh_mirror.h" +#include "BKE_modifier.h" +#include "BKE_multires.h" +#include "BKE_node.h" +#include "BKE_object.h" +#include "BKE_paint.h" +#include "BKE_particle.h" +#include "BKE_pbvh.h" +#include "BKE_pointcache.h" +#include "BKE_report.h" +#include "BKE_scene.h" +#include "BKE_screen.h" +#include "BKE_subdiv_ccg.h" +#include "BKE_subsurf.h" + +#include "DEG_depsgraph.h" +#include "DEG_depsgraph_query.h" + +#include "IMB_colormanagement.h" + +#include "GPU_batch.h" +#include "GPU_batch_presets.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" +#include "WM_types.h" + +#include "ED_object.h" +#include "ED_screen.h" +#include "ED_sculpt.h" +#include "ED_space_api.h" +#include "ED_transform_snap_object_context.h" +#include "ED_view3d.h" + +#include "paint_intern.h" +#include "sculpt_intern.h" + +#include "RNA_access.h" +#include "RNA_define.h" + +#include "UI_interface.h" +#include "UI_resources.h" + +#include "bmesh.h" +#include "bmesh_tools.h" + +#include <math.h> +#include <stdlib.h> +#include <string.h> + +/* Reset the copy of the mesh that is being sculpted on (currently just for the layer brush). */ + +static int sculpt_set_persistent_base_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + Object *ob = CTX_data_active_object(C); + SculptSession *ss = ob->sculpt; + + if (!ss) { + return OPERATOR_FINISHED; + } + SCULPT_vertex_random_access_ensure(ss); + BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false); + + MEM_SAFE_FREE(ss->persistent_base); + + const int totvert = SCULPT_vertex_count_get(ss); + ss->persistent_base = MEM_mallocN(sizeof(SculptPersistentBase) * totvert, + "layer persistent base"); + + for (int i = 0; i < totvert; i++) { + copy_v3_v3(ss->persistent_base[i].co, SCULPT_vertex_co_get(ss, i)); + SCULPT_vertex_normal_get(ss, i, ss->persistent_base[i].no); + ss->persistent_base[i].disp = 0.0f; + } + + return OPERATOR_FINISHED; +} + +static void SCULPT_OT_set_persistent_base(wmOperatorType *ot) +{ + /* Identifiers. */ + ot->name = "Set Persistent Base"; + ot->idname = "SCULPT_OT_set_persistent_base"; + ot->description = "Reset the copy of the mesh that is being sculpted on"; + + /* API callbacks. */ + ot->exec = sculpt_set_persistent_base_exec; + ot->poll = SCULPT_mode_poll; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/************************* SCULPT_OT_optimize *************************/ + +static int sculpt_optimize_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *ob = CTX_data_active_object(C); + + SCULPT_pbvh_clear(ob); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + + return OPERATOR_FINISHED; +} + +/* The BVH gets less optimal more quickly with dynamic topology than + * regular sculpting. There is no doubt more clever stuff we can do to + * optimize it on the fly, but for now this gives the user a nicer way + * to recalculate it than toggling modes. */ +static void SCULPT_OT_optimize(wmOperatorType *ot) +{ + /* Identifiers. */ + ot->name = "Rebuild BVH"; + ot->idname = "SCULPT_OT_optimize"; + ot->description = "Recalculate the sculpt BVH to improve performance"; + + /* API callbacks. */ + ot->exec = sculpt_optimize_exec; + ot->poll = SCULPT_mode_poll; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +/********************* Dynamic topology symmetrize ********************/ + +static bool sculpt_no_multires_poll(bContext *C) +{ + Object *ob = CTX_data_active_object(C); + if (SCULPT_mode_poll(C) && ob->sculpt && ob->sculpt->pbvh) { + return BKE_pbvh_type(ob->sculpt->pbvh) != PBVH_GRIDS; + } + return false; +} + +static int sculpt_symmetrize_exec(bContext *C, wmOperator *op) +{ + Main *bmain = CTX_data_main(C); + Object *ob = CTX_data_active_object(C); + const Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + SculptSession *ss = ob->sculpt; + PBVH *pbvh = ss->pbvh; + const float dist = RNA_float_get(op->ptr, "merge_tolerance"); + + if (!pbvh) { + return OPERATOR_CANCELLED; + } + + switch (BKE_pbvh_type(pbvh)) { + case PBVH_BMESH: + /* Dyntopo Symmetrize. */ + + /* To simplify undo for symmetrize, all BMesh elements are logged + * as deleted, then after symmetrize operation all BMesh elements + * are logged as added (as opposed to attempting to store just the + * parts that symmetrize modifies). */ + SCULPT_undo_push_begin(ob, "Dynamic topology symmetrize"); + SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_SYMMETRIZE); + BM_log_before_all_removed(ss->bm, ss->bm_log); + + BM_mesh_toolflags_set(ss->bm, true); + + /* Symmetrize and re-triangulate. */ + BMO_op_callf(ss->bm, + (BMO_FLAG_DEFAULTS & ~BMO_FLAG_RESPECT_HIDE), + "symmetrize input=%avef direction=%i dist=%f use_shapekey=%b", + sd->symmetrize_direction, + dist, + true); + SCULPT_dynamic_topology_triangulate(ss->bm); + + /* Bisect operator flags edges (keep tags clean for edge queue). */ + BM_mesh_elem_hflag_disable_all(ss->bm, BM_EDGE, BM_ELEM_TAG, false); + + BM_mesh_toolflags_set(ss->bm, false); + + /* Finish undo. */ + BM_log_all_added(ss->bm, ss->bm_log); + SCULPT_undo_push_end(); + + break; + case PBVH_FACES: + /* Mesh Symmetrize. */ + ED_sculpt_undo_geometry_begin(ob, "mesh symmetrize"); + Mesh *mesh = ob->data; + + BKE_mesh_mirror_apply_mirror_on_axis(bmain, mesh, sd->symmetrize_direction, dist); + + ED_sculpt_undo_geometry_end(ob); + BKE_mesh_calc_normals(ob->data); + BKE_mesh_batch_cache_dirty_tag(ob->data, BKE_MESH_BATCH_DIRTY_ALL); + + break; + case PBVH_GRIDS: + return OPERATOR_CANCELLED; + } + + /* Redraw. */ + SCULPT_pbvh_clear(ob); + WM_event_add_notifier(C, NC_OBJECT | ND_DRAW, ob); + + return OPERATOR_FINISHED; +} + +static void SCULPT_OT_symmetrize(wmOperatorType *ot) +{ + /* Identifiers. */ + ot->name = "Symmetrize"; + ot->idname = "SCULPT_OT_symmetrize"; + ot->description = "Symmetrize the topology modifications"; + + /* API callbacks. */ + ot->exec = sculpt_symmetrize_exec; + ot->poll = sculpt_no_multires_poll; + + RNA_def_float(ot->srna, + "merge_tolerance", + 0.001f, + 0.0f, + FLT_MAX, + "Merge Distance", + "Distance within which symmetrical vertices are merged", + 0.0f, + 1.0f); +} + +/**** Toggle operator for turning sculpt mode on or off ****/ + +static void sculpt_init_session(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob) +{ + /* Create persistent sculpt mode data. */ + BKE_sculpt_toolsettings_data_ensure(scene); + + /* Create sculpt mode session data. */ + if (ob->sculpt != NULL) { + BKE_sculptsession_free(ob); + } + ob->sculpt = MEM_callocN(sizeof(SculptSession), "sculpt session"); + ob->sculpt->mode_type = OB_MODE_SCULPT; + + BKE_sculpt_ensure_orig_mesh_data(scene, ob); + + BKE_scene_graph_evaluated_ensure(depsgraph, bmain); + + /* This function expects a fully evaluated depsgraph. */ + BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false); + + /* Here we can detect geometry that was just added to Sculpt Mode as it has the + * SCULPT_FACE_SET_NONE assigned, so we can create a new Face Set for it. */ + /* In sculpt mode all geometry that is assigned to SCULPT_FACE_SET_NONE is considered as not + * initialized, which is used is some operators that modify the mesh topology to perform certain + * actions in the new polys. After these operations are finished, all polys should have a valid + * face set ID assigned (different from SCULPT_FACE_SET_NONE) to manage their visibility + * correctly. */ + /* TODO(pablodp606): Based on this we can improve the UX in future tools for creating new + * objects, like moving the transform pivot position to the new area or masking existing + * geometry. */ + SculptSession *ss = ob->sculpt; + const int new_face_set = SCULPT_face_set_next_available_get(ss); + for (int i = 0; i < ss->totfaces; i++) { + if (ss->face_sets[i] == SCULPT_FACE_SET_NONE) { + ss->face_sets[i] = new_face_set; + } + } +} + +void ED_object_sculptmode_enter_ex(Main *bmain, + Depsgraph *depsgraph, + Scene *scene, + Object *ob, + const bool force_dyntopo, + ReportList *reports) +{ + const int mode_flag = OB_MODE_SCULPT; + Mesh *me = BKE_mesh_from_object(ob); + + /* Enter sculpt mode. */ + ob->mode |= mode_flag; + + sculpt_init_session(bmain, depsgraph, scene, ob); + + if (!(fabsf(ob->scale[0] - ob->scale[1]) < 1e-4f && + fabsf(ob->scale[1] - ob->scale[2]) < 1e-4f)) { + BKE_report( + reports, RPT_WARNING, "Object has non-uniform scale, sculpting may be unpredictable"); + } + else if (is_negative_m4(ob->obmat)) { + BKE_report(reports, RPT_WARNING, "Object has negative scale, sculpting may be unpredictable"); + } + + Paint *paint = BKE_paint_get_active_from_paintmode(scene, PAINT_MODE_SCULPT); + BKE_paint_init(bmain, scene, PAINT_MODE_SCULPT, PAINT_CURSOR_SCULPT); + + paint_cursor_start(paint, SCULPT_mode_poll_view3d); + + /* Check dynamic-topology flag; re-enter dynamic-topology mode when changing modes, + * As long as no data was added that is not supported. */ + if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) { + MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob); + + const char *message_unsupported = NULL; + if (me->totloop != me->totpoly * 3) { + message_unsupported = TIP_("non-triangle face"); + } + else if (mmd != NULL) { + message_unsupported = TIP_("multi-res modifier"); + } + else { + enum eDynTopoWarnFlag flag = SCULPT_dynamic_topology_check(scene, ob); + if (flag == 0) { + /* pass */ + } + else if (flag & DYNTOPO_WARN_VDATA) { + message_unsupported = TIP_("vertex data"); + } + else if (flag & DYNTOPO_WARN_EDATA) { + message_unsupported = TIP_("edge data"); + } + else if (flag & DYNTOPO_WARN_LDATA) { + message_unsupported = TIP_("face data"); + } + else if (flag & DYNTOPO_WARN_MODIFIER) { + message_unsupported = TIP_("constructive modifier"); + } + else { + BLI_assert(0); + } + } + + if ((message_unsupported == NULL) || force_dyntopo) { + /* Needed because we may be entering this mode before the undo system loads. */ + wmWindowManager *wm = bmain->wm.first; + bool has_undo = wm->undo_stack != NULL; + /* Undo push is needed to prevent memory leak. */ + if (has_undo) { + SCULPT_undo_push_begin(ob, "Dynamic topology enable"); + } + SCULPT_dynamic_topology_enable_ex(bmain, depsgraph, scene, ob); + if (has_undo) { + SCULPT_undo_push_node(ob, NULL, SCULPT_UNDO_DYNTOPO_BEGIN); + SCULPT_undo_push_end(); + } + } + else { + BKE_reportf( + reports, RPT_WARNING, "Dynamic Topology found: %s, disabled", message_unsupported); + me->flag &= ~ME_SCULPT_DYNAMIC_TOPOLOGY; + } + } + + /* Flush object mode. */ + DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); +} + +void ED_object_sculptmode_enter(struct bContext *C, Depsgraph *depsgraph, ReportList *reports) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = OBACT(view_layer); + ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, reports); +} + +void ED_object_sculptmode_exit_ex(Main *bmain, Depsgraph *depsgraph, Scene *scene, Object *ob) +{ + const int mode_flag = OB_MODE_SCULPT; + Mesh *me = BKE_mesh_from_object(ob); + + multires_flush_sculpt_updates(ob); + + /* Not needed for now. */ +#if 0 + MultiresModifierData *mmd = BKE_sculpt_multires_active(scene, ob); + const int flush_recalc = ed_object_sculptmode_flush_recalc_flag(scene, ob, mmd); +#endif + + /* Always for now, so leaving sculpt mode always ensures scene is in + * a consistent state. */ + if (true || /* flush_recalc || */ (ob->sculpt && ob->sculpt->bm)) { + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + } + + if (me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) { + /* Dynamic topology must be disabled before exiting sculpt + * mode to ensure the undo stack stays in a consistent + * state. */ + sculpt_dynamic_topology_disable_with_undo(bmain, depsgraph, scene, ob); + + /* Store so we know to re-enable when entering sculpt mode. */ + me->flag |= ME_SCULPT_DYNAMIC_TOPOLOGY; + } + + /* Leave sculpt mode. */ + ob->mode &= ~mode_flag; + + BKE_sculptsession_free(ob); + + paint_cursor_delete_textures(); + + /* Never leave derived meshes behind. */ + BKE_object_free_derived_caches(ob); + + /* Flush object mode. */ + DEG_id_tag_update(&ob->id, ID_RECALC_COPY_ON_WRITE); +} + +void ED_object_sculptmode_exit(bContext *C, Depsgraph *depsgraph) +{ + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = OBACT(view_layer); + ED_object_sculptmode_exit_ex(bmain, depsgraph, scene, ob); +} + +static int sculpt_mode_toggle_exec(bContext *C, wmOperator *op) +{ + struct wmMsgBus *mbus = CTX_wm_message_bus(C); + Main *bmain = CTX_data_main(C); + Depsgraph *depsgraph = CTX_data_depsgraph_on_load(C); + Scene *scene = CTX_data_scene(C); + ToolSettings *ts = scene->toolsettings; + ViewLayer *view_layer = CTX_data_view_layer(C); + Object *ob = OBACT(view_layer); + const int mode_flag = OB_MODE_SCULPT; + const bool is_mode_set = (ob->mode & mode_flag) != 0; + + if (!is_mode_set) { + if (!ED_object_mode_compat_set(C, ob, mode_flag, op->reports)) { + return OPERATOR_CANCELLED; + } + } + + if (is_mode_set) { + ED_object_sculptmode_exit_ex(bmain, depsgraph, scene, ob); + } + else { + if (depsgraph) { + depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + } + ED_object_sculptmode_enter_ex(bmain, depsgraph, scene, ob, false, op->reports); + BKE_paint_toolslots_brush_validate(bmain, &ts->sculpt->paint); + + if (ob->mode & mode_flag) { + Mesh *me = ob->data; + /* Dyntopo adds its own undo step. */ + if ((me->flag & ME_SCULPT_DYNAMIC_TOPOLOGY) == 0) { + /* Without this the memfile undo step is used, + * while it works it causes lag when undoing the first undo step, see T71564. */ + wmWindowManager *wm = CTX_wm_manager(C); + if (wm->op_undo_depth <= 1) { + SCULPT_undo_push_begin(ob, op->type->name); + } + } + } + } + + WM_event_add_notifier(C, NC_SCENE | ND_MODE, scene); + + WM_msg_publish_rna_prop(mbus, &ob->id, ob, Object, mode); + + WM_toolsystem_update_from_context_view3d(C); + + return OPERATOR_FINISHED; +} + +static void SCULPT_OT_sculptmode_toggle(wmOperatorType *ot) +{ + /* Identifiers. */ + ot->name = "Sculpt Mode"; + ot->idname = "SCULPT_OT_sculptmode_toggle"; + ot->description = "Toggle sculpt mode in 3D view"; + + /* API callbacks. */ + ot->exec = sculpt_mode_toggle_exec; + ot->poll = ED_operator_object_active_editable_mesh; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +void SCULPT_geometry_preview_lines_update(bContext *C, SculptSession *ss, float radius) +{ + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + Object *ob = CTX_data_active_object(C); + + ss->preview_vert_index_count = 0; + int totpoints = 0; + + /* This function is called from the cursor drawing code, so the PBVH may not be build yet. */ + if (!ss->pbvh) { + return; + } + + if (!ss->deform_modifiers_active) { + return; + } + + if (BKE_pbvh_type(ss->pbvh) == PBVH_GRIDS) { + return; + } + + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); + + if (!ss->pmap) { + return; + } + + float brush_co[3]; + copy_v3_v3(brush_co, SCULPT_active_vertex_co_get(ss)); + + BLI_bitmap *visited_vertices = BLI_BITMAP_NEW(SCULPT_vertex_count_get(ss), "visited_vertices"); + + /* Assuming an average of 6 edges per vertex in a triangulated mesh. */ + const int max_preview_vertices = SCULPT_vertex_count_get(ss) * 3 * 2; + + if (ss->preview_vert_index_list == NULL) { + ss->preview_vert_index_list = MEM_callocN(max_preview_vertices * sizeof(int), "preview lines"); + } + + GSQueue *not_visited_vertices = BLI_gsqueue_new(sizeof(int)); + int active_v = SCULPT_active_vertex_get(ss); + BLI_gsqueue_push(not_visited_vertices, &active_v); + + while (!BLI_gsqueue_is_empty(not_visited_vertices)) { + int from_v; + BLI_gsqueue_pop(not_visited_vertices, &from_v); + SculptVertexNeighborIter ni; + SCULPT_VERTEX_NEIGHBORS_ITER_BEGIN (ss, from_v, ni) { + if (totpoints + (ni.size * 2) < max_preview_vertices) { + int to_v = ni.index; + ss->preview_vert_index_list[totpoints] = from_v; + totpoints++; + ss->preview_vert_index_list[totpoints] = to_v; + totpoints++; + if (BLI_BITMAP_TEST(visited_vertices, to_v)) { + continue; + } + BLI_BITMAP_ENABLE(visited_vertices, to_v); + const float *co = SCULPT_vertex_co_for_grab_active_get(ss, to_v); + if (len_squared_v3v3(brush_co, co) < radius * radius) { + BLI_gsqueue_push(not_visited_vertices, &to_v); + } + } + } + SCULPT_VERTEX_NEIGHBORS_ITER_END(ni); + } + + BLI_gsqueue_free(not_visited_vertices); + + MEM_freeN(visited_vertices); + + ss->preview_vert_index_count = totpoints; +} + +static int vertex_to_loop_colors_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *ob = CTX_data_active_object(C); + + ID *data; + data = ob->data; + if (data && ID_IS_LINKED(data)) { + return OPERATOR_CANCELLED; + } + + if (ob->type != OB_MESH) { + return OPERATOR_CANCELLED; + } + + Mesh *mesh = ob->data; + + const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_MLOOPCOL); + if (mloopcol_layer_n == -1) { + return OPERATOR_CANCELLED; + } + MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPCOL, mloopcol_layer_n); + + const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR); + if (MPropCol_layer_n == -1) { + return OPERATOR_CANCELLED; + } + MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n); + + MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP); + MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY); + + for (int i = 0; i < mesh->totpoly; i++) { + MPoly *c_poly = &polys[i]; + for (int j = 0; j < c_poly->totloop; j++) { + int loop_index = c_poly->loopstart + j; + MLoop *c_loop = &loops[c_poly->loopstart + j]; + float srgb_color[4]; + linearrgb_to_srgb_v4(srgb_color, vertcols[c_loop->v].color); + loopcols[loop_index].r = (char)(srgb_color[0] * 255); + loopcols[loop_index].g = (char)(srgb_color[1] * 255); + loopcols[loop_index].b = (char)(srgb_color[2] * 255); + loopcols[loop_index].a = (char)(srgb_color[3] * 255); + } + } + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + + return OPERATOR_FINISHED; +} + +static void SCULPT_OT_vertex_to_loop_colors(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Sculpt Vertex Color to Vertex Color"; + ot->description = "Copy the Sculpt Vertex Color to a regular color layer"; + ot->idname = "SCULPT_OT_vertex_to_loop_colors"; + + /* api callbacks */ + ot->poll = SCULPT_vertex_colors_poll; + ot->exec = vertex_to_loop_colors_exec; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +static int loop_to_vertex_colors_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Object *ob = CTX_data_active_object(C); + + ID *data; + data = ob->data; + if (data && ID_IS_LINKED(data)) { + return OPERATOR_CANCELLED; + } + + if (ob->type != OB_MESH) { + return OPERATOR_CANCELLED; + } + + Mesh *mesh = ob->data; + + const int mloopcol_layer_n = CustomData_get_active_layer(&mesh->ldata, CD_MLOOPCOL); + if (mloopcol_layer_n == -1) { + return OPERATOR_CANCELLED; + } + MLoopCol *loopcols = CustomData_get_layer_n(&mesh->ldata, CD_MLOOPCOL, mloopcol_layer_n); + + const int MPropCol_layer_n = CustomData_get_active_layer(&mesh->vdata, CD_PROP_COLOR); + if (MPropCol_layer_n == -1) { + return OPERATOR_CANCELLED; + } + MPropCol *vertcols = CustomData_get_layer_n(&mesh->vdata, CD_PROP_COLOR, MPropCol_layer_n); + + MLoop *loops = CustomData_get_layer(&mesh->ldata, CD_MLOOP); + MPoly *polys = CustomData_get_layer(&mesh->pdata, CD_MPOLY); + + for (int i = 0; i < mesh->totpoly; i++) { + MPoly *c_poly = &polys[i]; + for (int j = 0; j < c_poly->totloop; j++) { + int loop_index = c_poly->loopstart + j; + MLoop *c_loop = &loops[c_poly->loopstart + j]; + vertcols[c_loop->v].color[0] = (loopcols[loop_index].r / 255.0f); + vertcols[c_loop->v].color[1] = (loopcols[loop_index].g / 255.0f); + vertcols[c_loop->v].color[2] = (loopcols[loop_index].b / 255.0f); + vertcols[c_loop->v].color[3] = (loopcols[loop_index].a / 255.0f); + srgb_to_linearrgb_v4(vertcols[c_loop->v].color, vertcols[c_loop->v].color); + } + } + + DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY); + WM_event_add_notifier(C, NC_GEOM | ND_DATA, ob->data); + + return OPERATOR_FINISHED; +} + +static void SCULPT_OT_loop_to_vertex_colors(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Vertex Color to Sculpt Vertex Color"; + ot->description = "Copy the active loop color layer to the vertex color"; + ot->idname = "SCULPT_OT_loop_to_vertex_colors"; + + /* api callbacks */ + ot->poll = SCULPT_vertex_colors_poll; + ot->exec = loop_to_vertex_colors_exec; + + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} + +static int sculpt_sample_color_invoke(bContext *C, + wmOperator *UNUSED(op), + const wmEvent *UNUSED(e)) +{ + Sculpt *sd = CTX_data_tool_settings(C)->sculpt; + Scene *scene = CTX_data_scene(C); + Object *ob = CTX_data_active_object(C); + Brush *brush = BKE_paint_brush(&sd->paint); + SculptSession *ss = ob->sculpt; + int active_vertex = SCULPT_active_vertex_get(ss); + const float *active_vertex_color = SCULPT_vertex_color_get(ss, active_vertex); + if (!active_vertex_color) { + return OPERATOR_CANCELLED; + } + + float color_srgb[3]; + copy_v3_v3(color_srgb, active_vertex_color); + IMB_colormanagement_scene_linear_to_srgb_v3(color_srgb); + BKE_brush_color_set(scene, brush, color_srgb); + + WM_event_add_notifier(C, NC_BRUSH | NA_EDITED, brush); + + return OPERATOR_FINISHED; +} + +static void SCULPT_OT_sample_color(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Sample Color"; + ot->idname = "SCULPT_OT_sample_color"; + ot->description = "Sample the vertex color of the active vertex"; + + /* api callbacks */ + ot->invoke = sculpt_sample_color_invoke; + ot->poll = SCULPT_vertex_colors_poll; + + ot->flag = OPTYPE_REGISTER; +} + +/** + * #sculpt_mask_by_color_delta_get returns values in the (0,1) range that are used to generate the + * mask based on the difference between two colors (the active color and the color of any other + * vertex). Ideally, a threshold of 0 should mask only the colors that are equal to the active + * color and threshold of 1 should mask all colors. In order to avoid artifacts and produce softer + * falloffs in the mask, the MASK_BY_COLOR_SLOPE defines the size of the transition values between + * masked and unmasked vertices. The smaller this value is, the sharper the generated mask is going + * to be. + */ +#define MASK_BY_COLOR_SLOPE 0.25f + +static float sculpt_mask_by_color_delta_get(const float *color_a, + const float *color_b, + const float threshold, + const bool invert) +{ + float len = len_v3v3(color_a, color_b); + /* Normalize len to the (0, 1) range. */ + len = len / M_SQRT3; + + if (len < threshold - MASK_BY_COLOR_SLOPE) { + len = 1.0f; + } + else if (len >= threshold) { + len = 0.0f; + } + else { + len = (-len + threshold) / MASK_BY_COLOR_SLOPE; + } + + if (invert) { + return 1.0f - len; + } + return len; +} + +static float sculpt_mask_by_color_final_mask_get(const float current_mask, + const float new_mask, + const bool invert, + const bool preserve_mask) +{ + if (preserve_mask) { + if (invert) { + return min_ff(current_mask, new_mask); + } + return max_ff(current_mask, new_mask); + } + return new_mask; +} + +typedef struct MaskByColorContiguousFloodFillData { + float threshold; + bool invert; + float *new_mask; + float initial_color[3]; +} MaskByColorContiguousFloodFillData; + +static void do_mask_by_color_contiguous_update_nodes_cb( + void *__restrict userdata, const int n, const TaskParallelTLS *__restrict UNUSED(tls)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + + SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_MASK); + bool update_node = false; + + const bool invert = data->mask_by_color_invert; + const bool preserve_mask = data->mask_by_color_preserve_mask; + + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + const float current_mask = *vd.mask; + const float new_mask = data->mask_by_color_floodfill[vd.index]; + *vd.mask = sculpt_mask_by_color_final_mask_get(current_mask, new_mask, invert, preserve_mask); + if (current_mask == *vd.mask) { + continue; + } + update_node = true; + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; + if (update_node) { + BKE_pbvh_node_mark_redraw(data->nodes[n]); + } +} + +static bool sculpt_mask_by_color_contiguous_floodfill_cb( + SculptSession *ss, int from_v, int to_v, bool is_duplicate, void *userdata) +{ + MaskByColorContiguousFloodFillData *data = userdata; + const float *current_color = SCULPT_vertex_color_get(ss, to_v); + float new_vertex_mask = sculpt_mask_by_color_delta_get( + current_color, data->initial_color, data->threshold, data->invert); + data->new_mask[to_v] = new_vertex_mask; + + if (is_duplicate) { + data->new_mask[to_v] = data->new_mask[from_v]; + } + + float len = len_v3v3(current_color, data->initial_color); + len = len / M_SQRT3; + return len <= data->threshold; +} + +static void sculpt_mask_by_color_contiguous(Object *object, + const int vertex, + const float threshold, + const bool invert, + const bool preserve_mask) +{ + SculptSession *ss = object->sculpt; + const int totvert = SCULPT_vertex_count_get(ss); + + float *new_mask = MEM_calloc_arrayN(totvert, sizeof(float), "new mask"); + + if (invert) { + for (int i = 0; i < totvert; i++) { + new_mask[i] = 1.0f; + } + } + + SculptFloodFill flood; + SCULPT_floodfill_init(ss, &flood); + SCULPT_floodfill_add_initial(&flood, vertex); + + MaskByColorContiguousFloodFillData ffd; + ffd.threshold = threshold; + ffd.invert = invert; + ffd.new_mask = new_mask; + copy_v3_v3(ffd.initial_color, SCULPT_vertex_color_get(ss, vertex)); + + SCULPT_floodfill_execute(ss, &flood, sculpt_mask_by_color_contiguous_floodfill_cb, &ffd); + SCULPT_floodfill_free(&flood); + + int totnode; + PBVHNode **nodes; + BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); + + SculptThreadedTaskData data = { + .ob = object, + .nodes = nodes, + .mask_by_color_floodfill = new_mask, + .mask_by_color_vertex = vertex, + .mask_by_color_threshold = threshold, + .mask_by_color_invert = invert, + .mask_by_color_preserve_mask = preserve_mask, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range( + 0, totnode, &data, do_mask_by_color_contiguous_update_nodes_cb, &settings); + + MEM_SAFE_FREE(nodes); + + MEM_freeN(new_mask); +} + +static void do_mask_by_color_task_cb(void *__restrict userdata, + const int n, + const TaskParallelTLS *__restrict UNUSED(tls)) +{ + SculptThreadedTaskData *data = userdata; + SculptSession *ss = data->ob->sculpt; + + SCULPT_undo_push_node(data->ob, data->nodes[n], SCULPT_UNDO_MASK); + bool update_node = false; + + const float threshold = data->mask_by_color_threshold; + const bool invert = data->mask_by_color_invert; + const bool preserve_mask = data->mask_by_color_preserve_mask; + const float *active_color = SCULPT_vertex_color_get(ss, data->mask_by_color_vertex); + + PBVHVertexIter vd; + BKE_pbvh_vertex_iter_begin (ss->pbvh, data->nodes[n], vd, PBVH_ITER_UNIQUE) { + const float current_mask = *vd.mask; + const float new_mask = sculpt_mask_by_color_delta_get(active_color, vd.col, threshold, invert); + *vd.mask = sculpt_mask_by_color_final_mask_get(current_mask, new_mask, invert, preserve_mask); + + if (current_mask == *vd.mask) { + continue; + } + update_node = true; + if (vd.mvert) { + vd.mvert->flag |= ME_VERT_PBVH_UPDATE; + } + } + BKE_pbvh_vertex_iter_end; + if (update_node) { + BKE_pbvh_node_mark_redraw(data->nodes[n]); + } +} + +static void sculpt_mask_by_color_full_mesh(Object *object, + const int vertex, + const float threshold, + const bool invert, + const bool preserve_mask) +{ + SculptSession *ss = object->sculpt; + + int totnode; + PBVHNode **nodes; + BKE_pbvh_search_gather(ss->pbvh, NULL, NULL, &nodes, &totnode); + + SculptThreadedTaskData data = { + .ob = object, + .nodes = nodes, + .mask_by_color_vertex = vertex, + .mask_by_color_threshold = threshold, + .mask_by_color_invert = invert, + .mask_by_color_preserve_mask = preserve_mask, + }; + + TaskParallelSettings settings; + BKE_pbvh_parallel_range_settings(&settings, true, totnode); + BLI_task_parallel_range(0, totnode, &data, do_mask_by_color_task_cb, &settings); + + MEM_SAFE_FREE(nodes); +} + +static int sculpt_mask_by_color_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); + Object *ob = CTX_data_active_object(C); + SculptSession *ss = ob->sculpt; + + BKE_sculpt_update_object_for_edit(depsgraph, ob, true, true, false); + + /* Color data is not available in Multires. */ + if (BKE_pbvh_type(ss->pbvh) != PBVH_FACES) { + return OPERATOR_CANCELLED; + } + + if (!ss->vcol) { + return OPERATOR_CANCELLED; + } + + SCULPT_vertex_random_access_ensure(ss); + + /* Tools that are not brushes do not have the brush gizmo to update the vertex as the mouse move, + * so it needs to be updated here. */ + SculptCursorGeometryInfo sgi; + float mouse[2]; + mouse[0] = event->mval[0]; + mouse[1] = event->mval[1]; + SCULPT_cursor_geometry_info_update(C, &sgi, mouse, false); + + SCULPT_undo_push_begin(ob, "Mask by color"); + + const int active_vertex = SCULPT_active_vertex_get(ss); + const float threshold = RNA_float_get(op->ptr, "threshold"); + const bool invert = RNA_boolean_get(op->ptr, "invert"); + const bool preserve_mask = RNA_boolean_get(op->ptr, "preserve_previous_mask"); + + if (RNA_boolean_get(op->ptr, "contiguous")) { + sculpt_mask_by_color_contiguous(ob, active_vertex, threshold, invert, preserve_mask); + } + else { + sculpt_mask_by_color_full_mesh(ob, active_vertex, threshold, invert, preserve_mask); + } + + BKE_pbvh_update_vertex_data(ss->pbvh, PBVH_UpdateMask); + SCULPT_undo_push_end(); + + SCULPT_flush_update_done(C, ob, SCULPT_UPDATE_MASK); + + return OPERATOR_FINISHED; +} + +static void SCULPT_OT_mask_by_color(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Mask by Color"; + ot->idname = "SCULPT_OT_mask_by_color"; + ot->description = "Creates a mask based on the sculpt vertex colors"; + + /* api callbacks */ + ot->invoke = sculpt_mask_by_color_invoke; + ot->poll = SCULPT_vertex_colors_poll; + + ot->flag = OPTYPE_REGISTER; + + ot->prop = RNA_def_boolean( + ot->srna, "contiguous", false, "Contiguous", "Mask only contiguous color areas"); + + ot->prop = RNA_def_boolean(ot->srna, "invert", false, "Invert", "Invert the generated mask"); + ot->prop = RNA_def_boolean( + ot->srna, + "preserve_previous_mask", + false, + "Preserve Previous Mask", + "Preserve the previous mask and add or subtract the new one generated by the colors"); + + RNA_def_float(ot->srna, + "threshold", + 0.35f, + 0.0f, + 1.0f, + "Threshold", + "How much changes in color affect the mask generation", + 0.0f, + 1.0f); +} + +void ED_operatortypes_sculpt(void) +{ + WM_operatortype_append(SCULPT_OT_brush_stroke); + WM_operatortype_append(SCULPT_OT_sculptmode_toggle); + WM_operatortype_append(SCULPT_OT_set_persistent_base); + WM_operatortype_append(SCULPT_OT_dynamic_topology_toggle); + WM_operatortype_append(SCULPT_OT_optimize); + WM_operatortype_append(SCULPT_OT_symmetrize); + WM_operatortype_append(SCULPT_OT_detail_flood_fill); + WM_operatortype_append(SCULPT_OT_sample_detail_size); + WM_operatortype_append(SCULPT_OT_set_detail_size); + WM_operatortype_append(SCULPT_OT_mesh_filter); + WM_operatortype_append(SCULPT_OT_mask_filter); + WM_operatortype_append(SCULPT_OT_dirty_mask); + WM_operatortype_append(SCULPT_OT_mask_expand); + WM_operatortype_append(SCULPT_OT_set_pivot_position); + WM_operatortype_append(SCULPT_OT_face_sets_create); + WM_operatortype_append(SCULPT_OT_face_sets_change_visibility); + WM_operatortype_append(SCULPT_OT_face_sets_randomize_colors); + WM_operatortype_append(SCULPT_OT_face_sets_init); + WM_operatortype_append(SCULPT_OT_cloth_filter); + WM_operatortype_append(SCULPT_OT_face_sets_edit); + WM_operatortype_append(SCULPT_OT_face_set_lasso_gesture); + WM_operatortype_append(SCULPT_OT_face_set_box_gesture); + WM_operatortype_append(SCULPT_OT_trim_box_gesture); + WM_operatortype_append(SCULPT_OT_trim_lasso_gesture); + WM_operatortype_append(SCULPT_OT_project_line_gesture); + + WM_operatortype_append(SCULPT_OT_sample_color); + WM_operatortype_append(SCULPT_OT_loop_to_vertex_colors); + WM_operatortype_append(SCULPT_OT_vertex_to_loop_colors); + WM_operatortype_append(SCULPT_OT_color_filter); + WM_operatortype_append(SCULPT_OT_mask_by_color); + WM_operatortype_append(SCULPT_OT_dyntopo_detail_size_edit); + WM_operatortype_append(SCULPT_OT_mask_init); + + WM_operatortype_append(SCULPT_OT_expand); +} diff --git a/source/blender/editors/sculpt_paint/sculpt_smooth.c b/source/blender/editors/sculpt_paint/sculpt_smooth.c index 847f42fe9e8..c65489548b7 100644 --- a/source/blender/editors/sculpt_paint/sculpt_smooth.c +++ b/source/blender/editors/sculpt_paint/sculpt_smooth.c @@ -538,13 +538,6 @@ static void SCULPT_do_surface_smooth_brush_displace_task_cb_ex( void SCULPT_do_surface_smooth_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, int totnode) { Brush *brush = BKE_paint_brush(&sd->paint); - SculptSession *ss = ob->sculpt; - - if (SCULPT_stroke_is_first_brush_step(ss->cache)) { - BLI_assert(ss->cache->surface_smooth_laplacian_disp == NULL); - ss->cache->surface_smooth_laplacian_disp = MEM_callocN( - sizeof(float[3]) * SCULPT_vertex_count_get(ss), "HC smooth laplacian b"); - } /* Threaded loop over nodes. */ SculptThreadedTaskData data = { diff --git a/source/blender/editors/sculpt_paint/sculpt_transform.c b/source/blender/editors/sculpt_paint/sculpt_transform.c index bfbe545d1ef..b91e05f226e 100644 --- a/source/blender/editors/sculpt_paint/sculpt_transform.c +++ b/source/blender/editors/sculpt_paint/sculpt_transform.c @@ -70,10 +70,6 @@ void ED_sculpt_init_transform(struct bContext *C, Object *ob) copy_v4_v4(ss->init_pivot_rot, ss->pivot_rot); copy_v3_v3(ss->init_pivot_scale, ss->pivot_scale); - copy_v3_v3(ss->prev_pivot_pos, ss->pivot_pos); - copy_v4_v4(ss->prev_pivot_rot, ss->pivot_rot); - copy_v3_v3(ss->prev_pivot_scale, ss->pivot_scale); - SCULPT_undo_push_begin(ob, "Transform"); BKE_sculpt_update_object_for_edit(depsgraph, ob, false, false, false); @@ -81,13 +77,10 @@ void ED_sculpt_init_transform(struct bContext *C, Object *ob) SCULPT_vertex_random_access_ensure(ss); SCULPT_filter_cache_init(C, ob, sd, SCULPT_UNDO_COORDS); - - ss->filter_cache->transform_displacement_mode = SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL; } static void sculpt_transform_matrices_init(SculptSession *ss, const char symm, - const SculptTransformDisplacementMode t_mode, float r_transform_mats[8][4][4]) { @@ -96,18 +89,9 @@ static void sculpt_transform_matrices_init(SculptSession *ss, transform_mat[4][4]; float start_pivot_pos[3], start_pivot_rot[4], start_pivot_scale[3]; - switch (t_mode) { - case SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL: - copy_v3_v3(start_pivot_pos, ss->init_pivot_pos); - copy_v4_v4(start_pivot_rot, ss->init_pivot_rot); - copy_v3_v3(start_pivot_scale, ss->init_pivot_scale); - break; - case SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL: - copy_v3_v3(start_pivot_pos, ss->prev_pivot_pos); - copy_v4_v4(start_pivot_rot, ss->prev_pivot_rot); - copy_v3_v3(start_pivot_scale, ss->prev_pivot_scale); - break; - } + copy_v3_v3(start_pivot_pos, ss->init_pivot_pos); + copy_v4_v4(start_pivot_rot, ss->init_pivot_rot); + copy_v3_v3(start_pivot_scale, ss->init_pivot_scale); for (int i = 0; i < PAINT_SYMM_AREAS; i++) { ePaintSymmetryAreas v_symm = i; @@ -167,25 +151,15 @@ static void sculpt_transform_task_cb(void *__restrict userdata, BKE_pbvh_vertex_iter_begin (ss->pbvh, node, vd, PBVH_ITER_UNIQUE) { SCULPT_orig_vert_data_update(&orig_data, &vd); float transformed_co[3], orig_co[3], disp[3]; - float *start_co; float fade = vd.mask ? *vd.mask : 0.0f; copy_v3_v3(orig_co, orig_data.co); char symm_area = SCULPT_get_vertex_symm_area(orig_co); - switch (ss->filter_cache->transform_displacement_mode) { - case SCULPT_TRANSFORM_DISPLACEMENT_ORIGINAL: - start_co = orig_co; - break; - case SCULPT_TRANSFORM_DISPLACEMENT_INCREMENTAL: - start_co = vd.co; - break; - } - - copy_v3_v3(transformed_co, start_co); + copy_v3_v3(transformed_co, orig_co); mul_m4_v3(data->transform_mats[(int)symm_area], transformed_co); - sub_v3_v3v3(disp, transformed_co, start_co); + sub_v3_v3v3(disp, transformed_co, orig_co); mul_v3_fl(disp, 1.0f - fade); - add_v3_v3v3(vd.co, start_co, disp); + add_v3_v3v3(vd.co, orig_co, disp); if (vd.mvert) { vd.mvert->flag |= ME_VERT_PBVH_UPDATE; @@ -207,8 +181,7 @@ static void sculpt_transform_all_vertices(Sculpt *sd, Object *ob) .nodes = ss->filter_cache->nodes, }; - sculpt_transform_matrices_init( - ss, symm, ss->filter_cache->transform_displacement_mode, data.transform_mats); + sculpt_transform_matrices_init(ss, symm, data.transform_mats); /* Regular transform applies all symmetry passes at once as it is split by symmetry areas * (each vertex can only be transformed once by the transform matrix of its area). */ @@ -229,10 +202,6 @@ void ED_sculpt_update_modal_transform(struct bContext *C, Object *ob) sculpt_transform_all_vertices(sd, ob); - copy_v3_v3(ss->prev_pivot_pos, ss->pivot_pos); - copy_v4_v4(ss->prev_pivot_rot, ss->pivot_rot); - copy_v3_v3(ss->prev_pivot_scale, ss->pivot_scale); - if (ss->deform_modifiers_active || ss->shapekey_active) { SCULPT_flush_stroke_deform(sd, ob, true); } diff --git a/source/blender/editors/sculpt_paint/sculpt_undo.c b/source/blender/editors/sculpt_paint/sculpt_undo.c index 4a88b75cf25..8819496c168 100644 --- a/source/blender/editors/sculpt_paint/sculpt_undo.c +++ b/source/blender/editors/sculpt_paint/sculpt_undo.c @@ -1107,10 +1107,10 @@ static void sculpt_undo_store_coords(Object *ob, SculptUndoNode *unode) BKE_pbvh_vertex_iter_begin (ss->pbvh, unode->node, vd, PBVH_ITER_ALL) { copy_v3_v3(unode->co[vd.i], vd.co); if (vd.no) { - copy_v3_v3_short(unode->no[vd.i], vd.no); + copy_v3_v3(unode->no[vd.i], vd.no); } else { - normal_float_to_short_v3(unode->no[vd.i], vd.fno); + copy_v3_v3(unode->no[vd.i], vd.fno); } if (ss->deform_modifiers_active) { diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c index f68446b1cae..184d715a347 100644 --- a/source/blender/editors/space_action/action_edit.c +++ b/source/blender/editors/space_action/action_edit.c @@ -642,6 +642,10 @@ static int actkeys_paste_exec(bContext *C, wmOperator *op) } } + /* Grease Pencil needs extra update to refresh the added keyframes. */ + if (ac.datatype == ANIMCONT_GPENCIL) { + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL); + } /* set notifier that keyframes have changed */ WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); diff --git a/source/blender/editors/space_action/space_action.c b/source/blender/editors/space_action/space_action.c index 4463856f40a..ba96ac52f1f 100644 --- a/source/blender/editors/space_action/space_action.c +++ b/source/blender/editors/space_action/space_action.c @@ -36,6 +36,7 @@ #include "BLI_utildefines.h" #include "BKE_context.h" +#include "BKE_lib_remap.h" #include "BKE_nla.h" #include "BKE_screen.h" @@ -814,20 +815,15 @@ static void action_refresh(const bContext *C, ScrArea *area) /* XXX re-sizing y-extents of tot should go here? */ } -static void action_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id) +static void action_id_remap(ScrArea *UNUSED(area), + SpaceLink *slink, + const struct IDRemapper *mappings) { SpaceAction *sact = (SpaceAction *)slink; - if ((ID *)sact->action == old_id) { - sact->action = (bAction *)new_id; - } - - if ((ID *)sact->ads.filter_grp == old_id) { - sact->ads.filter_grp = (Collection *)new_id; - } - if ((ID *)sact->ads.source == old_id) { - sact->ads.source = new_id; - } + BKE_id_remapper_apply(mappings, (ID **)&sact->action, ID_REMAP_APPLY_DEFAULT); + BKE_id_remapper_apply(mappings, (ID **)&sact->ads.filter_grp, ID_REMAP_APPLY_DEFAULT); + BKE_id_remapper_apply(mappings, &sact->ads.source, ID_REMAP_APPLY_DEFAULT); } /** diff --git a/source/blender/editors/space_api/spacetypes.c b/source/blender/editors/space_api/spacetypes.c index 035bc7e297d..f8adba30547 100644 --- a/source/blender/editors/space_api/spacetypes.c +++ b/source/blender/editors/space_api/spacetypes.c @@ -72,7 +72,7 @@ void ED_spacetypes_init(void) { - /* UI unit is a variable, may be used in some space type inits. */ + /* UI unit is a variable, may be used in some space type initialization. */ U.widget_unit = 20; /* Create space types. */ @@ -248,15 +248,16 @@ void *ED_region_draw_cb_activate(ARegionType *art, return rdc; } -void ED_region_draw_cb_exit(ARegionType *art, void *handle) +bool ED_region_draw_cb_exit(ARegionType *art, void *handle) { LISTBASE_FOREACH (RegionDrawCB *, rdc, &art->drawcalls) { if (rdc == (RegionDrawCB *)handle) { BLI_remlink(&art->drawcalls, rdc); MEM_freeN(rdc); - return; + return true; } } + return false; } static void ed_region_draw_cb_draw(const bContext *C, ARegion *region, ARegionType *art, int type) diff --git a/source/blender/editors/space_buttons/buttons_texture.c b/source/blender/editors/space_buttons/buttons_texture.c index 554edf680be..5dd7c3d240e 100644 --- a/source/blender/editors/space_buttons/buttons_texture.c +++ b/source/blender/editors/space_buttons/buttons_texture.c @@ -155,10 +155,10 @@ static void buttons_texture_users_find_nodetree(ListBase *users, for (node = ntree->nodes.first; node; node = node->next) { if (node->typeinfo->nclass == NODE_CLASS_TEXTURE) { PointerRNA ptr; - /* PropertyRNA *prop; */ /* UNUSED */ + // PropertyRNA *prop; /* UNUSED */ RNA_pointer_create(&ntree->id, &RNA_Node, node, &ptr); - /* prop = RNA_struct_find_property(&ptr, "texture"); */ /* UNUSED */ + // prop = RNA_struct_find_property(&ptr, "texture"); /* UNUSED */ buttons_texture_user_node_add( users, id, ntree, node, category, RNA_struct_ui_icon(ptr.type), node->name); diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index 007a9105c76..cf1e7788ff8 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -32,6 +32,7 @@ #include "BKE_context.h" #include "BKE_gpencil_modifier.h" /* Types for registering panels. */ +#include "BKE_lib_remap.h" #include "BKE_modifier.h" #include "BKE_screen.h" #include "BKE_shader_fx.h" @@ -860,54 +861,53 @@ static void buttons_area_listener(const wmSpaceTypeListenerParams *params) } } -static void buttons_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id) +static void buttons_id_remap(ScrArea *UNUSED(area), + SpaceLink *slink, + const struct IDRemapper *mappings) { SpaceProperties *sbuts = (SpaceProperties *)slink; - if (sbuts->pinid == old_id) { - sbuts->pinid = new_id; - if (new_id == NULL) { - sbuts->flag &= ~SB_PIN_CONTEXT; - } + if (BKE_id_remapper_apply(mappings, &sbuts->pinid, ID_REMAP_APPLY_DEFAULT) == + ID_REMAP_RESULT_SOURCE_UNASSIGNED) { + sbuts->flag &= ~SB_PIN_CONTEXT; } if (sbuts->path) { ButsContextPath *path = sbuts->path; + for (int i = 0; i < path->len; i++) { + switch (BKE_id_remapper_apply(mappings, &path->ptr[i].owner_id, ID_REMAP_APPLY_DEFAULT)) { + case ID_REMAP_RESULT_SOURCE_UNASSIGNED: { + if (i == 0) { + MEM_SAFE_FREE(sbuts->path); + } + else { + memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i)); + path->len = i; + } + break; + } + case ID_REMAP_RESULT_SOURCE_REMAPPED: { + RNA_id_pointer_create(path->ptr[i].owner_id, &path->ptr[i]); + /* There is no easy way to check/make path downwards valid, just nullify it. + * Next redraw will rebuild this anyway. */ + i++; + memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i)); + path->len = i; + break; + } - int i; - for (i = 0; i < path->len; i++) { - if (path->ptr[i].owner_id == old_id) { - break; - } - } - - if (i == path->len) { - /* pass */ - } - else if (new_id == NULL) { - if (i == 0) { - MEM_SAFE_FREE(sbuts->path); - } - else { - memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i)); - path->len = i; + case ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE: + case ID_REMAP_RESULT_SOURCE_UNAVAILABLE: { + /* Nothing to do. */ + break; + } } } - else { - RNA_id_pointer_create(new_id, &path->ptr[i]); - /* There is no easy way to check/make path downwards valid, just nullify it. - * Next redraw will rebuild this anyway. */ - i++; - memset(&path->ptr[i], 0, sizeof(path->ptr[i]) * (path->len - i)); - path->len = i; - } } if (sbuts->texuser) { ButsContextTexture *ct = sbuts->texuser; - if ((ID *)ct->texture == old_id) { - ct->texture = (Tex *)new_id; - } + BKE_id_remapper_apply(mappings, (ID **)&ct->texture, ID_REMAP_APPLY_DEFAULT); BLI_freelistN(&ct->users); ct->user = NULL; } diff --git a/source/blender/editors/space_clip/CMakeLists.txt b/source/blender/editors/space_clip/CMakeLists.txt index 8c7f59d61dd..db881dafa6b 100644 --- a/source/blender/editors/space_clip/CMakeLists.txt +++ b/source/blender/editors/space_clip/CMakeLists.txt @@ -31,6 +31,9 @@ set(INC ../../windowmanager ../../../../intern/glew-mx ../../../../intern/guardedalloc + + # dna_type_offsets.h + ${CMAKE_CURRENT_BINARY_DIR}/../../makesdna/intern ) set(SRC @@ -69,4 +72,8 @@ if(WITH_INTERNATIONAL) add_definitions(-DWITH_INTERNATIONAL) endif() + blender_add_lib(bf_editor_space_clip "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") + +# Needed so we can use dna_type_offsets.h for defaults initialization. +add_dependencies(bf_editor_space_clip bf_dna) diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c index 5a999b1fad7..d22e4864ecf 100644 --- a/source/blender/editors/space_clip/clip_editor.c +++ b/source/blender/editors/space_clip/clip_editor.c @@ -34,6 +34,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_defaults.h" #include "DNA_mask_types.h" #include "BLI_fileops.h" @@ -646,7 +647,7 @@ void ED_space_clip_set_mask(bContext *C, SpaceClip *sc, Mask *mask) * \{ */ typedef struct PrefetchJob { - /* Clip into which cache the frames will be prefetched into. */ + /** Clip into which cache the frames will be pre-fetched into. */ MovieClip *clip; /* Local copy of the clip which is used to decouple reading in a way which does not require @@ -686,7 +687,7 @@ static bool check_prefetch_break(void) static uchar *prefetch_read_file_to_memory( MovieClip *clip, int current_frame, short render_size, short render_flag, size_t *r_size) { - MovieClipUser user = {0}; + MovieClipUser user = *DNA_struct_default_get(MovieClipUser); user.framenr = current_frame; user.render_size = render_size; user.render_flag = render_flag; @@ -733,7 +734,7 @@ static int prefetch_find_uncached_frame(MovieClip *clip, short direction) { int current_frame; - MovieClipUser user = {0}; + MovieClipUser user = *DNA_struct_default_get(MovieClipUser); user.render_size = render_size; user.render_flag = render_flag; @@ -833,7 +834,7 @@ static void prefetch_task_func(TaskPool *__restrict pool, void *task_data) while ((mem = prefetch_thread_next_frame(queue, clip, &size, ¤t_frame))) { ImBuf *ibuf; - MovieClipUser user = {0}; + MovieClipUser user = *DNA_struct_default_get(MovieClipUser); int flag = IB_rect | IB_multilayer | IB_alphamode_detect | IB_metadata; int result; char *colorspace_name = NULL; @@ -915,7 +916,7 @@ static bool prefetch_movie_frame(MovieClip *clip, short render_flag, short *stop) { - MovieClipUser user = {0}; + MovieClipUser user = *DNA_struct_default_get(MovieClipUser); if (check_prefetch_break() || *stop) { return false; diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h index 20cc6e3da15..15f905f3157 100644 --- a/source/blender/editors/space_clip/clip_intern.h +++ b/source/blender/editors/space_clip/clip_intern.h @@ -184,7 +184,7 @@ void clip_delete_plane_track(struct bContext *C, * Calculate space clip offset to be centered at the given point. */ void clip_view_offset_for_center_to_point( - SpaceClip *sc, const float x, const float y, float *r_offset_x, float *r_offset_y); + SpaceClip *sc, float x, float y, float *r_offset_x, float *r_offset_y); void clip_view_center_to_point(SpaceClip *sc, float x, float y); bool clip_view_calculate_view_selection( diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index 0aa7e35aed6..03b6d8c7381 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -33,6 +33,7 @@ #include "MEM_guardedalloc.h" +#include "DNA_defaults.h" #include "DNA_scene_types.h" /* min/max frames */ #include "DNA_userdef_types.h" @@ -1321,7 +1322,7 @@ static uchar *proxy_thread_next_frame(ProxyQueue *queue, BLI_spin_lock(&queue->spin); if (!*queue->stop && queue->cfra <= queue->efra) { - MovieClipUser user = {0}; + MovieClipUser user = *DNA_struct_default_get(MovieClipUser); char name[FILE_MAX]; size_t size; int file; @@ -1559,7 +1560,8 @@ static int clip_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op)) clip->proxy.build_size_flag, clip->proxy.quality, true, - NULL); + NULL, + false); } WM_jobs_customdata_set(wm_job, pj, proxy_freejob); diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index 91083fa9682..da1d2dea653 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -24,6 +24,8 @@ #include <stdio.h> #include <string.h> +#include "DNA_defaults.h" + #include "DNA_mask_types.h" #include "DNA_movieclip_types.h" #include "DNA_scene_types.h" @@ -37,6 +39,7 @@ #include "BKE_context.h" #include "BKE_lib_id.h" +#include "BKE_lib_remap.h" #include "BKE_movieclip.h" #include "BKE_screen.h" #include "BKE_tracking.h" @@ -239,14 +242,7 @@ static SpaceLink *clip_create(const ScrArea *area, const Scene *scene) ARegion *region; SpaceClip *sc; - sc = MEM_callocN(sizeof(SpaceClip), "initclip"); - sc->spacetype = SPACE_CLIP; - sc->flag = SC_SHOW_MARKER_PATTERN | SC_SHOW_TRACK_PATH | SC_SHOW_GRAPH_TRACKS_MOTION | - SC_SHOW_GRAPH_FRAMES | SC_SHOW_ANNOTATION; - sc->zoom = 1.0f; - sc->path_length = 20; - sc->scopes.track_preview_height = 120; - sc->around = V3D_AROUND_CENTER_MEDIAN; + sc = DNA_struct_default_alloc(SpaceClip); /* header */ region = MEM_callocN(sizeof(ARegion), "header for clip"); @@ -1079,6 +1075,9 @@ static void graph_region_draw(const bContext *C, ARegion *region) /* time-scrubbing */ ED_time_scrub_draw(region, scene, sc->flag & SC_SHOW_SECONDS, true); + /* current frame indicator */ + ED_time_scrub_draw_current_frame(region, scene, sc->flag & SC_SHOW_SECONDS); + /* scrollers */ UI_view2d_scrollers_draw(v2d, NULL); @@ -1126,6 +1125,9 @@ static void dopesheet_region_draw(const bContext *C, ARegion *region) /* time-scrubbing */ ED_time_scrub_draw(region, scene, sc->flag & SC_SHOW_SECONDS, true); + /* current frame indicator */ + ED_time_scrub_draw_current_frame(region, scene, sc->flag & SC_SHOW_SECONDS); + /* scrollers */ UI_view2d_scrollers_draw(v2d, NULL); } @@ -1316,23 +1318,18 @@ static void clip_properties_region_listener(const wmRegionListenerParams *params /********************* registration ********************/ -static void clip_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id) +static void clip_id_remap(ScrArea *UNUSED(area), + SpaceLink *slink, + const struct IDRemapper *mappings) { SpaceClip *sclip = (SpaceClip *)slink; - if (!ELEM(GS(old_id->name), ID_MC, ID_MSK)) { + if (!BKE_id_remapper_has_mapping_for(mappings, FILTER_ID_MC | FILTER_ID_MSK)) { return; } - if ((ID *)sclip->clip == old_id) { - sclip->clip = (MovieClip *)new_id; - id_us_ensure_real(new_id); - } - - if ((ID *)sclip->mask_info.mask == old_id) { - sclip->mask_info.mask = (Mask *)new_id; - id_us_ensure_real(new_id); - } + BKE_id_remapper_apply(mappings, (ID **)&sclip->clip, ID_REMAP_APPLY_ENSURE_REAL); + BKE_id_remapper_apply(mappings, (ID **)&sclip->mask_info.mask, ID_REMAP_APPLY_ENSURE_REAL); } void ED_spacetype_clip(void) diff --git a/source/blender/editors/space_file/CMakeLists.txt b/source/blender/editors/space_file/CMakeLists.txt index 1651269869e..cbeb2e6f529 100644 --- a/source/blender/editors/space_file/CMakeLists.txt +++ b/source/blender/editors/space_file/CMakeLists.txt @@ -16,8 +16,8 @@ # ***** END GPL LICENSE BLOCK ***** set(INC - ../include ../asset + ../include ../../blenfont ../../blenkernel ../../blenlib diff --git a/source/blender/editors/space_file/asset_catalog_tree_view.cc b/source/blender/editors/space_file/asset_catalog_tree_view.cc index 86c4b78dea4..4107669630f 100644 --- a/source/blender/editors/space_file/asset_catalog_tree_view.cc +++ b/source/blender/editors/space_file/asset_catalog_tree_view.cc @@ -325,7 +325,7 @@ void AssetCatalogTreeViewItem::build_context_menu(bContext &C, uiLayout &column) /* Doesn't actually exist right now, but could be defined in Python. Reason that this isn't done * in Python yet is that catalogs are not exposed in BPY, and we'd somehow pass the clicked on - * catalog to the menu draw callback (via context probably).*/ + * catalog to the menu draw callback (via context probably). */ MenuType *mt = WM_menutype_find("ASSETBROWSER_MT_catalog_context_menu", true); if (!mt) { return; @@ -679,7 +679,7 @@ using namespace blender::ed::asset_browser; FileAssetCatalogFilterSettingsHandle *file_create_asset_catalog_filter_settings() { - AssetCatalogFilterSettings *filter_settings = OBJECT_GUARDED_NEW(AssetCatalogFilterSettings); + AssetCatalogFilterSettings *filter_settings = MEM_new<AssetCatalogFilterSettings>(__func__); return reinterpret_cast<FileAssetCatalogFilterSettingsHandle *>(filter_settings); } @@ -688,7 +688,8 @@ void file_delete_asset_catalog_filter_settings( { AssetCatalogFilterSettings **filter_settings = reinterpret_cast<AssetCatalogFilterSettings **>( filter_settings_handle); - OBJECT_GUARDED_SAFE_DELETE(*filter_settings, AssetCatalogFilterSettings); + MEM_delete(*filter_settings); + *filter_settings = nullptr; } bool file_set_asset_catalog_filter_settings( diff --git a/source/blender/editors/space_file/file_draw.c b/source/blender/editors/space_file/file_draw.c index 44e9735866d..14c786e5dea 100644 --- a/source/blender/editors/space_file/file_draw.c +++ b/source/blender/editors/space_file/file_draw.c @@ -240,6 +240,7 @@ static void file_draw_string(int sx, UI_fontstyle_draw(&fs, &rect, fname, + sizeof(fname), col, &(struct uiFontStyleDraw_Params){ .align = align, @@ -289,12 +290,12 @@ static void file_draw_string_multiline(int sx, UI_fontstyle_draw_ex(&style->widget, &rect, string, + len, text_col, &(struct uiFontStyleDraw_Params){ .align = UI_STYLE_TEXT_LEFT, .word_wrap = true, }, - len, NULL, NULL, &result); @@ -402,19 +403,19 @@ static void file_draw_preview(const SpaceFile *sfile, } IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); - immDrawPixelsTexScaled(&state, - (float)xco, - (float)yco, - imb->x, - imb->y, - GPU_RGBA8, - true, - imb->rect, - scale, - scale, - 1.0f, - 1.0f, - col); + immDrawPixelsTexTiled_scaling(&state, + (float)xco, + (float)yco, + imb->x, + imb->y, + GPU_RGBA8, + true, + imb->rect, + scale, + scale, + 1.0f, + 1.0f, + col); GPU_blend(GPU_BLEND_ALPHA); @@ -905,7 +906,8 @@ void file_draw_list(const bContext *C, ARegion *region) * since it's filelist_file_cache_block() and filelist_cache_previews_update() * which controls previews task. */ { - const bool previews_running = filelist_cache_previews_running(files); + const bool previews_running = filelist_cache_previews_running(files) && + !filelist_cache_previews_done(files); // printf("%s: preview task: %d\n", __func__, previews_running); if (previews_running && !sfile->previews_timer) { sfile->previews_timer = WM_event_add_timer_notifier( diff --git a/source/blender/editors/space_file/file_intern.h b/source/blender/editors/space_file/file_intern.h index 3fe48157a09..bd55e6f78ab 100644 --- a/source/blender/editors/space_file/file_intern.h +++ b/source/blender/editors/space_file/file_intern.h @@ -34,11 +34,11 @@ extern "C" { struct ARegion; struct ARegionType; struct AssetLibrary; -struct FileSelectParams; struct FileAssetSelectParams; +struct FileSelectParams; struct SpaceFile; -struct uiLayout; struct View2D; +struct uiLayout; /* file_draw.c */ @@ -128,7 +128,7 @@ void fileselect_refresh_params(struct SpaceFile *sfile); /** * Sets #FileSelectParams.file (name of selected file) */ -void fileselect_file_set(SpaceFile *sfile, const int index); +void fileselect_file_set(SpaceFile *sfile, int index); bool file_attribute_column_type_enabled(const FileSelectParams *params, FileAttributeColumnType column); /** @@ -204,7 +204,7 @@ void file_tools_region_panels_register(struct ARegionType *art); /* file_utils.c */ -void file_tile_boundbox(const ARegion *region, FileLayout *layout, const int file, rcti *r_bounds); +void file_tile_boundbox(const ARegion *region, FileLayout *layout, int file, rcti *r_bounds); /** * If \a path leads to a .blend, remove the trailing slash (if needed). diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index 76a0e4f42e7..a1472a2c1b3 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -2463,9 +2463,10 @@ static void file_expand_directory(bContext *C) if (params) { if (BLI_path_is_rel(params->dir)) { /* Use of 'default' folder here is just to avoid an error message on '//' prefix. */ + const char *blendfile_path = BKE_main_blendfile_path(bmain); BLI_path_abs(params->dir, - G.relbase_valid ? BKE_main_blendfile_path(bmain) : - BKE_appdir_folder_default_or_root()); + (blendfile_path[0] != '\0') ? blendfile_path : + BKE_appdir_folder_default_or_root()); } else if (params->dir[0] == '~') { char tmpstr[sizeof(params->dir) - 1]; @@ -2623,7 +2624,8 @@ void file_filename_enter_handle(bContext *C, void *UNUSED(arg_unused), void *arg matches = file_select_match(sfile, params->file, matched_file); /* *After* file_select_match! */ - BLI_filename_make_safe(params->file); + const bool allow_tokens = (params->flag & FILE_PATH_TOKENS_ALLOW) != 0; + BLI_filename_make_safe_ex(params->file, allow_tokens); if (matches) { /* replace the pattern (or filename that the user typed in, diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c index e4ea832fe2f..2d31e8030a4 100644 --- a/source/blender/editors/space_file/filelist.c +++ b/source/blender/editors/space_file/filelist.c @@ -339,7 +339,10 @@ typedef struct FileListEntryCache { /* Previews handling. */ TaskPool *previews_pool; ThreadQueue *previews_done; - size_t previews_todo_count; + /** Counter for previews that are not fully loaded and ready to display yet. So includes all + * previews either in `previews_pool` or `previews_done`. #filelist_cache_previews_update() makes + * previews in `preview_done` ready for display, so the counter is decremented there. */ + int previews_todo_count; } FileListEntryCache; /* FileListCache.flags */ @@ -852,7 +855,8 @@ static bool is_filtered_hidden(const char *filename, /** * Apply the filter string as file path matching pattern. - * \return true when the file should be in the result set, false if it should be filtered out. */ + * \return true when the file should be in the result set, false if it should be filtered out. + */ static bool is_filtered_file_relpath(const FileListInternEntry *file, const FileListFilter *filter) { if (filter->filter_search[0] == '\0') { @@ -1646,7 +1650,6 @@ static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdat preview_taskdata->preview = NULL; BLI_thread_queue_push(cache->previews_done, preview); - atomic_fetch_and_sub_z(&cache->previews_todo_count, 1); // printf("%s: End (%d)...\n", __func__, threadid); } @@ -1688,6 +1691,7 @@ static void filelist_cache_previews_clear(FileListEntryCache *cache) } MEM_freeN(preview); } + cache->previews_todo_count = 0; } } @@ -1758,7 +1762,6 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry preview->icon_id = BKE_icon_imbuf_create(imbuf); } BLI_thread_queue_push(cache->previews_done, preview); - atomic_fetch_and_sub_z(&cache->previews_todo_count, 1); } else { if (entry->redirection_path) { @@ -1779,6 +1782,7 @@ static void filelist_cache_previews_push(FileList *filelist, FileDirEntry *entry true, filelist_cache_preview_freef); } + cache->previews_todo_count++; } static void filelist_cache_init(FileListEntryCache *cache, size_t cache_size) @@ -1876,8 +1880,6 @@ FileList *filelist_new(short type) p->filelist.nbr_entries = FILEDIR_NBR_ENTRIES_UNSET; filelist_settype(p, type); - p->indexer = &file_indexer_noop; - return p; } @@ -1889,6 +1891,7 @@ void filelist_settype(FileList *filelist, short type) filelist->type = type; filelist->tags = 0; + filelist->indexer = &file_indexer_noop; switch (filelist->type) { case FILE_MAIN: filelist->check_dir_fn = filelist_checkdir_main; @@ -2064,7 +2067,7 @@ static char *fileentry_uiname(const char *root, BLI_join_dirfile(abspath, sizeof(abspath), root, relpath); name = BLF_display_name_from_file(abspath); if (name) { - /* Allocated string, so no need to BLI_strdup.*/ + /* Allocated string, so no need to #BLI_strdup. */ return name; } } @@ -2693,6 +2696,7 @@ bool filelist_cache_previews_update(FileList *filelist) } MEM_freeN(preview); + cache->previews_todo_count--; } return changed; @@ -2714,7 +2718,7 @@ bool filelist_cache_previews_done(FileList *filelist) } return (cache->previews_pool == NULL) || (cache->previews_done == NULL) || - (cache->previews_todo_count == (size_t)BLI_thread_queue_len(cache->previews_done)); + (cache->previews_todo_count == 0); } /* would recognize .blend as well */ @@ -3661,7 +3665,7 @@ static void filelist_readjob_recursive_dir_add_items(const bool do_lib, list_lib_options |= LIST_LIB_RECURSIVE; } /* Only load assets when browsing an asset library. For normal file browsing we return all - * entries. `FLF_ASSETS_ONLY` filter can be enabled/disabled by the user.*/ + * entries. `FLF_ASSETS_ONLY` filter can be enabled/disabled by the user. */ if (filelist->asset_library_ref) { list_lib_options |= LIST_LIB_ASSETS_ONLY; } diff --git a/source/blender/editors/space_file/filelist.h b/source/blender/editors/space_file/filelist.h index 0119a9b4f52..696986d4660 100644 --- a/source/blender/editors/space_file/filelist.h +++ b/source/blender/editors/space_file/filelist.h @@ -62,16 +62,16 @@ void folder_history_list_ensure_for_active_browse_mode(struct SpaceFile *sfile); void folder_history_list_free(struct SpaceFile *sfile); struct ListBase folder_history_list_duplicate(struct ListBase *listbase); -void filelist_setsorting(struct FileList *filelist, const short sort, bool invert_sort); +void filelist_setsorting(struct FileList *filelist, short sort, bool invert_sort); void filelist_sort(struct FileList *filelist); void filelist_setfilter_options(struct FileList *filelist, - const bool do_filter, - const bool hide_dot, - const bool hide_parent, - const uint64_t filter, - const uint64_t filter_id, - const bool filter_assets_only, + bool do_filter, + bool hide_dot, + bool hide_parent, + uint64_t filter, + uint64_t filter_id, + bool filter_assets_only, const char *filter_glob, const char *filter_search); /** @@ -98,19 +98,19 @@ void filelist_setlibrary(struct FileList *filelist, void filelist_init_icons(void); void filelist_free_icons(void); -struct ImBuf *filelist_getimage(struct FileList *filelist, const int index); +struct ImBuf *filelist_getimage(struct FileList *filelist, int index); struct ImBuf *filelist_file_getimage(const FileDirEntry *file); struct ImBuf *filelist_geticon_image_ex(const FileDirEntry *file); -struct ImBuf *filelist_geticon_image(struct FileList *filelist, const int index); -int filelist_geticon(struct FileList *filelist, const int index, const bool is_main); +struct ImBuf *filelist_geticon_image(struct FileList *filelist, int index); +int filelist_geticon(struct FileList *filelist, int index, bool is_main); struct FileList *filelist_new(short type); void filelist_settype(struct FileList *filelist, short type); void filelist_clear(struct FileList *filelist); void filelist_clear_ex(struct FileList *filelist, - const bool do_asset_library, - const bool do_cache, - const bool do_selection); + bool do_asset_library, + bool do_cache, + bool do_selection); /** * A "smarter" version of #filelist_clear() that calls partial clearing based on the filelist * force-reset flags. @@ -156,7 +156,7 @@ void filelist_file_cache_slidingwindow_set(struct FileList *filelist, size_t win /** * Load in cache all entries "around" given index (as much as block cache may hold). */ -bool filelist_file_cache_block(struct FileList *filelist, const int index); +bool filelist_file_cache_block(struct FileList *filelist, int index); bool filelist_needs_force_reset(struct FileList *filelist); void filelist_tag_force_reset(struct FileList *filelist); @@ -171,7 +171,7 @@ unsigned int filelist_entry_select_set(const struct FileList *filelist, unsigned int flag, FileCheckType check); void filelist_entry_select_index_set(struct FileList *filelist, - const int index, + int index, FileSelType select, unsigned int flag, FileCheckType check); @@ -184,9 +184,9 @@ unsigned int filelist_entry_select_get(struct FileList *filelist, struct FileDirEntry *entry, FileCheckType check); unsigned int filelist_entry_select_index_get(struct FileList *filelist, - const int index, + int index, FileCheckType check); -bool filelist_entry_is_selected(struct FileList *filelist, const int index); +bool filelist_entry_is_selected(struct FileList *filelist, int index); /** * Set selection of the '..' parent entry, but only if it's actually visible. */ @@ -195,7 +195,7 @@ void filelist_entry_parent_select_set(struct FileList *filelist, unsigned int flag, FileCheckType check); -void filelist_setrecursion(struct FileList *filelist, const int recursion_level); +void filelist_setrecursion(struct FileList *filelist, int recursion_level); struct AssetLibrary *filelist_asset_library(struct FileList *filelist); @@ -213,7 +213,7 @@ void filelist_readjob_stop(struct FileList *filelist, struct wmWindowManager *wm int filelist_readjob_running(struct FileList *filelist, struct wmWindowManager *wm); bool filelist_cache_previews_update(struct FileList *filelist); -void filelist_cache_previews_set(struct FileList *filelist, const bool use_previews); +void filelist_cache_previews_set(struct FileList *filelist, bool use_previews); bool filelist_cache_previews_running(struct FileList *filelist); bool filelist_cache_previews_done(struct FileList *filelist); diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c index e3ac5840da3..f9783d1b19f 100644 --- a/source/blender/editors/space_file/filesel.c +++ b/source/blender/editors/space_file/filesel.c @@ -275,6 +275,9 @@ static FileSelectParams *fileselect_ensure_updated_file_params(SpaceFile *sfile) if ((prop = RNA_struct_find_property(op->ptr, "filter_usd"))) { params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_USD : 0; } + if ((prop = RNA_struct_find_property(op->ptr, "filter_obj"))) { + params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_OBJECT_IO : 0; + } if ((prop = RNA_struct_find_property(op->ptr, "filter_volume"))) { params->filter |= RNA_property_boolean_get(op->ptr, prop) ? FILE_TYPE_VOLUME : 0; } @@ -318,6 +321,10 @@ static FileSelectParams *fileselect_ensure_updated_file_params(SpaceFile *sfile) params->flag |= RNA_boolean_get(op->ptr, "active_collection") ? FILE_ACTIVE_COLLECTION : 0; } + if ((prop = RNA_struct_find_property(op->ptr, "allow_path_tokens"))) { + params->flag |= RNA_property_boolean_get(op->ptr, prop) ? FILE_PATH_TOKENS_ALLOW : 0; + } + if ((prop = RNA_struct_find_property(op->ptr, "display_type"))) { params->display = RNA_property_enum_get(op->ptr, prop); } diff --git a/source/blender/editors/space_file/fsmenu.c b/source/blender/editors/space_file/fsmenu.c index 97f22ca7d89..14f596ae7bf 100644 --- a/source/blender/editors/space_file/fsmenu.c +++ b/source/blender/editors/space_file/fsmenu.c @@ -185,8 +185,8 @@ static void fsmenu_xdg_user_dirs_free(GHash *xdg_map) /** * Add fsmenu entry for system folders on linux. - * - Check if a path is stored in the GHash generated from user-dirs.dirs - * - If not, check for a default path in $HOME + * - Check if a path is stored in the #GHash generated from `user-dirs.dirs`. + * - If not, check for a default path in `$HOME`. * * \param key: Use `user-dirs.dirs` format "XDG_EXAMPLE_DIR" * \param default_path: Directory name to check in $HOME, also used for the menu entry name. diff --git a/source/blender/editors/space_file/fsmenu.h b/source/blender/editors/space_file/fsmenu.h index 6296314d40a..0915c9a5a2f 100644 --- a/source/blender/editors/space_file/fsmenu.h +++ b/source/blender/editors/space_file/fsmenu.h @@ -42,7 +42,7 @@ void fsmenu_insert_entry(struct FSMenu *fsmenu, const char *path, const char *name, int icon, - const enum FSMenuInsert flag); + enum FSMenuInsert flag); /** Refresh 'valid' status of given menu entry */ void fsmenu_entry_refresh_valid(struct FSMenuEntry *fsentry); diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index bbf3c6f768c..470128f61bd 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -33,6 +33,7 @@ #include "BKE_appdir.h" #include "BKE_context.h" #include "BKE_global.h" +#include "BKE_lib_remap.h" #include "BKE_main.h" #include "BKE_screen.h" @@ -57,14 +58,11 @@ #include "UI_view2d.h" #include "GPU_framebuffer.h" +#include "file_indexer.h" #include "file_intern.h" /* own include */ #include "filelist.h" #include "fsmenu.h" -/* Enable asset indexing. Currently disabled as ID properties aren't indexed yet and is needed for - * object snapping. See {D12990}. */ -//#define SPACE_FILE_ENABLE_ASSET_INDEXING - static ARegion *file_ui_region_ensure(ScrArea *area, ARegion *region_prev) { ARegion *region; @@ -359,11 +357,11 @@ static void file_refresh(const bContext *C, ScrArea *area) sfile->files, asset_params->asset_catalog_visibility, &asset_params->catalog_id); } -#ifdef SPACE_FILE_ENABLE_ASSET_INDEXING if (ED_fileselect_is_asset_browser(sfile)) { - filelist_setindexer(sfile->files, &file_indexer_asset); + const bool use_asset_indexer = !USER_EXPERIMENTAL_TEST(&U, no_asset_indexing); + filelist_setindexer(sfile->files, + use_asset_indexer ? &file_indexer_asset : &file_indexer_noop); } -#endif /* Update the active indices of bookmarks & co. */ sfile->systemnr = fsmenu_get_active_indices(fsmenu, FS_CATEGORY_SYSTEM, params->dir); @@ -992,7 +990,7 @@ static int /*eContextResult*/ file_context(const bContext *C, return CTX_RESULT_MEMBER_NOT_FOUND; } -static void file_id_remap(ScrArea *area, SpaceLink *sl, ID *UNUSED(old_id), ID *UNUSED(new_id)) +static void file_id_remap(ScrArea *area, SpaceLink *sl, const struct IDRemapper *UNUSED(mappings)) { SpaceFile *sfile = (SpaceFile *)sl; diff --git a/source/blender/editors/space_graph/graph_edit.c b/source/blender/editors/space_graph/graph_edit.c index 2afee277847..9675901ead3 100644 --- a/source/blender/editors/space_graph/graph_edit.c +++ b/source/blender/editors/space_graph/graph_edit.c @@ -2353,6 +2353,103 @@ void GRAPH_OT_snap(wmOperatorType *ot) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Equalize Handles Operator + * \{ */ + +/* Defines for equalize handles tool. */ +static const EnumPropertyItem prop_graphkeys_equalize_handles_sides[] = { + {GRAPHKEYS_EQUALIZE_LEFT, "LEFT", 0, "Left", "Equalize selected keyframes' left handles"}, + {GRAPHKEYS_EQUALIZE_RIGHT, "RIGHT", 0, "Right", "Equalize selected keyframes' right handles"}, + {GRAPHKEYS_EQUALIZE_BOTH, "BOTH", 0, "Both", "Equalize both of a keyframe's handles"}, + {0, NULL, 0, NULL, NULL}, +}; + +/* ------------------- */ + +/* Equalize selected keyframes' bezier handles. */ +static void equalize_graph_keys(bAnimContext *ac, int mode, float handle_length, bool flatten) +{ + /* Filter data. */ + const int filter = (ANIMFILTER_DATA_VISIBLE | ANIMFILTER_CURVE_VISIBLE | ANIMFILTER_FOREDIT | + ANIMFILTER_NODUPLIS); + ListBase anim_data = {NULL, NULL}; + ANIM_animdata_filter(ac, &anim_data, filter, ac->data, ac->datatype); + + /* Equalize keyframes. */ + LISTBASE_FOREACH (bAnimListElem *, ale, &anim_data) { + ANIM_fcurve_equalize_keyframes_loop(ale->key_data, mode, handle_length, flatten); + ale->update |= ANIM_UPDATE_DEFAULT; + } + + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); +} + +static int graphkeys_equalize_handles_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + + /* Get editor data. */ + if (ANIM_animdata_get_context(C, &ac) == 0) { + return OPERATOR_CANCELLED; + } + + /* Get equalize mode. */ + int mode = RNA_enum_get(op->ptr, "side"); + float handle_length = RNA_float_get(op->ptr, "handle_length"); + bool flatten = RNA_boolean_get(op->ptr, "flatten"); + + /* Equalize graph keyframes. */ + equalize_graph_keys(&ac, mode, handle_length, flatten); + + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +void GRAPH_OT_equalize_handles(wmOperatorType *ot) +{ + /* Identifiers */ + ot->name = "Equalize Handles"; + ot->idname = "GRAPH_OT_equalize_handles"; + ot->description = + "Ensure selected keyframes' handles have equal length, optionally making them horizontal"; + + /* API callbacks */ + ot->invoke = WM_menu_invoke; + ot->exec = graphkeys_equalize_handles_exec; + ot->poll = graphop_editable_keyframes_poll; + + /* Flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* Properties */ + ot->prop = RNA_def_enum(ot->srna, + "side", + prop_graphkeys_equalize_handles_sides, + 0, + "Side", + "Side of the keyframes' bezier handles to affect"); + RNA_def_float(ot->srna, + "handle_length", + 5.0f, + 0.1f, + FLT_MAX, + "Handle Length", + "Length to make selected keyframes' bezier handles", + 1.0f, + 50.0f); + RNA_def_boolean( + ot->srna, + "flatten", + false, + "Flatten", + "Make the values of the selected keyframes' handles the same as their respective keyframes"); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Mirror Keyframes Operator * \{ */ diff --git a/source/blender/editors/space_graph/graph_intern.h b/source/blender/editors/space_graph/graph_intern.h index 4db1eb5214e..a59fb63dd22 100644 --- a/source/blender/editors/space_graph/graph_intern.h +++ b/source/blender/editors/space_graph/graph_intern.h @@ -109,8 +109,8 @@ void get_graph_keyframe_extents(struct bAnimContext *ac, float *xmax, float *ymin, float *ymax, - const bool do_sel_only, - const bool include_handles); + bool do_sel_only, + bool include_handles); void GRAPH_OT_previewrange_set(struct wmOperatorType *ot); void GRAPH_OT_view_all(struct wmOperatorType *ot); @@ -126,6 +126,8 @@ void GRAPH_OT_paste(struct wmOperatorType *ot); void GRAPH_OT_duplicate(struct wmOperatorType *ot); void GRAPH_OT_delete(struct wmOperatorType *ot); void GRAPH_OT_clean(struct wmOperatorType *ot); +void GRAPH_OT_blend_to_neighbor(struct wmOperatorType *ot); +void GRAPH_OT_breakdown(struct wmOperatorType *ot); void GRAPH_OT_decimate(struct wmOperatorType *ot); void GRAPH_OT_sample(struct wmOperatorType *ot); void GRAPH_OT_bake(struct wmOperatorType *ot); @@ -142,6 +144,7 @@ void GRAPH_OT_easing_type(struct wmOperatorType *ot); void GRAPH_OT_frame_jump(struct wmOperatorType *ot); void GRAPH_OT_snap_cursor_value(struct wmOperatorType *ot); void GRAPH_OT_snap(struct wmOperatorType *ot); +void GRAPH_OT_equalize_handles(struct wmOperatorType *ot); void GRAPH_OT_mirror(struct wmOperatorType *ot); /* defines for snap keyframes @@ -156,6 +159,15 @@ enum eGraphKeys_Snap_Mode { GRAPHKEYS_SNAP_VALUE, }; +/* Defines for equalize keyframe handles. + * NOTE: Keep in sync with eEditKeyframes_Equalize (in ED_keyframes_edit.h). + */ +enum eGraphKeys_Equalize_Mode { + GRAPHKEYS_EQUALIZE_LEFT = 1, + GRAPHKEYS_EQUALIZE_RIGHT, + GRAPHKEYS_EQUALIZE_BOTH, +}; + /* defines for mirror keyframes * NOTE: keep in sync with eEditKeyframes_Mirror (in ED_keyframes_edit.h) */ diff --git a/source/blender/editors/space_graph/graph_ops.c b/source/blender/editors/space_graph/graph_ops.c index ecafc75fc06..7606dcc60cf 100644 --- a/source/blender/editors/space_graph/graph_ops.c +++ b/source/blender/editors/space_graph/graph_ops.c @@ -456,6 +456,7 @@ void graphedit_operatortypes(void) /* editing */ WM_operatortype_append(GRAPH_OT_snap); + WM_operatortype_append(GRAPH_OT_equalize_handles); WM_operatortype_append(GRAPH_OT_mirror); WM_operatortype_append(GRAPH_OT_frame_jump); WM_operatortype_append(GRAPH_OT_snap_cursor_value); @@ -470,6 +471,8 @@ void graphedit_operatortypes(void) WM_operatortype_append(GRAPH_OT_smooth); WM_operatortype_append(GRAPH_OT_clean); WM_operatortype_append(GRAPH_OT_decimate); + WM_operatortype_append(GRAPH_OT_blend_to_neighbor); + WM_operatortype_append(GRAPH_OT_breakdown); WM_operatortype_append(GRAPH_OT_euler_filter); WM_operatortype_append(GRAPH_OT_delete); WM_operatortype_append(GRAPH_OT_duplicate); diff --git a/source/blender/editors/space_graph/graph_slider_ops.c b/source/blender/editors/space_graph/graph_slider_ops.c index 0bb5e8b8d9c..4b8c983a761 100644 --- a/source/blender/editors/space_graph/graph_slider_ops.c +++ b/source/blender/editors/space_graph/graph_slider_ops.c @@ -99,8 +99,10 @@ typedef struct tBeztCopyData { /** \name Utility Functions * \{ */ -/* Construct a list with the original bezt arrays so we can restore them during modal operation. - * The data is stored on the struct that is passed.*/ +/** + * Construct a list with the original bezt arrays so we can restore them during modal operation. + * The data is stored on the struct that is passed. + */ static void store_original_bezt_arrays(tGraphSliderOp *gso) { ListBase anim_data = {NULL, NULL}; @@ -313,8 +315,7 @@ static int graph_slider_invoke(bContext *C, wmOperator *op, const wmEvent *event ED_slider_init(gso->slider, event); if (gso->bezt_arr_list.first == NULL) { - WM_report(RPT_WARNING, - "Fcurve Slider: Can't work on baked channels. Unbake them and try again."); + WM_report(RPT_ERROR, "Cannot find keys to operate on."); graph_slider_exit(C, op); return OPERATOR_CANCELLED; } @@ -552,3 +553,256 @@ void GRAPH_OT_decimate(wmOperatorType *ot) } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Blend To Neighbor Operator + * \{ */ + +static void blend_to_neighbor_graph_keys(bAnimContext *ac, float factor) +{ + ListBase anim_data = {NULL, NULL}; + ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype); + + bAnimListElem *ale; + + /* Loop through filtered data and blend keys. */ + + for (ale = anim_data.first; ale; ale = ale->next) { + FCurve *fcu = (FCurve *)ale->key_data; + ListBase segments = find_fcurve_segments(fcu); + LISTBASE_FOREACH (FCurveSegment *, segment, &segments) { + blend_to_neighbor_fcurve_segment(fcu, segment, factor); + } + BLI_freelistN(&segments); + ale->update |= ANIM_UPDATE_DEFAULT; + } + + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); +} + +static void blend_to_neighbor_draw_status_header(bContext *C, tGraphSliderOp *gso) +{ + char status_str[UI_MAX_DRAW_STR]; + char mode_str[32]; + char slider_string[UI_MAX_DRAW_STR]; + + ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR); + + strcpy(mode_str, TIP_("Blend To Neighbor")); + + if (hasNumInput(&gso->num)) { + char str_ofs[NUM_STR_REP_LEN]; + + outputNumInput(&gso->num, str_ofs, &gso->scene->unit); + + BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs); + } + else { + BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string); + } + + ED_workspace_status_text(C, status_str); +} + +static void blend_to_neighbor_modal_update(bContext *C, wmOperator *op) +{ + tGraphSliderOp *gso = op->customdata; + + blend_to_neighbor_draw_status_header(C, gso); + + /* Reset keyframe data to the state at invoke. */ + reset_bezts(gso); + + const float factor = ED_slider_factor_get(gso->slider); + RNA_property_float_set(op->ptr, gso->factor_prop, factor); + blend_to_neighbor_graph_keys(&gso->ac, factor); + + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); +} + +static int blend_to_neighbor_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + const int invoke_result = graph_slider_invoke(C, op, event); + + if (invoke_result == OPERATOR_CANCELLED) { + return invoke_result; + } + + tGraphSliderOp *gso = op->customdata; + gso->modal_update = blend_to_neighbor_modal_update; + gso->factor_prop = RNA_struct_find_property(op->ptr, "factor"); + blend_to_neighbor_draw_status_header(C, gso); + + return invoke_result; +} + +static int blend_to_neighbor_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + + if (ANIM_animdata_get_context(C, &ac) == 0) { + return OPERATOR_CANCELLED; + } + + const float factor = RNA_float_get(op->ptr, "factor"); + + blend_to_neighbor_graph_keys(&ac, factor); + + /* Set notifier that keyframes have changed. */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +void GRAPH_OT_blend_to_neighbor(wmOperatorType *ot) +{ + /* Identifiers. */ + ot->name = "Blend To Neighbor"; + ot->idname = "GRAPH_OT_blend_to_neighbor"; + ot->description = "Blend selected keyframes to their left or right neighbor"; + + /* API callbacks. */ + ot->invoke = blend_to_neighbor_invoke; + ot->modal = graph_slider_modal; + ot->exec = blend_to_neighbor_exec; + ot->poll = graphop_editable_keyframes_poll; + + /* Flags. */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_float_factor(ot->srna, + "factor", + 1.0f / 3.0f, + -FLT_MAX, + FLT_MAX, + "Blend", + "The blend factor with 0.5 being the current frame", + 0.0f, + 1.0f); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Breakdown Operator + * \{ */ + +static void breakdown_graph_keys(bAnimContext *ac, float factor) +{ + ListBase anim_data = {NULL, NULL}; + ANIM_animdata_filter(ac, &anim_data, OPERATOR_DATA_FILTER, ac->data, ac->datatype); + + bAnimListElem *ale; + + for (ale = anim_data.first; ale; ale = ale->next) { + FCurve *fcu = (FCurve *)ale->key_data; + ListBase segments = find_fcurve_segments(fcu); + LISTBASE_FOREACH (FCurveSegment *, segment, &segments) { + breakdown_fcurve_segment(fcu, segment, factor); + } + BLI_freelistN(&segments); + ale->update |= ANIM_UPDATE_DEFAULT; + } + + ANIM_animdata_update(ac, &anim_data); + ANIM_animdata_freelist(&anim_data); +} + +static void breakdown_draw_status_header(bContext *C, tGraphSliderOp *gso) +{ + char status_str[UI_MAX_DRAW_STR]; + char mode_str[32]; + char slider_string[UI_MAX_DRAW_STR]; + + ED_slider_status_string_get(gso->slider, slider_string, UI_MAX_DRAW_STR); + + strcpy(mode_str, TIP_("Breakdown")); + + if (hasNumInput(&gso->num)) { + char str_ofs[NUM_STR_REP_LEN]; + + outputNumInput(&gso->num, str_ofs, &gso->scene->unit); + + BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs); + } + else { + BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string); + } + + ED_workspace_status_text(C, status_str); +} + +static void breakdown_modal_update(bContext *C, wmOperator *op) +{ + tGraphSliderOp *gso = op->customdata; + + breakdown_draw_status_header(C, gso); + + /* Reset keyframe data to the state at invoke. */ + reset_bezts(gso); + breakdown_graph_keys(&gso->ac, ED_slider_factor_get(gso->slider)); + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); +} + +static int breakdown_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + const int invoke_result = graph_slider_invoke(C, op, event); + + if (invoke_result == OPERATOR_CANCELLED) { + return invoke_result; + } + + tGraphSliderOp *gso = op->customdata; + gso->modal_update = breakdown_modal_update; + breakdown_draw_status_header(C, gso); + + return invoke_result; +} + +static int breakdown_exec(bContext *C, wmOperator *op) +{ + bAnimContext ac; + + if (ANIM_animdata_get_context(C, &ac) == 0) { + return OPERATOR_CANCELLED; + } + + const float factor = RNA_float_get(op->ptr, "factor"); + + breakdown_graph_keys(&ac, factor); + + /* Set notifier that keyframes have changed. */ + WM_event_add_notifier(C, NC_ANIMATION | ND_KEYFRAME | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +void GRAPH_OT_breakdown(wmOperatorType *ot) +{ + /* Identifiers. */ + ot->name = "Breakdown"; + ot->idname = "GRAPH_OT_breakdown"; + ot->description = "Move selected keyframes to an inbetween position relative to adjacent keys"; + + /* API callbacks. */ + ot->invoke = breakdown_invoke; + ot->modal = graph_slider_modal; + ot->exec = breakdown_exec; + ot->poll = graphop_editable_keyframes_poll; + + /* Flags. */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + RNA_def_float_factor(ot->srna, + "factor", + 1.0f / 3.0f, + -FLT_MAX, + FLT_MAX, + "Factor", + "Favor either the left or the right key", + 0.0f, + 1.0f); +} + +/** \} */ diff --git a/source/blender/editors/space_graph/space_graph.c b/source/blender/editors/space_graph/space_graph.c index 40c95d4f382..7d5e8836490 100644 --- a/source/blender/editors/space_graph/space_graph.c +++ b/source/blender/editors/space_graph/space_graph.c @@ -36,6 +36,7 @@ #include "BKE_context.h" #include "BKE_fcurve.h" +#include "BKE_lib_remap.h" #include "BKE_screen.h" #include "ED_anim_api.h" @@ -796,18 +797,17 @@ static void graph_refresh(const bContext *C, ScrArea *area) graph_refresh_fcurve_colors(C); } -static void graph_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id) +static void graph_id_remap(ScrArea *UNUSED(area), + SpaceLink *slink, + const struct IDRemapper *mappings) { SpaceGraph *sgraph = (SpaceGraph *)slink; - - if (sgraph->ads) { - if ((ID *)sgraph->ads->filter_grp == old_id) { - sgraph->ads->filter_grp = (Collection *)new_id; - } - if ((ID *)sgraph->ads->source == old_id) { - sgraph->ads->source = new_id; - } + if (!sgraph->ads) { + return; } + + BKE_id_remapper_apply(mappings, (ID **)&sgraph->ads->filter_grp, ID_REMAP_APPLY_DEFAULT); + BKE_id_remapper_apply(mappings, (ID **)&sgraph->ads->source, ID_REMAP_APPLY_DEFAULT); } static int graph_space_subtype_get(ScrArea *area) diff --git a/source/blender/editors/space_image/image_draw.c b/source/blender/editors/space_image/image_draw.c index ade5993cdb9..8858df3323f 100644 --- a/source/blender/editors/space_image/image_draw.c +++ b/source/blender/editors/space_image/image_draw.c @@ -591,7 +591,7 @@ float ED_space_image_zoom_level(const View2D *v2d, const int grid_dimension) * - Default grid size on startup, which is 256x256 pixels * - How blend factor for grid lines is set up in the fragment shader `grid_frag.glsl`. */ float zoom_factor; - zoom_factor = (xzoom + yzoom) / 2.0f; /* Average for accuracy. */ + zoom_factor = (xzoom + yzoom) / 2.0f; /* Average for accuracy. */ zoom_factor *= 256.0f / (powf(grid_dimension, 2)); return zoom_factor; } diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index f9160774c41..23d07c9b45b 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -1499,6 +1499,13 @@ static void image_open_draw(bContext *UNUSED(C), wmOperator *op) } } +static void image_operator_prop_allow_tokens(wmOperatorType *ot) +{ + PropertyRNA *prop = RNA_def_boolean( + ot->srna, "allow_path_tokens", true, "", "Allow the path to contain substitution tokens"); + RNA_def_property_flag(prop, PROP_HIDDEN); +} + void IMAGE_OT_open(wmOperatorType *ot) { /* identifiers */ @@ -1516,6 +1523,7 @@ void IMAGE_OT_open(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; /* properties */ + image_operator_prop_allow_tokens(ot); WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, @@ -1767,7 +1775,13 @@ static int image_save_options_init(Main *bmain, opts->im_format.views_format = ima->views_format; } - BLI_strncpy(opts->filepath, ibuf->name, sizeof(opts->filepath)); + if (ima->source == IMA_SRC_TILED) { + BLI_strncpy(opts->filepath, ima->filepath, sizeof(opts->filepath)); + BLI_path_abs(opts->filepath, ID_BLEND_PATH_FROM_GLOBAL(&ima->id)); + } + else { + BLI_strncpy(opts->filepath, ibuf->name, sizeof(opts->filepath)); + } /* sanitize all settings */ @@ -1804,14 +1818,10 @@ static int image_save_options_init(Main *bmain, BLI_path_abs(opts->filepath, is_prev_save ? G.ima : BKE_main_blendfile_path(bmain)); } - /* append UDIM numbering if not present */ - if (ima->source == IMA_SRC_TILED) { - char udim[6]; - ImageTile *tile = ima->tiles.first; - BLI_snprintf(udim, sizeof(udim), ".%d", tile->tile_number); - + /* append UDIM marker if not present */ + if (ima->source == IMA_SRC_TILED && strstr(opts->filepath, "<UDIM>") == NULL) { int len = strlen(opts->filepath); - STR_CONCAT(opts->filepath, len, udim); + STR_CONCAT(opts->filepath, len, ".<UDIM>"); } } @@ -2070,6 +2080,7 @@ void IMAGE_OT_save_as(wmOperatorType *ot) "Copy", "Create a new image file without modifying the current image in blender"); + image_operator_prop_allow_tokens(ot); WM_operator_properties_filesel(ot, FILE_TYPE_FOLDER | FILE_TYPE_IMAGE | FILE_TYPE_MOVIE, FILE_SPECIAL, @@ -2584,6 +2595,11 @@ static int image_new_exec(bContext *C, wmOperator *op) else if (sima) { ED_space_image_set(bmain, sima, ima, false); } + else { + /* #BKE_image_add_generated creates one user by default, remove it if image is not linked to + * anything. ref. T94599. */ + id_us_min(&ima->id); + } BKE_image_signal(bmain, ima, (sima) ? &sima->iuser : NULL, IMA_SIGNAL_USER_NEW_IMAGE); diff --git a/source/blender/editors/space_image/image_sequence.c b/source/blender/editors/space_image/image_sequence.c index 87bff913ff2..84b85b396fe 100644 --- a/source/blender/editors/space_image/image_sequence.c +++ b/source/blender/editors/space_image/image_sequence.c @@ -115,79 +115,17 @@ static int image_cmp_frame(const void *a, const void *b) return 0; } -/* - * Checks whether the given filepath refers to a UDIM texture. - * If yes, the range from 1001 to the highest tile is returned, otherwise 0. - * - * If the result is positive, the filepath will be overwritten with that of - * the 1001 tile. - * - * udim_tiles may get filled even if the result ultimately is false! - */ -static bool image_get_udim(char *filepath, ListBase *udim_tiles, int *udim_start, int *udim_range) -{ - char filename[FILE_MAX], dirname[FILE_MAXDIR]; - BLI_split_dirfile(filepath, dirname, filename, sizeof(dirname), sizeof(filename)); - - ushort digits; - char base_head[FILE_MAX], base_tail[FILE_MAX]; - int id = BLI_path_sequence_decode(filename, base_head, base_tail, &digits); - - if (id < 1001 || id > IMA_UDIM_MAX) { - return false; - } - - bool is_udim = true; - int min_udim = IMA_UDIM_MAX + 1; - int max_udim = 0; - - struct direntry *dir; - uint totfile = BLI_filelist_dir_contents(dirname, &dir); - for (int i = 0; i < totfile; i++) { - if (!(dir[i].type & S_IFREG)) { - continue; - } - char head[FILE_MAX], tail[FILE_MAX]; - id = BLI_path_sequence_decode(dir[i].relname, head, tail, &digits); - - if (digits > 4 || !(STREQLEN(base_head, head, FILE_MAX)) || - !(STREQLEN(base_tail, tail, FILE_MAX))) { - continue; - } - - if (id < 1001 || id > IMA_UDIM_MAX) { - is_udim = false; - break; - } - - BLI_addtail(udim_tiles, BLI_genericNodeN(POINTER_FROM_INT(id))); - min_udim = min_ii(min_udim, id); - max_udim = max_ii(max_udim, id); - } - BLI_filelist_free(dir, totfile); - - if (is_udim && min_udim <= IMA_UDIM_MAX) { - char primary_filename[FILE_MAX]; - BLI_path_sequence_encode(primary_filename, base_head, base_tail, digits, min_udim); - BLI_join_dirfile(filepath, FILE_MAX, dirname, primary_filename); - - *udim_start = min_udim; - *udim_range = max_udim - min_udim + 1; - return true; - } - return false; -} - /** * From a list of frames, compute the start (offset) and length of the sequence - * of contiguous frames. If UDIM is detect, it will return UDIM tiles as well. + * of contiguous frames. If `detect_udim` is set, it will return UDIM tiles as well. */ static void image_detect_frame_range(ImageFrameRange *range, const bool detect_udim) { /* UDIM */ if (detect_udim) { int udim_start, udim_range; - bool result = image_get_udim(range->filepath, &range->udim_tiles, &udim_start, &udim_range); + bool result = BKE_image_get_tile_info( + range->filepath, &range->udim_tiles, &udim_start, &udim_range); if (result) { range->offset = udim_start; diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c index dad494e6984..eb5b6104a79 100644 --- a/source/blender/editors/space_image/space_image.c +++ b/source/blender/editors/space_image/space_image.c @@ -37,6 +37,7 @@ #include "BKE_context.h" #include "BKE_image.h" #include "BKE_lib_id.h" +#include "BKE_lib_remap.h" #include "BKE_screen.h" #include "RNA_access.h" @@ -297,7 +298,7 @@ static void image_refresh(const bContext *C, ScrArea *area) ima = ED_space_image(sima); BKE_image_user_frame_calc(ima, &sima->iuser, scene->r.cfra); - /* check if we have to set the image from the editmesh */ + /* Check if we have to set the image from the edit-mesh. */ if (ima && (ima->source == IMA_SRC_VIEWER && sima->mode == SI_MODE_MASK)) { if (scene->nodetree) { Mask *mask = ED_space_image_get_mask(sima); @@ -983,29 +984,19 @@ static void image_header_region_listener(const wmRegionListenerParams *params) } } -static void image_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id) +static void image_id_remap(ScrArea *UNUSED(area), + SpaceLink *slink, + const struct IDRemapper *mappings) { SpaceImage *simg = (SpaceImage *)slink; - if (!ELEM(GS(old_id->name), ID_IM, ID_GD, ID_MSK)) { + if (!BKE_id_remapper_has_mapping_for(mappings, FILTER_ID_IM | FILTER_ID_GD | FILTER_ID_MSK)) { return; } - if ((ID *)simg->image == old_id) { - simg->image = (Image *)new_id; - id_us_ensure_real(new_id); - } - - if ((ID *)simg->gpd == old_id) { - simg->gpd = (bGPdata *)new_id; - id_us_min(old_id); - id_us_plus(new_id); - } - - if ((ID *)simg->mask_info.mask == old_id) { - simg->mask_info.mask = (Mask *)new_id; - id_us_ensure_real(new_id); - } + BKE_id_remapper_apply(mappings, (ID **)&simg->image, ID_REMAP_APPLY_ENSURE_REAL); + BKE_id_remapper_apply(mappings, (ID **)&simg->gpd, ID_REMAP_APPLY_UPDATE_REFCOUNT); + BKE_id_remapper_apply(mappings, (ID **)&simg->mask_info.mask, ID_REMAP_APPLY_ENSURE_REAL); } /** diff --git a/source/blender/editors/space_info/info_ops.c b/source/blender/editors/space_info/info_ops.c index 8e37e5fe9a8..2a797fd1a78 100644 --- a/source/blender/editors/space_info/info_ops.c +++ b/source/blender/editors/space_info/info_ops.c @@ -408,13 +408,14 @@ void FILE_OT_unpack_item(wmOperatorType *ot) static int make_paths_relative_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); + const char *blendfile_path = BKE_main_blendfile_path(bmain); - if (!G.relbase_valid) { + if (blendfile_path[0] == '\0') { BKE_report(op->reports, RPT_WARNING, "Cannot set relative paths with an unsaved blend file"); return OPERATOR_CANCELLED; } - BKE_bpath_relative_convert(bmain, BKE_main_blendfile_path(bmain), op->reports); + BKE_bpath_relative_convert(bmain, blendfile_path, op->reports); /* redraw everything so any changed paths register */ WM_main_add_notifier(NC_WINDOW, NULL); @@ -445,13 +446,14 @@ void FILE_OT_make_paths_relative(wmOperatorType *ot) static int make_paths_absolute_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); + const char *blendfile_path = BKE_main_blendfile_path(bmain); - if (!G.relbase_valid) { + if (blendfile_path[0] == '\0') { BKE_report(op->reports, RPT_WARNING, "Cannot set absolute paths with an unsaved blend file"); return OPERATOR_CANCELLED; } - BKE_bpath_absolute_convert(bmain, BKE_main_blendfile_path(bmain), op->reports); + BKE_bpath_absolute_convert(bmain, blendfile_path, op->reports); /* redraw everything so any changed paths register */ WM_main_add_notifier(NC_WINDOW, NULL); diff --git a/source/blender/editors/space_info/info_stats.cc b/source/blender/editors/space_info/info_stats.cc index bcf26743030..005ae0214cd 100644 --- a/source/blender/editors/space_info/info_stats.cc +++ b/source/blender/editors/space_info/info_stats.cc @@ -43,6 +43,7 @@ #include "BLT_translation.h" +#include "BKE_action.h" #include "BKE_armature.h" #include "BKE_blender_version.h" #include "BKE_context.h" @@ -351,7 +352,7 @@ static void stats_object_pose(const Object *ob, SceneStats *stats) LISTBASE_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) { stats->totbone++; if (pchan->bone && (pchan->bone->flag & BONE_SELECTED)) { - if (pchan->bone->layer & arm->layer) { + if (BKE_pose_is_layer_visible(arm, pchan)) { stats->totbonesel++; } } diff --git a/source/blender/editors/space_info/textview.h b/source/blender/editors/space_info/textview.h index 96f537b4b97..38c073a328a 100644 --- a/source/blender/editors/space_info/textview.h +++ b/source/blender/editors/space_info/textview.h @@ -81,7 +81,7 @@ typedef struct TextViewContext { * Use for selection. */ int textview_draw(struct TextViewContext *tvc, - const bool do_draw, + bool do_draw, const int mval_init[2], void **r_mval_pick_item, int *r_mval_pick_offset); diff --git a/source/blender/editors/space_nla/nla_draw.c b/source/blender/editors/space_nla/nla_draw.c index 12f0011b499..7dfe0e89e90 100644 --- a/source/blender/editors/space_nla/nla_draw.c +++ b/source/blender/editors/space_nla/nla_draw.c @@ -324,7 +324,7 @@ static void nla_draw_strip_curves(NlaStrip *strip, float yminc, float ymaxc, uin GPU_line_smooth(true); GPU_blend(GPU_BLEND_ALPHA); - /* Fully opaque line on selected strips. */ + /* Fully opaque line on selected strips. */ if (strip->flag & NLASTRIP_FLAG_SELECT) { /* TODO: Use theme setting. */ immUniformColor3f(1.0f, 1.0f, 1.0f); diff --git a/source/blender/editors/space_nla/space_nla.c b/source/blender/editors/space_nla/space_nla.c index 0771153c5f5..962b5151661 100644 --- a/source/blender/editors/space_nla/space_nla.c +++ b/source/blender/editors/space_nla/space_nla.c @@ -33,6 +33,7 @@ #include "BLI_utildefines.h" #include "BKE_context.h" +#include "BKE_lib_remap.h" #include "BKE_screen.h" #include "ED_anim_api.h" @@ -577,18 +578,17 @@ static void nla_listener(const wmSpaceTypeListenerParams *params) } } -static void nla_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id) +static void nla_id_remap(ScrArea *UNUSED(area), + SpaceLink *slink, + const struct IDRemapper *mappings) { SpaceNla *snla = (SpaceNla *)slink; - if (snla->ads) { - if ((ID *)snla->ads->filter_grp == old_id) { - snla->ads->filter_grp = (Collection *)new_id; - } - if ((ID *)snla->ads->source == old_id) { - snla->ads->source = new_id; - } + if (snla->ads == NULL) { + return; } + BKE_id_remapper_apply(mappings, (ID **)&snla->ads->filter_grp, ID_REMAP_APPLY_DEFAULT); + BKE_id_remapper_apply(mappings, (ID **)&snla->ads->source, ID_REMAP_APPLY_DEFAULT); } void ED_spacetype_nla(void) diff --git a/source/blender/editors/space_node/CMakeLists.txt b/source/blender/editors/space_node/CMakeLists.txt index e88d61fe880..41d6388c947 100644 --- a/source/blender/editors/space_node/CMakeLists.txt +++ b/source/blender/editors/space_node/CMakeLists.txt @@ -39,6 +39,7 @@ set(INC set(SRC drawnode.cc + link_drag_search.cc node_add.cc node_context_path.cc node_draw.cc @@ -50,7 +51,6 @@ set(SRC node_relationships.cc node_select.cc node_templates.cc - node_toolbar.cc node_view.cc space_node.cc diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc index 87f7bfdafb0..94da7d55e5d 100644 --- a/source/blender/editors/space_node/drawnode.cc +++ b/source/blender/editors/space_node/drawnode.cc @@ -36,6 +36,7 @@ #include "BKE_image.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BKE_node_tree_update.h" #include "BKE_scene.h" #include "BKE_tracking.h" @@ -50,7 +51,9 @@ #include "GPU_immediate.h" #include "GPU_matrix.h" #include "GPU_platform.h" +#include "GPU_shader_shared.h" #include "GPU_state.h" +#include "GPU_uniform_buffer.h" #include "DRW_engine.h" @@ -76,7 +79,7 @@ #include "NOD_texture.h" #include "node_intern.hh" /* own include */ -using blender::float2; +namespace blender::ed::space_node { /* Default flags for uiItemR(). Name is kept short since this is used a lot in this file. */ #define DEFAULT_FLAGS UI_ITEM_R_SPLIT_EMPTY_NAME @@ -135,24 +138,11 @@ static void node_buts_mix_rgb(uiLayout *layout, bContext *UNUSED(C), PointerRNA static void node_buts_time(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { -#if 0 - /* XXX no context access here. */ - bNode *node = (bNode*)ptr->data; - CurveMapping *cumap = node->storage; - - if (cumap) { - cumap->flag |= CUMA_DRAW_CFRA; - if (node->custom1 < node->custom2) { - cumap->sample[0] = (float)(CFRA - node->custom1) / (float)(node->custom2 - node->custom1); - } - } -#endif - uiTemplateCurveMapping(layout, ptr, "curve", 's', false, false, false, false); - uiLayout *row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "frame_start", DEFAULT_FLAGS, IFACE_("Start"), ICON_NONE); - uiItemR(row, ptr, "frame_end", DEFAULT_FLAGS, IFACE_("End"), ICON_NONE); + uiLayout *col = uiLayoutColumn(layout, true); + uiItemR(col, ptr, "frame_start", DEFAULT_FLAGS, IFACE_("Start"), ICON_NONE); + uiItemR(col, ptr, "frame_end", DEFAULT_FLAGS, IFACE_("End"), ICON_NONE); } static void node_buts_colorramp(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -170,6 +160,8 @@ static void node_buts_curvefloat(uiLayout *layout, bContext *UNUSED(C), PointerR uiTemplateCurveMapping(layout, ptr, "mapping", 0, false, false, false, false); } +} // namespace blender::ed::space_node + #define SAMPLE_FLT_ISNONE FLT_MAX /* Bad bad, 2.5 will do better? ... no it won't! */ static float _sample_col[4] = {SAMPLE_FLT_ISNONE}; @@ -183,6 +175,8 @@ void ED_node_sample_set(const float col[4]) } } +namespace blender::ed::space_node { + static void node_buts_curvecol(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { bNode *node = (bNode *)ptr->data; @@ -228,22 +222,6 @@ static void node_buts_texture(uiLayout *layout, bContext *UNUSED(C), PointerRNA } } -static void node_shader_buts_clamp(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "clamp_type", DEFAULT_FLAGS, "", ICON_NONE); -} - -static void node_shader_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE); - uiItemR(layout, ptr, "interpolation_type", DEFAULT_FLAGS, "", ICON_NONE); - if (!ELEM(RNA_enum_get(ptr, "interpolation_type"), - NODE_MAP_RANGE_SMOOTHSTEP, - NODE_MAP_RANGE_SMOOTHERSTEP)) { - uiItemR(layout, ptr, "clamp", DEFAULT_FLAGS, nullptr, ICON_NONE); - } -} - static void node_buts_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE); @@ -392,40 +370,6 @@ static void node_buts_image_user(uiLayout *layout, } } -static void node_shader_buts_mapping(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "vector_type", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_shader_buts_vector_rotate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "rotation_type", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "invert", DEFAULT_FLAGS, nullptr, 0); -} - -static void node_shader_buts_vect_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE); -} - -static void node_shader_buts_vect_transform(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "vector_type", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE); - uiItemR(layout, ptr, "convert_from", DEFAULT_FLAGS, "", ICON_NONE); - uiItemR(layout, ptr, "convert_to", DEFAULT_FLAGS, "", ICON_NONE); -} - -static void node_shader_buts_attribute(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "attribute_type", DEFAULT_FLAGS, IFACE_("Type"), ICON_NONE); - uiItemR(layout, ptr, "attribute_name", DEFAULT_FLAGS, IFACE_("Name"), ICON_NONE); -} - -static void node_shader_buts_wireframe(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "use_pixel_size", DEFAULT_FLAGS, nullptr, 0); -} - static void node_shader_buts_tex_image(uiLayout *layout, bContext *C, PointerRNA *ptr) { PointerRNA imaptr = RNA_pointer_get(ptr, "image"); @@ -495,375 +439,21 @@ static void node_shader_buts_tex_environment_ex(uiLayout *layout, bContext *C, P uiItemR(layout, ptr, "projection", DEFAULT_FLAGS, IFACE_("Projection"), ICON_NONE); } -static void node_shader_buts_tex_sky(uiLayout *layout, bContext *C, PointerRNA *ptr) -{ - uiItemR(layout, ptr, "sky_type", DEFAULT_FLAGS, "", ICON_NONE); - - if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_PREETHAM) { - uiItemR(layout, ptr, "sun_direction", DEFAULT_FLAGS, "", ICON_NONE); - uiItemR(layout, ptr, "turbidity", DEFAULT_FLAGS, nullptr, ICON_NONE); - } - if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_HOSEK) { - uiItemR(layout, ptr, "sun_direction", DEFAULT_FLAGS, "", ICON_NONE); - uiItemR(layout, ptr, "turbidity", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "ground_albedo", DEFAULT_FLAGS, nullptr, ICON_NONE); - } - if (RNA_enum_get(ptr, "sky_type") == SHD_SKY_NISHITA) { - Scene *scene = CTX_data_scene(C); - if (BKE_scene_uses_blender_eevee(scene)) { - uiItemL(layout, TIP_("Nishita not available in Eevee"), ICON_ERROR); - } - uiItemR(layout, ptr, "sun_disc", DEFAULT_FLAGS, nullptr, 0); - - uiLayout *col; - if (RNA_boolean_get(ptr, "sun_disc")) { - col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "sun_size", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(col, ptr, "sun_intensity", DEFAULT_FLAGS, nullptr, ICON_NONE); - } - - col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "sun_elevation", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(col, ptr, "sun_rotation", DEFAULT_FLAGS, nullptr, ICON_NONE); - - uiItemR(layout, ptr, "altitude", DEFAULT_FLAGS, nullptr, ICON_NONE); - - col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "air_density", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(col, ptr, "dust_density", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(col, ptr, "ozone_density", DEFAULT_FLAGS, nullptr, ICON_NONE); - } -} - -static void node_shader_buts_tex_gradient(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "gradient_type", DEFAULT_FLAGS, "", ICON_NONE); -} - -static void node_shader_buts_tex_magic(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "turbulence_depth", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_shader_buts_tex_brick(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiLayout *col; - - col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "offset", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, IFACE_("Offset"), ICON_NONE); - uiItemR(col, ptr, "offset_frequency", DEFAULT_FLAGS, IFACE_("Frequency"), ICON_NONE); - - col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "squash", DEFAULT_FLAGS, IFACE_("Squash"), ICON_NONE); - uiItemR(col, ptr, "squash_frequency", DEFAULT_FLAGS, IFACE_("Frequency"), ICON_NONE); -} - -static void node_shader_buts_tex_wave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "wave_type", DEFAULT_FLAGS, "", ICON_NONE); - int type = RNA_enum_get(ptr, "wave_type"); - if (type == SHD_WAVE_BANDS) { - uiItemR(layout, ptr, "bands_direction", DEFAULT_FLAGS, "", ICON_NONE); - } - else { /* SHD_WAVE_RINGS */ - uiItemR(layout, ptr, "rings_direction", DEFAULT_FLAGS, "", ICON_NONE); - } - - uiItemR(layout, ptr, "wave_profile", DEFAULT_FLAGS, "", ICON_NONE); -} - -static void node_shader_buts_tex_musgrave(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "musgrave_dimensions", DEFAULT_FLAGS, "", ICON_NONE); - uiItemR(layout, ptr, "musgrave_type", DEFAULT_FLAGS, "", ICON_NONE); -} - -static void node_shader_buts_tex_voronoi(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "voronoi_dimensions", DEFAULT_FLAGS, "", ICON_NONE); - uiItemR(layout, ptr, "feature", DEFAULT_FLAGS, "", ICON_NONE); - int feature = RNA_enum_get(ptr, "feature"); - if (!ELEM(feature, SHD_VORONOI_DISTANCE_TO_EDGE, SHD_VORONOI_N_SPHERE_RADIUS) && - RNA_enum_get(ptr, "voronoi_dimensions") != 1) { - uiItemR(layout, ptr, "distance", DEFAULT_FLAGS, "", ICON_NONE); - } -} - -static void node_shader_buts_tex_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "noise_dimensions", DEFAULT_FLAGS, "", ICON_NONE); -} - -static void node_shader_buts_tex_pointdensity(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) -{ - bNode *node = (bNode *)ptr->data; - NodeShaderTexPointDensity *shader_point_density = (NodeShaderTexPointDensity *)node->storage; - Object *ob = (Object *)node->id; - - PointerRNA ob_ptr, obdata_ptr; - RNA_id_pointer_create((ID *)ob, &ob_ptr); - RNA_id_pointer_create(ob ? (ID *)ob->data : nullptr, &obdata_ptr); - - uiItemR(layout, ptr, "point_source", UI_ITEM_R_EXPAND, nullptr, ICON_NONE); - uiItemR(layout, ptr, "object", DEFAULT_FLAGS, nullptr, ICON_NONE); - - if (node->id && shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) { - PointerRNA dataptr; - RNA_id_pointer_create((ID *)node->id, &dataptr); - uiItemPointerR( - layout, ptr, "particle_system", &dataptr, "particle_systems", nullptr, ICON_NONE); - } - - uiItemR(layout, ptr, "space", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "radius", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "interpolation", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "resolution", DEFAULT_FLAGS, nullptr, ICON_NONE); - if (shader_point_density->point_source == SHD_POINTDENSITY_SOURCE_PSYS) { - uiItemR(layout, ptr, "particle_color_source", DEFAULT_FLAGS, nullptr, ICON_NONE); - } - else { - uiItemR(layout, ptr, "vertex_color_source", DEFAULT_FLAGS, nullptr, ICON_NONE); - if (shader_point_density->ob_color_source == SHD_POINTDENSITY_COLOR_VERTWEIGHT) { - if (ob_ptr.data) { - uiItemPointerR( - layout, ptr, "vertex_attribute_name", &ob_ptr, "vertex_groups", "", ICON_NONE); - } - } - if (shader_point_density->ob_color_source == SHD_POINTDENSITY_COLOR_VERTCOL) { - if (obdata_ptr.data) { - uiItemPointerR( - layout, ptr, "vertex_attribute_name", &obdata_ptr, "vertex_colors", "", ICON_NONE); - } - } - } -} - -static void node_shader_buts_tex_coord(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "object", DEFAULT_FLAGS, nullptr, 0); - uiItemR(layout, ptr, "from_instancer", DEFAULT_FLAGS, nullptr, 0); -} - -static void node_shader_buts_bump(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "invert", DEFAULT_FLAGS, nullptr, 0); -} - -static void node_shader_buts_uvmap(uiLayout *layout, bContext *C, PointerRNA *ptr) -{ - uiItemR(layout, ptr, "from_instancer", DEFAULT_FLAGS, nullptr, 0); - - if (!RNA_boolean_get(ptr, "from_instancer")) { - PointerRNA obptr = CTX_data_pointer_get(C, "active_object"); - - if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) { - PointerRNA dataptr = RNA_pointer_get(&obptr, "data"); - uiItemPointerR(layout, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE); - } - } -} - -static void node_shader_buts_vertex_color(uiLayout *layout, bContext *C, PointerRNA *ptr) -{ - PointerRNA obptr = CTX_data_pointer_get(C, "active_object"); - if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) { - PointerRNA dataptr = RNA_pointer_get(&obptr, "data"); - - if (U.experimental.use_sculpt_vertex_colors && - RNA_collection_length(&dataptr, "sculpt_vertex_colors")) { - uiItemPointerR( - layout, ptr, "layer_name", &dataptr, "sculpt_vertex_colors", "", ICON_GROUP_VCOL); - } - else { - uiItemPointerR(layout, ptr, "layer_name", &dataptr, "vertex_colors", "", ICON_GROUP_VCOL); - } - } - else { - uiItemL(layout, TIP_("No mesh in active object"), ICON_ERROR); - } -} - -static void node_shader_buts_uvalongstroke(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "use_tips", DEFAULT_FLAGS, nullptr, 0); -} - -static void node_shader_buts_normal_map(uiLayout *layout, bContext *C, PointerRNA *ptr) -{ - uiItemR(layout, ptr, "space", DEFAULT_FLAGS, "", 0); - - if (RNA_enum_get(ptr, "space") == SHD_SPACE_TANGENT) { - PointerRNA obptr = CTX_data_pointer_get(C, "active_object"); - - if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) { - PointerRNA dataptr = RNA_pointer_get(&obptr, "data"); - uiItemPointerR(layout, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE); - } - else { - uiItemR(layout, ptr, "uv_map", DEFAULT_FLAGS, "", 0); - } - } -} - static void node_shader_buts_displacement(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "space", DEFAULT_FLAGS, "", 0); } -static void node_shader_buts_tangent(uiLayout *layout, bContext *C, PointerRNA *ptr) -{ - uiLayout *split, *row; - - split = uiLayoutSplit(layout, 0.0f, false); - - uiItemR(split, ptr, "direction_type", DEFAULT_FLAGS, "", 0); - - row = uiLayoutRow(split, false); - - if (RNA_enum_get(ptr, "direction_type") == SHD_TANGENT_UVMAP) { - PointerRNA obptr = CTX_data_pointer_get(C, "active_object"); - - if (obptr.data && RNA_enum_get(&obptr, "type") == OB_MESH) { - PointerRNA dataptr = RNA_pointer_get(&obptr, "data"); - uiItemPointerR(row, ptr, "uv_map", &dataptr, "uv_layers", "", ICON_NONE); - } - else { - uiItemR(row, ptr, "uv_map", DEFAULT_FLAGS, "", 0); - } - } - else { - uiItemR(row, ptr, "axis", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, 0); - } -} - static void node_shader_buts_glossy(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "distribution", DEFAULT_FLAGS, "", ICON_NONE); } -static void node_shader_buts_principled(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "distribution", DEFAULT_FLAGS, "", ICON_NONE); - uiItemR(layout, ptr, "subsurface_method", DEFAULT_FLAGS, "", ICON_NONE); -} - -static void node_shader_buts_anisotropic(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "distribution", DEFAULT_FLAGS, "", ICON_NONE); -} - -static void node_shader_buts_subsurface(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "falloff", DEFAULT_FLAGS, "", ICON_NONE); -} - -static void node_shader_buts_toon(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "component", DEFAULT_FLAGS, "", ICON_NONE); -} - -static void node_shader_buts_hair(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "component", DEFAULT_FLAGS, "", ICON_NONE); -} - -static void node_shader_buts_principled_hair(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) -{ - uiItemR(layout, ptr, "parametrization", DEFAULT_FLAGS, "", ICON_NONE); -} - -static void node_shader_buts_ies(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiLayout *row; - - row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "mode", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE); - - row = uiLayoutRow(layout, true); - - if (RNA_enum_get(ptr, "mode") == NODE_IES_INTERNAL) { - uiItemR(row, ptr, "ies", DEFAULT_FLAGS, "", ICON_NONE); - } - else { - uiItemR(row, ptr, "filepath", DEFAULT_FLAGS, "", ICON_NONE); - } -} - -static void node_shader_buts_script(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiLayout *row; - - row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "mode", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE); - - row = uiLayoutRow(layout, true); - - if (RNA_enum_get(ptr, "mode") == NODE_SCRIPT_INTERNAL) { - uiItemR(row, ptr, "script", DEFAULT_FLAGS, "", ICON_NONE); - } - else { - uiItemR(row, ptr, "filepath", DEFAULT_FLAGS, "", ICON_NONE); - } - - uiItemO(row, "", ICON_FILE_REFRESH, "node.shader_script_update"); -} - -static void node_shader_buts_script_ex(uiLayout *layout, bContext *C, PointerRNA *ptr) -{ - uiItemS(layout); - - node_shader_buts_script(layout, C, ptr); - -#if 0 /* not implemented yet */ - if (RNA_enum_get(ptr, "mode") == NODE_SCRIPT_EXTERNAL) { - uiItemR(layout, ptr, "use_auto_update", DEFAULT_FLAGS, nullptr, ICON_NONE); - } -#endif -} - static void node_buts_output_shader(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { uiItemR(layout, ptr, "target", DEFAULT_FLAGS, "", ICON_NONE); } -static void node_buts_output_linestyle(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiLayout *row, *col; - - col = uiLayoutColumn(layout, false); - row = uiLayoutRow(col, true); - uiItemR(row, ptr, "blend_type", DEFAULT_FLAGS, "", ICON_NONE); - uiItemR(col, ptr, "use_clamp", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_shader_buts_bevel(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "samples", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_shader_buts_ambient_occlusion(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) -{ - uiItemR(layout, ptr, "samples", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "inside", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "only_local", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_shader_buts_white_noise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "noise_dimensions", DEFAULT_FLAGS, "", ICON_NONE); -} - -static void node_shader_buts_output_aov(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "name", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - /* only once called */ static void node_shader_set_butfunc(bNodeType *ntype) { @@ -880,9 +470,6 @@ static void node_shader_set_butfunc(bNodeType *ntype) case SH_NODE_CURVE_FLOAT: ntype->draw_buttons = node_buts_curvefloat; break; - case SH_NODE_MAPPING: - ntype->draw_buttons = node_shader_buts_mapping; - break; case SH_NODE_VALUE: ntype->draw_buttons = node_buts_value; break; @@ -895,33 +482,9 @@ static void node_shader_set_butfunc(bNodeType *ntype) case SH_NODE_VALTORGB: ntype->draw_buttons = node_buts_colorramp; break; - case SH_NODE_CLAMP: - ntype->draw_buttons = node_shader_buts_clamp; - break; - case SH_NODE_MAP_RANGE: - ntype->draw_buttons = node_shader_buts_map_range; - break; case SH_NODE_MATH: ntype->draw_buttons = node_buts_math; break; - case SH_NODE_VECTOR_MATH: - ntype->draw_buttons = node_shader_buts_vect_math; - break; - case SH_NODE_VECTOR_ROTATE: - ntype->draw_buttons = node_shader_buts_vector_rotate; - break; - case SH_NODE_VECT_TRANSFORM: - ntype->draw_buttons = node_shader_buts_vect_transform; - break; - case SH_NODE_ATTRIBUTE: - ntype->draw_buttons = node_shader_buts_attribute; - break; - case SH_NODE_WIREFRAME: - ntype->draw_buttons = node_shader_buts_wireframe; - break; - case SH_NODE_TEX_SKY: - ntype->draw_buttons = node_shader_buts_tex_sky; - break; case SH_NODE_TEX_IMAGE: ntype->draw_buttons = node_shader_buts_tex_image; ntype->draw_buttons_ex = node_shader_buts_tex_image_ex; @@ -930,105 +493,20 @@ static void node_shader_set_butfunc(bNodeType *ntype) ntype->draw_buttons = node_shader_buts_tex_environment; ntype->draw_buttons_ex = node_shader_buts_tex_environment_ex; break; - case SH_NODE_TEX_GRADIENT: - ntype->draw_buttons = node_shader_buts_tex_gradient; - break; - case SH_NODE_TEX_MAGIC: - ntype->draw_buttons = node_shader_buts_tex_magic; - break; - case SH_NODE_TEX_BRICK: - ntype->draw_buttons = node_shader_buts_tex_brick; - break; - case SH_NODE_TEX_WAVE: - ntype->draw_buttons = node_shader_buts_tex_wave; - break; - case SH_NODE_TEX_MUSGRAVE: - ntype->draw_buttons = node_shader_buts_tex_musgrave; - break; - case SH_NODE_TEX_VORONOI: - ntype->draw_buttons = node_shader_buts_tex_voronoi; - break; - case SH_NODE_TEX_NOISE: - ntype->draw_buttons = node_shader_buts_tex_noise; - break; - case SH_NODE_TEX_POINTDENSITY: - ntype->draw_buttons = node_shader_buts_tex_pointdensity; - break; - case SH_NODE_TEX_COORD: - ntype->draw_buttons = node_shader_buts_tex_coord; - break; - case SH_NODE_BUMP: - ntype->draw_buttons = node_shader_buts_bump; - break; - case SH_NODE_NORMAL_MAP: - ntype->draw_buttons = node_shader_buts_normal_map; - break; case SH_NODE_DISPLACEMENT: case SH_NODE_VECTOR_DISPLACEMENT: ntype->draw_buttons = node_shader_buts_displacement; break; - case SH_NODE_TANGENT: - ntype->draw_buttons = node_shader_buts_tangent; - break; case SH_NODE_BSDF_GLOSSY: case SH_NODE_BSDF_GLASS: case SH_NODE_BSDF_REFRACTION: ntype->draw_buttons = node_shader_buts_glossy; break; - case SH_NODE_BSDF_PRINCIPLED: - ntype->draw_buttons = node_shader_buts_principled; - break; - case SH_NODE_BSDF_ANISOTROPIC: - ntype->draw_buttons = node_shader_buts_anisotropic; - break; - case SH_NODE_SUBSURFACE_SCATTERING: - ntype->draw_buttons = node_shader_buts_subsurface; - break; - case SH_NODE_BSDF_TOON: - ntype->draw_buttons = node_shader_buts_toon; - break; - case SH_NODE_BSDF_HAIR: - ntype->draw_buttons = node_shader_buts_hair; - break; - case SH_NODE_BSDF_HAIR_PRINCIPLED: - ntype->draw_buttons = node_shader_buts_principled_hair; - break; - case SH_NODE_SCRIPT: - ntype->draw_buttons = node_shader_buts_script; - ntype->draw_buttons_ex = node_shader_buts_script_ex; - break; - case SH_NODE_UVMAP: - ntype->draw_buttons = node_shader_buts_uvmap; - break; - case SH_NODE_VERTEX_COLOR: - ntype->draw_buttons = node_shader_buts_vertex_color; - break; - case SH_NODE_UVALONGSTROKE: - ntype->draw_buttons = node_shader_buts_uvalongstroke; - break; case SH_NODE_OUTPUT_MATERIAL: case SH_NODE_OUTPUT_LIGHT: case SH_NODE_OUTPUT_WORLD: ntype->draw_buttons = node_buts_output_shader; break; - case SH_NODE_OUTPUT_LINESTYLE: - ntype->draw_buttons = node_buts_output_linestyle; - break; - case SH_NODE_TEX_IES: - ntype->draw_buttons = node_shader_buts_ies; - break; - case SH_NODE_BEVEL: - ntype->draw_buttons = node_shader_buts_bevel; - break; - case SH_NODE_AMBIENT_OCCLUSION: - ntype->draw_buttons = node_shader_buts_ambient_occlusion; - break; - case SH_NODE_TEX_WHITE_NOISE: - ntype->draw_buttons = node_shader_buts_white_noise; - break; - case SH_NODE_OUTPUT_AOV: - ntype->draw_buttons = node_shader_buts_output_aov; - break; } } @@ -1095,763 +573,6 @@ static void node_composit_buts_image_ex(uiLayout *layout, bContext *C, PointerRN uiTemplateImage(layout, C, ptr, "image", &iuserptr, false, true); } -static void node_composit_buts_viewlayers(uiLayout *layout, bContext *C, PointerRNA *ptr) -{ - bNode *node = (bNode *)ptr->data; - uiLayout *col, *row; - - uiTemplateID(layout, - C, - ptr, - "scene", - nullptr, - nullptr, - nullptr, - UI_TEMPLATE_ID_FILTER_ALL, - false, - nullptr); - - if (!node->id) { - return; - } - - col = uiLayoutColumn(layout, false); - row = uiLayoutRow(col, true); - uiItemR(row, ptr, "layer", DEFAULT_FLAGS, "", ICON_NONE); - - PropertyRNA *prop = RNA_struct_find_property(ptr, "layer"); - const char *layer_name; - if (!(RNA_property_enum_identifier( - C, ptr, prop, RNA_property_enum_get(ptr, prop), &layer_name))) { - return; - } - - PointerRNA scn_ptr; - char scene_name[MAX_ID_NAME - 2]; - scn_ptr = RNA_pointer_get(ptr, "scene"); - RNA_string_get(&scn_ptr, "name", scene_name); - - PointerRNA op_ptr; - uiItemFullO( - row, "RENDER_OT_render", "", ICON_RENDER_STILL, nullptr, WM_OP_INVOKE_DEFAULT, 0, &op_ptr); - RNA_string_set(&op_ptr, "layer", layer_name); - RNA_string_set(&op_ptr, "scene", scene_name); -} - -static void node_composit_buts_blur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiLayout *col, *row; - - col = uiLayoutColumn(layout, false); - const int filter = RNA_enum_get(ptr, "filter_type"); - const int reference = RNA_boolean_get(ptr, "use_variable_size"); - - uiItemR(col, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE); - if (filter != R_FILTER_FAST_GAUSS) { - uiItemR(col, ptr, "use_variable_size", DEFAULT_FLAGS, nullptr, ICON_NONE); - if (!reference) { - uiItemR(col, ptr, "use_bokeh", DEFAULT_FLAGS, nullptr, ICON_NONE); - } - uiItemR(col, ptr, "use_gamma_correction", DEFAULT_FLAGS, nullptr, ICON_NONE); - } - - uiItemR(col, ptr, "use_relative", DEFAULT_FLAGS, nullptr, ICON_NONE); - - if (RNA_boolean_get(ptr, "use_relative")) { - uiItemL(col, IFACE_("Aspect Correction"), ICON_NONE); - row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "aspect_correction", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE); - - col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "factor_x", DEFAULT_FLAGS, IFACE_("X"), ICON_NONE); - uiItemR(col, ptr, "factor_y", DEFAULT_FLAGS, IFACE_("Y"), ICON_NONE); - } - else { - col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "size_x", DEFAULT_FLAGS, IFACE_("X"), ICON_NONE); - uiItemR(col, ptr, "size_y", DEFAULT_FLAGS, IFACE_("Y"), ICON_NONE); - } - uiItemR(col, ptr, "use_extended_bounds", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_composit_buts_dblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiLayout *col; - - uiItemR(layout, ptr, "iterations", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "use_wrap", DEFAULT_FLAGS, nullptr, ICON_NONE); - - col = uiLayoutColumn(layout, true); - uiItemL(col, IFACE_("Center:"), ICON_NONE); - uiItemR(col, ptr, "center_x", DEFAULT_FLAGS, IFACE_("X"), ICON_NONE); - uiItemR(col, ptr, "center_y", DEFAULT_FLAGS, IFACE_("Y"), ICON_NONE); - - uiItemS(layout); - - col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "distance", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(col, ptr, "angle", DEFAULT_FLAGS, nullptr, ICON_NONE); - - uiItemS(layout); - - uiItemR(layout, ptr, "spin", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "zoom", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_composit_buts_bilateralblur(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) -{ - uiLayout *col; - - col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "iterations", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(col, ptr, "sigma_color", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(col, ptr, "sigma_space", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_composit_buts_defocus(uiLayout *layout, bContext *C, PointerRNA *ptr) -{ - uiLayout *sub, *col; - - col = uiLayoutColumn(layout, false); - uiItemL(col, IFACE_("Bokeh Type:"), ICON_NONE); - uiItemR(col, ptr, "bokeh", DEFAULT_FLAGS, "", ICON_NONE); - uiItemR(col, ptr, "angle", DEFAULT_FLAGS, nullptr, ICON_NONE); - - uiItemR(layout, ptr, "use_gamma_correction", DEFAULT_FLAGS, nullptr, ICON_NONE); - - col = uiLayoutColumn(layout, false); - uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_zbuffer") == true); - uiItemR(col, ptr, "f_stop", DEFAULT_FLAGS, nullptr, ICON_NONE); - - uiItemR(layout, ptr, "blur_max", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "threshold", DEFAULT_FLAGS, nullptr, ICON_NONE); - - col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "use_preview", DEFAULT_FLAGS, nullptr, ICON_NONE); - - uiTemplateID(layout, - C, - ptr, - "scene", - nullptr, - nullptr, - nullptr, - UI_TEMPLATE_ID_FILTER_ALL, - false, - nullptr); - - col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "use_zbuffer", DEFAULT_FLAGS, nullptr, ICON_NONE); - sub = uiLayoutColumn(col, false); - uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_zbuffer") == false); - uiItemR(sub, ptr, "z_scale", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_composit_buts_antialiasing(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiLayout *col; - - col = uiLayoutColumn(layout, false); - - uiItemR(col, ptr, "threshold", 0, nullptr, ICON_NONE); - uiItemR(col, ptr, "contrast_limit", 0, nullptr, ICON_NONE); - uiItemR(col, ptr, "corner_rounding", 0, nullptr, ICON_NONE); -} - -/* glare node */ -static void node_composit_buts_glare(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "glare_type", DEFAULT_FLAGS, "", ICON_NONE); - uiItemR(layout, ptr, "quality", DEFAULT_FLAGS, "", ICON_NONE); - - if (RNA_enum_get(ptr, "glare_type") != 1) { - uiItemR(layout, ptr, "iterations", DEFAULT_FLAGS, nullptr, ICON_NONE); - - if (RNA_enum_get(ptr, "glare_type") != 0) { - uiItemR( - layout, ptr, "color_modulation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - } - } - - uiItemR(layout, ptr, "mix", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "threshold", DEFAULT_FLAGS, nullptr, ICON_NONE); - - if (RNA_enum_get(ptr, "glare_type") == 2) { - uiItemR(layout, ptr, "streaks", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "angle_offset", DEFAULT_FLAGS, nullptr, ICON_NONE); - } - if (RNA_enum_get(ptr, "glare_type") == 0 || RNA_enum_get(ptr, "glare_type") == 2) { - uiItemR(layout, ptr, "fade", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - - if (RNA_enum_get(ptr, "glare_type") == 0) { - uiItemR(layout, ptr, "use_rotate_45", DEFAULT_FLAGS, nullptr, ICON_NONE); - } - } - if (RNA_enum_get(ptr, "glare_type") == 1) { - uiItemR(layout, ptr, "size", DEFAULT_FLAGS, nullptr, ICON_NONE); - } -} - -static void node_composit_buts_tonemap(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiLayout *col; - - col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "tonemap_type", DEFAULT_FLAGS, "", ICON_NONE); - if (RNA_enum_get(ptr, "tonemap_type") == 0) { - uiItemR(col, ptr, "key", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(col, ptr, "offset", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(col, ptr, "gamma", DEFAULT_FLAGS, nullptr, ICON_NONE); - } - else { - uiItemR(col, ptr, "intensity", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(col, ptr, "contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(col, ptr, "adaptation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(col, ptr, "correction", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - } -} - -static void node_composit_buts_lensdist(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiLayout *col; - - col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "use_projector", DEFAULT_FLAGS, nullptr, ICON_NONE); - - col = uiLayoutColumn(col, false); - uiLayoutSetActive(col, RNA_boolean_get(ptr, "use_projector") == false); - uiItemR(col, ptr, "use_jitter", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(col, ptr, "use_fit", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_composit_buts_vecblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiLayout *col; - - col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "samples", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(col, ptr, "factor", DEFAULT_FLAGS, IFACE_("Blur"), ICON_NONE); - - col = uiLayoutColumn(layout, true); - uiItemL(col, IFACE_("Speed:"), ICON_NONE); - uiItemR(col, ptr, "speed_min", DEFAULT_FLAGS, IFACE_("Min"), ICON_NONE); - uiItemR(col, ptr, "speed_max", DEFAULT_FLAGS, IFACE_("Max"), ICON_NONE); - - uiItemR(layout, ptr, "use_curved", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_composit_buts_filter(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE); -} - -static void node_composit_buts_flip(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "axis", DEFAULT_FLAGS, "", ICON_NONE); -} - -static void node_composit_buts_crop(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiLayout *col; - - uiItemR(layout, ptr, "use_crop_size", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "relative", DEFAULT_FLAGS, nullptr, ICON_NONE); - - col = uiLayoutColumn(layout, true); - if (RNA_boolean_get(ptr, "relative")) { - uiItemR(col, ptr, "rel_min_x", DEFAULT_FLAGS, IFACE_("Left"), ICON_NONE); - uiItemR(col, ptr, "rel_max_x", DEFAULT_FLAGS, IFACE_("Right"), ICON_NONE); - uiItemR(col, ptr, "rel_min_y", DEFAULT_FLAGS, IFACE_("Up"), ICON_NONE); - uiItemR(col, ptr, "rel_max_y", DEFAULT_FLAGS, IFACE_("Down"), ICON_NONE); - } - else { - uiItemR(col, ptr, "min_x", DEFAULT_FLAGS, IFACE_("Left"), ICON_NONE); - uiItemR(col, ptr, "max_x", DEFAULT_FLAGS, IFACE_("Right"), ICON_NONE); - uiItemR(col, ptr, "min_y", DEFAULT_FLAGS, IFACE_("Up"), ICON_NONE); - uiItemR(col, ptr, "max_y", DEFAULT_FLAGS, IFACE_("Down"), ICON_NONE); - } -} - -static void node_composit_buts_splitviewer(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiLayout *row, *col; - - col = uiLayoutColumn(layout, false); - row = uiLayoutRow(col, false); - uiItemR(row, ptr, "axis", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE); - uiItemR(col, ptr, "factor", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_composit_buts_double_edge_mask(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) -{ - uiLayout *col; - - col = uiLayoutColumn(layout, false); - - uiItemL(col, IFACE_("Inner Edge:"), ICON_NONE); - uiItemR(col, ptr, "inner_mode", DEFAULT_FLAGS, "", ICON_NONE); - uiItemL(col, IFACE_("Buffer Edge:"), ICON_NONE); - uiItemR(col, ptr, "edge_mode", DEFAULT_FLAGS, "", ICON_NONE); -} - -static void node_composit_buts_map_range(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiLayout *col; - - col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "use_clamp", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_composit_buts_map_value(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiLayout *sub, *col; - - col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "offset", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(col, ptr, "size", DEFAULT_FLAGS, nullptr, ICON_NONE); - - col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "use_min", DEFAULT_FLAGS, nullptr, ICON_NONE); - sub = uiLayoutColumn(col, false); - uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_min")); - uiItemR(sub, ptr, "min", DEFAULT_FLAGS, "", ICON_NONE); - - col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "use_max", DEFAULT_FLAGS, nullptr, ICON_NONE); - sub = uiLayoutColumn(col, false); - uiLayoutSetActive(sub, RNA_boolean_get(ptr, "use_max")); - uiItemR(sub, ptr, "max", DEFAULT_FLAGS, "", ICON_NONE); -} - -static void node_composit_buts_alphaover(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiLayout *col; - - col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "use_premultiply", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(col, ptr, "premul", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_composit_buts_zcombine(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiLayout *col; - - col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "use_alpha", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(col, ptr, "use_antialias_z", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_composit_buts_dilateerode(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "distance", DEFAULT_FLAGS, nullptr, ICON_NONE); - switch (RNA_enum_get(ptr, "mode")) { - case CMP_NODE_DILATEERODE_DISTANCE_THRESH: - uiItemR(layout, ptr, "edge", DEFAULT_FLAGS, nullptr, ICON_NONE); - break; - case CMP_NODE_DILATEERODE_DISTANCE_FEATHER: - uiItemR(layout, ptr, "falloff", DEFAULT_FLAGS, nullptr, ICON_NONE); - break; - } -} - -static void node_composit_buts_inpaint(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "distance", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_composit_buts_despeckle(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiLayout *col; - - col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "threshold", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(col, ptr, "threshold_neighbor", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_composit_buts_diff_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiLayout *col; - - col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(col, ptr, "falloff", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); -} - -static void node_composit_buts_distance_matte(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) -{ - uiLayout *col, *row; - - col = uiLayoutColumn(layout, true); - - uiItemL(layout, IFACE_("Color Space:"), ICON_NONE); - row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE); - - uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(col, ptr, "falloff", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); -} - -static void node_composit_buts_color_spill(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiLayout *row, *col; - - uiItemL(layout, IFACE_("Despill Channel:"), ICON_NONE); - row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE); - - col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "limit_method", DEFAULT_FLAGS, nullptr, ICON_NONE); - - if (RNA_enum_get(ptr, "limit_method") == 0) { - uiItemL(col, IFACE_("Limiting Channel:"), ICON_NONE); - row = uiLayoutRow(col, false); - uiItemR(row, ptr, "limit_channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE); - } - - uiItemR(col, ptr, "ratio", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(col, ptr, "use_unspill", DEFAULT_FLAGS, nullptr, ICON_NONE); - if (RNA_boolean_get(ptr, "use_unspill") == true) { - uiItemR(col, ptr, "unspill_red", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(col, ptr, "unspill_green", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(col, ptr, "unspill_blue", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - } -} - -static void node_composit_buts_chroma_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiLayout *col; - - col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "tolerance", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(col, ptr, "threshold", DEFAULT_FLAGS, nullptr, ICON_NONE); - - col = uiLayoutColumn(layout, true); - /* Removed for now. */ - // uiItemR(col, ptr, "lift", UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(col, ptr, "gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - /* Removed for now. */ - // uiItemR(col, ptr, "shadow_adjust", UI_ITEM_R_SLIDER, nullptr, ICON_NONE); -} - -static void node_composit_buts_color_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiLayout *col; - - col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "color_hue", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(col, ptr, "color_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(col, ptr, "color_value", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); -} - -static void node_composit_buts_channel_matte(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) -{ - uiLayout *col, *row; - - uiItemL(layout, IFACE_("Color Space:"), ICON_NONE); - row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "color_space", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE); - - col = uiLayoutColumn(layout, false); - uiItemL(col, IFACE_("Key Channel:"), ICON_NONE); - row = uiLayoutRow(col, false); - uiItemR(row, ptr, "matte_channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE); - - col = uiLayoutColumn(layout, false); - - uiItemR(col, ptr, "limit_method", DEFAULT_FLAGS, nullptr, ICON_NONE); - if (RNA_enum_get(ptr, "limit_method") == 0) { - uiItemL(col, IFACE_("Limiting Channel:"), ICON_NONE); - row = uiLayoutRow(col, false); - uiItemR(row, ptr, "limit_channel", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE); - } - - uiItemR(col, ptr, "limit_max", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(col, ptr, "limit_min", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); -} - -static void node_composit_buts_luma_matte(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiLayout *col; - - col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "limit_max", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(col, ptr, "limit_min", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); -} - -static void node_composit_buts_map_uv(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "alpha", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_composit_buts_id_mask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "index", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "use_antialiasing", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_composit_buts_file_output(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - PointerRNA imfptr = RNA_pointer_get(ptr, "format"); - const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER; - - if (multilayer) { - uiItemL(layout, IFACE_("Path:"), ICON_NONE); - } - else { - uiItemL(layout, IFACE_("Base Path:"), ICON_NONE); - } - uiItemR(layout, ptr, "base_path", DEFAULT_FLAGS, "", ICON_NONE); -} -static void node_composit_buts_file_output_ex(uiLayout *layout, bContext *C, PointerRNA *ptr) -{ - Scene *scene = CTX_data_scene(C); - PointerRNA imfptr = RNA_pointer_get(ptr, "format"); - PointerRNA active_input_ptr, op_ptr; - uiLayout *row, *col; - const bool multilayer = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_MULTILAYER; - const bool is_exr = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_OPENEXR; - const bool is_multiview = (scene->r.scemode & R_MULTIVIEW) != 0; - - node_composit_buts_file_output(layout, C, ptr); - uiTemplateImageSettings(layout, &imfptr, false); - - /* disable stereo output for multilayer, too much work for something that no one will use */ - /* if someone asks for that we can implement it */ - if (is_multiview) { - uiTemplateImageFormatViews(layout, &imfptr, nullptr); - } - - uiItemS(layout); - - uiItemO(layout, IFACE_("Add Input"), ICON_ADD, "NODE_OT_output_file_add_socket"); - - row = uiLayoutRow(layout, false); - col = uiLayoutColumn(row, true); - - const int active_index = RNA_int_get(ptr, "active_input_index"); - /* using different collection properties if multilayer format is enabled */ - if (multilayer) { - uiTemplateList(col, - C, - "UI_UL_list", - "file_output_node", - ptr, - "layer_slots", - ptr, - "active_input_index", - nullptr, - 0, - 0, - 0, - 0, - UI_TEMPLATE_LIST_FLAG_NONE); - RNA_property_collection_lookup_int( - ptr, RNA_struct_find_property(ptr, "layer_slots"), active_index, &active_input_ptr); - } - else { - uiTemplateList(col, - C, - "UI_UL_list", - "file_output_node", - ptr, - "file_slots", - ptr, - "active_input_index", - nullptr, - 0, - 0, - 0, - 0, - UI_TEMPLATE_LIST_FLAG_NONE); - RNA_property_collection_lookup_int( - ptr, RNA_struct_find_property(ptr, "file_slots"), active_index, &active_input_ptr); - } - /* XXX collection lookup does not return the ID part of the pointer, - * setting this manually here */ - active_input_ptr.owner_id = ptr->owner_id; - - col = uiLayoutColumn(row, true); - wmOperatorType *ot = WM_operatortype_find("NODE_OT_output_file_move_active_socket", false); - uiItemFullO_ptr(col, ot, "", ICON_TRIA_UP, nullptr, WM_OP_INVOKE_DEFAULT, 0, &op_ptr); - RNA_enum_set(&op_ptr, "direction", 1); - uiItemFullO_ptr(col, ot, "", ICON_TRIA_DOWN, nullptr, WM_OP_INVOKE_DEFAULT, 0, &op_ptr); - RNA_enum_set(&op_ptr, "direction", 2); - - if (active_input_ptr.data) { - if (multilayer) { - col = uiLayoutColumn(layout, true); - - uiItemL(col, IFACE_("Layer:"), ICON_NONE); - row = uiLayoutRow(col, false); - uiItemR(row, &active_input_ptr, "name", DEFAULT_FLAGS, "", ICON_NONE); - uiItemFullO(row, - "NODE_OT_output_file_remove_active_socket", - "", - ICON_X, - nullptr, - WM_OP_EXEC_DEFAULT, - UI_ITEM_R_ICON_ONLY, - nullptr); - } - else { - col = uiLayoutColumn(layout, true); - - uiItemL(col, IFACE_("File Subpath:"), ICON_NONE); - row = uiLayoutRow(col, false); - uiItemR(row, &active_input_ptr, "path", DEFAULT_FLAGS, "", ICON_NONE); - uiItemFullO(row, - "NODE_OT_output_file_remove_active_socket", - "", - ICON_X, - nullptr, - WM_OP_EXEC_DEFAULT, - UI_ITEM_R_ICON_ONLY, - nullptr); - - /* format details for individual files */ - imfptr = RNA_pointer_get(&active_input_ptr, "format"); - - col = uiLayoutColumn(layout, true); - uiItemL(col, IFACE_("Format:"), ICON_NONE); - uiItemR(col, &active_input_ptr, "use_node_format", DEFAULT_FLAGS, nullptr, ICON_NONE); - - const bool is_socket_exr = RNA_enum_get(&imfptr, "file_format") == R_IMF_IMTYPE_OPENEXR; - const bool use_node_format = RNA_boolean_get(&active_input_ptr, "use_node_format"); - - if ((!is_exr && use_node_format) || (!is_socket_exr && !use_node_format)) { - uiItemR(col, &active_input_ptr, "save_as_render", DEFAULT_FLAGS, nullptr, ICON_NONE); - } - - col = uiLayoutColumn(layout, false); - uiLayoutSetActive(col, use_node_format == false); - uiTemplateImageSettings(col, &imfptr, false); - - if (is_multiview) { - uiTemplateImageFormatViews(layout, &imfptr, nullptr); - } - } - } -} - -static void node_composit_buts_scale(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "space", DEFAULT_FLAGS, "", ICON_NONE); - - if (RNA_enum_get(ptr, "space") == CMP_SCALE_RENDERPERCENT) { - uiLayout *row; - uiItemR(layout, ptr, "frame_method", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, nullptr, ICON_NONE); - row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "offset_x", DEFAULT_FLAGS, "X", ICON_NONE); - uiItemR(row, ptr, "offset_y", DEFAULT_FLAGS, "Y", ICON_NONE); - } -} - -static void node_composit_buts_rotate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE); -} - -static void node_composit_buts_invert(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiLayout *col; - - col = uiLayoutColumn(layout, false); - uiItemR(col, ptr, "invert_rgb", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(col, ptr, "invert_alpha", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_composit_buts_premulkey(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "mapping", DEFAULT_FLAGS, "", ICON_NONE); -} - -static void node_composit_buts_view_levels(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "channel", DEFAULT_FLAGS, "", ICON_NONE); -} - -static void node_composit_buts_colorbalance(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiLayout *split, *col, *row; - - uiItemR(layout, ptr, "correction_method", DEFAULT_FLAGS, nullptr, ICON_NONE); - - if (RNA_enum_get(ptr, "correction_method") == 0) { - - split = uiLayoutSplit(layout, 0.0f, false); - col = uiLayoutColumn(split, false); - uiTemplateColorPicker(col, ptr, "lift", true, true, false, true); - row = uiLayoutRow(col, false); - uiItemR(row, ptr, "lift", DEFAULT_FLAGS, nullptr, ICON_NONE); - - col = uiLayoutColumn(split, false); - uiTemplateColorPicker(col, ptr, "gamma", true, true, true, true); - row = uiLayoutRow(col, false); - uiItemR(row, ptr, "gamma", DEFAULT_FLAGS, nullptr, ICON_NONE); - - col = uiLayoutColumn(split, false); - uiTemplateColorPicker(col, ptr, "gain", true, true, true, true); - row = uiLayoutRow(col, false); - uiItemR(row, ptr, "gain", DEFAULT_FLAGS, nullptr, ICON_NONE); - } - else { - - split = uiLayoutSplit(layout, 0.0f, false); - col = uiLayoutColumn(split, false); - uiTemplateColorPicker(col, ptr, "offset", true, true, false, true); - row = uiLayoutRow(col, false); - uiItemR(row, ptr, "offset", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(col, ptr, "offset_basis", DEFAULT_FLAGS, nullptr, ICON_NONE); - - col = uiLayoutColumn(split, false); - uiTemplateColorPicker(col, ptr, "power", true, true, false, true); - row = uiLayoutRow(col, false); - uiItemR(row, ptr, "power", DEFAULT_FLAGS, nullptr, ICON_NONE); - - col = uiLayoutColumn(split, false); - uiTemplateColorPicker(col, ptr, "slope", true, true, false, true); - row = uiLayoutRow(col, false); - uiItemR(row, ptr, "slope", DEFAULT_FLAGS, nullptr, ICON_NONE); - } -} -static void node_composit_buts_colorbalance_ex(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) -{ - uiItemR(layout, ptr, "correction_method", DEFAULT_FLAGS, nullptr, ICON_NONE); - - if (RNA_enum_get(ptr, "correction_method") == 0) { - - uiTemplateColorPicker(layout, ptr, "lift", true, true, false, true); - uiItemR(layout, ptr, "lift", DEFAULT_FLAGS, nullptr, ICON_NONE); - - uiTemplateColorPicker(layout, ptr, "gamma", true, true, true, true); - uiItemR(layout, ptr, "gamma", DEFAULT_FLAGS, nullptr, ICON_NONE); - - uiTemplateColorPicker(layout, ptr, "gain", true, true, true, true); - uiItemR(layout, ptr, "gain", DEFAULT_FLAGS, nullptr, ICON_NONE); - } - else { - uiTemplateColorPicker(layout, ptr, "offset", true, true, false, true); - uiItemR(layout, ptr, "offset", DEFAULT_FLAGS, nullptr, ICON_NONE); - - uiTemplateColorPicker(layout, ptr, "power", true, true, false, true); - uiItemR(layout, ptr, "power", DEFAULT_FLAGS, nullptr, ICON_NONE); - - uiTemplateColorPicker(layout, ptr, "slope", true, true, false, true); - uiItemR(layout, ptr, "slope", DEFAULT_FLAGS, nullptr, ICON_NONE); - } -} - static void node_composit_buts_huecorrect(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { bNode *node = (bNode *)ptr->data; @@ -1873,260 +594,6 @@ static void node_composit_buts_ycc(uiLayout *layout, bContext *UNUSED(C), Pointe uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, "", ICON_NONE); } -static void node_composit_buts_movieclip(uiLayout *layout, bContext *C, PointerRNA *ptr) -{ - uiTemplateID(layout, - C, - ptr, - "clip", - nullptr, - "CLIP_OT_open", - nullptr, - UI_TEMPLATE_ID_FILTER_ALL, - false, - nullptr); -} - -static void node_composit_buts_movieclip_ex(uiLayout *layout, bContext *C, PointerRNA *ptr) -{ - bNode *node = (bNode *)ptr->data; - PointerRNA clipptr; - - uiTemplateID(layout, - C, - ptr, - "clip", - nullptr, - "CLIP_OT_open", - nullptr, - UI_TEMPLATE_ID_FILTER_ALL, - false, - nullptr); - - if (!node->id) { - return; - } - - clipptr = RNA_pointer_get(ptr, "clip"); - - uiTemplateColorspaceSettings(layout, &clipptr, "colorspace_settings"); -} - -static void node_composit_buts_stabilize2d(uiLayout *layout, bContext *C, PointerRNA *ptr) -{ - bNode *node = (bNode *)ptr->data; - - uiTemplateID(layout, - C, - ptr, - "clip", - nullptr, - "CLIP_OT_open", - nullptr, - UI_TEMPLATE_ID_FILTER_ALL, - false, - nullptr); - - if (!node->id) { - return; - } - - uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE); - uiItemR(layout, ptr, "invert", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_composit_buts_translate(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "use_relative", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "wrap_axis", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_composit_buts_transform(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "filter_type", DEFAULT_FLAGS, "", ICON_NONE); -} - -static void node_composit_buts_moviedistortion(uiLayout *layout, bContext *C, PointerRNA *ptr) -{ - bNode *node = (bNode *)ptr->data; - - uiTemplateID(layout, - C, - ptr, - "clip", - nullptr, - "CLIP_OT_open", - nullptr, - UI_TEMPLATE_ID_FILTER_ALL, - false, - nullptr); - - if (!node->id) { - return; - } - - uiItemR(layout, ptr, "distortion_type", DEFAULT_FLAGS, "", ICON_NONE); -} - -static void node_composit_buts_colorcorrection(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) -{ - uiLayout *row; - - row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "red", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(row, ptr, "green", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(row, ptr, "blue", DEFAULT_FLAGS, nullptr, ICON_NONE); - - row = uiLayoutRow(layout, false); - uiItemL(row, "", ICON_NONE); - uiItemL(row, IFACE_("Saturation"), ICON_NONE); - uiItemL(row, IFACE_("Contrast"), ICON_NONE); - uiItemL(row, IFACE_("Gamma"), ICON_NONE); - uiItemL(row, IFACE_("Gain"), ICON_NONE); - uiItemL(row, IFACE_("Lift"), ICON_NONE); - - row = uiLayoutRow(layout, false); - uiItemL(row, IFACE_("Master"), ICON_NONE); - uiItemR(row, ptr, "master_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "master_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "master_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "master_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "master_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); - - row = uiLayoutRow(layout, false); - uiItemL(row, IFACE_("Highlights"), ICON_NONE); - uiItemR(row, ptr, "highlights_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "highlights_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "highlights_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "highlights_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "highlights_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); - - row = uiLayoutRow(layout, false); - uiItemL(row, IFACE_("Midtones"), ICON_NONE); - uiItemR(row, ptr, "midtones_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "midtones_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "midtones_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "midtones_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "midtones_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); - - row = uiLayoutRow(layout, false); - uiItemL(row, IFACE_("Shadows"), ICON_NONE); - uiItemR(row, ptr, "shadows_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "shadows_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "shadows_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "shadows_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); - uiItemR(row, ptr, "shadows_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, "", ICON_NONE); - - row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "midtones_start", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(row, ptr, "midtones_end", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); -} - -static void node_composit_buts_colorcorrection_ex(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) -{ - uiLayout *row; - - row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "red", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(row, ptr, "green", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(row, ptr, "blue", DEFAULT_FLAGS, nullptr, ICON_NONE); - row = layout; - uiItemL(row, IFACE_("Saturation"), ICON_NONE); - uiItemR(row, ptr, "master_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(row, ptr, "highlights_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(row, ptr, "midtones_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(row, ptr, "shadows_saturation", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - - uiItemL(row, IFACE_("Contrast"), ICON_NONE); - uiItemR(row, ptr, "master_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(row, ptr, "highlights_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(row, ptr, "midtones_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(row, ptr, "shadows_contrast", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - - uiItemL(row, IFACE_("Gamma"), ICON_NONE); - uiItemR(row, ptr, "master_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(row, ptr, "highlights_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(row, ptr, "midtones_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(row, ptr, "shadows_gamma", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - - uiItemL(row, IFACE_("Gain"), ICON_NONE); - uiItemR(row, ptr, "master_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(row, ptr, "highlights_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(row, ptr, "midtones_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(row, ptr, "shadows_gain", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - - uiItemL(row, IFACE_("Lift"), ICON_NONE); - uiItemR(row, ptr, "master_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(row, ptr, "highlights_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(row, ptr, "midtones_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(row, ptr, "shadows_lift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - - row = uiLayoutRow(layout, false); - uiItemR(row, ptr, "midtones_start", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(row, ptr, "midtones_end", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_composit_buts_set_alpha(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "mode", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_composit_buts_switch(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "check", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_composit_buts_switch_view_ex(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *UNUSED(ptr)) -{ - uiItemFullO(layout, - "NODE_OT_switch_view_update", - "Update Views", - ICON_FILE_REFRESH, - nullptr, - WM_OP_INVOKE_DEFAULT, - 0, - nullptr); -} - -static void node_composit_buts_boxmask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiLayout *row; - - row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "x", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(row, ptr, "y", DEFAULT_FLAGS, nullptr, ICON_NONE); - - row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "width", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(row, ptr, "height", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - - uiItemR(layout, ptr, "rotation", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "mask_type", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_composit_buts_bokehimage(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "flaps", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "angle", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "rounding", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(layout, ptr, "catadioptric", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(layout, ptr, "shift", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); -} - -static void node_composit_buts_bokehblur(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "use_variable_size", DEFAULT_FLAGS, nullptr, ICON_NONE); - // uiItemR(layout, ptr, "f_stop", DEFAULT_FLAGS, nullptr, ICON_NONE); /* UNUSED */ - uiItemR(layout, ptr, "blur_max", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "use_extended_bounds", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - static void node_composit_backdrop_viewer( SpaceNode *snode, ImBuf *backdrop, bNode *node, int x, int y) { @@ -2246,221 +713,6 @@ static void node_composit_backdrop_ellipsemask( immUnbindProgram(); } -static void node_composit_buts_ellipsemask(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiLayout *row; - row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "x", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(row, ptr, "y", DEFAULT_FLAGS, nullptr, ICON_NONE); - row = uiLayoutRow(layout, true); - uiItemR(row, ptr, "width", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - uiItemR(row, ptr, "height", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); - - uiItemR(layout, ptr, "rotation", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "mask_type", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_composit_buts_composite(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_composit_buts_viewer(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_composit_buts_viewer_ex(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiLayout *col; - - uiItemR(layout, ptr, "use_alpha", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "tile_order", DEFAULT_FLAGS, nullptr, ICON_NONE); - if (RNA_enum_get(ptr, "tile_order") == 0) { - col = uiLayoutColumn(layout, true); - uiItemR(col, ptr, "center_x", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(col, ptr, "center_y", DEFAULT_FLAGS, nullptr, ICON_NONE); - } -} - -static void node_composit_buts_mask(uiLayout *layout, bContext *C, PointerRNA *ptr) -{ - bNode *node = (bNode *)ptr->data; - - uiTemplateID(layout, - C, - ptr, - "mask", - nullptr, - nullptr, - nullptr, - UI_TEMPLATE_ID_FILTER_ALL, - false, - nullptr); - uiItemR(layout, ptr, "use_feather", DEFAULT_FLAGS, nullptr, ICON_NONE); - - uiItemR(layout, ptr, "size_source", DEFAULT_FLAGS, "", ICON_NONE); - - if (node->custom1 & (CMP_NODEFLAG_MASK_FIXED | CMP_NODEFLAG_MASK_FIXED_SCENE)) { - uiItemR(layout, ptr, "size_x", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "size_y", DEFAULT_FLAGS, nullptr, ICON_NONE); - } - - uiItemR(layout, ptr, "use_motion_blur", DEFAULT_FLAGS, nullptr, ICON_NONE); - if (node->custom1 & CMP_NODEFLAG_MASK_MOTION_BLUR) { - uiItemR(layout, ptr, "motion_blur_samples", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "motion_blur_shutter", DEFAULT_FLAGS, nullptr, ICON_NONE); - } -} - -static void node_composit_buts_keyingscreen(uiLayout *layout, bContext *C, PointerRNA *ptr) -{ - bNode *node = (bNode *)ptr->data; - - uiTemplateID(layout, - C, - ptr, - "clip", - nullptr, - nullptr, - nullptr, - UI_TEMPLATE_ID_FILTER_ALL, - false, - nullptr); - - if (node->id) { - MovieClip *clip = (MovieClip *)node->id; - uiLayout *col; - PointerRNA tracking_ptr; - - RNA_pointer_create(&clip->id, &RNA_MovieTracking, &clip->tracking, &tracking_ptr); - - col = uiLayoutColumn(layout, true); - uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA); - } -} - -static void node_composit_buts_keying(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - /* bNode *node = (bNode*)ptr->data; */ /* UNUSED */ - - uiItemR(layout, ptr, "blur_pre", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "screen_balance", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "despill_factor", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "despill_balance", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "edge_kernel_radius", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "edge_kernel_tolerance", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "clip_black", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "clip_white", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "dilate_distance", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "feather_falloff", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "feather_distance", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "blur_post", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_composit_buts_trackpos(uiLayout *layout, bContext *C, PointerRNA *ptr) -{ - bNode *node = (bNode *)ptr->data; - - uiTemplateID(layout, - C, - ptr, - "clip", - nullptr, - "CLIP_OT_open", - nullptr, - UI_TEMPLATE_ID_FILTER_ALL, - false, - nullptr); - - if (node->id) { - MovieClip *clip = (MovieClip *)node->id; - MovieTracking *tracking = &clip->tracking; - MovieTrackingObject *object; - uiLayout *col; - PointerRNA tracking_ptr; - NodeTrackPosData *data = (NodeTrackPosData *)node->storage; - - RNA_pointer_create(&clip->id, &RNA_MovieTracking, tracking, &tracking_ptr); - - col = uiLayoutColumn(layout, false); - uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA); - - object = BKE_tracking_object_get_named(tracking, data->tracking_object); - if (object) { - PointerRNA object_ptr; - - RNA_pointer_create(&clip->id, &RNA_MovieTrackingObject, object, &object_ptr); - - uiItemPointerR(col, ptr, "track_name", &object_ptr, "tracks", "", ICON_ANIM_DATA); - } - else { - uiItemR(layout, ptr, "track_name", DEFAULT_FLAGS, "", ICON_ANIM_DATA); - } - - uiItemR(layout, ptr, "position", DEFAULT_FLAGS, nullptr, ICON_NONE); - - if (ELEM(node->custom1, CMP_TRACKPOS_RELATIVE_FRAME, CMP_TRACKPOS_ABSOLUTE_FRAME)) { - uiItemR(layout, ptr, "frame_relative", DEFAULT_FLAGS, nullptr, ICON_NONE); - } - } -} - -static void node_composit_buts_planetrackdeform(uiLayout *layout, bContext *C, PointerRNA *ptr) -{ - bNode *node = (bNode *)ptr->data; - NodePlaneTrackDeformData *data = (NodePlaneTrackDeformData *)node->storage; - - uiTemplateID(layout, - C, - ptr, - "clip", - nullptr, - "CLIP_OT_open", - nullptr, - UI_TEMPLATE_ID_FILTER_ALL, - false, - nullptr); - - if (node->id) { - MovieClip *clip = (MovieClip *)node->id; - MovieTracking *tracking = &clip->tracking; - MovieTrackingObject *object; - uiLayout *col; - PointerRNA tracking_ptr; - - RNA_pointer_create(&clip->id, &RNA_MovieTracking, tracking, &tracking_ptr); - - col = uiLayoutColumn(layout, false); - uiItemPointerR(col, ptr, "tracking_object", &tracking_ptr, "objects", "", ICON_OBJECT_DATA); - - object = BKE_tracking_object_get_named(tracking, data->tracking_object); - if (object) { - PointerRNA object_ptr; - - RNA_pointer_create(&clip->id, &RNA_MovieTrackingObject, object, &object_ptr); - - uiItemPointerR( - col, ptr, "plane_track_name", &object_ptr, "plane_tracks", "", ICON_ANIM_DATA); - } - else { - uiItemR(layout, ptr, "plane_track_name", 0, "", ICON_ANIM_DATA); - } - } - - uiItemR(layout, ptr, "use_motion_blur", DEFAULT_FLAGS, nullptr, ICON_NONE); - if (data->flag & CMP_NODEFLAG_PLANETRACKDEFORM_MOTION_BLUR) { - uiItemR(layout, ptr, "motion_blur_samples", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "motion_blur_shutter", DEFAULT_FLAGS, nullptr, ICON_NONE); - } -} - -static void node_composit_buts_sunbeams(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ - uiItemR(layout, ptr, "source", DEFAULT_FLAGS | UI_ITEM_R_EXPAND, "", ICON_NONE); - uiItemR(layout, ptr, "ray_length", DEFAULT_FLAGS | UI_ITEM_R_SLIDER, nullptr, ICON_NONE); -} - static void node_composit_buts_cryptomatte_legacy(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) @@ -2536,31 +788,6 @@ static void node_composit_buts_cryptomatte(uiLayout *layout, bContext *C, Pointe uiTemplateCryptoPicker(row, ptr, "remove", ICON_REMOVE); } -static void node_composit_buts_brightcontrast(uiLayout *layout, - bContext *UNUSED(C), - PointerRNA *ptr) -{ - uiItemR(layout, ptr, "use_premultiply", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - -static void node_composit_buts_denoise(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) -{ -#ifndef WITH_OPENIMAGEDENOISE - uiItemL(layout, IFACE_("Disabled, built without OpenImageDenoise"), ICON_ERROR); -#else - /* Always supported through Accelerate framework BNNS on macOS. */ -# ifndef __APPLE__ - if (!BLI_cpu_support_sse41()) { - uiItemL(layout, IFACE_("Disabled, CPU with SSE4.1 is required"), ICON_ERROR); - } -# endif -#endif - - uiItemL(layout, IFACE_("Prefilter:"), ICON_NONE); - uiItemR(layout, ptr, "prefilter", DEFAULT_FLAGS, nullptr, ICON_NONE); - uiItemR(layout, ptr, "use_hdr", DEFAULT_FLAGS, nullptr, ICON_NONE); -} - /* only once called */ static void node_composit_set_butfunc(bNodeType *ntype) { @@ -2569,15 +796,6 @@ static void node_composit_set_butfunc(bNodeType *ntype) ntype->draw_buttons = node_composit_buts_image; ntype->draw_buttons_ex = node_composit_buts_image_ex; break; - case CMP_NODE_R_LAYERS: - ntype->draw_buttons = node_composit_buts_viewlayers; - break; - case CMP_NODE_NORMAL: - ntype->draw_buttons = node_buts_normal; - break; - case CMP_NODE_CURVE_VEC: - ntype->draw_buttons = node_buts_curvevec; - break; case CMP_NODE_CURVE_RGB: ntype->draw_buttons = node_buts_curvecol; break; @@ -2587,210 +805,34 @@ static void node_composit_set_butfunc(bNodeType *ntype) case CMP_NODE_RGB: ntype->draw_buttons = node_buts_rgb; break; - case CMP_NODE_FLIP: - ntype->draw_buttons = node_composit_buts_flip; - break; - case CMP_NODE_SPLITVIEWER: - ntype->draw_buttons = node_composit_buts_splitviewer; - break; case CMP_NODE_MIX_RGB: ntype->draw_buttons = node_buts_mix_rgb; break; case CMP_NODE_VALTORGB: ntype->draw_buttons = node_buts_colorramp; break; - case CMP_NODE_CROP: - ntype->draw_buttons = node_composit_buts_crop; - break; - case CMP_NODE_BLUR: - ntype->draw_buttons = node_composit_buts_blur; - break; - case CMP_NODE_DBLUR: - ntype->draw_buttons = node_composit_buts_dblur; - break; - case CMP_NODE_BILATERALBLUR: - ntype->draw_buttons = node_composit_buts_bilateralblur; - break; - case CMP_NODE_DEFOCUS: - ntype->draw_buttons = node_composit_buts_defocus; - break; - case CMP_NODE_ANTIALIASING: - ntype->draw_buttons = node_composit_buts_antialiasing; - break; - case CMP_NODE_GLARE: - ntype->draw_buttons = node_composit_buts_glare; - break; - case CMP_NODE_TONEMAP: - ntype->draw_buttons = node_composit_buts_tonemap; - break; - case CMP_NODE_LENSDIST: - ntype->draw_buttons = node_composit_buts_lensdist; - break; - case CMP_NODE_VECBLUR: - ntype->draw_buttons = node_composit_buts_vecblur; - break; - case CMP_NODE_FILTER: - ntype->draw_buttons = node_composit_buts_filter; - break; - case CMP_NODE_MAP_VALUE: - ntype->draw_buttons = node_composit_buts_map_value; - break; - case CMP_NODE_MAP_RANGE: - ntype->draw_buttons = node_composit_buts_map_range; - break; case CMP_NODE_TIME: ntype->draw_buttons = node_buts_time; break; - case CMP_NODE_ALPHAOVER: - ntype->draw_buttons = node_composit_buts_alphaover; - break; case CMP_NODE_TEXTURE: ntype->draw_buttons = node_buts_texture; break; - case CMP_NODE_DILATEERODE: - ntype->draw_buttons = node_composit_buts_dilateerode; - break; - case CMP_NODE_INPAINT: - ntype->draw_buttons = node_composit_buts_inpaint; - break; - case CMP_NODE_DESPECKLE: - ntype->draw_buttons = node_composit_buts_despeckle; - break; - case CMP_NODE_OUTPUT_FILE: - ntype->draw_buttons = node_composit_buts_file_output; - ntype->draw_buttons_ex = node_composit_buts_file_output_ex; - break; - case CMP_NODE_DIFF_MATTE: - ntype->draw_buttons = node_composit_buts_diff_matte; - break; - case CMP_NODE_DIST_MATTE: - ntype->draw_buttons = node_composit_buts_distance_matte; - break; - case CMP_NODE_COLOR_SPILL: - ntype->draw_buttons = node_composit_buts_color_spill; - break; - case CMP_NODE_CHROMA_MATTE: - ntype->draw_buttons = node_composit_buts_chroma_matte; - break; - case CMP_NODE_COLOR_MATTE: - ntype->draw_buttons = node_composit_buts_color_matte; - break; - case CMP_NODE_SCALE: - ntype->draw_buttons = node_composit_buts_scale; - break; - case CMP_NODE_ROTATE: - ntype->draw_buttons = node_composit_buts_rotate; - break; - case CMP_NODE_CHANNEL_MATTE: - ntype->draw_buttons = node_composit_buts_channel_matte; - break; - case CMP_NODE_LUMA_MATTE: - ntype->draw_buttons = node_composit_buts_luma_matte; - break; - case CMP_NODE_MAP_UV: - ntype->draw_buttons = node_composit_buts_map_uv; - break; - case CMP_NODE_ID_MASK: - ntype->draw_buttons = node_composit_buts_id_mask; - break; - case CMP_NODE_DOUBLEEDGEMASK: - ntype->draw_buttons = node_composit_buts_double_edge_mask; - break; case CMP_NODE_MATH: ntype->draw_buttons = node_buts_math; break; - case CMP_NODE_INVERT: - ntype->draw_buttons = node_composit_buts_invert; - break; - case CMP_NODE_PREMULKEY: - ntype->draw_buttons = node_composit_buts_premulkey; - break; - case CMP_NODE_VIEW_LEVELS: - ntype->draw_buttons = node_composit_buts_view_levels; - break; - case CMP_NODE_COLORBALANCE: - ntype->draw_buttons = node_composit_buts_colorbalance; - ntype->draw_buttons_ex = node_composit_buts_colorbalance_ex; - break; case CMP_NODE_HUECORRECT: ntype->draw_buttons = node_composit_buts_huecorrect; break; - case CMP_NODE_ZCOMBINE: - ntype->draw_buttons = node_composit_buts_zcombine; - break; case CMP_NODE_COMBYCCA: case CMP_NODE_SEPYCCA: ntype->draw_buttons = node_composit_buts_ycc; break; - case CMP_NODE_MOVIECLIP: - ntype->draw_buttons = node_composit_buts_movieclip; - ntype->draw_buttons_ex = node_composit_buts_movieclip_ex; - break; - case CMP_NODE_STABILIZE2D: - ntype->draw_buttons = node_composit_buts_stabilize2d; - break; - case CMP_NODE_TRANSFORM: - ntype->draw_buttons = node_composit_buts_transform; - break; - case CMP_NODE_TRANSLATE: - ntype->draw_buttons = node_composit_buts_translate; - break; - case CMP_NODE_MOVIEDISTORTION: - ntype->draw_buttons = node_composit_buts_moviedistortion; - break; - case CMP_NODE_COLORCORRECTION: - ntype->draw_buttons = node_composit_buts_colorcorrection; - ntype->draw_buttons_ex = node_composit_buts_colorcorrection_ex; - break; - case CMP_NODE_SETALPHA: - ntype->draw_buttons = node_composit_buts_set_alpha; - break; - case CMP_NODE_SWITCH: - ntype->draw_buttons = node_composit_buts_switch; - break; - case CMP_NODE_SWITCH_VIEW: - ntype->draw_buttons_ex = node_composit_buts_switch_view_ex; - break; case CMP_NODE_MASK_BOX: - ntype->draw_buttons = node_composit_buts_boxmask; ntype->draw_backdrop = node_composit_backdrop_boxmask; break; case CMP_NODE_MASK_ELLIPSE: - ntype->draw_buttons = node_composit_buts_ellipsemask; ntype->draw_backdrop = node_composit_backdrop_ellipsemask; break; - case CMP_NODE_BOKEHIMAGE: - ntype->draw_buttons = node_composit_buts_bokehimage; - break; - case CMP_NODE_BOKEHBLUR: - ntype->draw_buttons = node_composit_buts_bokehblur; - break; - case CMP_NODE_VIEWER: - ntype->draw_buttons = node_composit_buts_viewer; - ntype->draw_buttons_ex = node_composit_buts_viewer_ex; - ntype->draw_backdrop = node_composit_backdrop_viewer; - break; - case CMP_NODE_COMPOSITE: - ntype->draw_buttons = node_composit_buts_composite; - break; - case CMP_NODE_MASK: - ntype->draw_buttons = node_composit_buts_mask; - break; - case CMP_NODE_KEYINGSCREEN: - ntype->draw_buttons = node_composit_buts_keyingscreen; - break; - case CMP_NODE_KEYING: - ntype->draw_buttons = node_composit_buts_keying; - break; - case CMP_NODE_TRACKPOS: - ntype->draw_buttons = node_composit_buts_trackpos; - break; - case CMP_NODE_PLANETRACKDEFORM: - ntype->draw_buttons = node_composit_buts_planetrackdeform; - break; - case CMP_NODE_SUNBEAMS: - ntype->draw_buttons = node_composit_buts_sunbeams; - break; case CMP_NODE_CRYPTOMATTE: ntype->draw_buttons = node_composit_buts_cryptomatte; break; @@ -2798,11 +840,8 @@ static void node_composit_set_butfunc(bNodeType *ntype) ntype->draw_buttons = node_composit_buts_cryptomatte_legacy; ntype->draw_buttons_ex = node_composit_buts_cryptomatte_legacy_ex; break; - case CMP_NODE_BRIGHTCONTRAST: - ntype->draw_buttons = node_composit_buts_brightcontrast; - break; - case CMP_NODE_DENOISE: - ntype->draw_buttons = node_composit_buts_denoise; + case CMP_NODE_VIEWER: + ntype->draw_backdrop = node_composit_backdrop_viewer; break; } } @@ -2997,7 +1036,8 @@ static void node_property_update_default(Main *bmain, Scene *UNUSED(scene), Poin { bNodeTree *ntree = (bNodeTree *)ptr->owner_id; bNode *node = (bNode *)ptr->data; - ED_node_tag_update_nodetree(bmain, ntree, node); + BKE_ntree_update_tag_node_property(ntree, node); + ED_node_tree_propagate_change(nullptr, bmain, ntree); } static void node_socket_template_properties_update(bNodeType *ntype, bNodeSocketTemplate *stemp) @@ -3065,8 +1105,12 @@ static void node_socket_undefined_interface_draw_color(bContext *UNUSED(C), /** \} */ +} // namespace blender::ed::space_node + void ED_node_init_butfuncs() { + using namespace blender::ed::space_node; + /* Fallback types for undefined tree, nodes, sockets * Defined in blenkernel, but not registered in type hashes. */ @@ -3091,12 +1135,6 @@ void ED_node_init_butfuncs() node_template_properties_update(ntype); } NODE_TYPES_END; - - /* tree type icons */ - ntreeType_Composite->ui_icon = ICON_NODE_COMPOSITING; - ntreeType_Shader->ui_icon = ICON_NODE_MATERIAL; - ntreeType_Texture->ui_icon = ICON_NODE_TEXTURE; - ntreeType_Geometry->ui_icon = ICON_NODETREE; } void ED_init_custom_node_type(bNodeType *UNUSED(ntype)) @@ -3105,9 +1143,11 @@ void ED_init_custom_node_type(bNodeType *UNUSED(ntype)) void ED_init_custom_node_socket_type(bNodeSocketType *stype) { - stype->draw = node_socket_button_label; + stype->draw = blender::ed::space_node::node_socket_button_label; } +namespace blender::ed::space_node { + static const float virtual_node_socket_color[4] = {0.2, 0.2, 0.2, 1.0}; /* maps standard socket integer type to a color */ @@ -3390,14 +1430,6 @@ static void std_node_socket_interface_draw(bContext *UNUSED(C), uiLayout *layout uiItemR(layout, ptr, "hide_value", DEFAULT_FLAGS, nullptr, 0); } -void ED_init_standard_node_socket_type(bNodeSocketType *stype) -{ - stype->draw = std_node_socket_draw; - stype->draw_color = std_node_socket_draw_color; - stype->interface_draw = std_node_socket_interface_draw; - stype->interface_draw_color = std_node_socket_interface_draw_color; -} - static void node_socket_virtual_draw_color(bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PointerRNA *UNUSED(node_ptr), @@ -3406,12 +1438,26 @@ static void node_socket_virtual_draw_color(bContext *UNUSED(C), copy_v4_v4(r_color, virtual_node_socket_color); } +} // namespace blender::ed::space_node + +void ED_init_standard_node_socket_type(bNodeSocketType *stype) +{ + using namespace blender::ed::space_node; + stype->draw = std_node_socket_draw; + stype->draw_color = std_node_socket_draw_color; + stype->interface_draw = std_node_socket_interface_draw; + stype->interface_draw_color = std_node_socket_interface_draw_color; +} + void ED_init_node_socket_type_virtual(bNodeSocketType *stype) { + using namespace blender::ed::space_node; stype->draw = node_socket_button_label; stype->draw_color = node_socket_virtual_draw_color; } +namespace blender::ed::space_node { + /* ************** Generic drawing ************** */ void draw_nodespace_back_pix(const bContext &C, @@ -3845,23 +1891,29 @@ static void nodelink_batch_draw(const SpaceNode &snode) } GPU_blend(GPU_BLEND_ALPHA); + NodeLinkInstanceData node_link_data; + + UI_GetThemeColor4fv(TH_WIRE_INNER, node_link_data.colors[nodelink_get_color_id(TH_WIRE_INNER)]); + UI_GetThemeColor4fv(TH_WIRE, node_link_data.colors[nodelink_get_color_id(TH_WIRE)]); + UI_GetThemeColor4fv(TH_ACTIVE, node_link_data.colors[nodelink_get_color_id(TH_ACTIVE)]); + UI_GetThemeColor4fv(TH_EDGE_SELECT, + node_link_data.colors[nodelink_get_color_id(TH_EDGE_SELECT)]); + UI_GetThemeColor4fv(TH_REDALERT, node_link_data.colors[nodelink_get_color_id(TH_REDALERT)]); + node_link_data.expandSize = snode.runtime->aspect * LINK_WIDTH; + node_link_data.arrowSize = ARROW_SIZE; - float colors[6][4] = {{0.0f}}; - UI_GetThemeColor4fv(TH_WIRE_INNER, colors[nodelink_get_color_id(TH_WIRE_INNER)]); - UI_GetThemeColor4fv(TH_WIRE, colors[nodelink_get_color_id(TH_WIRE)]); - UI_GetThemeColor4fv(TH_ACTIVE, colors[nodelink_get_color_id(TH_ACTIVE)]); - UI_GetThemeColor4fv(TH_EDGE_SELECT, colors[nodelink_get_color_id(TH_EDGE_SELECT)]); - UI_GetThemeColor4fv(TH_REDALERT, colors[nodelink_get_color_id(TH_REDALERT)]); + GPUUniformBuf *ubo = GPU_uniformbuf_create_ex(sizeof(node_link_data), &node_link_data, __func__); GPU_vertbuf_data_len_set(g_batch_link.inst_vbo, g_batch_link.count); GPU_vertbuf_use(g_batch_link.inst_vbo); /* force update. */ GPU_batch_program_set_builtin(g_batch_link.batch, GPU_SHADER_2D_NODELINK_INST); - GPU_batch_uniform_4fv_array(g_batch_link.batch, "colors", 6, colors); - GPU_batch_uniform_1f(g_batch_link.batch, "expandSize", snode.runtime->aspect * LINK_WIDTH); - GPU_batch_uniform_1f(g_batch_link.batch, "arrowSize", ARROW_SIZE); + GPU_batch_uniformbuf_bind(g_batch_link.batch, "node_link_data", ubo); GPU_batch_draw(g_batch_link.batch); + GPU_uniformbuf_unbind(ubo); + GPU_uniformbuf_free(ubo); + nodelink_batch_reset(); GPU_blend(GPU_BLEND_NONE); @@ -4032,19 +2084,32 @@ void node_draw_link_bezier(const bContext &C, copy_v4_v4(colors[2], link_preselection_highlight_color); } + NodeLinkData node_link_data; + for (int i = 0; i < 4; i++) { + copy_v2_v2(node_link_data.bezierPts[i], vec[i]); + } + for (int i = 0; i < 3; i++) { + copy_v4_v4(node_link_data.colors[i], colors[i]); + } + node_link_data.doArrow = drawarrow; + node_link_data.doMuted = drawmuted; + node_link_data.dim_factor = dim_factor; + node_link_data.thickness = thickness; + node_link_data.dash_factor = dash_factor; + node_link_data.dash_alpha = dash_alpha; + node_link_data.expandSize = snode.runtime->aspect * LINK_WIDTH; + node_link_data.arrowSize = ARROW_SIZE; + GPUBatch *batch = g_batch_link.batch_single; + GPUUniformBuf *ubo = GPU_uniformbuf_create_ex( + sizeof(NodeLinkData), &node_link_data, __func__); + GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_NODELINK); - GPU_batch_uniform_2fv_array(batch, "bezierPts", 4, vec); - GPU_batch_uniform_4fv_array(batch, "colors", 3, colors); - GPU_batch_uniform_1f(batch, "expandSize", snode.runtime->aspect * LINK_WIDTH); - GPU_batch_uniform_1f(batch, "arrowSize", ARROW_SIZE); - GPU_batch_uniform_1i(batch, "doArrow", drawarrow); - GPU_batch_uniform_1i(batch, "doMuted", drawmuted); - GPU_batch_uniform_1f(batch, "dim_factor", dim_factor); - GPU_batch_uniform_1f(batch, "thickness", thickness); - GPU_batch_uniform_1f(batch, "dash_factor", dash_factor); - GPU_batch_uniform_1f(batch, "dash_alpha", dash_alpha); + GPU_batch_uniformbuf_bind(batch, "node_link_data", ubo); GPU_batch_draw(batch); + + GPU_uniformbuf_unbind(ubo); + GPU_uniformbuf_free(ubo); } } } @@ -4099,6 +2164,8 @@ void node_draw_link(const bContext &C, node_draw_link_bezier(C, v2d, snode, link, th_col1, th_col2, th_col3); } +} // namespace blender::ed::space_node + void ED_node_draw_snap(View2D *v2d, const float cent[2], float size, NodeBorder border, uint pos) { immBegin(GPU_PRIM_LINES, 4); diff --git a/source/blender/editors/space_node/link_drag_search.cc b/source/blender/editors/space_node/link_drag_search.cc new file mode 100644 index 00000000000..45126e9cee0 --- /dev/null +++ b/source/blender/editors/space_node/link_drag_search.cc @@ -0,0 +1,327 @@ +/* + * 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_string_search.h" + +#include "DNA_space_types.h" + +#include "BKE_context.h" + +#include "NOD_socket_search_link.hh" + +#include "BLT_translation.h" + +#include "RNA_access.h" + +#include "WM_api.h" + +#include "ED_node.h" + +#include "node_intern.hh" + +using blender::nodes::SocketLinkOperation; + +namespace blender::ed::space_node { + +struct LinkDragSearchStorage { + bNode &from_node; + bNodeSocket &from_socket; + float2 cursor; + Vector<SocketLinkOperation> search_link_ops; + char search[256]; + + eNodeSocketInOut in_out() const + { + return static_cast<eNodeSocketInOut>(from_socket.in_out); + } +}; + +static void add_reroute_node_fn(nodes::LinkSearchOpParams ¶ms) +{ + bNode &reroute = params.add_node("NodeReroute"); + if (params.socket.in_out == SOCK_IN) { + nodeAddLink(¶ms.node_tree, + &reroute, + static_cast<bNodeSocket *>(reroute.outputs.first), + ¶ms.node, + ¶ms.socket); + } + else { + nodeAddLink(¶ms.node_tree, + ¶ms.node, + ¶ms.socket, + &reroute, + static_cast<bNodeSocket *>(reroute.inputs.first)); + } +} + +static void add_group_input_node_fn(nodes::LinkSearchOpParams ¶ms) +{ + /* Add a group input based on the connected socket, and add a new group input node. */ + bNodeSocket *interface_socket = ntreeAddSocketInterfaceFromSocket( + ¶ms.node_tree, ¶ms.node, ¶ms.socket); + const int group_input_index = BLI_findindex(¶ms.node_tree.inputs, interface_socket); + + bNode &group_input = params.add_node("NodeGroupInput"); + + /* This is necessary to create the new sockets in the other input nodes. */ + ED_node_tree_propagate_change(¶ms.C, CTX_data_main(¶ms.C), ¶ms.node_tree); + + /* Hide the new input in all other group input nodes, to avoid making them taller. */ + LISTBASE_FOREACH (bNode *, node, ¶ms.node_tree.nodes) { + if (node->type == NODE_GROUP_INPUT) { + bNodeSocket *new_group_input_socket = (bNodeSocket *)BLI_findlink(&node->outputs, + group_input_index); + new_group_input_socket->flag |= SOCK_HIDDEN; + } + } + + /* Hide all existing inputs in the new group input node, to only display the new one. */ + LISTBASE_FOREACH (bNodeSocket *, socket, &group_input.outputs) { + socket->flag |= SOCK_HIDDEN; + } + + bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&group_input.outputs, group_input_index); + if (socket == nullptr) { + /* Adding sockets can fail in some cases. There's no good reason not to be safe here. */ + return; + } + /* Unhide the socket for the new input in the new node and make a connection to it. */ + socket->flag &= ~SOCK_HIDDEN; + nodeAddLink(¶ms.node_tree, &group_input, socket, ¶ms.node, ¶ms.socket); +} + +static void add_existing_group_input_fn(nodes::LinkSearchOpParams ¶ms, + const bNodeSocket &interface_socket) +{ + const int group_input_index = BLI_findindex(¶ms.node_tree.inputs, &interface_socket); + bNode &group_input = params.add_node("NodeGroupInput"); + + LISTBASE_FOREACH (bNodeSocket *, socket, &group_input.outputs) { + socket->flag |= SOCK_HIDDEN; + } + + bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&group_input.outputs, group_input_index); + if (socket == nullptr) { + /* Adding sockets can fail in some cases. There's no good reason not to be safe here. */ + return; + } + + socket->flag &= ~SOCK_HIDDEN; + nodeAddLink(¶ms.node_tree, &group_input, socket, ¶ms.node, ¶ms.socket); +} + +/** + * Call the callback to gather compatible socket connections for all node types, and the operations + * that will actually make the connections. Also add some custom operations like connecting a group + * output node. + */ +static void gather_socket_link_operations(bNodeTree &node_tree, + const bNodeSocket &socket, + Vector<SocketLinkOperation> &search_link_ops) +{ + NODE_TYPES_BEGIN (node_type) { + if (StringRef(node_type->idname).find("Legacy") != StringRef::not_found) { + continue; + } + const char *disabled_hint; + if (!(node_type->poll && node_type->poll(node_type, &node_tree, &disabled_hint))) { + continue; + } + + if (node_type->gather_link_search_ops) { + nodes::GatherLinkSearchOpParams params{*node_type, node_tree, socket, search_link_ops}; + node_type->gather_link_search_ops(params); + } + } + NODE_TYPES_END; + + search_link_ops.append({IFACE_("Reroute"), add_reroute_node_fn}); + + const bool is_node_group = !(node_tree.id.flag & LIB_EMBEDDED_DATA); + + if (is_node_group && socket.in_out == SOCK_IN) { + search_link_ops.append({IFACE_("Group Input"), add_group_input_node_fn}); + + int weight = -1; + LISTBASE_FOREACH (const bNodeSocket *, interface_socket, &node_tree.inputs) { + eNodeSocketDatatype from = (eNodeSocketDatatype)interface_socket->type; + eNodeSocketDatatype to = (eNodeSocketDatatype)socket.type; + if (node_tree.typeinfo->validate_link && !node_tree.typeinfo->validate_link(from, to)) { + continue; + } + search_link_ops.append( + {std::string(IFACE_("Group Input ")) + UI_MENU_ARROW_SEP + interface_socket->name, + [interface_socket](nodes::LinkSearchOpParams ¶ms) { + add_existing_group_input_fn(params, *interface_socket); + }, + weight}); + weight--; + } + } +} + +static void link_drag_search_update_fn(const bContext *UNUSED(C), + void *arg, + const char *str, + uiSearchItems *items, + const bool is_first) +{ + LinkDragSearchStorage &storage = *static_cast<LinkDragSearchStorage *>(arg); + + StringSearch *search = BLI_string_search_new(); + + for (SocketLinkOperation &op : storage.search_link_ops) { + BLI_string_search_add(search, op.name.c_str(), &op, op.weight); + } + + /* 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; + SocketLinkOperation **filtered_items; + const int filtered_amount = BLI_string_search_query(search, string, (void ***)&filtered_items); + + for (const int i : IndexRange(filtered_amount)) { + SocketLinkOperation &item = *filtered_items[i]; + if (!UI_search_item_add(items, item.name.c_str(), &item, ICON_NONE, 0, 0)) { + break; + } + } + + MEM_freeN(filtered_items); + BLI_string_search_free(search); +} + +static void link_drag_search_exec_fn(bContext *C, void *arg1, void *arg2) +{ + Main &bmain = *CTX_data_main(C); + SpaceNode &snode = *CTX_wm_space_node(C); + LinkDragSearchStorage &storage = *static_cast<LinkDragSearchStorage *>(arg1); + SocketLinkOperation *item = static_cast<SocketLinkOperation *>(arg2); + if (item == nullptr) { + return; + } + + node_deselect_all(snode); + + Vector<bNode *> new_nodes; + nodes::LinkSearchOpParams params{ + *C, *snode.edittree, storage.from_node, storage.from_socket, new_nodes}; + item->fn(params); + if (new_nodes.is_empty()) { + return; + } + + /* For now, assume that only one node is created by the callback. */ + BLI_assert(new_nodes.size() == 1); + bNode *new_node = new_nodes.first(); + + new_node->locx = storage.cursor.x / UI_DPI_FAC; + new_node->locy = storage.cursor.y / UI_DPI_FAC + 20 * UI_DPI_FAC; + if (storage.in_out() == SOCK_IN) { + new_node->locx -= new_node->width; + } + + nodeSetSelected(new_node, true); + nodeSetActive(snode.edittree, new_node); + + /* Ideally it would be possible to tag the node tree in some way so it updates only after the + * translate operation is finished, but normally moving nodes around doesn't cause updates. */ + ED_node_tree_propagate_change(C, &bmain, snode.edittree); + + /* Start translation operator with the new node. */ + wmOperatorType *ot = WM_operatortype_find("TRANSFORM_OT_translate", true); + BLI_assert(ot); + PointerRNA ptr; + WM_operator_properties_create_ptr(&ptr, ot); + RNA_boolean_set(&ptr, "view2d_edge_pan", true); + WM_operator_name_call_ptr(C, ot, WM_OP_INVOKE_DEFAULT, &ptr); + WM_operator_properties_free(&ptr); +} + +static void link_drag_search_free_fn(void *arg) +{ + LinkDragSearchStorage *storage = static_cast<LinkDragSearchStorage *>(arg); + delete storage; +} + +static uiBlock *create_search_popup_block(bContext *C, ARegion *region, void *arg_op) +{ + LinkDragSearchStorage &storage = *(LinkDragSearchStorage *)arg_op; + + bNodeTree *node_tree = CTX_wm_space_node(C)->nodetree; + gather_socket_link_operations(*node_tree, storage.from_socket, storage.search_link_ops); + + uiBlock *block = UI_block_begin(C, region, "_popup", UI_EMBOSS); + UI_block_flag_enable(block, UI_BLOCK_LOOP | UI_BLOCK_MOVEMOUSE_QUIT | UI_BLOCK_SEARCH_MENU); + UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP); + + uiBut *but = uiDefSearchBut(block, + storage.search, + 0, + ICON_VIEWZOOM, + sizeof(storage.search), + storage.in_out() == SOCK_OUT ? 10 : 10 - UI_searchbox_size_x(), + 10, + UI_searchbox_size_x(), + UI_UNIT_Y, + 0, + 0, + ""); + UI_but_func_search_set_sep_string(but, UI_MENU_ARROW_SEP); + UI_but_func_search_set(but, + nullptr, + link_drag_search_update_fn, + &storage, + false, + link_drag_search_free_fn, + link_drag_search_exec_fn, + nullptr); + UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT); + + /* Fake button to hold space for the search items. */ + uiDefBut(block, + UI_BTYPE_LABEL, + 0, + "", + storage.in_out() == SOCK_OUT ? 10 : 10 - UI_searchbox_size_x(), + 10 - UI_searchbox_size_y(), + UI_searchbox_size_x(), + UI_searchbox_size_y(), + nullptr, + 0, + 0, + 0, + 0, + nullptr); + + const int offset[2] = {0, -UI_UNIT_Y}; + UI_block_bounds_set_popup(block, 0.3f * U.widget_unit, offset); + return block; +} + +void invoke_node_link_drag_add_menu(bContext &C, + bNode &node, + bNodeSocket &socket, + const float2 &cursor) +{ + LinkDragSearchStorage *storage = new LinkDragSearchStorage{node, socket, cursor}; + /* Use the "_ex" variant with `can_refresh` false to avoid a double free when closing Blender. */ + UI_popup_block_invoke_ex(&C, create_search_popup_block, storage, nullptr, false); +} + +} // namespace blender::ed::space_node diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc index c6a5e8e68c0..8e88f1fad5a 100644 --- a/source/blender/editors/space_node/node_add.cc +++ b/source/blender/editors/space_node/node_add.cc @@ -36,6 +36,7 @@ #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BKE_node_tree_update.h" #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_texture.h" @@ -61,6 +62,8 @@ /** \name Utilities * \{ */ +namespace blender::ed::space_node { + bNode *node_add_node(const bContext &C, const char *idname, int type, float locx, float locy) { SpaceNode &snode = *CTX_wm_space_node(&C); @@ -83,15 +86,8 @@ bNode *node_add_node(const bContext &C, const char *idname, int type, float locx nodeSetSelected(node, true); - ntreeUpdateTree(&bmain, snode.edittree); ED_node_set_active(&bmain, &snode, snode.edittree, node, nullptr); - - snode_update(snode, node); - - if (snode.nodetree->type == NTREE_TEXTURE) { - ntreeTexCheckCyclics(snode.edittree); - } - + ED_node_tree_propagate_change(&C, &bmain, snode.edittree); return node; } @@ -136,7 +132,7 @@ static bNodeSocketLink *add_reroute_insert_socket_link(ListBase *lb, { bNodeSocketLink *socklink, *prev; - socklink = (bNodeSocketLink *)MEM_callocN(sizeof(bNodeSocketLink), "socket link"); + socklink = MEM_cnew<bNodeSocketLink>("socket link"); socklink->sock = sock; socklink->link = link; copy_v2_v2(socklink->point, point); @@ -281,10 +277,7 @@ static int add_reroute_exec(bContext *C, wmOperator *op) BLI_freelistN(&input_links); /* always last */ - ntreeUpdateTree(CTX_data_main(C), &ntree); - snode_notify(*C, snode); - snode_dag_update(*C, snode); - + ED_node_tree_propagate_change(C, CTX_data_main(C), &ntree); return OPERATOR_FINISHED; } @@ -383,14 +376,10 @@ static int node_add_group_exec(bContext *C, wmOperator *op) group_node->id = &node_group->id; id_us_plus(group_node->id); + BKE_ntree_update_tag_node_property(snode->edittree, group_node); nodeSetActive(ntree, group_node); - ntreeUpdateTree(bmain, node_group); - ntreeUpdateTree(bmain, ntree); - - snode_notify(*C, *snode); - snode_dag_update(*C, *snode); - + ED_node_tree_propagate_change(C, bmain, nullptr); return OPERATOR_FINISHED; } @@ -479,12 +468,7 @@ static int node_add_object_exec(bContext *C, wmOperator *op) id_us_plus(&object->id); nodeSetActive(ntree, object_node); - ntreeUpdateTree(bmain, ntree); - - snode_notify(*C, *snode); - snode_dag_update(*C, *snode); - - ED_node_tag_update_nodetree(bmain, ntree, object_node); + ED_node_tree_propagate_change(C, bmain, ntree); DEG_relations_tag_update(bmain); return OPERATOR_FINISHED; @@ -517,6 +501,8 @@ static bool node_add_object_poll(bContext *C) void NODE_OT_add_object(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Add Node Object"; ot->description = "Add an object info node to the current node editor"; @@ -531,15 +517,16 @@ void NODE_OT_add_object(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; RNA_def_string(ot->srna, "name", "Object", MAX_ID_NAME - 2, "Name", "Data-block name to assign"); - RNA_def_int(ot->srna, - "session_uuid", - 0, - INT32_MIN, - INT32_MAX, - "Session UUID", - "Session UUID of the data-block to assign", - INT32_MIN, - INT32_MAX); + prop = RNA_def_int(ot->srna, + "session_uuid", + 0, + INT32_MIN, + INT32_MAX, + "Session UUID", + "Session UUID of the data-block to assign", + INT32_MIN, + INT32_MAX); + RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE)); } /** \} */ @@ -587,14 +574,9 @@ static int node_add_texture_exec(bContext *C, wmOperator *op) id_us_plus(&texture->id); nodeSetActive(ntree, texture_node); - ntreeUpdateTree(bmain, ntree); - - snode_notify(*C, *snode); - snode_dag_update(*C, *snode); + ED_node_tree_propagate_change(C, bmain, ntree); DEG_relations_tag_update(bmain); - ED_node_tag_update_nodetree(bmain, ntree, texture_node); - return OPERATOR_FINISHED; } @@ -625,6 +607,8 @@ static bool node_add_texture_poll(bContext *C) void NODE_OT_add_texture(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Add Node Texture"; ot->description = "Add a texture to the current node editor"; @@ -640,15 +624,16 @@ void NODE_OT_add_texture(wmOperatorType *ot) RNA_def_string( ot->srna, "name", "Texture", MAX_ID_NAME - 2, "Name", "Data-block name to assign"); - RNA_def_int(ot->srna, - "session_uuid", - 0, - INT32_MIN, - INT32_MAX, - "Session UUID", - "Session UUID of the data-block to assign", - INT32_MIN, - INT32_MAX); + prop = RNA_def_int(ot->srna, + "session_uuid", + 0, + INT32_MIN, + INT32_MAX, + "Session UUID", + "Session UUID of the data-block to assign", + INT32_MIN, + INT32_MAX); + RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE)); } /** \} */ @@ -701,14 +686,9 @@ static int node_add_collection_exec(bContext *C, wmOperator *op) id_us_plus(&collection->id); nodeSetActive(ntree, collection_node); - ntreeUpdateTree(bmain, ntree); - - snode_notify(*C, snode); - snode_dag_update(*C, snode); + ED_node_tree_propagate_change(C, bmain, ntree); DEG_relations_tag_update(bmain); - ED_node_tag_update_nodetree(bmain, ntree, collection_node); - return OPERATOR_FINISHED; } @@ -739,6 +719,8 @@ static bool node_add_collection_poll(bContext *C) void NODE_OT_add_collection(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Add Node Collection"; ot->description = "Add an collection info node to the current node editor"; @@ -754,15 +736,16 @@ void NODE_OT_add_collection(wmOperatorType *ot) RNA_def_string( ot->srna, "name", "Collection", MAX_ID_NAME - 2, "Name", "Data-block name to assign"); - RNA_def_int(ot->srna, - "session_uuid", - 0, - INT32_MIN, - INT32_MAX, - "Session UUID", - "Session UUID of the data-block to assign", - INT32_MIN, - INT32_MAX); + prop = RNA_def_int(ot->srna, + "session_uuid", + 0, + INT32_MIN, + INT32_MAX, + "Session UUID", + "Session UUID of the data-block to assign", + INT32_MIN, + INT32_MAX); + RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE)); } /** \} */ @@ -834,8 +817,7 @@ static int node_add_file_exec(bContext *C, wmOperator *op) WM_event_add_notifier(C, NC_IMAGE | NA_EDITED, ima); } - snode_notify(*C, snode); - snode_dag_update(*C, snode); + ED_node_tree_propagate_change(C, bmain, snode.edittree); DEG_relations_tag_update(bmain); return OPERATOR_FINISHED; @@ -937,8 +919,7 @@ static int node_add_mask_exec(bContext *C, wmOperator *op) node->id = mask; id_us_plus(mask); - snode_notify(*C, snode); - snode_dag_update(*C, snode); + ED_node_tree_propagate_change(C, bmain, snode.edittree); DEG_relations_tag_update(bmain); return OPERATOR_FINISHED; @@ -946,6 +927,8 @@ static int node_add_mask_exec(bContext *C, wmOperator *op) void NODE_OT_add_mask(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Add Mask Node"; ot->description = "Add a mask node to the current node editor"; @@ -959,15 +942,16 @@ void NODE_OT_add_mask(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL; RNA_def_string(ot->srna, "name", "Mask", MAX_ID_NAME - 2, "Name", "Data-block name to assign"); - RNA_def_int(ot->srna, - "session_uuid", - 0, - INT32_MIN, - INT32_MAX, - "Session UUID", - "Session UUID of the data-block to assign", - INT32_MIN, - INT32_MAX); + prop = RNA_def_int(ot->srna, + "session_uuid", + 0, + INT32_MIN, + INT32_MAX, + "Session UUID", + "Session UUID of the data-block to assign", + INT32_MIN, + INT32_MAX); + RNA_def_property_flag(prop, (PropertyFlag)(PROP_HIDDEN | PROP_SKIP_SAVE)); } /** \} */ @@ -1064,3 +1048,5 @@ void NODE_OT_new_node_tree(wmOperatorType *ot) } /** \} */ + +} // namespace blender::ed::space_node diff --git a/source/blender/editors/space_node/node_context_path.cc b/source/blender/editors/space_node/node_context_path.cc index 2f3855fd654..cab7cbf10be 100644 --- a/source/blender/editors/space_node/node_context_path.cc +++ b/source/blender/editors/space_node/node_context_path.cc @@ -45,11 +45,11 @@ #include "node_intern.hh" -struct Mesh; struct Curve; struct Light; -struct World; struct Material; +struct Mesh; +struct World; namespace blender::ed::space_node { diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc index d68f16f6197..82da890fa9b 100644 --- a/source/blender/editors/space_node/node_draw.cc +++ b/source/blender/editors/space_node/node_draw.cc @@ -88,13 +88,6 @@ #include "node_intern.hh" /* own include */ -using blender::Array; -using blender::float2; -using blender::Map; -using blender::Set; -using blender::Span; -using blender::Vector; -using blender::VectorSet; using blender::fn::CPPType; using blender::fn::FieldCPPType; using blender::fn::FieldInput; @@ -115,6 +108,8 @@ float ED_node_grid_size() void ED_node_tree_update(const bContext *C) { + using namespace blender::ed::space_node; + SpaceNode *snode = CTX_wm_space_node(C); if (snode) { snode_set_context(*C); @@ -176,34 +171,7 @@ void ED_node_tag_update_id(ID *id) } } -void ED_node_tag_update_nodetree(Main *bmain, bNodeTree *ntree, bNode *node) -{ - if (!ntree) { - return; - } - - bool do_tag_update = true; - if (node != nullptr) { - if (!node_connected_to_output(*bmain, *ntree, *node)) { - do_tag_update = false; - } - } - - /* Look through all datablocks to support groups. */ - if (do_tag_update) { - FOREACH_NODETREE_BEGIN (bmain, tntree, id) { - /* Check if nodetree uses the group. */ - if (ntreeHasTree(tntree, ntree)) { - ED_node_tag_update_id(id); - } - } - FOREACH_NODETREE_END; - } - - if (ntree->type == NTREE_TEXTURE) { - ntreeTexCheckCyclics(ntree); - } -} +namespace blender::ed::space_node { static bool compare_nodes(const bNode *a, const bNode *b) { @@ -261,14 +229,14 @@ static bool compare_nodes(const bNode *a, const bNode *b) return false; } -void ED_node_sort(bNodeTree *ntree) +void node_sort(bNodeTree &ntree) { /* Merge sort is the algorithm of choice here. */ - int totnodes = BLI_listbase_count(&ntree->nodes); + int totnodes = BLI_listbase_count(&ntree.nodes); int k = 1; while (k < totnodes) { - bNode *first_a = (bNode *)ntree->nodes.first; + bNode *first_a = (bNode *)ntree.nodes.first; bNode *first_b = first_a; do { @@ -295,8 +263,8 @@ void ED_node_sort(bNodeTree *ntree) bNode *tmp = node_b; node_b = node_b->next; b++; - BLI_remlink(&ntree->nodes, tmp); - BLI_insertlinkbefore(&ntree->nodes, node_a, tmp); + BLI_remlink(&ntree.nodes, tmp); + BLI_insertlinkbefore(&ntree.nodes, node_a, tmp); } } @@ -365,6 +333,10 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node, PointerRNA nodeptr; RNA_pointer_create(&ntree.id, &RNA_Node, &node, &nodeptr); + const bool node_options = node.typeinfo->draw_buttons && (node.flag & NODE_OPTIONS); + const bool inputs_first = node.inputs.first && + !(node.outputs.first || (node.flag & NODE_PREVIEW) || node_options); + /* Get "global" coordinates. */ float2 loc = node_to_view(node, float2(0)); /* Round the node origin because text contents are always pixel-aligned. */ @@ -377,7 +349,7 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node, dy -= NODE_DY; /* Add a little bit of padding above the top socket. */ - if (node.outputs.first || node.inputs.first) { + if (node.outputs.first || inputs_first) { dy -= NODE_DYS / 2; } @@ -478,7 +450,7 @@ static void node_update_basis(const bContext &C, bNodeTree &ntree, bNode &node, } /* Buttons rect? */ - if (node.typeinfo->draw_buttons && (node.flag & NODE_OPTIONS)) { + if (node_options) { dy -= NODE_DYS / 2; uiLayout *layout = UI_block_layout(&block, @@ -1096,8 +1068,12 @@ static void node_socket_draw_nested(const bContext &C, UI_block_emboss_set(&block, old_emboss); } +} // namespace blender::ed::space_node + void ED_node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[4], float scale) { + using namespace blender::ed::space_node; + const float size = 2.25f * NODE_SOCKSIZE * scale; rcti draw_rect = *rect; float outline_color[4] = {0}; @@ -1144,6 +1120,8 @@ void ED_node_socket_draw(bNodeSocket *sock, const rcti *rect, const float color[ GPU_blend(state); } +namespace blender::ed::space_node { + /* ************** Socket callbacks *********** */ static void node_draw_preview_background(rctf *rect) @@ -1194,17 +1172,17 @@ static void node_draw_preview(bNodePreview *preview, rctf *prv) GPU_blend(GPU_BLEND_ALPHA); IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR); - immDrawPixelsTex(&state, - draw_rect.xmin, - draw_rect.ymin, - preview->xsize, - preview->ysize, - GPU_RGBA8, - true, - preview->rect, - scale, - scale, - nullptr); + immDrawPixelsTexTiled(&state, + draw_rect.xmin, + draw_rect.ymin, + preview->xsize, + preview->ysize, + GPU_RGBA8, + true, + preview->rect, + scale, + scale, + nullptr); GPU_blend(GPU_BLEND_NONE); @@ -2405,7 +2383,6 @@ static void node_update_nodetree(const bContext &C, { /* Make sure socket "used" tags are correct, for displaying value buttons. */ SpaceNode *snode = CTX_wm_space_node(&C); - ntreeTagUsedSockets(&ntree); count_multi_input_socket_links(ntree, *snode); @@ -2414,9 +2391,11 @@ static void node_update_nodetree(const bContext &C, bNode &node = *nodes[i]; uiBlock &block = *blocks[i]; if (node.type == NODE_FRAME) { - frame_node_prepare_for_draw(node, nodes); + /* Frame sizes are calculated after all other nodes have calculating their #totr. */ + continue; } - else if (node.type == NODE_REROUTE) { + + if (node.type == NODE_REROUTE) { reroute_node_prepare_for_draw(node); } else { @@ -2428,6 +2407,13 @@ static void node_update_nodetree(const bContext &C, } } } + + /* Now calculate the size of frame nodes, which can depend on the size of other nodes. */ + for (const int i : nodes.index_range()) { + if (nodes[i]->type == NODE_FRAME) { + frame_node_prepare_for_draw(*nodes[i], nodes); + } + } } static void frame_node_draw_label(const bNodeTree &ntree, @@ -2469,7 +2455,7 @@ static void frame_node_draw_label(const bNodeTree &ntree, const bool has_label = node.label[0] != '\0'; if (has_label) { BLF_position(fontid, x, y, 0); - BLF_draw(fontid, label, BLF_DRAW_STR_DUMMY_MAX); + BLF_draw(fontid, label, sizeof(label)); } /* draw text body */ @@ -2896,3 +2882,5 @@ void node_draw_space(const bContext &C, ARegion ®ion) /* Scrollers. */ UI_view2d_scrollers_draw(&v2d, nullptr); } + +} // namespace blender::ed::space_node diff --git a/source/blender/editors/space_node/node_edit.cc b/source/blender/editors/space_node/node_edit.cc index fb90e2bfe50..6275e7e4656 100644 --- a/source/blender/editors/space_node/node_edit.cc +++ b/source/blender/editors/space_node/node_edit.cc @@ -38,6 +38,7 @@ #include "BKE_main.h" #include "BKE_material.h" #include "BKE_node.h" +#include "BKE_node_tree_update.h" #include "BKE_report.h" #include "BKE_scene.h" #include "BKE_workspace.h" @@ -75,9 +76,9 @@ #include "NOD_texture.h" #include "node_intern.hh" /* own include */ -#define USE_ESC_COMPO +namespace blender::ed::space_node { -using blender::float2; +#define USE_ESC_COMPO /* ***************** composite job manager ********************** */ @@ -318,8 +319,12 @@ static void compo_startjob(void *cjv, ntree->progress = nullptr; } +} // namespace blender::ed::space_node + void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene *scene_owner) { + using namespace blender::ed::space_node; + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); @@ -342,7 +347,7 @@ void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene "Compositing", WM_JOB_EXCL_RENDER | WM_JOB_PROGRESS, WM_JOB_TYPE_COMPOSITE); - CompoJob *cj = (CompoJob *)MEM_callocN(sizeof(CompoJob), "compo job"); + CompoJob *cj = MEM_cnew<CompoJob>("compo job"); /* customdata for preview thread */ cj->bmain = bmain; @@ -359,6 +364,8 @@ void ED_node_composite_job(const bContext *C, struct bNodeTree *nodetree, Scene WM_jobs_start(CTX_wm_manager(C), wm_job); } +namespace blender::ed::space_node { + /* ***************************************** */ bool composite_node_active(bContext *C) @@ -383,31 +390,11 @@ bool composite_node_editable(bContext *C) return false; } -void snode_dag_update(bContext &C, SpaceNode &snode) -{ - Main *bmain = CTX_data_main(&C); - - /* for groups, update all ID's using this */ - if ((snode.edittree->id.flag & LIB_EMBEDDED_DATA) == 0) { - FOREACH_NODETREE_BEGIN (bmain, tntree, id) { - if (ntreeHasTree(tntree, snode.edittree)) { - DEG_id_tag_update(id, 0); - } - } - FOREACH_NODETREE_END; - } - - DEG_id_tag_update(snode.id, 0); - DEG_id_tag_update(&snode.nodetree->id, 0); -} - -void snode_notify(bContext &C, SpaceNode &snode) +static void send_notifiers_after_tree_change(ID *id, bNodeTree *ntree) { - ID *id = snode.id; + WM_main_add_notifier(NC_NODE | NA_EDITED, nullptr); - WM_event_add_notifier(&C, NC_NODE | NA_EDITED, nullptr); - - if (ED_node_is_shader(&snode)) { + if (ntree->type == NTREE_SHADER) { if (GS(id->name) == ID_MA) { WM_main_add_notifier(NC_MATERIAL | ND_SHADING, id); } @@ -418,17 +405,40 @@ void snode_notify(bContext &C, SpaceNode &snode) WM_main_add_notifier(NC_WORLD | ND_WORLD, id); } } - else if (ED_node_is_compositor(&snode)) { - WM_event_add_notifier(&C, NC_SCENE | ND_NODES, id); + else if (ntree->type == NTREE_COMPOSIT) { + WM_main_add_notifier(NC_SCENE | ND_NODES, id); } - else if (ED_node_is_texture(&snode)) { - WM_event_add_notifier(&C, NC_TEXTURE | ND_NODES, id); + else if (ntree->type == NTREE_TEXTURE) { + WM_main_add_notifier(NC_TEXTURE | ND_NODES, id); } - else if (ED_node_is_geometry(&snode)) { + else if (ntree->type == NTREE_GEOMETRY) { WM_main_add_notifier(NC_OBJECT | ND_MODIFIER, id); } } +} // namespace blender::ed::space_node + +void ED_node_tree_propagate_change(const bContext *C, Main *bmain, bNodeTree *root_ntree) +{ + if (C != nullptr) { + SpaceNode *snode = CTX_wm_space_node(C); + if (snode != nullptr && root_ntree != nullptr) { + blender::ed::space_node::send_notifiers_after_tree_change(snode->id, root_ntree); + } + } + + NodeTreeUpdateExtraParams params = {nullptr}; + params.tree_changed_fn = [](ID *id, bNodeTree *ntree, void *UNUSED(user_data)) { + blender::ed::space_node::send_notifiers_after_tree_change(id, ntree); + DEG_id_tag_update(&ntree->id, ID_RECALC_COPY_ON_WRITE); + }; + params.tree_output_changed_fn = [](ID *UNUSED(id), bNodeTree *ntree, void *UNUSED(user_data)) { + DEG_id_tag_update(&ntree->id, ID_RECALC_NTREE_OUTPUT); + }; + + BKE_ntree_update_main_tree(bmain, root_ntree, ¶ms); +} + void ED_node_set_tree_type(SpaceNode *snode, bNodeTreeType *typeinfo) { if (typeinfo) { @@ -477,7 +487,7 @@ void ED_node_shader_default(const bContext *C, ID *id) } ma->nodetree = ntreeCopyTree(bmain, ma_default->nodetree); - ntreeUpdateTree(bmain, ma->nodetree); + BKE_ntree_update_main_tree(bmain, ma->nodetree, nullptr); } else if (ELEM(GS(id->name), ID_WO, ID_LA)) { /* Emission */ @@ -517,7 +527,7 @@ void ED_node_shader_default(const bContext *C, ID *id) output->locx = 300.0f; output->locy = 300.0f; nodeSetActive(ntree, output); - ntreeUpdateTree(bmain, ntree); + BKE_ntree_update_main_tree(bmain, ntree, nullptr); } else { printf("ED_node_shader_default called on wrong ID type.\n"); @@ -555,7 +565,7 @@ void ED_node_composit_default(const bContext *C, struct Scene *sce) bNodeSocket *tosock = (bNodeSocket *)out->inputs.first; nodeAddLink(sce->nodetree, in, fromsock, out, tosock); - ntreeUpdateTree(CTX_data_main(C), sce->nodetree); + BKE_ntree_update_main_tree(CTX_data_main(C), sce->nodetree, nullptr); } void ED_node_texture_default(const bContext *C, Tex *tex) @@ -583,9 +593,11 @@ void ED_node_texture_default(const bContext *C, Tex *tex) bNodeSocket *tosock = (bNodeSocket *)out->inputs.first; nodeAddLink(tex->nodetree, in, fromsock, out, tosock); - ntreeUpdateTree(CTX_data_main(C), tex->nodetree); + BKE_ntree_update_main_tree(CTX_data_main(C), tex->nodetree, nullptr); } +namespace blender::ed::space_node { + /** * Here we set the active tree(s), even called for each redraw now, so keep it fast :) */ @@ -628,27 +640,7 @@ void snode_set_context(const bContext &C) } } -void snode_update(SpaceNode &snode, bNode *node) -{ - /* XXX this only updates nodes in the current node space tree path. - * The function supposedly should update any potential group node linking to changed tree, - * this really requires a working depsgraph ... - */ - - /* update all edited group nodes */ - bNodeTreePath *path = (bNodeTreePath *)snode.treepath.last; - if (path) { - bNodeTree *ngroup = path->nodetree; - for (path = path->prev; path; path = path->prev) { - nodeUpdateID(path->nodetree, (ID *)ngroup); - ngroup = path->nodetree; - } - } - - if (node) { - nodeUpdate(snode.edittree, node); - } -} +} // namespace blender::ed::space_node void ED_node_set_active( Main *bmain, SpaceNode *snode, bNodeTree *ntree, bNode *node, bool *r_active_texture_changed) @@ -680,11 +672,6 @@ void ED_node_set_active( /* tree specific activate calls */ if (ntree->type == NTREE_SHADER) { - /* when we select a material, active texture is cleared, for buttons */ - if (node->id && ELEM(GS(node->id->name), ID_MA, ID_LA, ID_WO)) { - nodeClearActiveID(ntree, ID_TE); - } - if (ELEM(node->type, SH_NODE_OUTPUT_MATERIAL, SH_NODE_OUTPUT_WORLD, @@ -697,14 +684,10 @@ void ED_node_set_active( } node->flag |= NODE_DO_OUTPUT; - if (was_output == 0) { - ED_node_tag_update_nodetree(bmain, ntree, node); - } - } - else if (do_update) { - ED_node_tag_update_nodetree(bmain, ntree, node); } + ED_node_tree_propagate_change(nullptr, bmain, ntree); + if ((node->flag & NODE_ACTIVE_TEXTURE) && !was_active_texture) { /* If active texture changed, free glsl materials. */ LISTBASE_FOREACH (Material *, ma, &bmain->materials) { @@ -750,7 +733,7 @@ void ED_node_set_active( if (r_active_texture_changed) { *r_active_texture_changed = true; } - ED_node_tag_update_nodetree(bmain, ntree, node); + ED_node_tree_propagate_change(nullptr, bmain, ntree); WM_main_add_notifier(NC_IMAGE, nullptr); } @@ -767,7 +750,7 @@ void ED_node_set_active( node->flag |= NODE_DO_OUTPUT; if (was_output == 0) { - ED_node_tag_update_nodetree(bmain, ntree, node); + ED_node_tree_propagate_change(nullptr, bmain, ntree); } /* Adding a node doesn't link this yet. */ @@ -782,11 +765,11 @@ void ED_node_set_active( } node->flag |= NODE_DO_OUTPUT; - ED_node_tag_update_nodetree(bmain, ntree, node); + ED_node_tree_propagate_change(nullptr, bmain, ntree); } } else if (do_update) { - ED_node_tag_update_nodetree(bmain, ntree, node); + ED_node_tree_propagate_change(nullptr, bmain, ntree); } } else if (ntree->type == NTREE_TEXTURE) { @@ -824,6 +807,8 @@ void ED_node_post_apply_transform(bContext *UNUSED(C), bNodeTree *UNUSED(ntree)) // node_update_nodetree(C, ntree, 0.0f, 0.0f); } +namespace blender::ed::space_node { + /* ***************** generic operator functions for nodes ***************** */ #if 0 /* UNUSED */ @@ -931,7 +916,7 @@ static void node_resize_init(bContext *C, { SpaceNode *snode = CTX_wm_space_node(C); - NodeSizeWidget *nsw = (NodeSizeWidget *)MEM_callocN(sizeof(NodeSizeWidget), __func__); + NodeSizeWidget *nsw = MEM_cnew<NodeSizeWidget>(__func__); op->customdata = nsw; nsw->mxstart = snode->runtime->cursor[0] * UI_DPI_FAC; @@ -1274,7 +1259,8 @@ bool node_link_is_hidden_or_dimmed(const View2D &v2d, const bNodeLink &link) /* ****************** Duplicate *********************** */ -static void node_duplicate_reparent_recursive(bNode *node) +static void node_duplicate_reparent_recursive(const Map<const bNode *, bNode *> &node_map, + bNode *node) { bNode *parent; @@ -1284,15 +1270,15 @@ static void node_duplicate_reparent_recursive(bNode *node) for (parent = node->parent; parent; parent = parent->parent) { if (parent->flag & SELECT) { if (!(parent->flag & NODE_TEST)) { - node_duplicate_reparent_recursive(parent); + node_duplicate_reparent_recursive(node_map, parent); } break; } } /* reparent node copy to parent copy */ if (parent) { - nodeDetachNode(node->new_node); - nodeAttachNode(node->new_node, parent->new_node); + nodeDetachNode(node_map.lookup(node)); + nodeAttachNode(node_map.lookup(node), node_map.lookup(parent)); } } @@ -1302,17 +1288,18 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) SpaceNode *snode = CTX_wm_space_node(C); bNodeTree *ntree = snode->edittree; const bool keep_inputs = RNA_boolean_get(op->ptr, "keep_inputs"); - bool do_tag_update = false; ED_preview_kill_jobs(CTX_wm_manager(C), bmain); + Map<const bNode *, bNode *> node_map; + Map<const bNodeSocket *, bNodeSocket *> socket_map; + bNode *lastnode = (bNode *)ntree->nodes.last; LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->flag & SELECT) { - BKE_node_copy_store_new_pointers(ntree, node, LIB_ID_COPY_DEFAULT); - - /* To ensure redraws or re-renders happen. */ - ED_node_tag_update_id(snode->id); + bNode *new_node = blender::bke::node_copy_with_mapping( + ntree, *node, LIB_ID_COPY_DEFAULT, true, socket_map); + node_map.add_new(node, new_node); } /* make sure we don't copy new nodes again! */ @@ -1321,8 +1308,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) } } - /* Copy links between selected nodes. - * NOTE: this depends on correct node->new_node and sock->new_sock pointers from above copy! */ + /* Copy links between selected nodes. */ bNodeLink *lastlink = (bNodeLink *)ntree->links.last; LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { /* This creates new links between copied nodes. @@ -1330,13 +1316,13 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) */ if (link->tonode && (link->tonode->flag & NODE_SELECT) && (keep_inputs || (link->fromnode && (link->fromnode->flag & NODE_SELECT)))) { - bNodeLink *newlink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "bNodeLink"); + bNodeLink *newlink = MEM_cnew<bNodeLink>("bNodeLink"); newlink->flag = link->flag; - newlink->tonode = link->tonode->new_node; - newlink->tosock = link->tosock->new_sock; + newlink->tonode = node_map.lookup(link->tonode); + newlink->tosock = socket_map.lookup(link->tosock); if (link->fromnode && (link->fromnode->flag & NODE_SELECT)) { - newlink->fromnode = link->fromnode->new_node; - newlink->fromsock = link->fromsock->new_sock; + newlink->fromnode = node_map.lookup(link->fromnode); + newlink->fromsock = socket_map.lookup(link->fromsock); } else { /* input node not copied, this keeps the original input linked */ @@ -1360,7 +1346,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) /* reparent copied nodes */ LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if ((node->flag & SELECT) && !(node->flag & NODE_TEST)) { - node_duplicate_reparent_recursive(node); + node_duplicate_reparent_recursive(node_map, node); } /* only has to check old nodes */ @@ -1373,13 +1359,11 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->flag & SELECT) { /* has been set during copy above */ - bNode *newnode = node->new_node; + bNode *newnode = node_map.lookup(node); nodeSetSelected(node, false); node->flag &= ~(NODE_ACTIVE | NODE_ACTIVE_TEXTURE); nodeSetSelected(newnode, true); - - do_tag_update |= (do_tag_update || node_connected_to_output(*bmain, *ntree, *newnode)); } /* make sure we don't copy new nodes again! */ @@ -1388,13 +1372,7 @@ static int node_duplicate_exec(bContext *C, wmOperator *op) } } - ntreeUpdateTree(CTX_data_main(C), snode->edittree); - - snode_notify(*C, *snode); - if (do_tag_update) { - snode_dag_update(*C, *snode); - } - + ED_node_tree_propagate_change(C, bmain, snode->edittree); return OPERATOR_FINISHED; } @@ -1416,7 +1394,7 @@ void NODE_OT_duplicate(wmOperatorType *ot) ot->srna, "keep_inputs", false, "Keep Inputs", "Keep the input links to duplicated nodes"); } -bool ED_node_select_check(const ListBase *lb) +static bool node_select_check(const ListBase *lb) { LISTBASE_FOREACH (const bNode *, node, lb) { if (node->flag & NODE_SELECT) { @@ -1427,10 +1405,10 @@ bool ED_node_select_check(const ListBase *lb) return false; } -void ED_node_select_all(ListBase *lb, int action) +void node_select_all(ListBase *lb, int action) { if (action == SEL_TOGGLE) { - if (ED_node_select_check(lb)) { + if (node_select_check(lb)) { action = SEL_DESELECT; } else { @@ -1485,8 +1463,7 @@ static int node_read_viewlayers_exec(bContext *C, wmOperator *UNUSED(op)) } } - snode_notify(*C, *snode); - snode_dag_update(*C, *snode); + ED_node_tree_propagate_change(C, bmain, snode->edittree); return OPERATOR_FINISHED; } @@ -1653,7 +1630,7 @@ static int node_preview_toggle_exec(bContext *C, wmOperator *UNUSED(op)) node_flag_toggle_exec(snode, NODE_PREVIEW); - snode_notify(*C, *snode); + ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree); return OPERATOR_FINISHED; } @@ -1732,7 +1709,7 @@ static int node_socket_toggle_exec(bContext *C, wmOperator *UNUSED(op)) } } - ntreeUpdateTree(CTX_data_main(C), snode->edittree); + ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree); WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr); @@ -1760,23 +1737,17 @@ static int node_mute_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); - bool do_tag_update = false; ED_preview_kill_jobs(CTX_wm_manager(C), bmain); LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { if ((node->flag & SELECT) && !node->typeinfo->no_muting) { node->flag ^= NODE_MUTED; - snode_update(*snode, node); - do_tag_update |= (do_tag_update || - node_connected_to_output(*bmain, *snode->edittree, *node)); + BKE_ntree_update_tag_node_mute(snode->edittree, node); } } - snode_notify(*C, *snode); - if (do_tag_update) { - snode_dag_update(*C, *snode); - } + ED_node_tree_propagate_change(C, bmain, snode->edittree); return OPERATOR_FINISHED; } @@ -1802,24 +1773,16 @@ static int node_delete_exec(bContext *C, wmOperator *UNUSED(op)) { Main *bmain = CTX_data_main(C); SpaceNode *snode = CTX_wm_space_node(C); - bool do_tag_update = false; ED_preview_kill_jobs(CTX_wm_manager(C), bmain); LISTBASE_FOREACH_MUTABLE (bNode *, node, &snode->edittree->nodes) { if (node->flag & SELECT) { - do_tag_update |= (do_tag_update || - node_connected_to_output(*bmain, *snode->edittree, *node)); nodeRemoveNode(bmain, snode->edittree, node, true); } } - ntreeUpdateTree(CTX_data_main(C), snode->edittree); - - snode_notify(*C, *snode); - if (do_tag_update) { - snode_dag_update(*C, *snode); - } + ED_node_tree_propagate_change(C, bmain, snode->edittree); return OPERATOR_FINISHED; } @@ -1863,10 +1826,7 @@ static int node_switch_view_exec(bContext *C, wmOperator *UNUSED(op)) } } - ntreeUpdateTree(CTX_data_main(C), snode->edittree); - - snode_notify(*C, *snode); - snode_dag_update(*C, *snode); + ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree); return OPERATOR_FINISHED; } @@ -1901,10 +1861,7 @@ static int node_delete_reconnect_exec(bContext *C, wmOperator *UNUSED(op)) } } - ntreeUpdateTree(CTX_data_main(C), snode->edittree); - - snode_notify(*C, *snode); - snode_dag_update(*C, *snode); + ED_node_tree_propagate_change(C, bmain, snode->edittree); return OPERATOR_FINISHED; } @@ -1951,7 +1908,7 @@ static int node_output_file_add_socket_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "file_path", file_path); ntreeCompositOutputFileAddSocket(ntree, node, file_path, &scene->r.im_format); - snode_notify(*C, *snode); + ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree); return OPERATOR_FINISHED; } @@ -2000,7 +1957,7 @@ static int node_output_file_remove_active_socket_exec(bContext *C, wmOperator *U return OPERATOR_CANCELLED; } - snode_notify(*C, *snode); + ED_node_tree_propagate_change(C, CTX_data_main(C), ntree); return OPERATOR_FINISHED; } @@ -2067,7 +2024,7 @@ static int node_output_file_move_active_socket_exec(bContext *C, wmOperator *op) nimf->active_input++; } - snode_notify(*C, *snode); + ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree); return OPERATOR_FINISHED; } @@ -2096,18 +2053,15 @@ void NODE_OT_output_file_move_active_socket(wmOperatorType *ot) static int node_copy_color_exec(bContext *C, wmOperator *UNUSED(op)) { - SpaceNode *snode = CTX_wm_space_node(C); - bNodeTree *ntree = snode->edittree; + SpaceNode &snode = *CTX_wm_space_node(C); + bNodeTree &ntree = *snode.edittree; - if (!ntree) { - return OPERATOR_CANCELLED; - } - bNode *node = nodeGetActive(ntree); + bNode *node = nodeGetActive(&ntree); if (!node) { return OPERATOR_CANCELLED; } - LISTBASE_FOREACH (bNode *, node_iter, &ntree->nodes) { + LISTBASE_FOREACH (bNode *, node_iter, &ntree.nodes) { if (node_iter->flag & NODE_SELECT && node_iter != node) { if (node->flag & NODE_CUSTOM_COLOR) { node_iter->flag |= NODE_CUSTOM_COLOR; @@ -2119,7 +2073,7 @@ static int node_copy_color_exec(bContext *C, wmOperator *UNUSED(op)) } } - ED_node_sort(ntree); + node_sort(ntree); WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr); return OPERATOR_FINISHED; @@ -2153,47 +2107,48 @@ static int node_clipboard_copy_exec(bContext *C, wmOperator *UNUSED(op)) BKE_node_clipboard_clear(); BKE_node_clipboard_init(ntree); + Map<const bNode *, bNode *> node_map; + Map<const bNodeSocket *, bNodeSocket *> socket_map; + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { if (node->flag & SELECT) { /* No ID refcounting, this node is virtual, * detached from any actual Blender data currently. */ - bNode *new_node = BKE_node_copy_store_new_pointers( - nullptr, node, LIB_ID_CREATE_NO_USER_REFCOUNT | LIB_ID_CREATE_NO_MAIN); - BKE_node_clipboard_add_node(new_node); + bNode *new_node = blender::bke::node_copy_with_mapping(nullptr, + *node, + LIB_ID_CREATE_NO_USER_REFCOUNT | + LIB_ID_CREATE_NO_MAIN, + false, + socket_map); + node_map.add_new(node, new_node); } } - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - if (node->flag & SELECT) { - bNode *new_node = node->new_node; - - /* ensure valid pointers */ - if (new_node->parent) { - /* parent pointer must be redirected to new node or detached if parent is - * not copied */ - if (new_node->parent->flag & NODE_SELECT) { - new_node->parent = new_node->parent->new_node; - } - else { - nodeDetachNode(new_node); - } + for (bNode *new_node : node_map.values()) { + BKE_node_clipboard_add_node(new_node); + + /* Parent pointer must be redirected to new node or detached if parent is not copied. */ + if (new_node->parent) { + if (node_map.contains(new_node->parent)) { + new_node->parent = node_map.lookup(new_node->parent); + } + else { + nodeDetachNode(new_node); } } } - /* Copy links between selected nodes. - * NOTE: this depends on correct node->new_node and sock->new_sock pointers from above copy! */ - + /* Copy links between selected nodes. */ LISTBASE_FOREACH (bNodeLink *, link, &ntree->links) { - /* This creates new links between copied nodes. */ - if (link->tonode && (link->tonode->flag & NODE_SELECT) && link->fromnode && - (link->fromnode->flag & NODE_SELECT)) { - bNodeLink *newlink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "bNodeLink"); + BLI_assert(link->tonode); + BLI_assert(link->fromnode); + if (link->tonode->flag & NODE_SELECT && link->fromnode->flag & NODE_SELECT) { + bNodeLink *newlink = MEM_cnew<bNodeLink>(__func__); newlink->flag = link->flag; - newlink->tonode = link->tonode->new_node; - newlink->tosock = link->tosock->new_sock; - newlink->fromnode = link->fromnode->new_node; - newlink->fromsock = link->fromsock->new_sock; + newlink->tonode = node_map.lookup(link->tonode); + newlink->tosock = socket_map.lookup(link->tosock); + newlink->fromnode = node_map.lookup(link->fromnode); + newlink->fromsock = socket_map.lookup(link->fromsock); BKE_node_clipboard_add_link(newlink); } @@ -2288,35 +2243,38 @@ static int node_clipboard_paste_exec(bContext *C, wmOperator *op) } mul_v2_fl(center, 1.0 / num_nodes); + Map<const bNode *, bNode *> node_map; + Map<const bNodeSocket *, bNodeSocket *> socket_map; + /* copy nodes from clipboard */ LISTBASE_FOREACH (bNode *, node, clipboard_nodes_lb) { - bNode *new_node = BKE_node_copy_store_new_pointers(ntree, node, LIB_ID_COPY_DEFAULT); + bNode *new_node = blender::bke::node_copy_with_mapping( + ntree, *node, LIB_ID_COPY_DEFAULT, true, socket_map); + node_map.add_new(node, new_node); + } + for (bNode *new_node : node_map.values()) { /* pasted nodes are selected */ nodeSetSelected(new_node, true); - } - /* reparent copied nodes */ - LISTBASE_FOREACH (bNode *, node, clipboard_nodes_lb) { - bNode *new_node = node->new_node; + /* The parent pointer must be redirected to new node. */ if (new_node->parent) { - new_node->parent = new_node->parent->new_node; + if (node_map.contains(new_node->parent)) { + new_node->parent = node_map.lookup(new_node->parent); + } } } LISTBASE_FOREACH (bNodeLink *, link, clipboard_links_lb) { nodeAddLink(ntree, - link->fromnode->new_node, - link->fromsock->new_sock, - link->tonode->new_node, - link->tosock->new_sock); + node_map.lookup(link->fromnode), + socket_map.lookup(link->fromsock), + node_map.lookup(link->tonode), + socket_map.lookup(link->tosock)); } Main *bmain = CTX_data_main(C); - ntreeUpdateTree(bmain, snode->edittree); - - snode_notify(*C, *snode); - snode_dag_update(*C, *snode); + ED_node_tree_propagate_change(C, bmain, snode->edittree); /* Pasting nodes can create arbitrary new relations, because nodes can reference IDs. */ DEG_relations_tag_update(bmain); @@ -2384,10 +2342,7 @@ static int ntree_socket_add_exec(bContext *C, wmOperator *op) /* make the new socket active */ sock->flag |= SELECT; - ntreeUpdateTree(CTX_data_main(C), ntree); - - snode_notify(*C, *snode); - snode_dag_update(*C, *snode); + ED_node_tree_propagate_change(C, CTX_data_main(C), snode->edittree); WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr); @@ -2434,10 +2389,7 @@ static int ntree_socket_remove_exec(bContext *C, wmOperator *op) active_sock->flag |= SELECT; } - ntreeUpdateTree(CTX_data_main(C), ntree); - - snode_notify(*C, *snode); - snode_dag_update(*C, *snode); + ED_node_tree_propagate_change(C, CTX_data_main(C), ntree); WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr); @@ -2488,7 +2440,7 @@ static int ntree_socket_change_type_exec(bContext *C, wmOperator *op) /* Need the extra update here because the loop above does not check for valid links in the node * group we're currently editing. */ - ntree->update |= NTREE_UPDATE_GROUP | NTREE_UPDATE_LINKS; + BKE_ntree_update_tag_interface(ntree); /* Deactivate sockets. */ LISTBASE_FOREACH (bNodeSocket *, socket_iter, sockets) { @@ -2497,10 +2449,7 @@ static int ntree_socket_change_type_exec(bContext *C, wmOperator *op) /* Make the new socket active. */ iosock->flag |= SELECT; - ntreeUpdateTree(main, ntree); - - snode_notify(*C, *snode); - snode_dag_update(*C, *snode); + ED_node_tree_propagate_change(C, main, ntree); WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr); @@ -2611,11 +2560,8 @@ static int ntree_socket_move_exec(bContext *C, wmOperator *op) } } - ntree->update |= NTREE_UPDATE_GROUP; - ntreeUpdateTree(CTX_data_main(C), ntree); - - snode_notify(*C, *snode); - snode_dag_update(*C, *snode); + BKE_ntree_update_tag_interface(ntree); + ED_node_tree_propagate_change(C, CTX_data_main(C), ntree); WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr); @@ -2846,7 +2792,7 @@ static int viewer_border_exec(bContext *C, wmOperator *op) btree->flag |= NTREE_VIEWER_BORDER; } - snode_notify(*C, *snode); + ED_node_tree_propagate_change(C, bmain, btree); WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr); } else { @@ -2886,7 +2832,7 @@ static int clear_viewer_border_exec(bContext *C, wmOperator *UNUSED(op)) bNodeTree *btree = snode->nodetree; btree->flag &= ~NTREE_VIEWER_BORDER; - snode_notify(*C, *snode); + ED_node_tree_propagate_change(C, CTX_data_main(C), btree); WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr); return OPERATOR_FINISHED; @@ -2931,7 +2877,7 @@ static int node_cryptomatte_add_socket_exec(bContext *C, wmOperator *UNUSED(op)) ntreeCompositCryptomatteAddSocket(ntree, node); - snode_notify(*C, *snode); + ED_node_tree_propagate_change(C, CTX_data_main(C), ntree); return OPERATOR_FINISHED; } @@ -2977,7 +2923,7 @@ static int node_cryptomatte_remove_socket_exec(bContext *C, wmOperator *UNUSED(o return OPERATOR_CANCELLED; } - snode_notify(*C, *snode); + ED_node_tree_propagate_change(C, CTX_data_main(C), ntree); return OPERATOR_FINISHED; } @@ -2996,3 +2942,4 @@ void NODE_OT_cryptomatte_layer_remove(wmOperatorType *ot) /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +} // namespace blender::ed::space_node 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 4890c3e39cf..542e6fd748f 100644 --- a/source/blender/editors/space_node/node_geometry_attribute_search.cc +++ b/source/blender/editors/space_node/node_geometry_attribute_search.cc @@ -46,13 +46,11 @@ #include "node_intern.hh" -using blender::IndexRange; -using blender::Map; -using blender::Set; -using blender::StringRef; namespace geo_log = blender::nodes::geometry_nodes_eval_log; using geo_log::GeometryAttributeInfo; +namespace blender::ed::space_node { + struct AttributeSearchData { const bNodeTree *tree; const bNode *node; @@ -125,8 +123,8 @@ void node_geometry_add_attribute_search_button(const bContext &UNUSED(C), 0.0f, ""); - AttributeSearchData *data = OBJECT_GUARDED_NEW( - AttributeSearchData, {&node_tree, &node, (bNodeSocket *)socket_ptr.data}); + AttributeSearchData *data = MEM_new<AttributeSearchData>( + __func__, AttributeSearchData{&node_tree, &node, (bNodeSocket *)socket_ptr.data}); UI_but_func_search_set_results_are_suggestions(but, true); UI_but_func_search_set_sep_string(but, UI_MENU_ARROW_SEP); @@ -139,3 +137,5 @@ void node_geometry_add_attribute_search_button(const bContext &UNUSED(C), attribute_search_exec_fn, nullptr); } + +} // namespace blender::ed::space_node diff --git a/source/blender/editors/space_node/node_gizmo.cc b/source/blender/editors/space_node/node_gizmo.cc index 717f4d2f4f9..8c60d100b26 100644 --- a/source/blender/editors/space_node/node_gizmo.cc +++ b/source/blender/editors/space_node/node_gizmo.cc @@ -43,6 +43,8 @@ #include "node_intern.hh" +namespace blender::ed::space_node { + /* -------------------------------------------------------------------- */ /** \name Local Utilities * \{ */ @@ -292,7 +294,11 @@ static void gizmo_node_crop_prop_matrix_set(const wmGizmo *gz, const bool ny = rct.ymin > rct.ymax; BLI_rctf_resize(&rct, fabsf(matrix[0][0]), fabsf(matrix[1][1])); BLI_rctf_recenter(&rct, (matrix[3][0] / dims[0]) + 0.5f, (matrix[3][1] / dims[1]) + 0.5f); - const rctf rct_isect{0, 0, 1, 1}; + rctf rct_isect{}; + rct_isect.xmin = 0; + rct_isect.xmax = 1; + rct_isect.ymin = 0; + rct_isect.ymax = 1; BLI_rctf_isect(&rct_isect, &rct, &rct); if (nx) { SWAP(float, rct.xmin, rct.xmax); @@ -380,7 +386,7 @@ static void WIDGETGROUP_node_crop_refresh(const bContext *C, wmGizmoGroup *gzgro params.value_get_fn = gizmo_node_crop_prop_matrix_get; params.value_set_fn = gizmo_node_crop_prop_matrix_set; params.range_get_fn = nullptr; - params.user_data = snode; + params.user_data = node; WM_gizmo_target_property_def_func(gz, "matrix", ¶ms); } else { @@ -632,3 +638,5 @@ void NODE_GGT_backdrop_corner_pin(wmGizmoGroupType *gzgt) } /** \} */ + +} // namespace blender::ed::space_node diff --git a/source/blender/editors/space_node/node_group.cc b/source/blender/editors/space_node/node_group.cc index 704ffe1e478..73e419d667a 100644 --- a/source/blender/editors/space_node/node_group.cc +++ b/source/blender/editors/space_node/node_group.cc @@ -28,10 +28,11 @@ #include "DNA_anim_types.h" #include "DNA_node_types.h" -#include "BLI_float2.hh" #include "BLI_linklist.h" #include "BLI_listbase.h" +#include "BLI_math_vec_types.hh" #include "BLI_string.h" +#include "BLI_vector.hh" #include "BLT_translation.h" @@ -40,6 +41,7 @@ #include "BKE_context.h" #include "BKE_lib_id.h" #include "BKE_main.h" +#include "BKE_node_tree_update.h" #include "BKE_report.h" #include "DEG_depsgraph_build.h" @@ -60,7 +62,7 @@ #include "NOD_socket.h" #include "node_intern.hh" /* own include */ -using blender::float2; +namespace blender::ed::space_node { /* -------------------------------------------------------------------- */ /** \name Local Utilities @@ -216,38 +218,34 @@ static void animation_basepath_change_free(AnimationBasePathChange *basepath_cha MEM_freeN(basepath_change); } -/* returns 1 if its OK */ -static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode) +/** + * \return True if successful. + */ +static bool node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode) { - /* Clear new pointers, set in #ntreeCopyTree_ex_new_pointers. */ - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { - node->new_node = nullptr; - } - ListBase anim_basepaths = {nullptr, nullptr}; - LinkNode *nodes_delayed_free = nullptr; - bNodeTree *ngroup = (bNodeTree *)gnode->id; + Vector<bNode *> nodes_delayed_free; + const bNodeTree *ngroup = reinterpret_cast<const bNodeTree *>(gnode->id); - /* wgroup is a temporary copy of the NodeTree we're merging in - * - all of wgroup's nodes are copied across to their new home - * - ngroup (i.e. the source NodeTree) is left unscathed - * - temp copy. do change ID usercount for the copies + /* `wgroup` is a temporary copy of the #NodeTree we're merging in + * - All of wgroup's nodes are copied across to their new home. + * - `ngroup` (i.e. the source NodeTree) is left unscathed. + * - Temp copy. do change ID user-count for the copies. */ - bNodeTree *wgroup = ntreeCopyTree_ex_new_pointers(ngroup, bmain, true); + bNodeTree *wgroup = ntreeCopyTree(bmain, ngroup); - /* Add the nodes into the ntree */ + /* Add the nodes into the `ntree`. */ LISTBASE_FOREACH_MUTABLE (bNode *, node, &wgroup->nodes) { /* Remove interface nodes. * This also removes remaining links to and from interface nodes. */ if (ELEM(node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) { /* We must delay removal since sockets will reference this node. see: T52092 */ - BLI_linklist_prepend(&nodes_delayed_free, node); + nodes_delayed_free.append(node); } - /* keep track of this node's RNA "base" path (the part of the path identifying the node) - * if the old nodetree has animation data which potentially covers this node - */ + /* Keep track of this node's RNA "base" path (the part of the path identifying the node) + * if the old node-tree has animation data which potentially covers this node. */ const char *old_animation_basepath = nullptr; if (wgroup->adt) { PointerRNA ptr; @@ -258,6 +256,7 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode) /* migrate node */ BLI_remlink(&wgroup->nodes, node); BLI_addtail(&ntree->nodes, node); + BKE_ntree_update_tag_node_new(ntree, node); /* ensure unique node name in the node tree */ nodeUniqueName(ntree, node); @@ -284,6 +283,7 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode) LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &wgroup->links) { BLI_remlink(&wgroup->links, link); BLI_addtail(&ntree->links, link); + BKE_ntree_update_tag_link_added(ntree, link); } bNodeLink *glinks_last = (bNodeLink *)ntree->links.last; @@ -385,17 +385,14 @@ static int node_group_ungroup(Main *bmain, bNodeTree *ntree, bNode *gnode) } } - while (nodes_delayed_free) { - bNode *node = (bNode *)BLI_linklist_pop(&nodes_delayed_free); + for (bNode *node : nodes_delayed_free) { nodeRemoveNode(bmain, ntree, node, false); } /* delete the group instance and dereference group tree */ nodeRemoveNode(bmain, ntree, gnode, true); - ntree->update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS; - - return 1; + return true; } static int node_group_ungroup_exec(bContext *C, wmOperator *op) @@ -412,16 +409,13 @@ static int node_group_ungroup_exec(bContext *C, wmOperator *op) } if (gnode->id && node_group_ungroup(bmain, snode->edittree, gnode)) { - ntreeUpdateTree(bmain, snode->nodetree); + ED_node_tree_propagate_change(C, CTX_data_main(C), nullptr); } else { BKE_report(op->reports, RPT_WARNING, "Cannot ungroup"); return OPERATOR_CANCELLED; } - snode_notify(*C, *snode); - snode_dag_update(*C, *snode); - return OPERATOR_FINISHED; } @@ -457,13 +451,11 @@ static bool node_group_separate_selected( nodeSetSelected(node, false); } - /* clear new pointers, set in BKE_node_copy_ex(). */ - LISTBASE_FOREACH (bNode *, node, &ngroup.nodes) { - node->new_node = nullptr; - } - ListBase anim_basepaths = {nullptr, nullptr}; + Map<const bNode *, bNode *> node_map; + Map<const bNodeSocket *, bNodeSocket *> socket_map; + /* add selected nodes into the ntree */ LISTBASE_FOREACH_MUTABLE (bNode *, node, &ngroup.nodes) { if (!(node->flag & NODE_SELECT)) { @@ -479,16 +471,17 @@ static bool node_group_separate_selected( bNode *newnode; if (make_copy) { /* make a copy */ - newnode = BKE_node_copy_store_new_pointers(&ngroup, node, LIB_ID_COPY_DEFAULT); + newnode = blender::bke::node_copy_with_mapping( + &ngroup, *node, LIB_ID_COPY_DEFAULT, true, socket_map); + node_map.add_new(node, newnode); } else { /* use the existing node */ newnode = node; } - /* keep track of this node's RNA "base" path (the part of the path identifying the node) - * if the old nodetree has animation data which potentially covers this node - */ + /* Keep track of this node's RNA "base" path (the part of the path identifying the node) + * if the old node-tree has animation data which potentially covers this node. */ if (ngroup.adt) { PointerRNA ptr; char *path; @@ -528,10 +521,10 @@ static bool node_group_separate_selected( /* make a copy of internal links */ if (fromselect && toselect) { nodeAddLink(&ntree, - link->fromnode->new_node, - link->fromsock->new_sock, - link->tonode->new_node, - link->tosock->new_sock); + node_map.lookup(link->fromnode), + socket_map.lookup(link->fromsock), + node_map.lookup(link->tonode), + socket_map.lookup(link->tosock)); } } else { @@ -558,9 +551,9 @@ static bool node_group_separate_selected( } } - ntree.update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS; + BKE_ntree_update_tag_all(&ntree); if (!make_copy) { - ngroup.update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS; + BKE_ntree_update_tag_all(&ngroup); } return true; @@ -614,10 +607,7 @@ static int node_group_separate_exec(bContext *C, wmOperator *op) /* switch to parent tree */ ED_node_tree_pop(snode); - ntreeUpdateTree(CTX_data_main(C), snode->nodetree); - - snode_notify(*C, *snode); - snode_dag_update(*C, *snode); + ED_node_tree_propagate_change(C, CTX_data_main(C), nullptr); return OPERATOR_FINISHED; } @@ -789,9 +779,8 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree, /* move nodes over */ LISTBASE_FOREACH_MUTABLE (bNode *, node, &ntree.nodes) { if (node_group_make_use_node(*node, gnode)) { - /* keep track of this node's RNA "base" path (the part of the pat identifying the node) - * if the old nodetree has animation data which potentially covers this node - */ + /* Keep track of this node's RNA "base" path (the part of the pat identifying the node) + * if the old node-tree has animation data which potentially covers this node. */ if (ntree.adt) { PointerRNA ptr; char *path; @@ -812,6 +801,8 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree, /* change node-collection membership */ BLI_remlink(&ntree.nodes, node); BLI_addtail(&ngroup->nodes, node); + BKE_ntree_update_tag_node_removed(&ntree); + BKE_ntree_update_tag_node_new(ngroup, node); /* ensure unique node name in the ngroup */ nodeUniqueName(ngroup, node); @@ -983,11 +974,6 @@ static void node_group_make_insert_selected(const bContext &C, bNodeTree &ntree, } } } - - /* update of the group tree */ - ngroup->update |= NTREE_UPDATE | NTREE_UPDATE_LINKS; - /* update of the tree containing the group instance node */ - ntree.update |= NTREE_UPDATE_NODES | NTREE_UPDATE_LINKS; } static bNode *node_group_make_from_selected(const bContext &C, @@ -1004,7 +990,7 @@ static bNode *node_group_make_from_selected(const bContext &C, return nullptr; } - /* new nodetree */ + /* New node-tree. */ bNodeTree *ngroup = ntreeAddTree(bmain, "NodeGroup", ntreetype); /* make group node */ @@ -1016,9 +1002,6 @@ static bNode *node_group_make_from_selected(const bContext &C, node_group_make_insert_selected(C, ntree, gnode); - /* update of the tree containing the group instance node */ - ntree.update |= NTREE_UPDATE_NODES; - return gnode; } @@ -1047,14 +1030,10 @@ static int node_group_make_exec(bContext *C, wmOperator *op) LISTBASE_FOREACH (bNode *, node, &ngroup->nodes) { sort_multi_input_socket_links(snode, *node, nullptr, nullptr); } - ntreeUpdateTree(bmain, ngroup); } } - ntreeUpdateTree(bmain, &ntree); - - snode_notify(*C, snode); - snode_dag_update(*C, snode); + ED_node_tree_propagate_change(C, bmain, nullptr); /* We broke relations in node tree, need to rebuild them in the graphs. */ DEG_relations_tag_update(bmain); @@ -1107,12 +1086,7 @@ static int node_group_insert_exec(bContext *C, wmOperator *op) nodeSetActive(ntree, gnode); ED_node_tree_push(snode, ngroup, gnode); - ntreeUpdateTree(bmain, ngroup); - - ntreeUpdateTree(bmain, ntree); - - snode_notify(*C, *snode); - snode_dag_update(*C, *snode); + ED_node_tree_propagate_change(C, bmain, nullptr); return OPERATOR_FINISHED; } @@ -1133,3 +1107,5 @@ void NODE_OT_group_insert(wmOperatorType *ot) } /** \} */ + +} // namespace blender::ed::space_node diff --git a/source/blender/editors/space_node/node_intern.hh b/source/blender/editors/space_node/node_intern.hh index f3ba405c6d0..c161fc70402 100644 --- a/source/blender/editors/space_node/node_intern.hh +++ b/source/blender/editors/space_node/node_intern.hh @@ -23,7 +23,7 @@ #pragma once -#include "BLI_float2.hh" +#include "BLI_math_vec_types.hh" #include "BLI_vector.hh" #include "BKE_node.h" @@ -45,19 +45,39 @@ struct wmGizmoGroupType; struct wmKeyConfig; struct wmWindow; +/* Outside of blender namespace to avoid Python documentation build error with `ctypes`. */ +extern const char *node_context_dir[]; + +namespace blender::ed::space_node { + /** Temporary data used in node link drag modal operator. */ struct bNodeLinkDrag { /** Links dragged by the operator. */ - blender::Vector<bNodeLink *> links; + Vector<bNodeLink *> links; bool from_multi_input_socket; - int in_out; + eNodeSocketInOut in_out; + + /** Draw handler for the "+" icon when dragging a link in empty space. */ + void *draw_handle; /** Temporarily stores the last picked link from multi-input socket operator. */ - struct bNodeLink *last_picked_multi_input_socket_link; + bNodeLink *last_picked_multi_input_socket_link; - /** Temporarily stores the last hovered socket for multi-input socket operator. - * Store it to recalculate sorting after it is no longer hovered. */ - struct bNode *last_node_hovered_while_dragging_a_link; + /** + * Temporarily stores the last hovered socket for multi-input socket operator. + * Store it to recalculate sorting after it is no longer hovered. + */ + bNode *last_node_hovered_while_dragging_a_link; + + /* The cursor position, used for drawing a + icon when dragging a node link. */ + std::array<int, 2> cursor; + + /** The node the drag started at. */ + bNode *start_node; + /** The socket the drag started at. */ + bNodeSocket *start_socket; + /** The number of links connected to the #start_socket when the drag started. */ + int start_link_count; /* Data for edge panning */ View2DEdgePanData pan_data; @@ -67,7 +87,7 @@ struct SpaceNode_Runtime { float aspect; /** Mouse position for drawing socket-less links and adding nodes. */ - blender::float2 cursor; + float2 cursor; /** For auto compositing. */ bool recalc; @@ -92,15 +112,15 @@ ENUM_OPERATORS(NodeResizeDirection, NODE_RESIZE_LEFT); /** * Transform between View2Ds in the tree path. */ -blender::float2 space_node_group_offset(const SpaceNode &snode); +float2 space_node_group_offset(const SpaceNode &snode); float node_socket_calculate_height(const bNodeSocket &socket); -blender::float2 node_link_calculate_multi_input_position(const blender::float2 &socket_position, - int index, - int total_inputs); +float2 node_link_calculate_multi_input_position(const float2 &socket_position, + int index, + int total_inputs); int node_get_resize_cursor(NodeResizeDirection directions); -NodeResizeDirection node_get_resize_direction(const bNode *node, const int x, const int y); +NodeResizeDirection node_get_resize_direction(const bNode *node, int x, int y); /** * Usual convention here would be #node_socket_get_color(), * but that's already used (for setting a color property socket). @@ -112,22 +132,26 @@ void node_socket_color_get(const bContext &C, float r_color[4]); void node_draw_space(const bContext &C, ARegion ®ion); -void node_set_cursor(wmWindow &win, SpaceNode &snode, const blender::float2 &cursor); +/** + * Sort nodes by selection: unselected nodes first, then selected, + * then the active node at the very end. Relative order is kept intact. + */ +void node_sort(bNodeTree &ntree); + +void node_set_cursor(wmWindow &win, SpaceNode &snode, const float2 &cursor); /* DPI scaled coords */ -blender::float2 node_to_view(const bNode &node, const blender::float2 &co); +float2 node_to_view(const bNode &node, const float2 &co); void node_to_updated_rect(const bNode &node, rctf &r_rect); -blender::float2 node_from_view(const bNode &node, const blender::float2 &co); - -void node_toolbar_register(ARegionType *art); +float2 node_from_view(const bNode &node, const float2 &co); -void node_operatortypes(void); +void node_operatortypes(); void node_keymap(wmKeyConfig *keyconf); void node_deselect_all(SpaceNode &snode); void node_socket_select(bNode *node, bNodeSocket &sock); -void node_socket_deselect(bNode *node, bNodeSocket &sock, const bool deselect_node); -void node_deselect_all_input_sockets(SpaceNode &snode, const bool deselect_nodes); -void node_deselect_all_output_sockets(SpaceNode &snode, const bool deselect_nodes); +void node_socket_deselect(bNode *node, bNodeSocket &sock, bool deselect_node); +void node_deselect_all_input_sockets(SpaceNode &snode, bool deselect_nodes); +void node_deselect_all_output_sockets(SpaceNode &snode, bool deselect_nodes); void node_select_single(bContext &C, bNode &node); void NODE_OT_select(wmOperatorType *ot); @@ -178,7 +202,7 @@ bool node_link_bezier_points(const View2D *v2d, const SpaceNode *snode, const bNodeLink &link, float coord_array[][2], - const int resol); + int resol); /** * Return quadratic beziers points for a given nodelink and clip if v2d is not nullptr. */ @@ -191,6 +215,8 @@ void draw_nodespace_back_pix(const bContext &C, SpaceNode &snode, bNodeInstanceKey parent_key); +void node_select_all(ListBase *lb, int action); + /** * XXX Does some additional initialization on top of #nodeAddNode * Can be used with both custom and static nodes, @@ -216,8 +242,7 @@ void NODE_OT_group_edit(wmOperatorType *ot); void sort_multi_input_socket_links(SpaceNode &snode, bNode &node, bNodeLink *drag_link, - const blender::float2 *cursor); -bool node_connected_to_output(Main &bmain, bNodeTree &ntree, bNode &node); + const float2 *cursor); void NODE_OT_link(wmOperatorType *ot); void NODE_OT_link_make(wmOperatorType *ot); @@ -234,12 +259,8 @@ void NODE_OT_link_viewer(wmOperatorType *ot); void NODE_OT_insert_offset(wmOperatorType *ot); -void snode_notify(bContext &C, SpaceNode &snode); -void snode_dag_update(bContext &C, SpaceNode &snode); void snode_set_context(const bContext &C); -void snode_update(SpaceNode &snode, bNode *node); -/** Operator poll callback. */ bool composite_node_active(bContext *C); /** Operator poll callback. */ bool composite_node_editable(bContext *C); @@ -251,7 +272,7 @@ int node_render_changed_exec(bContext *, wmOperator *); bool node_find_indicated_socket(SpaceNode &snode, bNode **nodep, bNodeSocket **sockp, - const blender::float2 &cursor, + const float2 &cursor, eNodeSocketInOut in_out); float node_link_dim_factor(const View2D &v2d, const bNodeLink &link); bool node_link_is_hidden_or_dimmed(const View2D &v2d, const bNodeLink &link); @@ -307,8 +328,6 @@ void node_geometry_add_attribute_search_button(const bContext &C, PointerRNA &socket_ptr, uiLayout &layout); -extern const char *node_context_dir[]; - /* Nodes draw without dpi - the view zoom is flexible. */ #define HIDDEN_RAD (0.75f * U.widget_unit) #define BASIS_RAD (0.2f * U.widget_unit) @@ -323,8 +342,11 @@ extern const char *node_context_dir[]; #define NODE_RESIZE_MARGIN (0.20f * U.widget_unit) #define NODE_LINK_RESOL 12 -namespace blender::ed::space_node { - Vector<ui::ContextPathItem> context_path_for_space_node(const bContext &C); -} +void invoke_node_link_drag_add_menu(bContext &C, + bNode &node, + bNodeSocket &socket, + const float2 &cursor); + +} // namespace blender::ed::space_node diff --git a/source/blender/editors/space_node/node_ops.cc b/source/blender/editors/space_node/node_ops.cc index a6264f151e4..2ca475f6948 100644 --- a/source/blender/editors/space_node/node_ops.cc +++ b/source/blender/editors/space_node/node_ops.cc @@ -35,6 +35,8 @@ #include "node_intern.hh" /* own include */ +namespace blender::ed::space_node { + void node_operatortypes() { WM_operatortype_append(NODE_OT_select); @@ -127,6 +129,17 @@ void node_operatortypes() WM_operatortype_append(NODE_OT_cryptomatte_layer_remove); } +void node_keymap(struct wmKeyConfig *keyconf) +{ + /* Entire Editor only ----------------- */ + WM_keymap_ensure(keyconf, "Node Generic", SPACE_NODE, 0); + + /* Main Region only ----------------- */ + WM_keymap_ensure(keyconf, "Node Editor", SPACE_NODE, 0); +} + +} // namespace blender::ed::space_node + void ED_operatormacros_node() { wmOperatorType *ot; @@ -203,12 +216,3 @@ void ED_operatormacros_node() WM_operatortype_macro_define(ot, "NODE_OT_links_detach"); WM_operatortype_macro_define(ot, "NODE_OT_translate_attach"); } - -void node_keymap(struct wmKeyConfig *keyconf) -{ - /* Entire Editor only ----------------- */ - WM_keymap_ensure(keyconf, "Node Generic", SPACE_NODE, 0); - - /* Main Region only ----------------- */ - WM_keymap_ensure(keyconf, "Node Editor", SPACE_NODE, 0); -} diff --git a/source/blender/editors/space_node/node_relationships.cc b/source/blender/editors/space_node/node_relationships.cc index ce07496068d..fd9420b173d 100644 --- a/source/blender/editors/space_node/node_relationships.cc +++ b/source/blender/editors/space_node/node_relationships.cc @@ -34,11 +34,13 @@ #include "BKE_lib_id.h" #include "BKE_main.h" #include "BKE_node.h" +#include "BKE_node_tree_update.h" #include "BKE_screen.h" #include "ED_node.h" /* own include */ #include "ED_render.h" #include "ED_screen.h" +#include "ED_space_api.h" #include "ED_spreadsheet.h" #include "ED_util.h" @@ -50,6 +52,9 @@ #include "WM_api.h" #include "WM_types.h" +#include "GPU_state.h" + +#include "UI_interface_icons.h" #include "UI_resources.h" #include "UI_view2d.h" @@ -57,127 +62,12 @@ #include "NOD_node_declaration.hh" #include "NOD_node_tree_ref.hh" +#include "NOD_socket_declarations.hh" +#include "NOD_socket_declarations_geometry.hh" #include "node_intern.hh" /* own include */ using namespace blender::nodes::node_tree_ref_types; -using blender::float2; -using blender::Vector; - -/* -------------------------------------------------------------------- */ -/** \name Relations Helpers - * \{ */ - -static bool ntree_has_drivers(bNodeTree &ntree) -{ - const AnimData *adt = BKE_animdata_from_id(&ntree.id); - if (adt == nullptr) { - return false; - } - return !BLI_listbase_is_empty(&adt->drivers); -} - -static bool ntree_check_nodes_connected_dfs(bNodeTree &ntree, bNode &from, bNode &to) -{ - if (from.flag & NODE_TEST) { - return false; - } - from.flag |= NODE_TEST; - LISTBASE_FOREACH (bNodeLink *, link, &ntree.links) { - if (link->fromnode == &from) { - if (link->tonode == &to) { - return true; - } - - if (ntree_check_nodes_connected_dfs(ntree, *link->tonode, to)) { - return true; - } - } - } - return false; -} - -static bool ntree_check_nodes_connected(bNodeTree &ntree, bNode &from, bNode &to) -{ - if (&from == &to) { - return true; - } - ntreeNodeFlagSet(&ntree, NODE_TEST, false); - return ntree_check_nodes_connected_dfs(ntree, from, to); -} - -static bool node_group_has_output_dfs(bNode &node) -{ - bNodeTree *ntree = (bNodeTree *)node.id; - if (ntree->id.tag & LIB_TAG_DOIT) { - return false; - } - ntree->id.tag |= LIB_TAG_DOIT; - LISTBASE_FOREACH (bNode *, current_node, &ntree->nodes) { - if (current_node->type == NODE_GROUP) { - if (current_node->id && node_group_has_output_dfs(*current_node)) { - return true; - } - } - if (current_node->flag & NODE_DO_OUTPUT && current_node->type != NODE_GROUP_OUTPUT) { - return true; - } - } - return false; -} - -static bool node_group_has_output(Main &bmain, bNode &node) -{ - BLI_assert(ELEM(node.type, NODE_GROUP, NODE_CUSTOM_GROUP)); - bNodeTree *ntree = (bNodeTree *)node.id; - if (ntree == nullptr) { - return false; - } - BKE_main_id_tag_listbase(&bmain.nodetrees, LIB_TAG_DOIT, false); - return node_group_has_output_dfs(node); -} - -bool node_connected_to_output(Main &bmain, bNodeTree &ntree, bNode &node) -{ - /* Special case for drivers: if node tree has any drivers we assume it is - * always to be tagged for update when node changes. Otherwise we will be - * doomed to do some deep and nasty deep search of indirect dependencies, - * which will be too complicated without real benefit. - */ - if (ntree_has_drivers(ntree)) { - return true; - } - LISTBASE_FOREACH (bNode *, current_node, &ntree.nodes) { - /* Special case for group nodes -- if modified node connected to a group - * with active output inside we consider refresh is needed. - * - * We could make check more grained here by taking which socket the node - * is connected to and so eventually. - */ - if (ELEM(current_node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) { - if (current_node->id != nullptr && ntree_has_drivers((bNodeTree &)current_node->id)) { - return true; - } - if (ntree_check_nodes_connected(ntree, node, *current_node) && - node_group_has_output(bmain, *current_node)) { - return true; - } - } - if (current_node->flag & NODE_DO_OUTPUT) { - if (ntree_check_nodes_connected(ntree, node, *current_node)) { - return true; - } - } - if (current_node->type == GEO_NODE_VIEWER) { - if (ntree_check_nodes_connected(ntree, node, *current_node)) { - return true; - } - } - } - return false; -} - -/** \} */ /* -------------------------------------------------------------------- */ /** \name Add Node @@ -206,9 +96,11 @@ static void clear_picking_highlight(ListBase *links) } } -static bNodeLink *create_drag_link(Main &bmain, SpaceNode &snode, bNode &node, bNodeSocket &sock) +namespace blender::ed::space_node { + +static bNodeLink *create_drag_link(bNode &node, bNodeSocket &sock) { - bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), __func__); + bNodeLink *oplink = MEM_cnew<bNodeLink>(__func__); if (sock.in_out == SOCK_OUT) { oplink->fromnode = &node; oplink->fromsock = &sock; @@ -218,27 +110,17 @@ static bNodeLink *create_drag_link(Main &bmain, SpaceNode &snode, bNode &node, b oplink->tosock = &sock; } oplink->flag |= NODE_LINK_VALID; - oplink->flag &= ~NODE_LINK_TEST; - if (node_connected_to_output(bmain, *snode.edittree, node)) { - oplink->flag |= NODE_LINK_TEST; - } oplink->flag |= NODE_LINK_DRAGGED; return oplink; } -static void pick_link(const bContext &C, - wmOperator &op, - bNodeLinkDrag &nldrag, - SpaceNode &snode, - bNode *node, - bNodeLink &link_to_pick) +static void pick_link( + wmOperator &op, bNodeLinkDrag &nldrag, SpaceNode &snode, bNode *node, bNodeLink &link_to_pick) { clear_picking_highlight(&snode.edittree->links); RNA_boolean_set(op.ptr, "has_link_picked", true); - Main *bmain = CTX_data_main(&C); - bNodeLink *link = create_drag_link( - *bmain, snode, *link_to_pick.fromnode, *link_to_pick.fromsock); + bNodeLink *link = create_drag_link(*link_to_pick.fromnode, *link_to_pick.fromsock); nldrag.links.append(link); nodeRemLink(snode.edittree, &link_to_pick); @@ -250,7 +132,7 @@ static void pick_link(const bContext &C, /* Send changed event to original link->tonode. */ if (node) { - snode_update(snode, node); + BKE_ntree_update_tag_node_property(snode.edittree, node); } } @@ -316,7 +198,7 @@ static void pick_input_link_by_link_intersect(const bContext &C, ED_area_tag_redraw(CTX_wm_area(&C)); if (!node_find_indicated_socket(*snode, &node, &socket, cursor, SOCK_IN)) { - pick_link(C, op, nldrag, *snode, node, *link_to_pick); + pick_link(op, nldrag, *snode, node, *link_to_pick); } } } @@ -328,7 +210,10 @@ static bool socket_is_available(bNodeTree *UNUSED(ntree), bNodeSocket *sock, con } if (!allow_used && (sock->flag & SOCK_IN_USE)) { - return false; + /* Multi input sockets are available (even if used). */ + if (!(sock->flag & SOCK_MULTI_INPUT)) { + return false; + } } return true; @@ -558,7 +443,7 @@ static void snode_autoconnect(Main &bmain, } if (numlinks > 0) { - ntreeUpdateTree(&bmain, ntree); + BKE_ntree_update_main_tree(&bmain, ntree, nullptr); } } @@ -568,7 +453,7 @@ static void snode_autoconnect(Main &bmain, /** \name Link Viewer Operator * \{ */ -namespace blender::ed::nodes::viewer_linking { +namespace viewer_linking { /* Depending on the node tree type, different socket types are supported by viewer nodes. */ static bool socket_can_be_viewed(const OutputSocketRef &socket) @@ -632,7 +517,7 @@ static bNodeSocket *node_link_viewer_get_socket(bNodeTree &ntree, (eNodeSocketDatatype)src_socket.type); BLI_assert(data_type != CD_AUTO_FROM_NAME); storage->data_type = data_type; - nodeUpdate(&ntree, &viewer_node); + viewer_node.typeinfo->updatefunc(&ntree, &viewer_node); return viewer_socket; } } @@ -802,7 +687,7 @@ static int link_socket_to_viewer(const bContext &C, else { link_to_change->fromnode = &bnode_to_view; link_to_change->fromsock = &bsocket_to_view; - btree.update |= NTREE_UPDATE_LINKS; + BKE_ntree_update_tag_link_changed(&btree); } remove_links_to_unavailable_viewer_sockets(btree, *viewer_bnode); @@ -811,10 +696,7 @@ static int link_socket_to_viewer(const bContext &C, ED_spreadsheet_context_paths_set_geometry_node(CTX_data_main(&C), &snode, viewer_bnode); } - ntreeUpdateTree(CTX_data_main(&C), &btree); - snode_update(snode, viewer_bnode); - DEG_id_tag_update(&btree.id, 0); - + ED_node_tree_propagate_change(&C, CTX_data_main(&C), &btree); return OPERATOR_FINISHED; } @@ -838,7 +720,7 @@ static int node_link_viewer(const bContext &C, bNode &bnode_to_view) return link_socket_to_viewer(C, viewer_bnode, bnode_to_view, bsocket_to_view); } -} // namespace blender::ed::nodes::viewer_linking +} // namespace viewer_linking static int node_active_link_viewer_exec(bContext *C, wmOperator *UNUSED(op)) { @@ -851,11 +733,11 @@ static int node_active_link_viewer_exec(bContext *C, wmOperator *UNUSED(op)) ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); - if (blender::ed::nodes::viewer_linking::node_link_viewer(*C, *node) == OPERATOR_CANCELLED) { + if (viewer_linking::node_link_viewer(*C, *node) == OPERATOR_CANCELLED) { return OPERATOR_CANCELLED; } - snode_notify(*C, snode); + ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree); return OPERATOR_FINISHED; } @@ -890,6 +772,83 @@ void NODE_OT_link_viewer(wmOperatorType *ot) /** \name Add Link Operator * \{ */ +/** + * Check if any of the dragged links are connected to a socket on the side that they are dragged + * from. + */ +static bool dragged_links_are_detached(const bNodeLinkDrag &nldrag) +{ + if (nldrag.in_out == SOCK_OUT) { + for (const bNodeLink *link : nldrag.links) { + if (link->tonode && link->tosock) { + return false; + } + } + } + else { + for (const bNodeLink *link : nldrag.links) { + if (link->fromnode && link->fromsock) { + return false; + } + } + } + return true; +} + +static bool should_create_drag_link_search_menu(const bNodeTree &node_tree, + const bNodeLinkDrag &nldrag) +{ + /* Custom node trees aren't supported yet. */ + if (node_tree.type == NTREE_CUSTOM) { + return false; + } + /* Only create the search menu when the drag has not already connected the links to a socket. */ + if (!dragged_links_are_detached(nldrag)) { + return false; + } + /* Don't create the search menu if the drag is disconnecting a link from an input node. */ + if (nldrag.start_socket->in_out == SOCK_IN && nldrag.start_link_count > 0) { + return false; + } + /* Don't allow a drag from the "new socket" of a group input node. Handling these + * properly in node callbacks increases the complexity too much for now. */ + if (ELEM(nldrag.start_node->type, NODE_GROUP_INPUT, NODE_GROUP_OUTPUT)) { + if (nldrag.start_socket->type == SOCK_CUSTOM) { + return false; + } + } + return true; +} + +static void draw_draglink_tooltip(const bContext *UNUSED(C), ARegion *UNUSED(region), void *arg) +{ + bNodeLinkDrag *nldrag = static_cast<bNodeLinkDrag *>(arg); + + const uchar text_col[4] = {255, 255, 255, 255}; + const int padding = 4 * UI_DPI_FAC; + const float x = nldrag->in_out == SOCK_IN ? nldrag->cursor[0] - 3.3f * padding : + nldrag->cursor[0]; + const float y = nldrag->cursor[1] - 2.0f * UI_DPI_FAC; + + UI_icon_draw_ex(x, y, ICON_ADD, U.inv_dpi_fac, 1.0f, 0.0f, text_col, false); +} + +static void draw_draglink_tooltip_activate(const ARegion ®ion, bNodeLinkDrag &nldrag) +{ + if (nldrag.draw_handle == nullptr) { + nldrag.draw_handle = ED_region_draw_cb_activate( + region.type, draw_draglink_tooltip, &nldrag, REGION_DRAW_POST_PIXEL); + } +} + +static void draw_draglink_tooltip_deactivate(const ARegion ®ion, bNodeLinkDrag &nldrag) +{ + if (nldrag.draw_handle) { + ED_region_draw_cb_exit(region.type, nldrag.draw_handle); + nldrag.draw_handle = nullptr; + } +} + static void node_link_update_header(bContext *C, bNodeLinkDrag *UNUSED(nldrag)) { char header[UI_MAX_DRAW_STR]; @@ -952,22 +911,14 @@ static void node_remove_extra_links(SpaceNode &snode, bNodeLink &link) static void node_link_exit(bContext &C, wmOperator &op, const bool apply_links) { Main *bmain = CTX_data_main(&C); + ARegion ®ion = *CTX_wm_region(&C); SpaceNode &snode = *CTX_wm_space_node(&C); bNodeTree &ntree = *snode.edittree; bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op.customdata; - bool do_tag_update = false; - /* View will be reset if no links connect. */ - bool reset_view = true; /* avoid updates while applying links */ ntree.is_updating = true; for (bNodeLink *link : nldrag->links) { - /* See note below, but basically TEST flag means that the link - * was connected to output (or to a node which affects the - * output). - */ - do_tag_update |= (link->flag & NODE_LINK_TEST) != 0; - link->flag &= ~NODE_LINK_DRAGGED; if (apply_links && link->tosock && link->fromsock) { @@ -983,20 +934,10 @@ static void node_link_exit(bContext &C, wmOperator &op, const bool apply_links) /* add link to the node tree */ BLI_addtail(&ntree.links, link); - - ntree.update |= NTREE_UPDATE_LINKS; - - /* tag tonode for update */ - link->tonode->update |= NODE_UPDATE; + BKE_ntree_update_tag_link_added(&ntree, link); /* we might need to remove a link */ node_remove_extra_links(snode, *link); - - if (link->tonode) { - do_tag_update |= (do_tag_update || node_connected_to_output(*bmain, ntree, *link->tonode)); - } - - reset_view = false; } else { nodeRemLink(&ntree, link); @@ -1004,15 +945,14 @@ static void node_link_exit(bContext &C, wmOperator &op, const bool apply_links) } ntree.is_updating = false; - ntreeUpdateTree(bmain, &ntree); - snode_notify(C, snode); - if (do_tag_update) { - snode_dag_update(C, snode); - } + ED_node_tree_propagate_change(&C, bmain, &ntree); - if (reset_view) { - UI_view2d_edge_pan_cancel(&C, &nldrag->pan_data); - } + /* Ensure draglink tooltip is disabled. */ + draw_draglink_tooltip_deactivate(*CTX_wm_region(&C), *nldrag); + + ED_workspace_status_text(&C, nullptr); + ED_region_tag_redraw(®ion); + clear_picking_highlight(&snode.edittree->links); snode.runtime->linkdrag.reset(); } @@ -1099,12 +1039,15 @@ static void node_link_find_socket(bContext &C, wmOperator &op, const float2 &cur static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event) { bNodeLinkDrag *nldrag = (bNodeLinkDrag *)op->customdata; + SpaceNode &snode = *CTX_wm_space_node(C); ARegion *region = CTX_wm_region(C); UI_view2d_edge_pan_apply_event(C, &nldrag->pan_data, event); float2 cursor; UI_view2d_region_to_view(®ion->v2d, event->mval[0], event->mval[1], &cursor.x, &cursor.y); + nldrag->cursor[0] = event->mval[0]; + nldrag->cursor[1] = event->mval[1]; switch (event->type) { case MOUSEMOVE: @@ -1117,29 +1060,50 @@ static int node_link_modal(bContext *C, wmOperator *op, const wmEvent *event) node_link_update_header(C, nldrag); ED_region_tag_redraw(region); } - break; + if (should_create_drag_link_search_menu(*snode.edittree, *nldrag)) { + draw_draglink_tooltip_activate(*region, *nldrag); + } + else { + draw_draglink_tooltip_deactivate(*region, *nldrag); + } + break; case LEFTMOUSE: + if (event->val == KM_RELEASE) { + /* Add a search menu for compatible sockets if the drag released on empty space. */ + if (should_create_drag_link_search_menu(*snode.edittree, *nldrag)) { + bNodeLink &link = *nldrag->links.first(); + if (nldrag->in_out == SOCK_OUT) { + invoke_node_link_drag_add_menu(*C, *link.fromnode, *link.fromsock, cursor); + } + else { + invoke_node_link_drag_add_menu(*C, *link.tonode, *link.tosock, cursor); + } + } + + /* Finish link. */ + node_link_exit(*C, *op, true); + return OPERATOR_FINISHED; + } + break; case RIGHTMOUSE: case MIDDLEMOUSE: { if (event->val == KM_RELEASE) { node_link_exit(*C, *op, true); - - ED_workspace_status_text(C, nullptr); - ED_region_tag_redraw(region); - SpaceNode &snode = *CTX_wm_space_node(C); - clear_picking_highlight(&snode.edittree->links); return OPERATOR_FINISHED; } break; } + case EVT_ESCKEY: { + node_link_exit(*C, *op, true); + return OPERATOR_FINISHED; + } } return OPERATOR_RUNNING_MODAL; } -static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain, - SpaceNode &snode, +static std::unique_ptr<bNodeLinkDrag> node_link_init(SpaceNode &snode, float2 cursor, const bool detach) { @@ -1148,32 +1112,22 @@ static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain, bNodeSocket *sock; if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_OUT)) { std::unique_ptr<bNodeLinkDrag> nldrag = std::make_unique<bNodeLinkDrag>(); - - const int num_links = nodeCountSocketLinks(snode.edittree, sock); + nldrag->start_node = node; + nldrag->start_socket = sock; + nldrag->start_link_count = nodeCountSocketLinks(snode.edittree, sock); int link_limit = nodeSocketLinkLimit(sock); - if (num_links > 0 && (num_links >= link_limit || detach)) { + if (nldrag->start_link_count > 0 && (nldrag->start_link_count >= link_limit || detach)) { /* dragged links are fixed on input side */ nldrag->in_out = SOCK_IN; /* detach current links and store them in the operator data */ LISTBASE_FOREACH_MUTABLE (bNodeLink *, link, &snode.edittree->links) { if (link->fromsock == sock) { - bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link"); + bNodeLink *oplink = MEM_cnew<bNodeLink>("drag link op link"); *oplink = *link; oplink->next = oplink->prev = nullptr; oplink->flag |= NODE_LINK_VALID; oplink->flag |= NODE_LINK_DRAGGED; - /* The link could be disconnected and in that case we - * wouldn't be able to check whether tag update is - * needed or not when releasing mouse button. So we - * cache whether the link affects output or not here - * using TEST flag. - */ - oplink->flag &= ~NODE_LINK_TEST; - if (node_connected_to_output(bmain, *snode.edittree, *link->tonode)) { - oplink->flag |= NODE_LINK_TEST; - } - nldrag->links.append(oplink); nodeRemLink(snode.edittree, link); } @@ -1183,7 +1137,7 @@ static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain, /* dragged links are fixed on output side */ nldrag->in_out = SOCK_OUT; /* create a new link */ - nldrag->links.append(create_drag_link(bmain, snode, *node, *sock)); + nldrag->links.append(create_drag_link(*node, *sock)); } return nldrag; } @@ -1192,9 +1146,11 @@ static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain, if (node_find_indicated_socket(snode, &node, &sock, cursor, SOCK_IN)) { std::unique_ptr<bNodeLinkDrag> nldrag = std::make_unique<bNodeLinkDrag>(); nldrag->last_node_hovered_while_dragging_a_link = node; + nldrag->start_node = node; + nldrag->start_socket = sock; - const int num_links = nodeCountSocketLinks(snode.edittree, sock); - if (num_links > 0) { + nldrag->start_link_count = nodeCountSocketLinks(snode.edittree, sock); + if (nldrag->start_link_count > 0) { /* dragged links are fixed on output side */ nldrag->in_out = SOCK_OUT; /* detach current links and store them in the operator data */ @@ -1209,22 +1165,18 @@ static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain, } if (link_to_pick != nullptr && !nldrag->from_multi_input_socket) { - bNodeLink *oplink = (bNodeLink *)MEM_callocN(sizeof(bNodeLink), "drag link op link"); + bNodeLink *oplink = MEM_cnew<bNodeLink>("drag link op link"); *oplink = *link_to_pick; oplink->next = oplink->prev = nullptr; oplink->flag |= NODE_LINK_VALID; oplink->flag |= NODE_LINK_DRAGGED; - oplink->flag &= ~NODE_LINK_TEST; - if (node_connected_to_output(bmain, *snode.edittree, *link_to_pick->tonode)) { - oplink->flag |= NODE_LINK_TEST; - } nldrag->links.append(oplink); nodeRemLink(snode.edittree, link_to_pick); /* send changed event to original link->tonode */ if (node) { - snode_update(snode, node); + BKE_ntree_update_tag_node_property(snode.edittree, node); } } } @@ -1232,7 +1184,7 @@ static std::unique_ptr<bNodeLinkDrag> node_link_init(Main &bmain, /* dragged links are fixed on input side */ nldrag->in_out = SOCK_IN; /* create a new link */ - nldrag->links.append(create_drag_link(bmain, snode, *node, *sock)); + nldrag->links.append(create_drag_link(*node, *sock)); } return nldrag; } @@ -1255,11 +1207,15 @@ static int node_link_invoke(bContext *C, wmOperator *op, const wmEvent *event) ED_preview_kill_jobs(CTX_wm_manager(C), &bmain); - std::unique_ptr<bNodeLinkDrag> nldrag = node_link_init(bmain, snode, cursor, detach); + std::unique_ptr<bNodeLinkDrag> nldrag = node_link_init(snode, cursor, detach); if (nldrag) { UI_view2d_edge_pan_operator_init(C, &nldrag->pan_data, op); + /* Add "+" icon when the link is dragged in empty space. */ + if (should_create_drag_link_search_menu(*snode.edittree, *nldrag)) { + draw_draglink_tooltip_activate(*CTX_wm_region(C), *nldrag); + } snode.runtime->linkdrag = std::move(nldrag); op->customdata = snode.runtime->linkdrag.get(); @@ -1354,9 +1310,7 @@ static int node_make_link_exec(bContext *C, wmOperator *op) node_deselect_all_input_sockets(snode, false); node_deselect_all_output_sockets(snode, false); - ntreeUpdateTree(CTX_data_main(C), snode.edittree); - snode_notify(*C, snode); - snode_dag_update(*C, snode); + ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree); return OPERATOR_FINISHED; } @@ -1413,7 +1367,6 @@ static int cut_links_exec(bContext *C, wmOperator *op) Main &bmain = *CTX_data_main(C); SpaceNode &snode = *CTX_wm_space_node(C); ARegion ®ion = *CTX_wm_region(C); - bool do_tag_update = false; int i = 0; float mcoords[256][2]; @@ -1448,23 +1401,14 @@ static int cut_links_exec(bContext *C, wmOperator *op) found = true; } - do_tag_update |= (do_tag_update || - node_connected_to_output(bmain, *snode.edittree, *link->tonode)); - - snode_update(snode, link->tonode); bNode *to_node = link->tonode; nodeRemLink(snode.edittree, link); sort_multi_input_socket_links(snode, *to_node, nullptr, nullptr); } } + ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree); if (found) { - ntreeUpdateTree(CTX_data_main(C), snode.edittree); - snode_notify(*C, snode); - if (do_tag_update) { - snode_dag_update(*C, snode); - } - return OPERATOR_FINISHED; } @@ -1510,7 +1454,6 @@ static int mute_links_exec(bContext *C, wmOperator *op) Main &bmain = *CTX_data_main(C); SpaceNode &snode = *CTX_wm_space_node(C); ARegion ®ion = *CTX_wm_region(C); - bool do_tag_update = false; int i = 0; float mcoords[256][2]; @@ -1552,10 +1495,6 @@ static int mute_links_exec(bContext *C, wmOperator *op) } if (node_links_intersect(*link, mcoords, i)) { - do_tag_update |= (do_tag_update || - node_connected_to_output(bmain, *snode.edittree, *link->tonode)); - - snode_update(snode, link->tonode); nodeMuteLinkToggle(snode.edittree, link); } } @@ -1568,12 +1507,7 @@ static int mute_links_exec(bContext *C, wmOperator *op) link->flag &= ~NODE_LINK_TEST; } - ntreeUpdateTree(CTX_data_main(C), snode.edittree); - snode_notify(*C, snode); - if (do_tag_update) { - snode_dag_update(*C, snode); - } - + ED_node_tree_propagate_change(C, CTX_data_main(C), snode.edittree); return OPERATOR_FINISHED; } @@ -1624,11 +1558,7 @@ static int detach_links_exec(bContext *C, wmOperator *UNUSED(op)) } } - ntreeUpdateTree(CTX_data_main(C), &ntree); - - snode_notify(*C, snode); - snode_dag_update(*C, snode); - + ED_node_tree_propagate_change(C, CTX_data_main(C), &ntree); return OPERATOR_FINISHED; } @@ -1654,14 +1584,14 @@ void NODE_OT_links_detach(wmOperatorType *ot) static int node_parent_set_exec(bContext *C, wmOperator *UNUSED(op)) { - SpaceNode *snode = CTX_wm_space_node(C); - bNodeTree *ntree = snode->edittree; - bNode *frame = nodeGetActive(ntree); + SpaceNode &snode = *CTX_wm_space_node(C); + bNodeTree &ntree = *snode.edittree; + bNode *frame = nodeGetActive(&ntree); if (!frame || frame->type != NODE_FRAME) { return OPERATOR_CANCELLED; } - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + LISTBASE_FOREACH (bNode *, node, &ntree.nodes) { if (node == frame) { continue; } @@ -1671,7 +1601,7 @@ static int node_parent_set_exec(bContext *C, wmOperator *UNUSED(op)) } } - ED_node_sort(ntree); + node_sort(ntree); WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr); return OPERATOR_FINISHED; @@ -1768,7 +1698,7 @@ static int node_join_exec(bContext *C, wmOperator *UNUSED(op)) } } - ED_node_sort(&ntree); + node_sort(ntree); WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr); return OPERATOR_FINISHED; @@ -1795,15 +1725,15 @@ void NODE_OT_join(wmOperatorType *ot) /** \name Attach Operator * \{ */ -static bNode *node_find_frame_to_attach(ARegion *region, - const bNodeTree *ntree, +static bNode *node_find_frame_to_attach(ARegion ®ion, + const bNodeTree &ntree, const int mouse_xy[2]) { /* convert mouse coordinates to v2d space */ float cursor[2]; - UI_view2d_region_to_view(®ion->v2d, UNPACK2(mouse_xy), &cursor[0], &cursor[1]); + UI_view2d_region_to_view(®ion.v2d, UNPACK2(mouse_xy), &cursor[0], &cursor[1]); - LISTBASE_FOREACH_BACKWARD (bNode *, frame, &ntree->nodes) { + LISTBASE_FOREACH_BACKWARD (bNode *, frame, &ntree.nodes) { /* skip selected, those are the nodes we want to attach */ if ((frame->type != NODE_FRAME) || (frame->flag & NODE_SELECT)) { continue; @@ -1818,13 +1748,13 @@ static bNode *node_find_frame_to_attach(ARegion *region, static int node_attach_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) { - ARegion *region = CTX_wm_region(C); - SpaceNode *snode = CTX_wm_space_node(C); - bNodeTree *ntree = snode->edittree; + ARegion ®ion = *CTX_wm_region(C); + SpaceNode &snode = *CTX_wm_space_node(C); + bNodeTree &ntree = *snode.edittree; bNode *frame = node_find_frame_to_attach(region, ntree, event->mval); if (frame) { - LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree->nodes) { + LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree.nodes) { if (node->flag & NODE_SELECT) { if (node->parent == nullptr) { /* disallow moving a parent into its child */ @@ -1854,7 +1784,7 @@ static int node_attach_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent } } - ED_node_sort(ntree); + node_sort(ntree); WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr); return OPERATOR_FINISHED; @@ -1914,23 +1844,23 @@ static void node_detach_recursive(bNode *node) /* detach the root nodes in the current selection */ static int node_detach_exec(bContext *C, wmOperator *UNUSED(op)) { - SpaceNode *snode = CTX_wm_space_node(C); - bNodeTree *ntree = snode->edittree; + SpaceNode &snode = *CTX_wm_space_node(C); + bNodeTree &ntree = *snode.edittree; /* reset tags */ - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + LISTBASE_FOREACH (bNode *, node, &ntree.nodes) { node->done = 0; } /* detach nodes recursively * relative order is preserved here! */ - LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + LISTBASE_FOREACH (bNode *, node, &ntree.nodes) { if (!(node->done & NODE_DETACH_DONE)) { node_detach_recursive(node); } } - ED_node_sort(ntree); + node_sort(ntree); WM_event_add_notifier(C, NC_NODE | ND_DISPLAY, nullptr); return OPERATOR_FINISHED; @@ -2015,8 +1945,12 @@ static bool ed_node_link_conditions(ScrArea *area, return true; } +} // namespace blender::ed::space_node + void ED_node_link_intersect_test(ScrArea *area, int test) { + using namespace blender::ed::space_node; + bNode *select; SpaceNode *snode; if (!ed_node_link_conditions(area, test, &snode, &select)) { @@ -2076,6 +2010,8 @@ void ED_node_link_intersect_test(ScrArea *area, int test) } } +namespace blender::ed::space_node { + /** \} */ /* -------------------------------------------------------------------- */ @@ -2115,20 +2051,17 @@ static int get_main_socket_priority(const bNodeSocket *socket) /** Get the "main" socket based on the node declaration or an heuristic. */ static bNodeSocket *get_main_socket(bNodeTree &ntree, bNode &node, eNodeSocketInOut in_out) { - using namespace blender; - using namespace blender::nodes; - ListBase *sockets = (in_out == SOCK_IN) ? &node.inputs : &node.outputs; /* Try to get the main socket based on the socket declaration. */ nodeDeclarationEnsure(&ntree, &node); - const NodeDeclaration *node_decl = node.declaration; + const nodes::NodeDeclaration *node_decl = node.declaration; if (node_decl != nullptr) { - Span<SocketDeclarationPtr> socket_decls = (in_out == SOCK_IN) ? node_decl->inputs() : - node_decl->outputs(); + Span<nodes::SocketDeclarationPtr> socket_decls = (in_out == SOCK_IN) ? node_decl->inputs() : + node_decl->outputs(); int index; LISTBASE_FOREACH_INDEX (bNodeSocket *, socket, sockets, index) { - const SocketDeclaration &socket_decl = *socket_decls[index]; + const nodes::SocketDeclaration &socket_decl = *socket_decls[index]; if (nodeSocketIsHidden(socket)) { continue; } @@ -2305,7 +2238,7 @@ static void node_link_insert_offset_ntree(NodeInsertOfsData *iofsd, /* frame attachment wasn't handled yet * so we search the frame that the node will be attached to later */ - insert.parent = node_find_frame_to_attach(region, ntree, mouse_xy); + insert.parent = node_find_frame_to_attach(*region, *ntree, mouse_xy); /* this makes sure nodes are also correctly offset when inserting a node on top of a frame * without actually making it a part of the frame (because mouse isn't intersecting it) @@ -2492,12 +2425,16 @@ void NODE_OT_insert_offset(wmOperatorType *ot) /** \} */ +} // namespace blender::ed::space_node + /* -------------------------------------------------------------------- */ /** \name Note Link Insert * \{ */ void ED_node_link_insert(Main *bmain, ScrArea *area) { + using namespace blender::ed::space_node; + bNode *select; SpaceNode *snode; if (!ed_node_link_conditions(area, true, &snode, &select)) { @@ -2534,8 +2471,7 @@ void ED_node_link_insert(Main *bmain, ScrArea *area) /* set up insert offset data, it needs stuff from here */ if ((snode->flag & SNODE_SKIP_INSOFFSET) == 0) { - NodeInsertOfsData *iofsd = (NodeInsertOfsData *)MEM_callocN(sizeof(NodeInsertOfsData), - __func__); + NodeInsertOfsData *iofsd = MEM_cnew<NodeInsertOfsData>(__func__); iofsd->insert = select; iofsd->prev = link->fromnode; @@ -2544,10 +2480,7 @@ void ED_node_link_insert(Main *bmain, ScrArea *area) snode->runtime->iofsd = iofsd; } - ntreeUpdateTree(bmain, snode->edittree); /* needed for pointers */ - snode_update(*snode, select); - ED_node_tag_update_id((ID *)snode->edittree); - ED_node_tag_update_id(snode->id); + ED_node_tree_propagate_change(nullptr, bmain, snode->edittree); } } } diff --git a/source/blender/editors/space_node/node_select.cc b/source/blender/editors/space_node/node_select.cc index 334ca1f76ee..2751a53e8af 100644 --- a/source/blender/editors/space_node/node_select.cc +++ b/source/blender/editors/space_node/node_select.cc @@ -62,7 +62,7 @@ #include "node_intern.hh" /* own include */ -using blender::float2; +namespace blender::ed::space_node { /** * Function to detect if there is a visible view3d that uses workbench in texture mode. @@ -111,11 +111,13 @@ static bNode *node_under_mouse_select(bNodeTree &ntree, int mx, int my) static bNode *node_under_mouse_tweak(bNodeTree &ntree, const float2 &mouse) { + using namespace blender::math; + LISTBASE_FOREACH_BACKWARD (bNode *, node, &ntree.nodes) { if (node->type == NODE_REROUTE) { bNodeSocket *socket = (bNodeSocket *)node->inputs.first; const float2 location{socket->locx, socket->locy}; - if (float2::distance(mouse, location) < 24.0f) { + if (distance(mouse, location) < 24.0f) { return node; } } @@ -278,57 +280,51 @@ void node_deselect_all_output_sockets(SpaceNode &snode, const bool deselect_node /* Return true if we need redraw, otherwise false. */ -static bool node_select_grouped_type(SpaceNode *snode, bNode *node_act) +static bool node_select_grouped_type(bNodeTree &node_tree, bNode &node_act) { - bNode *node; bool changed = false; - - for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) { if ((node->flag & SELECT) == 0) { - if (node->type == node_act->type) { + if (node->type == node_act.type) { nodeSetSelected(node, true); changed = true; } } } - return changed; } -static bool node_select_grouped_color(SpaceNode *snode, bNode *node_act) +static bool node_select_grouped_color(bNodeTree &node_tree, bNode &node_act) { bool changed = false; - - LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { + LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) { if ((node->flag & SELECT) == 0) { - if (compare_v3v3(node->color, node_act->color, 0.005f)) { + if (compare_v3v3(node->color, node_act.color, 0.005f)) { nodeSetSelected(node, true); changed = true; } } } - return changed; } -static bool node_select_grouped_name(SpaceNode *snode, bNode *node_act, const bool from_right) +static bool node_select_grouped_name(bNodeTree &node_tree, bNode &node_act, const bool from_right) { - bNode *node; bool changed = false; const uint delims[] = {'.', '-', '_', '\0'}; size_t pref_len_act, pref_len_curr; const char *sep, *suf_act, *suf_curr; pref_len_act = BLI_str_partition_ex_utf8( - node_act->name, nullptr, delims, &sep, &suf_act, from_right); + node_act.name, nullptr, delims, &sep, &suf_act, from_right); /* NOTE: in case we are searching for suffix, and found none, use whole name as suffix. */ if (from_right && !(sep && suf_act)) { pref_len_act = 0; - suf_act = node_act->name; + suf_act = node_act.name; } - for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) { if (node->flag & SELECT) { continue; } @@ -343,7 +339,7 @@ static bool node_select_grouped_name(SpaceNode *snode, bNode *node_act, const bo if ((from_right && STREQ(suf_act, suf_curr)) || (!from_right && (pref_len_act == pref_len_curr) && - STREQLEN(node_act->name, node->name, pref_len_act))) { + STREQLEN(node_act.name, node->name, pref_len_act))) { nodeSetSelected(node, true); changed = true; } @@ -361,20 +357,20 @@ enum { static int node_select_grouped_exec(bContext *C, wmOperator *op) { - SpaceNode *snode = CTX_wm_space_node(C); - bNode *node_act = nodeGetActive(snode->edittree); + SpaceNode &snode = *CTX_wm_space_node(C); + bNodeTree &node_tree = *snode.edittree; + bNode *node_act = nodeGetActive(snode.edittree); if (node_act == nullptr) { return OPERATOR_CANCELLED; } - bNode *node; bool changed = false; const bool extend = RNA_boolean_get(op->ptr, "extend"); const int type = RNA_enum_get(op->ptr, "type"); if (!extend) { - for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) { nodeSetSelected(node, false); } } @@ -382,23 +378,23 @@ static int node_select_grouped_exec(bContext *C, wmOperator *op) switch (type) { case NODE_SELECT_GROUPED_TYPE: - changed = node_select_grouped_type(snode, node_act); + changed = node_select_grouped_type(node_tree, *node_act); break; case NODE_SELECT_GROUPED_COLOR: - changed = node_select_grouped_color(snode, node_act); + changed = node_select_grouped_color(node_tree, *node_act); break; case NODE_SELECT_GROUPED_PREFIX: - changed = node_select_grouped_name(snode, node_act, false); + changed = node_select_grouped_name(node_tree, *node_act, false); break; case NODE_SELECT_GROUPED_SUFIX: - changed = node_select_grouped_name(snode, node_act, true); + changed = node_select_grouped_name(node_tree, *node_act, true); break; default: break; } if (changed) { - ED_node_sort(snode->edittree); + node_sort(node_tree); WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr); return OPERATOR_FINISHED; } @@ -449,26 +445,26 @@ void NODE_OT_select_grouped(wmOperatorType *ot) void node_select_single(bContext &C, bNode &node) { Main *bmain = CTX_data_main(&C); - SpaceNode *snode = CTX_wm_space_node(&C); + SpaceNode &snode = *CTX_wm_space_node(&C); + bNodeTree &node_tree = *snode.edittree; const Object *ob = CTX_data_active_object(&C); const Scene *scene = CTX_data_scene(&C); const wmWindowManager *wm = CTX_wm_manager(&C); bool active_texture_changed = false; - bNode *tnode; - for (tnode = (bNode *)snode->edittree->nodes.first; tnode; tnode = tnode->next) { - if (tnode != &node) { - nodeSetSelected(tnode, false); + LISTBASE_FOREACH (bNode *, node_iter, &node_tree.nodes) { + if (node_iter != &node) { + nodeSetSelected(node_iter, false); } } nodeSetSelected(&node, true); - ED_node_set_active(bmain, snode, snode->edittree, &node, &active_texture_changed); - ED_node_set_active_viewer_key(snode); + ED_node_set_active(bmain, &snode, &node_tree, &node, &active_texture_changed); + ED_node_set_active_viewer_key(&snode); - ED_node_sort(snode->edittree); + node_sort(node_tree); if (active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) { - DEG_id_tag_update(&snode->edittree->id, ID_RECALC_COPY_ON_WRITE); + DEG_id_tag_update(&node_tree.id, ID_RECALC_COPY_ON_WRITE); } WM_event_add_notifier(&C, NC_NODE | NA_SELECTED, nullptr); @@ -609,7 +605,7 @@ static int node_mouse_select(bContext *C, ED_spreadsheet_context_paths_set_geometry_node(&bmain, &snode, node); } ED_node_set_active_viewer_key(&snode); - ED_node_sort(snode.edittree); + node_sort(*snode.edittree); if ((active_texture_changed && has_workbench_in_texture_color(wm, scene, ob)) || viewer_node_changed) { DEG_id_tag_update(&snode.edittree->id, ID_RECALC_COPY_ON_WRITE); @@ -676,20 +672,21 @@ void NODE_OT_select(wmOperatorType *ot) static int node_box_select_exec(bContext *C, wmOperator *op) { - SpaceNode *snode = CTX_wm_space_node(C); - ARegion *region = CTX_wm_region(C); + SpaceNode &snode = *CTX_wm_space_node(C); + bNodeTree &node_tree = *snode.edittree; + const ARegion ®ion = *CTX_wm_region(C); rctf rectf; WM_operator_properties_border_to_rctf(op, &rectf); - UI_view2d_region_to_view_rctf(®ion->v2d, &rectf, &rectf); + UI_view2d_region_to_view_rctf(®ion.v2d, &rectf, &rectf); const eSelectOp sel_op = (eSelectOp)RNA_enum_get(op->ptr, "mode"); const bool select = (sel_op != SEL_OP_SUB); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { - ED_node_select_all(&snode->edittree->nodes, SEL_DESELECT); + node_select_all(&node_tree.nodes, SEL_DESELECT); } - LISTBASE_FOREACH (bNode *, node, &snode->edittree->nodes) { + LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) { bool is_inside; if (node->type == NODE_FRAME) { is_inside = BLI_rctf_inside_rctf(&rectf, &node->totr); @@ -703,7 +700,7 @@ static int node_box_select_exec(bContext *C, wmOperator *op) } } - ED_node_sort(snode->edittree); + node_sort(node_tree); WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr); @@ -773,7 +770,7 @@ static int node_circleselect_exec(bContext *C, wmOperator *op) WM_gesture_is_modal_first((const wmGesture *)op->customdata)); const bool select = (sel_op != SEL_OP_SUB); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { - ED_node_select_all(&snode->edittree->nodes, SEL_DESELECT); + node_select_all(&snode->edittree->nodes, SEL_DESELECT); } /* get operator properties */ @@ -848,7 +845,7 @@ static bool do_lasso_select_node(bContext *C, const bool select = (sel_op != SEL_OP_SUB); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { - ED_node_select_all(&snode->edittree->nodes, SEL_DESELECT); + node_select_all(&snode->edittree->nodes, SEL_DESELECT); changed = true; } @@ -935,13 +932,13 @@ void NODE_OT_select_lasso(wmOperatorType *ot) static int node_select_all_exec(bContext *C, wmOperator *op) { - SpaceNode *snode = CTX_wm_space_node(C); - ListBase *node_lb = &snode->edittree->nodes; + SpaceNode &snode = *CTX_wm_space_node(C); + ListBase *node_lb = &snode.edittree->nodes; int action = RNA_enum_get(op->ptr, "action"); - ED_node_select_all(node_lb, action); + node_select_all(node_lb, action); - ED_node_sort(snode->edittree); + node_sort(*snode.edittree); WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr); return OPERATOR_FINISHED; @@ -972,15 +969,14 @@ void NODE_OT_select_all(wmOperatorType *ot) static int node_select_linked_to_exec(bContext *C, wmOperator *UNUSED(op)) { - SpaceNode *snode = CTX_wm_space_node(C); - bNodeLink *link; - bNode *node; + SpaceNode &snode = *CTX_wm_space_node(C); + bNodeTree &node_tree = *snode.edittree; - for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) { node->flag &= ~NODE_TEST; } - for (link = (bNodeLink *)snode->edittree->links.first; link; link = link->next) { + LISTBASE_FOREACH (bNodeLink *, link, &node_tree.links) { if (nodeLinkIsHidden(link)) { continue; } @@ -989,13 +985,13 @@ static int node_select_linked_to_exec(bContext *C, wmOperator *UNUSED(op)) } } - for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) { if (node->flag & NODE_TEST) { nodeSetSelected(node, true); } } - ED_node_sort(snode->edittree); + node_sort(node_tree); WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr); return OPERATOR_FINISHED; @@ -1024,15 +1020,14 @@ void NODE_OT_select_linked_to(wmOperatorType *ot) static int node_select_linked_from_exec(bContext *C, wmOperator *UNUSED(op)) { - SpaceNode *snode = CTX_wm_space_node(C); - bNodeLink *link; - bNode *node; + SpaceNode &snode = *CTX_wm_space_node(C); + bNodeTree &node_tree = *snode.edittree; - for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) { node->flag &= ~NODE_TEST; } - for (link = (bNodeLink *)snode->edittree->links.first; link; link = link->next) { + LISTBASE_FOREACH (bNodeLink *, link, &node_tree.links) { if (nodeLinkIsHidden(link)) { continue; } @@ -1041,13 +1036,13 @@ static int node_select_linked_from_exec(bContext *C, wmOperator *UNUSED(op)) } } - for (node = (bNode *)snode->edittree->nodes.first; node; node = node->next) { + LISTBASE_FOREACH (bNode *, node, &node_tree.nodes) { if (node->flag & NODE_TEST) { nodeSetSelected(node, true); } } - ED_node_sort(snode->edittree); + node_sort(node_tree); WM_event_add_notifier(C, NC_NODE | NA_SELECTED, nullptr); return OPERATOR_FINISHED; @@ -1314,3 +1309,5 @@ void NODE_OT_find_node(wmOperatorType *ot) } /** \} */ + +} // namespace blender::ed::space_node diff --git a/source/blender/editors/space_node/node_templates.cc b/source/blender/editors/space_node/node_templates.cc index 386178596af..113e2bd3bb3 100644 --- a/source/blender/editors/space_node/node_templates.cc +++ b/source/blender/editors/space_node/node_templates.cc @@ -37,6 +37,7 @@ #include "BKE_context.h" #include "BKE_lib_id.h" #include "BKE_main.h" +#include "BKE_node_tree_update.h" #include "RNA_access.h" @@ -52,9 +53,10 @@ #include "ED_undo.h" -using blender::Vector; using blender::nodes::NodeDeclaration; +namespace blender::ed::space_node { + /************************* Node Socket Manipulation **************************/ /* describes an instance of a node type and a specific socket to link */ @@ -84,7 +86,7 @@ static void node_link_item_apply(Main *bmain, bNode *node, NodeLinkItem *item) { if (ELEM(node->type, NODE_GROUP, NODE_CUSTOM_GROUP)) { node->id = (ID *)item->ngroup; - ntreeUpdateTree(bmain, item->ngroup); + BKE_ntree_update_main_tree(bmain, item->ngroup, nullptr); } else { /* nothing to do for now */ @@ -179,10 +181,8 @@ static void node_socket_disconnect(Main *bmain, nodeRemLink(ntree, sock_to->link); sock_to->flag |= SOCK_COLLAPSED; - nodeUpdate(ntree, node_to); - ntreeUpdateTree(bmain, ntree); - - ED_node_tag_update_nodetree(bmain, ntree, node_to); + BKE_ntree_update_tag_node_property(ntree, node_to); + ED_node_tree_propagate_change(nullptr, bmain, ntree); } /* remove all nodes connected to this socket, if they aren't connected to other nodes */ @@ -195,10 +195,8 @@ static void node_socket_remove(Main *bmain, bNodeTree *ntree, bNode *node_to, bN node_remove_linked(bmain, ntree, sock_to->link->fromnode); sock_to->flag |= SOCK_COLLAPSED; - nodeUpdate(ntree, node_to); - ntreeUpdateTree(bmain, ntree); - - ED_node_tag_update_nodetree(bmain, ntree, node_to); + BKE_ntree_update_tag_node_property(ntree, node_to); + ED_node_tree_propagate_change(nullptr, bmain, ntree); } /* add new node connected to this socket, or replace an existing one */ @@ -299,11 +297,9 @@ static void node_socket_add_replace(const bContext *C, node_remove_linked(bmain, ntree, node_prev); } - nodeUpdate(ntree, node_from); - nodeUpdate(ntree, node_to); - ntreeUpdateTree(CTX_data_main(C), ntree); - - ED_node_tag_update_nodetree(CTX_data_main(C), ntree, node_to); + BKE_ntree_update_tag_node_property(ntree, node_from); + BKE_ntree_update_tag_node_property(ntree, node_to); + ED_node_tree_propagate_change(nullptr, bmain, ntree); } /****************************** Node Link Menu *******************************/ @@ -386,17 +382,42 @@ static Vector<NodeLinkItem> ui_node_link_items(NodeLinkArg *arg, const SocketDeclaration &socket_decl = *socket_decl_ptr; NodeLinkItem item; item.socket_index = index++; - /* A socket declaration does not necessarily map to exactly one built-in socket type. So only - * check for the types that matter here. */ - if (dynamic_cast<const decl::Color *>(&socket_decl)) { - item.socket_type = SOCK_RGBA; - } - else if (dynamic_cast<const decl::Float *>(&socket_decl)) { + if (dynamic_cast<const decl::Float *>(&socket_decl)) { item.socket_type = SOCK_FLOAT; } + else if (dynamic_cast<const decl::Int *>(&socket_decl)) { + item.socket_type = SOCK_INT; + } + else if (dynamic_cast<const decl::Bool *>(&socket_decl)) { + item.socket_type = SOCK_BOOLEAN; + } else if (dynamic_cast<const decl::Vector *>(&socket_decl)) { item.socket_type = SOCK_VECTOR; } + else if (dynamic_cast<const decl::Color *>(&socket_decl)) { + item.socket_type = SOCK_RGBA; + } + else if (dynamic_cast<const decl::String *>(&socket_decl)) { + item.socket_type = SOCK_STRING; + } + else if (dynamic_cast<const decl::Image *>(&socket_decl)) { + item.socket_type = SOCK_IMAGE; + } + else if (dynamic_cast<const decl::Texture *>(&socket_decl)) { + item.socket_type = SOCK_TEXTURE; + } + else if (dynamic_cast<const decl::Material *>(&socket_decl)) { + item.socket_type = SOCK_MATERIAL; + } + else if (dynamic_cast<const decl::Shader *>(&socket_decl)) { + item.socket_type = SOCK_SHADER; + } + else if (dynamic_cast<const decl::Collection *>(&socket_decl)) { + item.socket_type = SOCK_COLLECTION; + } + else if (dynamic_cast<const decl::Object *>(&socket_decl)) { + item.socket_type = SOCK_OBJECT; + } else { item.socket_type = SOCK_CUSTOM; } @@ -696,15 +717,19 @@ static void ui_template_node_link_menu(bContext *C, uiLayout *layout, void *but_ ui_node_menu_column(arg, NODE_CLASS_GROUP, N_("Group")); } +} // namespace blender::ed::space_node + void uiTemplateNodeLink( uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input) { + using namespace blender::ed::space_node; + uiBlock *block = uiLayoutGetBlock(layout); NodeLinkArg *arg; uiBut *but; float socket_col[4]; - arg = (NodeLinkArg *)MEM_callocN(sizeof(NodeLinkArg), "NodeLinkArg"); + arg = MEM_new<NodeLinkArg>("NodeLinkArg"); arg->ntree = ntree; arg->node = node; arg->sock = input; @@ -740,6 +765,8 @@ void uiTemplateNodeLink( } } +namespace blender::ed::space_node { + /**************************** Node Tree Layout *******************************/ static void ui_node_draw_input( @@ -892,9 +919,13 @@ static void ui_node_draw_input( node->flag &= ~NODE_TEST; } +} // namespace blender::ed::space_node + void uiTemplateNodeView( uiLayout *layout, bContext *C, bNodeTree *ntree, bNode *node, bNodeSocket *input) { + using namespace blender::ed::space_node; + bNode *tnode; if (!ntree) { diff --git a/source/blender/editors/space_node/node_view.cc b/source/blender/editors/space_node/node_view.cc index df629a983e3..9d99709a780 100644 --- a/source/blender/editors/space_node/node_view.cc +++ b/source/blender/editors/space_node/node_view.cc @@ -55,7 +55,7 @@ #include "node_intern.hh" /* own include */ -using blender::StringRef; +namespace blender::ed::space_node { /* -------------------------------------------------------------------- */ /** \name View All Operator @@ -255,7 +255,7 @@ static int snode_bg_viewmove_invoke(bContext *C, wmOperator *op, const wmEvent * return OPERATOR_CANCELLED; } - nvm = (NodeViewMove *)MEM_callocN(sizeof(NodeViewMove), "NodeViewMove struct"); + nvm = MEM_cnew<NodeViewMove>("NodeViewMove struct"); op->customdata = nvm; nvm->mvalo[0] = event->mval[0]; nvm->mvalo[1] = event->mval[1]; @@ -444,6 +444,8 @@ static void sample_draw(const bContext *C, ARegion *region, void *arg_info) } } +} // namespace blender::ed::space_node + bool ED_space_node_get_position( Main *bmain, SpaceNode *snode, struct ARegion *region, const int mval[2], float fpos[2]) { @@ -526,6 +528,8 @@ bool ED_space_node_color_sample( return ret; } +namespace blender::ed::space_node { + static void sample_apply(bContext *C, wmOperator *op, const wmEvent *event) { Main *bmain = CTX_data_main(C); @@ -643,7 +647,7 @@ static int sample_invoke(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_CANCELLED; } - info = (ImageSampleInfo *)MEM_callocN(sizeof(ImageSampleInfo), "ImageSampleInfo"); + info = MEM_cnew<ImageSampleInfo>("ImageSampleInfo"); info->art = region->type; info->draw_handle = ED_region_draw_cb_activate( region->type, sample_draw, info, REGION_DRAW_POST_PIXEL); @@ -783,3 +787,5 @@ void NODE_OT_geometry_node_view_legacy(wmOperatorType *ot) } /** \} */ + +} // namespace blender::ed::space_node diff --git a/source/blender/editors/space_node/space_node.cc b/source/blender/editors/space_node/space_node.cc index f3b95ca2024..00fd328b2ed 100644 --- a/source/blender/editors/space_node/space_node.cc +++ b/source/blender/editors/space_node/space_node.cc @@ -31,6 +31,7 @@ #include "BKE_context.h" #include "BKE_lib_id.h" +#include "BKE_lib_remap.h" #include "BKE_node.h" #include "BKE_screen.h" @@ -63,7 +64,7 @@ void ED_node_tree_start(SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from) BLI_listbase_clear(&snode->treepath); if (ntree) { - bNodeTreePath *path = (bNodeTreePath *)MEM_callocN(sizeof(bNodeTreePath), "node tree path"); + bNodeTreePath *path = MEM_cnew<bNodeTreePath>("node tree path"); path->nodetree = ntree; path->parent_key = NODE_INSTANCE_KEY_BASE; @@ -96,7 +97,7 @@ void ED_node_tree_start(SpaceNode *snode, bNodeTree *ntree, ID *id, ID *from) void ED_node_tree_push(SpaceNode *snode, bNodeTree *ntree, bNode *gnode) { - bNodeTreePath *path = (bNodeTreePath *)MEM_callocN(sizeof(bNodeTreePath), "node tree path"); + bNodeTreePath *path = MEM_cnew<bNodeTreePath>("node tree path"); bNodeTreePath *prev_path = (bNodeTreePath *)snode->treepath.last; path->nodetree = ntree; if (gnode) { @@ -206,6 +207,18 @@ void ED_node_set_active_viewer_key(SpaceNode *snode) } } +void ED_node_cursor_location_get(const SpaceNode *snode, float value[2]) +{ + copy_v2_v2(value, snode->runtime->cursor); +} + +void ED_node_cursor_location_set(SpaceNode *snode, const float value[2]) +{ + copy_v2_v2(snode->runtime->cursor, value); +} + +namespace blender::ed::space_node { + float2 space_node_group_offset(const SpaceNode &snode) { const bNodeTreePath *path = (bNodeTreePath *)snode.treepath.last; @@ -220,7 +233,7 @@ float2 space_node_group_offset(const SpaceNode &snode) static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(scene)) { - SpaceNode *snode = (SpaceNode *)MEM_callocN(sizeof(SpaceNode), "initnode"); + SpaceNode *snode = MEM_cnew<SpaceNode>("initnode"); snode->spacetype = SPACE_NODE; snode->flag = SNODE_SHOW_GPENCIL | SNODE_USE_ALPHA; @@ -238,21 +251,21 @@ static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(s NODE_TREE_TYPES_END; /* header */ - ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "header for node"); + ARegion *region = MEM_cnew<ARegion>("header for node"); BLI_addtail(&snode->regionbase, region); region->regiontype = RGN_TYPE_HEADER; region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP; /* buttons/list view */ - region = (ARegion *)MEM_callocN(sizeof(ARegion), "buttons for node"); + region = MEM_cnew<ARegion>("buttons for node"); BLI_addtail(&snode->regionbase, region); region->regiontype = RGN_TYPE_UI; region->alignment = RGN_ALIGN_RIGHT; /* toolbar */ - region = (ARegion *)MEM_callocN(sizeof(ARegion), "node tools"); + region = MEM_cnew<ARegion>("node tools"); BLI_addtail(&snode->regionbase, region); region->regiontype = RGN_TYPE_TOOLS; @@ -261,7 +274,7 @@ static SpaceLink *node_create(const ScrArea *UNUSED(area), const Scene *UNUSED(s region->flag = RGN_FLAG_HIDDEN; /* main region */ - region = (ARegion *)MEM_callocN(sizeof(ARegion), "main region for node"); + region = MEM_cnew<ARegion>("main region for node"); BLI_addtail(&snode->regionbase, region); region->regiontype = RGN_TYPE_WINDOW; @@ -309,8 +322,21 @@ static void node_init(struct wmWindowManager *UNUSED(wm), ScrArea *area) SpaceNode *snode = (SpaceNode *)area->spacedata.first; if (snode->runtime == nullptr) { - snode->runtime = (SpaceNode_Runtime *)MEM_callocN(sizeof(SpaceNode_Runtime), __func__); + snode->runtime = MEM_new<SpaceNode_Runtime>(__func__); + } +} + +static bool any_node_uses_id(const bNodeTree *ntree, const ID *id) +{ + if (ELEM(nullptr, ntree, id)) { + return false; } + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->id == id) { + return true; + } + } + return false; } static void node_area_listener(const wmSpaceTypeListenerParams *params) @@ -370,9 +396,6 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params) else if (wmn->data == ND_SHADING_LINKS) { ED_area_tag_refresh(area); } - else if (wmn->action == NA_ADDED && snode->edittree) { - nodeSetActiveID(snode->edittree, ID_MA, (ID *)wmn->reference); - } } break; case NC_TEXTURE: @@ -436,10 +459,9 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params) case NC_IMAGE: if (wmn->action == NA_EDITED) { if (ED_node_is_compositor(snode)) { - /* note that nodeUpdateID is already called by BKE_image_signal() on all - * scenes so really this is just to know if the images is used in the compo else - * painting on images could become very slow when the compositor is open. */ - if (nodeUpdateID(snode->nodetree, (ID *)wmn->reference)) { + /* Without this check drawing on an image could become very slow when the compositor is + * open. */ + if (any_node_uses_id(snode->nodetree, (ID *)wmn->reference)) { ED_area_tag_refresh(area); } } @@ -449,7 +471,7 @@ static void node_area_listener(const wmSpaceTypeListenerParams *params) case NC_MOVIECLIP: if (wmn->action == NA_EDITED) { if (ED_node_is_compositor(snode)) { - if (nodeUpdateID(snode->nodetree, (ID *)wmn->reference)) { + if (any_node_uses_id(snode->nodetree, (ID *)wmn->reference)) { ED_area_tag_refresh(area); } } @@ -482,27 +504,7 @@ static void node_area_refresh(const struct bContext *C, ScrArea *area) snode_set_context(*C); if (snode->nodetree) { - if (snode->nodetree->type == NTREE_SHADER) { - if (GS(snode->id->name) == ID_MA) { - Material *ma = (Material *)snode->id; - if (ma->use_nodes) { - ED_preview_shader_job(C, area, snode->id, nullptr, nullptr, 100, 100, PR_NODE_RENDER); - } - } - else if (GS(snode->id->name) == ID_LA) { - Light *la = (Light *)snode->id; - if (la->use_nodes) { - ED_preview_shader_job(C, area, snode->id, nullptr, nullptr, 100, 100, PR_NODE_RENDER); - } - } - else if (GS(snode->id->name) == ID_WO) { - World *wo = (World *)snode->id; - if (wo->use_nodes) { - ED_preview_shader_job(C, area, snode->id, nullptr, nullptr, 100, 100, PR_NODE_RENDER); - } - } - } - else if (snode->nodetree->type == NTREE_COMPOSIT) { + if (snode->nodetree->type == NTREE_COMPOSIT) { Scene *scene = (Scene *)snode->id; if (scene->use_nodes) { /* recalc is set on 3d view changes for auto compo */ @@ -515,12 +517,6 @@ static void node_area_refresh(const struct bContext *C, ScrArea *area) } } } - else if (snode->nodetree->type == NTREE_TEXTURE) { - Tex *tex = (Tex *)snode->id; - if (tex->use_nodes) { - ED_preview_shader_job(C, area, snode->id, nullptr, nullptr, 100, 100, PR_NODE_RENDER); - } - } } } @@ -573,16 +569,6 @@ static void node_toolbar_region_draw(const bContext *C, ARegion *region) ED_region_panels(C, region); } -void ED_node_cursor_location_get(const SpaceNode *snode, float value[2]) -{ - copy_v2_v2(value, snode->runtime->cursor); -} - -void ED_node_cursor_location_set(SpaceNode *snode, const float value[2]) -{ - copy_v2_v2(snode->runtime->cursor, value); -} - static void node_cursor(wmWindow *win, ScrArea *area, ARegion *region) { SpaceNode *snode = (SpaceNode *)area->spacedata.first; @@ -831,8 +817,14 @@ static void node_region_listener(const wmRegionListenerParams *params) } } +} // namespace blender::ed::space_node + +/* Outside of blender namespace to avoid Python documentation build error with `ctypes`. */ const char *node_context_dir[] = { "selected_nodes", "active_node", "light", "material", "world", nullptr}; + +namespace blender::ed::space_node { + static int /*eContextResult*/ node_context(const bContext *C, const char *member, bContextDataResult *result) @@ -905,9 +897,9 @@ static void node_widgets() WM_gizmogrouptype_append_and_link(gzmap_type, NODE_GGT_backdrop_corner_pin); } -static void node_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id) +static void node_id_remap_cb(ID *old_id, ID *new_id, void *user_data) { - SpaceNode *snode = (SpaceNode *)slink; + SpaceNode *snode = static_cast<SpaceNode *>(user_data); if (snode->id == old_id) { /* nasty DNA logic for SpaceNode: @@ -973,6 +965,24 @@ static void node_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, I } } +static void node_id_remap(ScrArea *UNUSED(area), + SpaceLink *slink, + const struct IDRemapper *mappings) +{ + /* Although we should be able to perform all the mappings in a single go this lead to issues when + * running the python test cases. Somehow the nodetree/edittree weren't updated to the new + * pointers that generated a SEGFAULT. + * + * To move forward we should perhaps remove snode->edittree and snode->nodetree as they are just + * copies of pointers. All usages should be calling a function that will receive the appropriate + * instance. + * + * We could also move a remap address at a time to ise the IDRemapper as that should get closer + * to cleaner code. See {D13615} for more information about this topic. + */ + BKE_id_remapper_iter(mappings, node_id_remap_cb, slink); +} + static int node_space_subtype_get(ScrArea *area) { SpaceNode *snode = (SpaceNode *)area->spacedata.first; @@ -995,9 +1005,13 @@ static void node_space_subtype_item_extend(bContext *C, EnumPropertyItem **item, } } +} // namespace blender::ed::space_node + void ED_spacetype_node() { - SpaceType *st = (SpaceType *)MEM_callocN(sizeof(SpaceType), "spacetype node"); + using namespace blender::ed::space_node; + + SpaceType *st = MEM_cnew<SpaceType>("spacetype node"); ARegionType *art; st->spaceid = SPACE_NODE; @@ -1020,7 +1034,7 @@ void ED_spacetype_node() st->space_subtype_set = node_space_subtype_set; /* regions: main window */ - art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype node region"); + art = MEM_cnew<ARegionType>("spacetype node region"); art->regionid = RGN_TYPE_WINDOW; art->init = node_main_region_init; art->draw = node_main_region_draw; @@ -1034,7 +1048,7 @@ void ED_spacetype_node() BLI_addhead(&st->regiontypes, art); /* regions: header */ - art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype node region"); + art = MEM_cnew<ARegionType>("spacetype node region"); art->regionid = RGN_TYPE_HEADER; art->prefsizey = HEADERY; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_FRAMES | ED_KEYMAP_HEADER; @@ -1045,7 +1059,7 @@ void ED_spacetype_node() BLI_addhead(&st->regiontypes, art); /* regions: listview/buttons */ - art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype node region"); + art = MEM_cnew<ARegionType>("spacetype node region"); art->regionid = RGN_TYPE_UI; art->prefsizex = UI_SIDEBAR_PANEL_WIDTH; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; @@ -1056,7 +1070,7 @@ void ED_spacetype_node() BLI_addhead(&st->regiontypes, art); /* regions: toolbar */ - art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype view3d tools region"); + art = MEM_cnew<ARegionType>("spacetype view3d tools region"); art->regionid = RGN_TYPE_TOOLS; art->prefsizex = 58; /* XXX */ art->prefsizey = 50; /* XXX */ @@ -1068,7 +1082,5 @@ void ED_spacetype_node() art->draw = node_toolbar_region_draw; BLI_addhead(&st->regiontypes, art); - node_toolbar_register(art); - BKE_spacetype_register(st); } diff --git a/source/blender/editors/space_outliner/CMakeLists.txt b/source/blender/editors/space_outliner/CMakeLists.txt index c31239f0e9c..bc6db978a4f 100644 --- a/source/blender/editors/space_outliner/CMakeLists.txt +++ b/source/blender/editors/space_outliner/CMakeLists.txt @@ -34,18 +34,18 @@ set(INC set(SRC - outliner_collections.c - outliner_context.c - outliner_dragdrop.c - outliner_draw.c - outliner_edit.c - outliner_ops.c - outliner_select.c - outliner_sync.c - outliner_tools.c - outliner_tree.c - outliner_utils.c - space_outliner.c + outliner_collections.cc + outliner_context.cc + outliner_dragdrop.cc + outliner_draw.cc + outliner_edit.cc + outliner_ops.cc + outliner_select.cc + outliner_sync.cc + outliner_tools.cc + outliner_tree.cc + outliner_utils.cc + space_outliner.cc tree/common.cc tree/tree_display.cc tree/tree_display_data.cc @@ -65,13 +65,14 @@ set(SRC tree/tree_element_id_scene.cc tree/tree_element_nla.cc tree/tree_element_overrides.cc + tree/tree_element_rna.cc tree/tree_element_scene_objects.cc + tree/tree_element_seq.cc tree/tree_element_view_layer.cc - outliner_intern.h - tree/tree_display.h + outliner_intern.hh + tree/common.hh tree/tree_display.hh - tree/tree_element.h tree/tree_element.hh tree/tree_element_anim_data.hh tree/tree_element_collection.hh @@ -82,7 +83,9 @@ set(SRC tree/tree_element_id_scene.hh tree/tree_element_nla.hh tree/tree_element_overrides.hh + tree/tree_element_rna.hh tree/tree_element_scene_objects.hh + tree/tree_element_seq.hh tree/tree_element_view_layer.hh ) diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.cc index 946d7a0538d..8d60a6088d3 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.cc @@ -18,7 +18,7 @@ * \ingroup spoutliner */ -#include <string.h> +#include <cstring> #include "BLI_listbase.h" #include "BLI_utildefines.h" @@ -49,7 +49,7 @@ #include "RNA_define.h" #include "RNA_enum_types.h" -#include "outliner_intern.h" /* own include */ +#include "outliner_intern.hh" /* own include */ /* -------------------------------------------------------------------- */ /** \name Utility API @@ -81,11 +81,11 @@ Collection *outliner_collection_from_tree_element(const TreeElement *te) TreeStoreElem *tselem = TREESTORE(te); if (!tselem) { - return NULL; + return nullptr; } if (tselem->type == TSE_LAYER_COLLECTION) { - LayerCollection *lc = te->directdata; + LayerCollection *lc = reinterpret_cast<LayerCollection *>(te->directdata); return lc->collection; } if (ELEM(tselem->type, TSE_SCENE_COLLECTION_BASE, TSE_VIEW_COLLECTION_BASE)) { @@ -96,12 +96,12 @@ Collection *outliner_collection_from_tree_element(const TreeElement *te) return (Collection *)tselem->id; } - return NULL; + return nullptr; } TreeTraversalAction outliner_find_selected_collections(TreeElement *te, void *customdata) { - struct IDsSelectedData *data = customdata; + struct IDsSelectedData *data = reinterpret_cast<IDsSelectedData *>(customdata); TreeStoreElem *tselem = TREESTORE(te); if (outliner_is_collection_tree_element(te)) { @@ -118,14 +118,15 @@ TreeTraversalAction outliner_find_selected_collections(TreeElement *te, void *cu TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *customdata) { - struct IDsSelectedData *data = customdata; + struct IDsSelectedData *data = reinterpret_cast<IDsSelectedData *>(customdata); TreeStoreElem *tselem = TREESTORE(te); if (outliner_is_collection_tree_element(te)) { return TRAVERSE_CONTINUE; } - if ((tselem->type != TSE_SOME_ID) || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) { + if ((tselem->type != TSE_SOME_ID) || (tselem->id == nullptr) || + (GS(tselem->id->name) != ID_OB)) { return TRAVERSE_SKIP_CHILDS; } @@ -137,7 +138,7 @@ TreeTraversalAction outliner_find_selected_objects(TreeElement *te, void *custom void ED_outliner_selected_objects_get(const bContext *C, ListBase *objects) { SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); - struct IDsSelectedData data = {{NULL}}; + struct IDsSelectedData data = {{nullptr}}; outliner_tree_traverse(space_outliner, &space_outliner->tree, 0, @@ -161,14 +162,14 @@ void ED_outliner_selected_objects_get(const bContext *C, ListBase *objects) bool ED_outliner_collections_editor_poll(bContext *C) { SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); - return (space_outliner != NULL) && + return (space_outliner != nullptr) && ELEM(space_outliner->outlinevis, SO_VIEW_LAYER, SO_SCENES, SO_LIBRARIES); } static bool outliner_view_layer_collections_editor_poll(bContext *C) { SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); - return (space_outliner != NULL) && (space_outliner->outlinevis == SO_VIEW_LAYER); + return (space_outliner != nullptr) && (space_outliner->outlinevis == SO_VIEW_LAYER); } static bool collection_edit_in_active_scene_poll(bContext *C) @@ -196,14 +197,14 @@ struct CollectionNewData { static TreeTraversalAction collection_find_selected_to_add(TreeElement *te, void *customdata) { - struct CollectionNewData *data = customdata; + struct CollectionNewData *data = reinterpret_cast<CollectionNewData *>(customdata); Collection *collection = outliner_collection_from_tree_element(te); if (!collection) { return TRAVERSE_SKIP_CHILDS; } - if (data->collection != NULL) { + if (data->collection != nullptr) { data->error = true; return TRAVERSE_BREAK; } @@ -220,10 +221,7 @@ static int collection_new_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - struct CollectionNewData data = { - .error = false, - .collection = NULL, - }; + CollectionNewData data{}; if (RNA_boolean_get(op->ptr, "nested")) { outliner_build_tree(bmain, scene, view_layer, space_outliner, region); @@ -241,7 +239,7 @@ static int collection_new_exec(bContext *C, wmOperator *op) } } - if (data.collection == NULL || ID_IS_LINKED(data.collection) || + if (data.collection == nullptr || ID_IS_LINKED(data.collection) || ID_IS_OVERRIDE_LIBRARY(data.collection)) { data.collection = scene->master_collection; } @@ -251,13 +249,13 @@ static int collection_new_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - BKE_collection_add(bmain, data.collection, NULL); + BKE_collection_add(bmain, data.collection, nullptr); DEG_id_tag_update(&data.collection->id, ID_RECALC_COPY_ON_WRITE); DEG_relations_tag_update(bmain); outliner_cleanup_tree(space_outliner); - WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + WM_main_add_notifier(NC_SCENE | ND_LAYER, nullptr); return OPERATOR_FINISHED; } @@ -295,7 +293,7 @@ struct CollectionEditData { static TreeTraversalAction collection_find_data_to_edit(TreeElement *te, void *customdata) { - struct CollectionEditData *data = customdata; + CollectionEditData *data = reinterpret_cast<CollectionEditData *>(customdata); Collection *collection = outliner_collection_from_tree_element(te); if (!collection) { @@ -321,10 +319,9 @@ void outliner_collection_delete( { SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); - struct CollectionEditData data = { - .scene = scene, - .space_outliner = space_outliner, - }; + CollectionEditData data{}; + data.scene = scene; + data.space_outliner = space_outliner; data.collections_to_edit = BLI_gset_ptr_new(__func__); @@ -336,7 +333,8 @@ void outliner_collection_delete( /* Effectively delete the collections. */ GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); + Collection *collection = reinterpret_cast<Collection *>( + BLI_gsetIterator_getKey(&collections_to_edit_iter)); /* Test in case collection got deleted as part of another one. */ if (BLI_findindex(&bmain->collections, collection) != -1) { @@ -358,7 +356,7 @@ void outliner_collection_delete( BLI_assert(parent->id.flag & LIB_EMBEDDED_DATA); const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(&parent->id); - BLI_assert(id_type->owner_get != NULL); + BLI_assert(id_type->owner_get != nullptr); ID *scene_owner = id_type->owner_get(bmain, &parent->id); BLI_assert(GS(scene_owner->name) == ID_SCE); @@ -384,9 +382,11 @@ void outliner_collection_delete( } } - BLI_gset_free(data.collections_to_edit, NULL); + BLI_gset_free(data.collections_to_edit, nullptr); } +/* FIXME: See comment above #WM_msg_publish_rna_prop(). */ +extern "C" { static int collection_hierarchy_delete_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); @@ -400,7 +400,7 @@ static int collection_hierarchy_delete_exec(bContext *C, wmOperator *op) DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); DEG_relations_tag_update(bmain); - WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + WM_main_add_notifier(NC_SCENE | ND_LAYER, nullptr); if (basact_prev != BASACT(view_layer)) { WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, LayerObjects, active); @@ -410,6 +410,7 @@ static int collection_hierarchy_delete_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +} void OUTLINER_OT_collection_hierarchy_delete(wmOperatorType *ot) { @@ -440,12 +441,12 @@ struct CollectionObjectsSelectData { static TreeTraversalAction outliner_find_first_selected_layer_collection(TreeElement *te, void *customdata) { - struct CollectionObjectsSelectData *data = customdata; + CollectionObjectsSelectData *data = reinterpret_cast<CollectionObjectsSelectData *>(customdata); TreeStoreElem *tselem = TREESTORE(te); switch (tselem->type) { case TSE_LAYER_COLLECTION: - data->layer_collection = te->directdata; + data->layer_collection = reinterpret_cast<LayerCollection *>(te->directdata); return TRAVERSE_BREAK; case TSE_R_LAYER: case TSE_SCENE_COLLECTION_BASE: @@ -460,9 +461,7 @@ static LayerCollection *outliner_active_layer_collection(bContext *C) { SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); - struct CollectionObjectsSelectData data = { - .layer_collection = NULL, - }; + CollectionObjectsSelectData data{}; outliner_tree_traverse(space_outliner, &space_outliner->tree, @@ -479,7 +478,7 @@ static int collection_objects_select_exec(bContext *C, wmOperator *op) LayerCollection *layer_collection = outliner_active_layer_collection(C); bool deselect = STREQ(op->idname, "OUTLINER_OT_collection_objects_deselect"); - if (layer_collection == NULL) { + if (layer_collection == nullptr) { return OPERATOR_CANCELLED; } @@ -536,7 +535,7 @@ struct CollectionDuplicateData { static TreeTraversalAction outliner_find_first_selected_collection(TreeElement *te, void *customdata) { - struct CollectionDuplicateData *data = customdata; + CollectionDuplicateData *data = reinterpret_cast<CollectionDuplicateData *>(customdata); TreeStoreElem *tselem = TREESTORE(te); switch (tselem->type) { @@ -555,9 +554,7 @@ static TreeElement *outliner_active_collection(bContext *C) { SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); - struct CollectionDuplicateData data = { - .te = NULL, - }; + CollectionDuplicateData data = {}; outliner_tree_traverse(space_outliner, &space_outliner->tree, @@ -572,38 +569,38 @@ static int collection_duplicate_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); TreeElement *te = outliner_active_collection(C); - const bool linked = strstr(op->idname, "linked") != NULL; + const bool linked = strstr(op->idname, "linked") != nullptr; /* Can happen when calling from a key binding. */ - if (te == NULL) { + if (te == nullptr) { BKE_report(op->reports, RPT_ERROR, "No active collection"); return OPERATOR_CANCELLED; } Collection *collection = outliner_collection_from_tree_element(te); - Collection *parent = (te->parent) ? outliner_collection_from_tree_element(te->parent) : NULL; + Collection *parent = (te->parent) ? outliner_collection_from_tree_element(te->parent) : nullptr; /* We are allowed to duplicated linked collections (they will become local IDs then), * but we should not allow its parent to be a linked ID, ever. * This can happen when a whole scene is linked e.g. */ - if (parent != NULL && (ID_IS_LINKED(parent) || ID_IS_OVERRIDE_LIBRARY(parent))) { + if (parent != nullptr && (ID_IS_LINKED(parent) || ID_IS_OVERRIDE_LIBRARY(parent))) { Scene *scene = CTX_data_scene(C); - parent = (ID_IS_LINKED(scene) || ID_IS_OVERRIDE_LIBRARY(scene)) ? NULL : + parent = (ID_IS_LINKED(scene) || ID_IS_OVERRIDE_LIBRARY(scene)) ? nullptr : scene->master_collection; } - else if (parent != NULL && (parent->flag & COLLECTION_IS_MASTER) != 0) { + else if (parent != nullptr && (parent->flag & COLLECTION_IS_MASTER) != 0) { BLI_assert(parent->id.flag & LIB_EMBEDDED_DATA); const IDTypeInfo *id_type = BKE_idtype_get_info_from_id(&parent->id); - BLI_assert(id_type->owner_get != NULL); + BLI_assert(id_type->owner_get != nullptr); Scene *scene_owner = (Scene *)id_type->owner_get(bmain, &parent->id); - BLI_assert(scene_owner != NULL); + BLI_assert(scene_owner != nullptr); BLI_assert(GS(scene_owner->id.name) == ID_SCE); if (ID_IS_LINKED(scene_owner) || ID_IS_OVERRIDE_LIBRARY(scene_owner)) { scene_owner = CTX_data_scene(C); - parent = ID_IS_LINKED(scene_owner) ? NULL : scene_owner->master_collection; + parent = ID_IS_LINKED(scene_owner) ? nullptr : scene_owner->master_collection; } } @@ -612,14 +609,15 @@ static int collection_duplicate_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - if (parent == NULL) { + if (parent == nullptr) { BKE_report(op->reports, RPT_WARNING, "Could not find a valid parent collection for the new duplicate, " "it won't be linked to any view layer"); } - const eDupli_ID_Flags dupli_flags = USER_DUP_OBJECT | (linked ? 0 : U.dupflag); + const eDupli_ID_Flags dupli_flags = (eDupli_ID_Flags)(USER_DUP_OBJECT | + (linked ? 0 : U.dupflag)); BKE_collection_duplicate(bmain, parent, collection, dupli_flags, LIB_ID_DUPLICATE_IS_ROOT_ID); DEG_relations_tag_update(bmain); @@ -674,10 +672,10 @@ static int collection_link_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); Collection *active_collection = CTX_data_layer_collection(C)->collection; SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); - struct CollectionEditData data = { - .scene = scene, - .space_outliner = space_outliner, - }; + + CollectionEditData data{}; + data.scene = scene; + data.space_outliner = space_outliner; if ((ID_IS_LINKED(active_collection) || ID_IS_OVERRIDE_LIBRARY(active_collection)) || ((active_collection->flag & COLLECTION_IS_MASTER) && @@ -696,17 +694,18 @@ static int collection_link_exec(bContext *C, wmOperator *op) /* Effectively link the collections. */ GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); + Collection *collection = reinterpret_cast<Collection *>( + BLI_gsetIterator_getKey(&collections_to_edit_iter)); BKE_collection_child_add(bmain, active_collection, collection); id_fake_user_clear(&collection->id); } - BLI_gset_free(data.collections_to_edit, NULL); + BLI_gset_free(data.collections_to_edit, nullptr); DEG_id_tag_update(&active_collection->id, ID_RECALC_COPY_ON_WRITE); DEG_relations_tag_update(bmain); - WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + WM_main_add_notifier(NC_SCENE | ND_LAYER, nullptr); return OPERATOR_FINISHED; } @@ -738,10 +737,9 @@ static int collection_instance_exec(bContext *C, wmOperator *UNUSED(op)) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); - struct CollectionEditData data = { - .scene = scene, - .space_outliner = space_outliner, - }; + CollectionEditData data{}; + data.scene = scene; + data.space_outliner = space_outliner; data.collections_to_edit = BLI_gset_ptr_new(__func__); @@ -755,7 +753,8 @@ static int collection_instance_exec(bContext *C, wmOperator *UNUSED(op)) GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); + Collection *collection = reinterpret_cast<Collection *>( + BLI_gsetIterator_getKey(&collections_to_edit_iter)); while (BKE_collection_cycle_find(active_lc->collection, collection)) { active_lc = BKE_layer_collection_activate_parent(view_layer, active_lc); @@ -764,20 +763,21 @@ static int collection_instance_exec(bContext *C, wmOperator *UNUSED(op)) /* Effectively instance the collections. */ GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); + Collection *collection = reinterpret_cast<Collection *>( + BLI_gsetIterator_getKey(&collections_to_edit_iter)); Object *ob = ED_object_add_type( - C, OB_EMPTY, collection->id.name + 2, scene->cursor.location, NULL, false, 0); + C, OB_EMPTY, collection->id.name + 2, scene->cursor.location, nullptr, false, 0); ob->instance_collection = collection; ob->transflag |= OB_DUPLICOLLECTION; id_lib_extern(&collection->id); id_us_plus(&collection->id); } - BLI_gset_free(data.collections_to_edit, NULL); + BLI_gset_free(data.collections_to_edit, nullptr); DEG_relations_tag_update(bmain); - WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + WM_main_add_notifier(NC_SCENE | ND_LAYER, nullptr); return OPERATOR_FINISHED; } @@ -805,14 +805,14 @@ void OUTLINER_OT_collection_instance(wmOperatorType *ot) static TreeTraversalAction layer_collection_find_data_to_edit(TreeElement *te, void *customdata) { - struct CollectionEditData *data = customdata; + CollectionEditData *data = reinterpret_cast<CollectionEditData *>(customdata); TreeStoreElem *tselem = TREESTORE(te); if (!(tselem && tselem->type == TSE_LAYER_COLLECTION)) { return TRAVERSE_CONTINUE; } - LayerCollection *lc = te->directdata; + LayerCollection *lc = reinterpret_cast<LayerCollection *>(te->directdata); if (lc->collection->flag & COLLECTION_IS_MASTER) { /* skip - showing warning/error message might be misleading @@ -836,10 +836,9 @@ static bool collections_view_layer_poll(bContext *C, bool clear, int flag) } Scene *scene = CTX_data_scene(C); - struct CollectionEditData data = { - .scene = scene, - .space_outliner = space_outliner, - }; + CollectionEditData data{}; + data.scene = scene; + data.space_outliner = space_outliner; data.collections_to_edit = BLI_gset_ptr_new(__func__); bool result = false; @@ -852,7 +851,8 @@ static bool collections_view_layer_poll(bContext *C, bool clear, int flag) GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter); + LayerCollection *lc = reinterpret_cast<LayerCollection *>( + BLI_gsetIterator_getKey(&collections_to_edit_iter)); if (clear && (lc->flag & flag)) { result = true; @@ -862,7 +862,7 @@ static bool collections_view_layer_poll(bContext *C, bool clear, int flag) } } - BLI_gset_free(data.collections_to_edit, NULL); + BLI_gset_free(data.collections_to_edit, nullptr); return result; } @@ -902,11 +902,10 @@ static int collection_view_layer_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); - struct CollectionEditData data = { - .scene = scene, - .space_outliner = space_outliner, - }; - bool clear = strstr(op->idname, "clear") != NULL; + CollectionEditData data{}; + data.scene = scene; + data.space_outliner = space_outliner; + bool clear = strstr(op->idname, "clear") != nullptr; int flag = strstr(op->idname, "holdout") ? LAYER_COLLECTION_HOLDOUT : strstr(op->idname, "indirect_only") ? LAYER_COLLECTION_INDIRECT_ONLY : LAYER_COLLECTION_EXCLUDE; @@ -922,16 +921,17 @@ static int collection_view_layer_exec(bContext *C, wmOperator *op) GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - LayerCollection *lc = BLI_gsetIterator_getKey(&collections_to_edit_iter); + LayerCollection *lc = reinterpret_cast<LayerCollection *>( + BLI_gsetIterator_getKey(&collections_to_edit_iter)); BKE_layer_collection_set_flag(lc, flag, !clear); } - BLI_gset_free(data.collections_to_edit, NULL); + BLI_gset_free(data.collections_to_edit, nullptr); BKE_layer_collection_sync(scene, view_layer); DEG_relations_tag_update(bmain); - WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); + WM_main_add_notifier(NC_SCENE | ND_LAYER, nullptr); return OPERATOR_FINISHED; } @@ -1040,10 +1040,9 @@ static int collection_isolate_exec(bContext *C, wmOperator *op) ViewLayer *view_layer = CTX_data_view_layer(C); SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); const bool extend = RNA_boolean_get(op->ptr, "extend"); - struct CollectionEditData data = { - .scene = scene, - .space_outliner = space_outliner, - }; + CollectionEditData data{}; + data.scene = scene; + data.space_outliner = space_outliner; data.collections_to_edit = BLI_gset_ptr_new(__func__); outliner_tree_traverse(space_outliner, &space_outliner->tree, @@ -1054,7 +1053,8 @@ static int collection_isolate_exec(bContext *C, wmOperator *op) GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); + LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>( + BLI_gsetIterator_getKey(&collections_to_edit_iter)); if (extend) { BKE_layer_collection_isolate_global(scene, view_layer, layer_collection, true); @@ -1069,16 +1069,16 @@ static int collection_isolate_exec(bContext *C, wmOperator *op) * was called. */ const bool value = !RNA_property_boolean_get(&ptr, prop); outliner_collection_isolate_flag( - scene, view_layer, layer_collection, NULL, prop, "hide_viewport", value); + scene, view_layer, layer_collection, nullptr, prop, "hide_viewport", value); break; } } - BLI_gset_free(data.collections_to_edit, NULL); + BLI_gset_free(data.collections_to_edit, nullptr); BKE_layer_collection_sync(scene, view_layer); DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); - WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL); + WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, nullptr); return OPERATOR_FINISHED; } @@ -1127,7 +1127,7 @@ static bool collection_inside_poll(bContext *C) if (!ED_outliner_collections_editor_poll(C)) { return false; } - return outliner_active_layer_collection(C) != NULL; + return outliner_active_layer_collection(C) != nullptr; } static int collection_visibility_exec(bContext *C, wmOperator *op) @@ -1135,12 +1135,11 @@ static int collection_visibility_exec(bContext *C, wmOperator *op) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); - const bool is_inside = strstr(op->idname, "inside") != NULL; - const bool show = strstr(op->idname, "show") != NULL; - struct CollectionEditData data = { - .scene = scene, - .space_outliner = space_outliner, - }; + const bool is_inside = strstr(op->idname, "inside") != nullptr; + const bool show = strstr(op->idname, "show") != nullptr; + CollectionEditData data{}; + data.scene = scene; + data.space_outliner = space_outliner; data.collections_to_edit = BLI_gset_ptr_new(__func__); outliner_tree_traverse(space_outliner, @@ -1152,15 +1151,16 @@ static int collection_visibility_exec(bContext *C, wmOperator *op) GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); + LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>( + BLI_gsetIterator_getKey(&collections_to_edit_iter)); BKE_layer_collection_set_visible(view_layer, layer_collection, show, is_inside); } - BLI_gset_free(data.collections_to_edit, NULL); + BLI_gset_free(data.collections_to_edit, nullptr); BKE_layer_collection_sync(scene, view_layer); DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); - WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL); + WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, nullptr); return OPERATOR_FINISHED; } @@ -1237,12 +1237,12 @@ static bool collection_flag_poll(bContext *C, bool clear, int flag) } TreeElement *te = outliner_active_collection(C); - if (te == NULL) { + if (te == nullptr) { return false; } Collection *collection = outliner_collection_from_tree_element(te); - if (collection == NULL) { + if (collection == nullptr) { return false; } @@ -1284,10 +1284,9 @@ static int collection_flag_exec(bContext *C, wmOperator *op) const bool is_render = strstr(op->idname, "render"); const bool clear = strstr(op->idname, "show") || strstr(op->idname, "enable"); int flag = is_render ? COLLECTION_HIDE_RENDER : COLLECTION_HIDE_VIEWPORT; - struct CollectionEditData data = { - .scene = scene, - .space_outliner = space_outliner, - }; + CollectionEditData data{}; + data.scene = scene; + data.space_outliner = space_outliner; data.collections_to_edit = BLI_gset_ptr_new(__func__); const bool has_layer_collection = space_outliner->outlinevis == SO_VIEW_LAYER; @@ -1300,7 +1299,8 @@ static int collection_flag_exec(bContext *C, wmOperator *op) &data); GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); + LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>( + BLI_gsetIterator_getKey(&collections_to_edit_iter)); Collection *collection = layer_collection->collection; if (ID_IS_LINKED(collection)) { continue; @@ -1317,7 +1317,7 @@ static int collection_flag_exec(bContext *C, wmOperator *op) layer_collection->flag &= ~LAYER_COLLECTION_HIDE; } } - BLI_gset_free(data.collections_to_edit, NULL); + BLI_gset_free(data.collections_to_edit, nullptr); } else { outliner_tree_traverse(space_outliner, @@ -1328,7 +1328,8 @@ static int collection_flag_exec(bContext *C, wmOperator *op) &data); GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - Collection *collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); + Collection *collection = reinterpret_cast<Collection *>( + BLI_gsetIterator_getKey(&collections_to_edit_iter)); if (ID_IS_LINKED(collection)) { continue; } @@ -1340,7 +1341,7 @@ static int collection_flag_exec(bContext *C, wmOperator *op) collection->flag |= flag; } } - BLI_gset_free(data.collections_to_edit, NULL); + BLI_gset_free(data.collections_to_edit, nullptr); } BKE_layer_collection_sync(scene, view_layer); @@ -1350,7 +1351,7 @@ static int collection_flag_exec(bContext *C, wmOperator *op) DEG_relations_tag_update(CTX_data_main(C)); } - WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL); + WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, nullptr); return OPERATOR_FINISHED; } @@ -1430,15 +1431,15 @@ struct OutlinerHideEditData { static TreeTraversalAction outliner_hide_find_data_to_edit(TreeElement *te, void *customdata) { - struct OutlinerHideEditData *data = customdata; + OutlinerHideEditData *data = reinterpret_cast<OutlinerHideEditData *>(customdata); TreeStoreElem *tselem = TREESTORE(te); - if (tselem == NULL) { + if (tselem == nullptr) { return TRAVERSE_CONTINUE; } if (tselem->type == TSE_LAYER_COLLECTION) { - LayerCollection *lc = te->directdata; + LayerCollection *lc = reinterpret_cast<LayerCollection *>(te->directdata); if (lc->collection->flag & COLLECTION_IS_MASTER) { /* Skip - showing warning/error message might be misleading @@ -1464,11 +1465,10 @@ static int outliner_hide_exec(bContext *C, wmOperator *UNUSED(op)) Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); - struct OutlinerHideEditData data = { - .scene = scene, - .view_layer = view_layer, - .space_outliner = space_outliner, - }; + OutlinerHideEditData data{}; + data.scene = scene; + data.view_layer = view_layer; + data.space_outliner = space_outliner; data.collections_to_edit = BLI_gset_ptr_new("outliner_hide_exec__collections_to_edit"); data.bases_to_edit = BLI_gset_ptr_new("outliner_hide_exec__bases_to_edit"); @@ -1481,22 +1481,23 @@ static int outliner_hide_exec(bContext *C, wmOperator *UNUSED(op)) GSetIterator collections_to_edit_iter; GSET_ITER (collections_to_edit_iter, data.collections_to_edit) { - LayerCollection *layer_collection = BLI_gsetIterator_getKey(&collections_to_edit_iter); + LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>( + BLI_gsetIterator_getKey(&collections_to_edit_iter)); BKE_layer_collection_set_visible(view_layer, layer_collection, false, false); } - BLI_gset_free(data.collections_to_edit, NULL); + BLI_gset_free(data.collections_to_edit, nullptr); GSetIterator bases_to_edit_iter; GSET_ITER (bases_to_edit_iter, data.bases_to_edit) { - Base *base = BLI_gsetIterator_getKey(&bases_to_edit_iter); + Base *base = reinterpret_cast<Base *>(BLI_gsetIterator_getKey(&bases_to_edit_iter)); base->flag |= BASE_HIDDEN; } - BLI_gset_free(data.bases_to_edit, NULL); + BLI_gset_free(data.bases_to_edit, nullptr); BKE_layer_collection_sync(scene, view_layer); DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); - WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL); + WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, nullptr); return OPERATOR_FINISHED; } @@ -1521,7 +1522,8 @@ static int outliner_unhide_all_exec(bContext *C, wmOperator *UNUSED(op)) ViewLayer *view_layer = CTX_data_view_layer(C); /* Unhide all the collections. */ - LayerCollection *lc_master = view_layer->layer_collections.first; + LayerCollection *lc_master = reinterpret_cast<LayerCollection *>( + view_layer->layer_collections.first); LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_master->layer_collections) { BKE_layer_collection_set_flag(lc_iter, LAYER_COLLECTION_HIDE, false); } @@ -1534,7 +1536,7 @@ static int outliner_unhide_all_exec(bContext *C, wmOperator *UNUSED(op)) BKE_layer_collection_sync(scene, view_layer); DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS); - WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, NULL); + WM_main_add_notifier(NC_SCENE | ND_LAYER_CONTENT, nullptr); return OPERATOR_FINISHED; } @@ -1565,9 +1567,7 @@ static int outliner_color_tag_set_exec(bContext *C, wmOperator *op) SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); const short color_tag = RNA_enum_get(op->ptr, "color"); - struct IDsSelectedData selected = { - .selected_array = {NULL, NULL}, - }; + IDsSelectedData selected{}; outliner_tree_traverse(space_outliner, &space_outliner->tree, @@ -1593,7 +1593,7 @@ static int outliner_color_tag_set_exec(bContext *C, wmOperator *op) BLI_freelistN(&selected.selected_array); - WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, NULL); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, nullptr); return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_outliner/outliner_context.c b/source/blender/editors/space_outliner/outliner_context.cc index d61bb17f661..d3b99928ec1 100644 --- a/source/blender/editors/space_outliner/outliner_context.c +++ b/source/blender/editors/space_outliner/outliner_context.cc @@ -27,7 +27,7 @@ #include "DNA_space_types.h" -#include "outliner_intern.h" +#include "outliner_intern.hh" static void outliner_context_selected_ids_recursive(const ListBase *subtree, bContextDataResult *result) @@ -48,7 +48,7 @@ static void outliner_context_selected_ids(const SpaceOutliner *space_outliner, CTX_data_type_set(result, CTX_DATA_TYPE_COLLECTION); } -static const char *outliner_context_dir[] = {"selected_ids", NULL}; +static const char *outliner_context_dir[] = {"selected_ids", nullptr}; int /*eContextResult*/ outliner_context(const bContext *C, const char *member, diff --git a/source/blender/editors/space_outliner/outliner_dragdrop.c b/source/blender/editors/space_outliner/outliner_dragdrop.cc index a4d5f2635d4..3745894d630 100644 --- a/source/blender/editors/space_outliner/outliner_dragdrop.c +++ b/source/blender/editors/space_outliner/outliner_dragdrop.cc @@ -21,7 +21,7 @@ * \ingroup spoutliner */ -#include <string.h> +#include <cstring> #include "MEM_guardedalloc.h" @@ -58,7 +58,7 @@ #include "WM_api.h" #include "WM_types.h" -#include "outliner_intern.h" +#include "outliner_intern.hh" static Collection *collection_parent_from_ID(ID *id); @@ -83,7 +83,7 @@ static TreeElement *outliner_dropzone_element(TreeElement *te, } } } - return NULL; + return nullptr; } /* Find tree element to drop into. */ @@ -97,7 +97,7 @@ static TreeElement *outliner_dropzone_find(const SpaceOutliner *space_outliner, return te_valid; } } - return NULL; + return nullptr; } static TreeElement *outliner_drop_find(bContext *C, const wmEvent *event) @@ -113,17 +113,17 @@ static TreeElement *outliner_drop_find(bContext *C, const wmEvent *event) 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; + TreeStoreElem *tselem = (te) ? TREESTORE(te) : nullptr; if (te && (te->idcode == idcode) && (tselem->type == TSE_SOME_ID)) { return tselem->id; } - return NULL; + return nullptr; } /* Find tree element to drop into, with additional before and after reorder support. */ static TreeElement *outliner_drop_insert_find(bContext *C, - const wmEvent *event, + const int xy[2], TreeElementInsertType *r_insert_type) { SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); @@ -133,11 +133,14 @@ static TreeElement *outliner_drop_insert_find(bContext *C, /* Empty tree, e.g. while filtered. */ if (BLI_listbase_is_empty(&space_outliner->tree)) { - return NULL; + return nullptr; } - UI_view2d_region_to_view( - ®ion->v2d, event->mval[0], event->mval[1], &view_mval[0], &view_mval[1]); + int mval[2]; + mval[0] = xy[0] - region->winrct.xmin; + mval[1] = xy[1] - region->winrct.ymin; + + UI_view2d_region_to_view(®ion->v2d, mval[0], mval[1], &view_mval[0], &view_mval[1]); te_hovered = outliner_find_item_at_y(space_outliner, &space_outliner->tree, view_mval[1]); if (te_hovered) { @@ -154,7 +157,7 @@ static TreeElement *outliner_drop_insert_find(bContext *C, return te_hovered; } *r_insert_type = TE_INSERT_BEFORE; - return te_hovered->subtree.first; + return reinterpret_cast<TreeElement *>(te_hovered->subtree.first); } *r_insert_type = TE_INSERT_AFTER; return te_hovered; @@ -169,8 +172,8 @@ static TreeElement *outliner_drop_insert_find(bContext *C, /* Mouse doesn't hover any item (ignoring x-axis), * so it's either above list bounds or below. */ - TreeElement *first = space_outliner->tree.first; - TreeElement *last = space_outliner->tree.last; + TreeElement *first = reinterpret_cast<TreeElement *>(space_outliner->tree.first); + TreeElement *last = reinterpret_cast<TreeElement *>(space_outliner->tree.last); if (view_mval[1] < last->ys) { *r_insert_type = TE_INSERT_AFTER; @@ -181,21 +184,21 @@ static TreeElement *outliner_drop_insert_find(bContext *C, return first; } BLI_assert(0); - return NULL; + return nullptr; } -typedef bool (*CheckTypeFn)(TreeElement *te); +using CheckTypeFn = bool (*)(TreeElement *te); static TreeElement *outliner_data_from_tree_element_and_parents(CheckTypeFn check_type, TreeElement *te) { - while (te != NULL) { + while (te != nullptr) { if (check_type(te)) { return te; } te = te->parent; } - return NULL; + return nullptr; } static bool is_collection_element(TreeElement *te) @@ -216,18 +219,18 @@ static bool is_pchan_element(TreeElement *te) } static TreeElement *outliner_drop_insert_collection_find(bContext *C, - const wmEvent *event, + const int xy[2], TreeElementInsertType *r_insert_type) { - TreeElement *te = outliner_drop_insert_find(C, event, r_insert_type); + TreeElement *te = outliner_drop_insert_find(C, xy, r_insert_type); if (!te) { - return NULL; + return nullptr; } TreeElement *collection_te = outliner_data_from_tree_element_and_parents(is_collection_element, te); if (!collection_te) { - return NULL; + return nullptr; } Collection *collection = outliner_collection_from_tree_element(collection_te); @@ -260,7 +263,7 @@ static int outliner_get_insert_index(TreeElement *drag_te, } } - if (drop_te == NULL) { + if (drop_te == nullptr) { return 0; } @@ -364,7 +367,7 @@ static void parent_drop_set_parents(bContext *C, TreeElement *te = outliner_find_id(space_outliner, &space_outliner->tree, &parent->id); Scene *scene = (Scene *)outliner_search_back(te, ID_SCE); - if (scene == NULL) { + if (scene == nullptr) { /* currently outliner organized in a way, that if there's no parent scene * element for object it means that all displayed objects belong to * active scene and parenting them is allowed (sergey) @@ -387,7 +390,7 @@ static void parent_drop_set_parents(bContext *C, } if (ED_object_parent_set( - reports, C, scene, object, parent, parent_type, false, keep_transform, NULL)) { + reports, C, scene, object, parent, parent_type, false, keep_transform, nullptr)) { parent_set = true; } } @@ -399,15 +402,15 @@ static void parent_drop_set_parents(bContext *C, if (parent_set) { DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); - WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, nullptr); + WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, nullptr); } } 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; + TreeStoreElem *tselem = te ? TREESTORE(te) : nullptr; if (!(te && (te->idcode == ID_OB) && (tselem->type == TSE_SOME_ID))) { return OPERATOR_CANCELLED; @@ -416,7 +419,7 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) Object *par = (Object *)tselem->id; Object *ob = (Object *)WM_drag_get_local_ID_from_event(event, ID_OB); - if (ELEM(NULL, ob, par)) { + if (ELEM(nullptr, ob, par)) { return OPERATOR_CANCELLED; } if (ob == par) { @@ -427,10 +430,11 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) return OPERATOR_CANCELLED; } - ListBase *lb = event->customdata; - wmDrag *drag = lb->first; + ListBase *lb = reinterpret_cast<ListBase *>(event->customdata); + wmDrag *drag = reinterpret_cast<wmDrag *>(lb->first); - parent_drop_set_parents(C, op->reports, drag->ids.first, par, PAR_OBJECT, event->alt); + parent_drop_set_parents( + C, op->reports, reinterpret_cast<wmDragID *>(drag->ids.first), par, PAR_OBJECT, event->alt); return OPERATOR_FINISHED; } @@ -501,8 +505,8 @@ static int parent_clear_invoke(bContext *C, wmOperator *UNUSED(op), const wmEven return OPERATOR_CANCELLED; } - ListBase *lb = event->customdata; - wmDrag *drag = lb->first; + ListBase *lb = reinterpret_cast<ListBase *>(event->customdata); + wmDrag *drag = reinterpret_cast<wmDrag *>(lb->first); LISTBASE_FOREACH (wmDragID *, drag_id, &drag->ids) { if (GS(drag_id->id->name) == ID_OB) { @@ -513,8 +517,8 @@ static int parent_clear_invoke(bContext *C, wmOperator *UNUSED(op), const wmEven } DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, NULL); - WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_TRANSFORM, nullptr); + WM_event_add_notifier(C, NC_OBJECT | ND_PARENT, nullptr); return OPERATOR_FINISHED; } @@ -540,7 +544,7 @@ static bool scene_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) { /* Ensure item under cursor is valid drop target */ Object *ob = (Object *)WM_drag_get_local_ID(drag, ID_OB); - return (ob && (outliner_ID_drop_find(C, event, ID_SCE) != NULL)); + return (ob && (outliner_ID_drop_find(C, event, ID_SCE) != nullptr)); } static int scene_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) @@ -549,7 +553,7 @@ static int scene_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent Scene *scene = (Scene *)outliner_ID_drop_find(C, event, ID_SCE); Object *ob = (Object *)WM_drag_get_local_ID_from_event(event, ID_OB); - if (ELEM(NULL, ob, scene) || ID_IS_LINKED(scene)) { + if (ELEM(nullptr, ob, scene) || ID_IS_LINKED(scene)) { return OPERATOR_CANCELLED; } @@ -605,7 +609,7 @@ static bool material_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) { /* Ensure item under cursor is valid drop target */ Material *ma = (Material *)WM_drag_get_local_ID(drag, ID_MA); - return (ma && (outliner_ID_drop_find(C, event, ID_OB) != NULL)); + return (ma && (outliner_ID_drop_find(C, event, ID_OB) != nullptr)); } static int material_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) @@ -614,19 +618,19 @@ static int material_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEve Object *ob = (Object *)outliner_ID_drop_find(C, event, ID_OB); Material *ma = (Material *)WM_drag_get_local_ID_from_event(event, ID_MA); - if (ELEM(NULL, ob, ma)) { + if (ELEM(nullptr, ob, ma)) { return OPERATOR_CANCELLED; } /* only drop grease pencil material on grease pencil objects */ - if ((ma->gp_style != NULL) && (ob->type != OB_GPENCIL)) { + if ((ma->gp_style != nullptr) && (ob->type != OB_GPENCIL)) { return OPERATOR_CANCELLED; } BKE_object_material_assign(bmain, ob, ma, ob->totcol + 1, BKE_MAT_ASSIGN_USERPREF); WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, ob); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, nullptr); WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, ma); return OPERATOR_FINISHED; @@ -658,13 +662,13 @@ void OUTLINER_OT_material_drop(wmOperatorType *ot) * - Copying a single modifier/constraint/effect to another object. * - Copying (linking) an object's modifiers/constraints/effects to another. */ -typedef enum eDataStackDropAction { +enum eDataStackDropAction { DATA_STACK_DROP_REORDER, DATA_STACK_DROP_COPY, DATA_STACK_DROP_LINK, -} eDataStackDropAction; +}; -typedef struct StackDropData { +struct StackDropData { Object *ob_parent; bPoseChannel *pchan_parent; TreeStoreElem *drag_tselem; @@ -674,7 +678,7 @@ typedef struct StackDropData { eDataStackDropAction drop_action; TreeElement *drop_te; TreeElementInsertType insert_type; -} StackDropData; +}; static void datastack_drop_data_init(wmDrag *drag, Object *ob, @@ -683,7 +687,7 @@ static void datastack_drop_data_init(wmDrag *drag, TreeStoreElem *tselem, void *directdata) { - StackDropData *drop_data = MEM_callocN(sizeof(*drop_data), "datastack drop data"); + StackDropData *drop_data = MEM_cnew<StackDropData>("datastack drop data"); drop_data->ob_parent = ob; drop_data->pchan_parent = pchan; @@ -707,7 +711,7 @@ static bool datastack_drop_init(bContext *C, const wmEvent *event, StackDropData return false; } - TreeElement *te_target = outliner_drop_insert_find(C, event, &drop_data->insert_type); + TreeElement *te_target = outliner_drop_insert_find(C, event->xy, &drop_data->insert_type); if (!te_target) { return false; } @@ -717,20 +721,20 @@ static bool datastack_drop_init(bContext *C, const wmEvent *event, StackDropData return false; } - Object *ob = NULL; + Object *ob = nullptr; TreeElement *object_te = outliner_data_from_tree_element_and_parents(is_object_element, te_target); if (object_te) { ob = (Object *)TREESTORE(object_te)->id; } - bPoseChannel *pchan = NULL; + bPoseChannel *pchan = nullptr; TreeElement *pchan_te = outliner_data_from_tree_element_and_parents(is_pchan_element, te_target); if (pchan_te) { pchan = (bPoseChannel *)pchan_te->directdata; } if (pchan) { - ob = NULL; + ob = nullptr; } if (ob && ID_IS_LINKED(&ob->id)) { @@ -833,7 +837,7 @@ static bool datastack_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event) bool changed = outliner_flag_set( &space_outliner->tree, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false); - StackDropData *drop_data = drag->poin; + StackDropData *drop_data = reinterpret_cast<StackDropData *>(drag->poin); if (!drop_data) { return false; } @@ -871,7 +875,7 @@ static char *datastack_drop_tooltip(bContext *UNUSED(C), const int UNUSED(xy[2]), struct wmDropBox *UNUSED(drop)) { - StackDropData *drop_data = drag->poin; + StackDropData *drop_data = reinterpret_cast<StackDropData *>(drag->poin); switch (drop_data->drop_action) { case DATA_STACK_DROP_REORDER: return BLI_strdup(TIP_("Reorder")); @@ -893,7 +897,7 @@ static char *datastack_drop_tooltip(bContext *UNUSED(C), } break; } - return NULL; + return nullptr; } static void datastack_drop_link(bContext *C, StackDropData *drop_data) @@ -948,20 +952,28 @@ static void datastack_drop_copy(bContext *C, StackDropData *drop_data) switch (drop_data->drag_tselem->type) { case TSE_MODIFIER: if (drop_data->ob_parent->type == OB_GPENCIL && ob_dst->type == OB_GPENCIL) { - ED_object_gpencil_modifier_copy_to_object(ob_dst, drop_data->drag_directdata); + ED_object_gpencil_modifier_copy_to_object( + ob_dst, reinterpret_cast<GpencilModifierData *>(drop_data->drag_directdata)); } else if (drop_data->ob_parent->type != OB_GPENCIL && ob_dst->type != OB_GPENCIL) { ED_object_modifier_copy_to_object( - C, ob_dst, drop_data->ob_parent, drop_data->drag_directdata); + C, + ob_dst, + drop_data->ob_parent, + reinterpret_cast<ModifierData *>(drop_data->drag_directdata)); } break; case TSE_CONSTRAINT: if (tselem->type == TSE_POSE_CHANNEL) { ED_object_constraint_copy_for_pose( - bmain, ob_dst, drop_data->drop_te->directdata, drop_data->drag_directdata); + bmain, + ob_dst, + reinterpret_cast<bPoseChannel *>(drop_data->drop_te->directdata), + reinterpret_cast<bConstraint *>(drop_data->drag_directdata)); } else { - ED_object_constraint_copy_for_object(bmain, ob_dst, drop_data->drag_directdata); + ED_object_constraint_copy_for_object( + bmain, ob_dst, reinterpret_cast<bConstraint *>(drop_data->drag_directdata)); } break; case TSE_GPENCIL_EFFECT: { @@ -969,7 +981,8 @@ static void datastack_drop_copy(bContext *C, StackDropData *drop_data) return; } - ED_object_shaderfx_copy(ob_dst, drop_data->drag_directdata); + ED_object_shaderfx_copy(ob_dst, + reinterpret_cast<ShaderFxData *>(drop_data->drag_directdata)); break; } } @@ -995,11 +1008,16 @@ static void datastack_drop_reorder(bContext *C, ReportList *reports, StackDropDa if (ob->type == OB_GPENCIL) { index = outliner_get_insert_index( drag_te, drop_te, insert_type, &ob->greasepencil_modifiers); - ED_object_gpencil_modifier_move_to_index(reports, ob, drop_data->drag_directdata, index); + ED_object_gpencil_modifier_move_to_index( + reports, + ob, + reinterpret_cast<GpencilModifierData *>(drop_data->drag_directdata), + index); } else { index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->modifiers); - ED_object_modifier_move_to_index(reports, ob, drop_data->drag_directdata, index); + ED_object_modifier_move_to_index( + reports, ob, reinterpret_cast<ModifierData *>(drop_data->drag_directdata), index); } break; case TSE_CONSTRAINT: @@ -1010,12 +1028,14 @@ static void datastack_drop_reorder(bContext *C, ReportList *reports, StackDropDa else { index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->constraints); } - ED_object_constraint_move_to_index(ob, drop_data->drag_directdata, index); + ED_object_constraint_move_to_index( + ob, reinterpret_cast<bConstraint *>(drop_data->drag_directdata), index); break; case TSE_GPENCIL_EFFECT: index = outliner_get_insert_index(drag_te, drop_te, insert_type, &ob->shader_fx); - ED_object_shaderfx_move_to_index(reports, ob, drop_data->drag_directdata, index); + ED_object_shaderfx_move_to_index( + reports, ob, reinterpret_cast<ShaderFxData *>(drop_data->drag_directdata), index); } } @@ -1025,9 +1045,9 @@ static int datastack_drop_invoke(bContext *C, wmOperator *op, const wmEvent *eve return OPERATOR_CANCELLED; } - ListBase *lb = event->customdata; - wmDrag *drag = lb->first; - StackDropData *drop_data = drag->poin; + ListBase *lb = reinterpret_cast<ListBase *>(event->customdata); + wmDrag *drag = reinterpret_cast<wmDrag *>(lb->first); + StackDropData *drop_data = reinterpret_cast<StackDropData *>(drag->poin); switch (drop_data->drop_action) { case DATA_STACK_DROP_LINK: @@ -1062,19 +1082,19 @@ void OUTLINER_OT_datastack_drop(wmOperatorType *ot) /* ******************** Collection Drop Operator *********************** */ -typedef struct CollectionDrop { +struct CollectionDrop { Collection *from; Collection *to; TreeElement *te; TreeElementInsertType insert_type; -} CollectionDrop; +}; static Collection *collection_parent_from_ID(ID *id) { /* Can't change linked parent collections. */ if (!id || ID_IS_LINKED(id)) { - return NULL; + return nullptr; } /* Also support dropping into/from scene collection. */ @@ -1085,17 +1105,15 @@ static Collection *collection_parent_from_ID(ID *id) return (Collection *)id; } - return NULL; + return nullptr; } -static bool collection_drop_init(bContext *C, - wmDrag *drag, - const wmEvent *event, - CollectionDrop *data) +static bool collection_drop_init( + bContext *C, wmDrag *drag, const int xy[2], const bool is_link, CollectionDrop *data) { /* Get collection to drop into. */ TreeElementInsertType insert_type; - TreeElement *te = outliner_drop_insert_collection_find(C, event, &insert_type); + TreeElement *te = outliner_drop_insert_collection_find(C, xy, &insert_type); if (!te) { return false; } @@ -1110,8 +1128,8 @@ static bool collection_drop_init(bContext *C, return false; } - wmDragID *drag_id = drag->ids.first; - if (drag_id == NULL) { + wmDragID *drag_id = reinterpret_cast<wmDragID *>(drag->ids.first); + if (drag_id == nullptr) { return false; } @@ -1123,12 +1141,12 @@ static bool collection_drop_init(bContext *C, /* Get collection to drag out of. */ ID *parent = drag_id->from_parent; Collection *from_collection = collection_parent_from_ID(parent); - if (event->ctrl) { - from_collection = NULL; + if (is_link) { + from_collection = nullptr; } /* Currently this should not be allowed, cannot edit items in an override of a Collection. */ - if (from_collection != NULL && ID_IS_OVERRIDE_LIBRARY(from_collection)) { + if (from_collection != nullptr && ID_IS_OVERRIDE_LIBRARY(from_collection)) { return false; } @@ -1164,7 +1182,7 @@ static bool collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event &space_outliner->tree, TSE_HIGHLIGHTED_ANY | TSE_DRAG_ANY, false); CollectionDrop data; - if (!event->shift && collection_drop_init(C, drag, event, &data)) { + if (!event->shift && collection_drop_init(C, drag, event->xy, event->ctrl, &data)) { TreeElement *te = data.te; TreeStoreElem *tselem = TREESTORE(te); if (!data.from || event->ctrl) { @@ -1201,13 +1219,14 @@ static bool collection_drop_poll(bContext *C, wmDrag *drag, const wmEvent *event static char *collection_drop_tooltip(bContext *C, wmDrag *drag, - const int UNUSED(xy[2]), + const int xy[2], wmDropBox *UNUSED(drop)) { - wmWindowManager *wm = CTX_wm_manager(C); - const wmEvent *event = wm->winactive ? wm->winactive->eventstate : NULL; + wmWindow *win = CTX_wm_window(C); + const wmEvent *event = win ? win->eventstate : nullptr; + CollectionDrop data; - if (event && !event->shift && collection_drop_init(C, drag, event, &data)) { + if (event && !event->shift && collection_drop_init(C, drag, xy, event->ctrl, &data)) { TreeElement *te = data.te; if (!data.from || event->ctrl) { return BLI_strdup(TIP_("Link inside Collection")); @@ -1244,7 +1263,7 @@ static char *collection_drop_tooltip(bContext *C, } } } - return NULL; + return nullptr; } static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *event) @@ -1256,16 +1275,16 @@ static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmE return OPERATOR_CANCELLED; } - ListBase *lb = event->customdata; - wmDrag *drag = lb->first; + ListBase *lb = reinterpret_cast<ListBase *>(event->customdata); + wmDrag *drag = reinterpret_cast<wmDrag *>(lb->first); CollectionDrop data; - if (!collection_drop_init(C, drag, event, &data)) { + if (!collection_drop_init(C, drag, event->xy, event->ctrl, &data)) { return OPERATOR_CANCELLED; } /* Before/after insert handling. */ - Collection *relative = NULL; + Collection *relative = nullptr; bool relative_after = false; if (ELEM(data.insert_type, TE_INSERT_BEFORE, TE_INSERT_AFTER)) { @@ -1274,8 +1293,8 @@ static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmE relative = data.to; relative_after = (data.insert_type == TE_INSERT_AFTER); - TreeElement *parent_te = outliner_find_parent_element(&space_outliner->tree, NULL, data.te); - data.to = (parent_te) ? outliner_collection_from_tree_element(parent_te) : NULL; + TreeElement *parent_te = outliner_find_parent_element(&space_outliner->tree, nullptr, data.te); + data.to = (parent_te) ? outliner_collection_from_tree_element(parent_te) : nullptr; } if (!data.to) { @@ -1288,7 +1307,7 @@ static int collection_drop_invoke(bContext *C, wmOperator *UNUSED(op), const wmE LISTBASE_FOREACH (wmDragID *, drag_id, &drag->ids) { /* Ctrl enables linking, so we don't need a from collection then. */ - Collection *from = (event->ctrl) ? NULL : collection_parent_from_ID(drag_id->from_parent); + Collection *from = (event->ctrl) ? nullptr : collection_parent_from_ID(drag_id->from_parent); if (GS(drag_id->id->name) == ID_OB) { /* Move/link object into collection. */ @@ -1400,10 +1419,10 @@ static int outliner_item_drag_drop_invoke(bContext *C, TSE_GPENCIL_EFFECT_BASE); const int wm_drag_type = use_datastack_drag ? WM_DRAG_DATASTACK : WM_DRAG_ID; - wmDrag *drag = WM_event_start_drag(C, data.icon, wm_drag_type, NULL, 0.0, WM_DRAG_NOP); + wmDrag *drag = WM_event_start_drag(C, data.icon, wm_drag_type, nullptr, 0.0, WM_DRAG_NOP); if (use_datastack_drag) { - TreeElement *te_bone = NULL; + TreeElement *te_bone = nullptr; bPoseChannel *pchan = outliner_find_parent_bone(te, &te_bone); datastack_drop_data_init(drag, (Object *)tselem->id, pchan, te, tselem, te->directdata); } @@ -1417,9 +1436,7 @@ static int outliner_item_drag_drop_invoke(bContext *C, } /* Gather all selected elements. */ - struct IDsSelectedData selected = { - .selected_array = {NULL, NULL}, - }; + IDsSelectedData selected{}; if (GS(data.drag_id->name) == ID_OB) { outliner_tree_traverse(space_outliner, @@ -1466,7 +1483,7 @@ static int outliner_item_drag_drop_invoke(bContext *C, } /* Find parent collection. */ - Collection *parent = NULL; + Collection *parent = nullptr; if (te_selected->parent) { for (TreeElement *te_parent = te_selected->parent; te_parent; @@ -1519,16 +1536,20 @@ void outliner_dropboxes(void) { ListBase *lb = WM_dropboxmap_find("Outliner", SPACE_OUTLINER, RGN_TYPE_WINDOW); - WM_dropbox_add(lb, "OUTLINER_OT_parent_drop", parent_drop_poll, NULL, NULL, NULL); - WM_dropbox_add(lb, "OUTLINER_OT_parent_clear", parent_clear_poll, NULL, NULL, NULL); - WM_dropbox_add(lb, "OUTLINER_OT_scene_drop", scene_drop_poll, NULL, NULL, NULL); - WM_dropbox_add(lb, "OUTLINER_OT_material_drop", material_drop_poll, NULL, NULL, NULL); - WM_dropbox_add( - lb, "OUTLINER_OT_datastack_drop", datastack_drop_poll, NULL, NULL, datastack_drop_tooltip); + WM_dropbox_add(lb, "OUTLINER_OT_parent_drop", parent_drop_poll, nullptr, nullptr, nullptr); + WM_dropbox_add(lb, "OUTLINER_OT_parent_clear", parent_clear_poll, nullptr, nullptr, nullptr); + WM_dropbox_add(lb, "OUTLINER_OT_scene_drop", scene_drop_poll, nullptr, nullptr, nullptr); + WM_dropbox_add(lb, "OUTLINER_OT_material_drop", material_drop_poll, nullptr, nullptr, nullptr); + WM_dropbox_add(lb, + "OUTLINER_OT_datastack_drop", + datastack_drop_poll, + nullptr, + nullptr, + datastack_drop_tooltip); WM_dropbox_add(lb, "OUTLINER_OT_collection_drop", collection_drop_poll, - NULL, - NULL, + nullptr, + nullptr, collection_drop_tooltip); } diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.cc index a586f268128..5fd7559370f 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.cc @@ -78,7 +78,12 @@ #include "RNA_access.h" -#include "outliner_intern.h" +#include "outliner_intern.hh" +#include "tree/tree_display.hh" +#include "tree/tree_element.hh" +#include "tree/tree_element_rna.hh" + +using namespace blender::ed::outliner; /* Disable - this is far too slow - campbell. */ /* #define USE_GROUP_SELECT */ @@ -93,7 +98,7 @@ static void outliner_tree_dimensions_impl(SpaceOutliner *space_outliner, { LISTBASE_FOREACH (TreeElement *, te, lb) { *width = MAX2(*width, te->xend); - if (height != NULL) { + if (height != nullptr) { *height += UI_UNIT_Y; } @@ -102,7 +107,7 @@ static void outliner_tree_dimensions_impl(SpaceOutliner *space_outliner, outliner_tree_dimensions_impl(space_outliner, &te->subtree, width, height); } else { - outliner_tree_dimensions_impl(space_outliner, &te->subtree, width, NULL); + outliner_tree_dimensions_impl(space_outliner, &te->subtree, width, nullptr); } } } @@ -119,7 +124,7 @@ void outliner_tree_dimensions(SpaceOutliner *space_outliner, int *r_width, int * */ static bool is_object_data_in_editmode(const ID *id, const Object *obact) { - if (id == NULL) { + if (id == nullptr) { return false; } @@ -141,9 +146,7 @@ static void restrictbutton_recursive_ebone(bArmature *arm, int flag, bool set_flag) { - EditBone *ebone; - - for (ebone = arm->edbo->first; ebone; ebone = ebone->next) { + LISTBASE_FOREACH (EditBone *, ebone, arm->edbo) { if (ED_armature_ebone_is_child_recursive(ebone_parent, ebone)) { if (set_flag) { ebone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); @@ -158,8 +161,7 @@ static void restrictbutton_recursive_ebone(bArmature *arm, static void restrictbutton_recursive_bone(Bone *bone_parent, int flag, bool set_flag) { - Bone *bone; - for (bone = bone_parent->childbase.first; bone; bone = bone->next) { + LISTBASE_FOREACH (Bone *, bone, &bone_parent->childbase) { if (set_flag) { bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); bone->flag |= flag; @@ -196,7 +198,7 @@ static void restrictbutton_bone_select_fn(bContext *C, void *UNUSED(poin), void restrictbutton_recursive_bone(bone, BONE_UNSELECTABLE, (bone->flag & BONE_UNSELECTABLE) != 0); } - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr); } static void restrictbutton_ebone_select_fn(bContext *C, void *poin, void *poin2) @@ -213,7 +215,7 @@ static void restrictbutton_ebone_select_fn(bContext *C, void *poin, void *poin2) arm, ebone, BONE_UNSELECTABLE, (ebone->flag & BONE_UNSELECTABLE) != 0); } - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr); } static void restrictbutton_ebone_visibility_fn(bContext *C, void *poin, void *poin2) @@ -228,7 +230,7 @@ static void restrictbutton_ebone_visibility_fn(bContext *C, void *poin, void *po restrictbutton_recursive_ebone(arm, ebone, BONE_HIDDEN_A, (ebone->flag & BONE_HIDDEN_A) != 0); } - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr); } static void restrictbutton_gp_layer_flag_fn(bContext *C, void *poin, void *UNUSED(poin2)) @@ -236,14 +238,14 @@ static void restrictbutton_gp_layer_flag_fn(bContext *C, void *poin, void *UNUSE ID *id = (ID *)poin; DEG_id_tag_update(id, ID_RECALC_GEOMETRY); - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, nullptr); } static void restrictbutton_id_user_toggle(bContext *UNUSED(C), void *poin, void *UNUSED(poin2)) { ID *id = (ID *)poin; - BLI_assert(id != NULL); + BLI_assert(id != nullptr); if (id->flag & LIB_FAKEUSER) { id_us_plus(id); @@ -281,7 +283,8 @@ static void outliner_object_set_flag_recursive_fn(bContext *C, Object *ob_parent = ob ? ob : base->object; - for (Object *ob_iter = bmain->objects.first; ob_iter; ob_iter = ob_iter->id.next) { + for (Object *ob_iter = reinterpret_cast<Object *>(bmain->objects.first); ob_iter; + ob_iter = reinterpret_cast<Object *>(ob_iter->id.next)) { if (BKE_object_is_child_recursive(ob_parent, ob_iter)) { if (ob) { RNA_id_pointer_create(&ob_iter->id, &ptr); @@ -290,7 +293,7 @@ static void outliner_object_set_flag_recursive_fn(bContext *C, else { Base *base_iter = BKE_view_layer_base_find(view_layer, ob_iter); /* Child can be in a collection excluded from viewlayer. */ - if (base_iter == NULL) { + if (base_iter == nullptr) { continue; } RNA_pointer_create(&scene->id, &RNA_ObjectBase, base_iter, &ptr); @@ -315,9 +318,9 @@ static void outliner_object_set_flag_recursive_fn(bContext *C, */ static void outliner__object_set_flag_recursive_fn(bContext *C, void *poin, void *poin2) { - Object *ob = poin; - char *propname = poin2; - outliner_object_set_flag_recursive_fn(C, NULL, ob, propname); + Object *ob = reinterpret_cast<Object *>(poin); + char *propname = reinterpret_cast<char *>(poin2); + outliner_object_set_flag_recursive_fn(C, nullptr, ob, propname); } /** @@ -325,9 +328,9 @@ static void outliner__object_set_flag_recursive_fn(bContext *C, void *poin, void */ static void outliner__base_set_flag_recursive_fn(bContext *C, void *poin, void *poin2) { - Base *base = poin; - char *propname = poin2; - outliner_object_set_flag_recursive_fn(C, base, NULL, propname); + Base *base = reinterpret_cast<Base *>(poin); + char *propname = reinterpret_cast<char *>(poin2); + outliner_object_set_flag_recursive_fn(C, base, nullptr, propname); } /** Create either a RNA_LayerCollection or a RNA_Collection pointer. */ @@ -392,9 +395,9 @@ static void outliner_collection_set_flag_recursive(Scene *scene, /* Keep going recursively. */ ListBase *lb = (layer_collection ? &layer_collection->layer_collections : &collection->children); LISTBASE_FOREACH (Link *, link, lb) { - LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : NULL; + LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : nullptr; Collection *collection_iter = layer_collection ? - (collection ? layer_collection_iter->collection : NULL) : + (collection ? layer_collection_iter->collection : nullptr) : ((CollectionChild *)link)->collection; outliner_collection_set_flag_recursive(scene, view_layer, @@ -458,9 +461,9 @@ static bool outliner_collection_is_isolated(Scene *scene, /* Keep going recursively. */ ListBase *lb = (layer_collection ? &layer_collection->layer_collections : &collection->children); LISTBASE_FOREACH (Link *, link, lb) { - LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : NULL; + LayerCollection *layer_collection_iter = layer_collection ? (LayerCollection *)link : nullptr; Collection *collection_iter = layer_collection ? - (collection ? layer_collection_iter->collection : NULL) : + (collection ? layer_collection_iter->collection : nullptr) : ((CollectionChild *)link)->collection; if (layer_collection_iter && layer_collection_iter->flag & LAYER_COLLECTION_EXCLUDE) { continue; @@ -488,11 +491,13 @@ void outliner_collection_isolate_flag(Scene *scene, const bool value) { PointerRNA ptr; - const bool is_hide = strstr(propname, "hide_") != NULL; + const bool is_hide = strstr(propname, "hide_") != nullptr; - LayerCollection *top_layer_collection = layer_collection ? view_layer->layer_collections.first : - NULL; - Collection *top_collection = collection ? scene->master_collection : NULL; + LayerCollection *top_layer_collection = layer_collection ? + reinterpret_cast<LayerCollection *>( + view_layer->layer_collections.first) : + nullptr; + Collection *top_collection = collection ? scene->master_collection : nullptr; bool was_isolated = (value == is_hide); was_isolated &= outliner_collection_is_isolated(scene, @@ -504,14 +509,14 @@ void outliner_collection_isolate_flag(Scene *scene, top_collection); if (was_isolated) { - const bool default_value = RNA_property_boolean_get_default(NULL, layer_or_collection_prop); + const bool default_value = RNA_property_boolean_get_default(nullptr, layer_or_collection_prop); /* Make every collection go back to its default "visibility" state. */ outliner_collection_set_flag_recursive(scene, view_layer, top_layer_collection, top_collection, layer_or_collection_prop, - NULL, + nullptr, default_value); return; } @@ -522,12 +527,17 @@ void outliner_collection_isolate_flag(Scene *scene, top_layer_collection, top_collection, layer_or_collection_prop, - NULL, + nullptr, is_hide); /* Make this collection and its children collections the only "visible". */ - outliner_collection_set_flag_recursive( - scene, view_layer, layer_collection, collection, layer_or_collection_prop, NULL, !is_hide); + outliner_collection_set_flag_recursive(scene, + view_layer, + layer_collection, + collection, + layer_or_collection_prop, + nullptr, + !is_hide); /* Make this collection direct parents also "visible". */ if (layer_collection) { @@ -541,7 +551,7 @@ void outliner_collection_isolate_flag(Scene *scene, while (lc_parent != layer_collection) { outliner_layer_or_collection_pointer_create( - scene, lc_parent, collection ? lc_parent->collection : NULL, &ptr); + scene, lc_parent, collection ? lc_parent->collection : nullptr, &ptr); RNA_property_boolean_set(&ptr, layer_or_collection_prop, !is_hide); LISTBASE_FOREACH (LayerCollection *, lc_iter, &lc_parent->layer_collections) { @@ -555,7 +565,7 @@ void outliner_collection_isolate_flag(Scene *scene, else { CollectionParent *parent; Collection *child = collection; - while ((parent = child->parents.first)) { + while ((parent = reinterpret_cast<CollectionParent *>(child->parents.first))) { if (parent->collection->flag & COLLECTION_IS_MASTER) { break; } @@ -594,8 +604,8 @@ static void outliner_collection_set_flag_recursive_fn(bContext *C, PropertyRNA *layer_or_collection_prop = RNA_struct_type_find_property(struct_rna, propname); const bool value = RNA_property_boolean_get(&ptr, layer_or_collection_prop); - PropertyRNA *base_or_object_prop = NULL; - if (layer_collection != NULL) { + PropertyRNA *base_or_object_prop = nullptr; + if (layer_collection != nullptr) { /* If we are toggling Layer collections we still want to change the properties of the base * or the objects. If we have a matching property, toggle it as well, it can be NULL. */ struct_rna = collection ? &RNA_Object : &RNA_ObjectBase; @@ -634,9 +644,9 @@ static void view_layer__layer_collection_set_flag_recursive_fn(bContext *C, void *poin, void *poin2) { - LayerCollection *layer_collection = poin; - char *propname = poin2; - outliner_collection_set_flag_recursive_fn(C, layer_collection, NULL, propname); + LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(poin); + char *propname = reinterpret_cast<char *>(poin2); + outliner_collection_set_flag_recursive_fn(C, layer_collection, nullptr, propname); } /** @@ -645,8 +655,8 @@ static void view_layer__layer_collection_set_flag_recursive_fn(bContext *C, */ static void view_layer__collection_set_flag_recursive_fn(bContext *C, void *poin, void *poin2) { - LayerCollection *layer_collection = poin; - char *propname = poin2; + LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(poin); + char *propname = reinterpret_cast<char *>(poin2); outliner_collection_set_flag_recursive_fn( C, layer_collection, layer_collection->collection, propname); } @@ -657,18 +667,20 @@ static void view_layer__collection_set_flag_recursive_fn(bContext *C, void *poin */ static void scenes__collection_set_flag_recursive_fn(bContext *C, void *poin, void *poin2) { - Collection *collection = poin; - char *propname = poin2; - outliner_collection_set_flag_recursive_fn(C, NULL, collection, propname); + Collection *collection = reinterpret_cast<Collection *>(poin); + char *propname = reinterpret_cast<char *>(poin2); + outliner_collection_set_flag_recursive_fn(C, nullptr, collection, propname); } +/* FIXME: See comment above #WM_msg_publish_rna_prop(). */ +extern "C" { static void namebutton_fn(bContext *C, void *tsep, char *oldname) { Main *bmain = CTX_data_main(C); SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); struct wmMsgBus *mbus = CTX_wm_message_bus(C); BLI_mempool *ts = space_outliner->treestore; - TreeStoreElem *tselem = tsep; + TreeStoreElem *tselem = reinterpret_cast<TreeStoreElem *>(tsep); if (ts && tselem) { TreeElement *te = outliner_find_tree_element(&space_outliner->tree, tselem); @@ -680,16 +692,16 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) switch (GS(tselem->id->name)) { case ID_MA: - WM_event_add_notifier(C, NC_MATERIAL, NULL); + WM_event_add_notifier(C, NC_MATERIAL, nullptr); break; case ID_TE: - WM_event_add_notifier(C, NC_TEXTURE, NULL); + WM_event_add_notifier(C, NC_TEXTURE, nullptr); break; case ID_IM: - WM_event_add_notifier(C, NC_IMAGE, NULL); + WM_event_add_notifier(C, NC_IMAGE, nullptr); break; case ID_SCE: - WM_event_add_notifier(C, NC_SCENE, NULL); + WM_event_add_notifier(C, NC_SCENE, nullptr); break; case ID_OB: { Object *ob = (Object *)tselem->id; @@ -702,7 +714,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) default: break; } - WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL); + WM_event_add_notifier(C, NC_ID | NA_RENAME, nullptr); /* Check the library target exists */ if (te->idcode == ID_LI) { @@ -732,7 +744,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) switch (tselem->type) { case TSE_DEFGROUP: { Object *ob = (Object *)tselem->id; - bDeformGroup *vg = te->directdata; + bDeformGroup *vg = reinterpret_cast<bDeformGroup *>(te->directdata); BKE_object_defgroup_unique_name(vg, ob); WM_msg_publish_rna_prop(mbus, &ob->id, vg, VertexGroup, name); break; @@ -746,7 +758,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) case TSE_EBONE: { bArmature *arm = (bArmature *)tselem->id; if (arm->edbo) { - EditBone *ebone = te->directdata; + EditBone *ebone = reinterpret_cast<EditBone *>(te->directdata); char newname[sizeof(ebone->name)]; /* restore bone name */ @@ -754,7 +766,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) BLI_strncpy(ebone->name, oldname, sizeof(ebone->name)); ED_armature_bone_rename(bmain, arm, oldname, newname); WM_msg_publish_rna_prop(mbus, &arm->id, ebone, EditBone, name); - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr); } break; } @@ -764,7 +776,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) outliner_viewcontext_init(C, &tvc); bArmature *arm = (bArmature *)tselem->id; - Bone *bone = te->directdata; + Bone *bone = reinterpret_cast<Bone *>(te->directdata); char newname[sizeof(bone->name)]; /* always make current object active */ @@ -775,7 +787,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) BLI_strncpy(bone->name, oldname, sizeof(bone->name)); ED_armature_bone_rename(bmain, arm, oldname, newname); WM_msg_publish_rna_prop(mbus, &arm->id, bone, Bone, name); - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr); break; } case TSE_POSE_CHANNEL: { @@ -784,7 +796,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) Object *ob = (Object *)tselem->id; bArmature *arm = (bArmature *)ob->data; - bPoseChannel *pchan = te->directdata; + bPoseChannel *pchan = reinterpret_cast<bPoseChannel *>(te->directdata); char newname[sizeof(pchan->name)]; /* always make current pose-bone active */ @@ -795,14 +807,15 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) /* restore bone name */ BLI_strncpy(newname, pchan->name, sizeof(pchan->name)); BLI_strncpy(pchan->name, oldname, sizeof(pchan->name)); - ED_armature_bone_rename(bmain, ob->data, oldname, newname); + ED_armature_bone_rename( + bmain, reinterpret_cast<bArmature *>(ob->data), oldname, newname); WM_msg_publish_rna_prop(mbus, &arm->id, pchan->bone, Bone, name); - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr); break; } case TSE_POSEGRP: { Object *ob = (Object *)tselem->id; /* id = object. */ - bActionGroup *grp = te->directdata; + bActionGroup *grp = reinterpret_cast<bActionGroup *>(te->directdata); BLI_uniquename(&ob->pose->agroups, grp, @@ -816,7 +829,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) } case TSE_GP_LAYER: { bGPdata *gpd = (bGPdata *)tselem->id; /* id = GP Datablock */ - bGPDlayer *gpl = te->directdata; + bGPDlayer *gpl = reinterpret_cast<bGPDlayer *>(te->directdata); /* always make layer active */ BKE_gpencil_layer_active_set(gpd, gpl); @@ -832,7 +845,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) } case TSE_R_LAYER: { Scene *scene = (Scene *)tselem->id; - ViewLayer *view_layer = te->directdata; + ViewLayer *view_layer = reinterpret_cast<ViewLayer *>(te->directdata); /* Restore old name. */ char newname[sizeof(view_layer->name)]; @@ -842,7 +855,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) /* Rename, preserving animation and compositing data. */ BKE_view_layer_rename(bmain, scene, view_layer, newname); WM_msg_publish_rna_prop(mbus, &scene->id, view_layer, ViewLayer, name); - WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL); + WM_event_add_notifier(C, NC_ID | NA_RENAME, nullptr); break; } case TSE_LAYER_COLLECTION: { @@ -850,7 +863,7 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) Collection *collection = (Collection *)tselem->id; BLI_libblock_ensure_unique_name(bmain, collection->id.name); WM_msg_publish_rna_prop(mbus, &collection->id, &collection->id, ID, name); - WM_event_add_notifier(C, NC_ID | NA_RENAME, NULL); + WM_event_add_notifier(C, NC_ID | NA_RENAME, nullptr); break; } } @@ -858,8 +871,9 @@ static void namebutton_fn(bContext *C, void *tsep, char *oldname) tselem->flag &= ~TSE_TEXTBUT; } } +} -typedef struct RestrictProperties { +struct RestrictProperties { bool initialized; PropertyRNA *object_hide_viewport, *object_hide_select, *object_hide_render; @@ -870,11 +884,11 @@ typedef struct RestrictProperties { PropertyRNA *modifier_show_viewport, *modifier_show_render; PropertyRNA *constraint_enable; PropertyRNA *bone_hide_viewport; -} RestrictProperties; +}; /* We don't care about the value of the property * but whether the property should be active or grayed out. */ -typedef struct RestrictPropertiesActive { +struct RestrictPropertiesActive { bool object_hide_viewport; bool object_hide_select; bool object_hide_render; @@ -890,7 +904,7 @@ typedef struct RestrictPropertiesActive { bool modifier_show_render; bool constraint_enable; bool bone_hide_viewport; -} RestrictPropertiesActive; +}; static void outliner_restrict_properties_enable_collection_set( PointerRNA *collection_ptr, RestrictProperties *props, RestrictPropertiesActive *props_active) @@ -982,8 +996,9 @@ static bool outliner_restrict_properties_collection_set(Scene *scene, RestrictPropertiesActive *props_active) { TreeStoreElem *tselem = TREESTORE(te); - LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ? te->directdata : - NULL; + LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ? + reinterpret_cast<LayerCollection *>(te->directdata) : + nullptr; Collection *collection = outliner_collection_from_tree_element(te); if (collection->flag & COLLECTION_IS_MASTER) { @@ -992,7 +1007,7 @@ static bool outliner_restrict_properties_collection_set(Scene *scene, /* Create the PointerRNA. */ RNA_id_pointer_create(&collection->id, collection_ptr); - if (layer_collection != NULL) { + if (layer_collection != nullptr) { RNA_pointer_create(&scene->id, &RNA_LayerCollection, layer_collection, layer_collection_ptr); } @@ -1096,7 +1111,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, ELEM(space_outliner->outlinevis, SO_SCENES, SO_VIEW_LAYER)) { if (space_outliner->show_restrict_flags & SO_RESTRICT_RENDER) { /* View layer render toggle. */ - ViewLayer *layer = te->directdata; + ViewLayer *layer = reinterpret_cast<ViewLayer *>(te->directdata); bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, @@ -1113,7 +1128,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, 0, TIP_("Use view layer for rendering")); - UI_but_func_set(bt, restrictbutton_r_lay_fn, tselem->id, NULL); + UI_but_func_set(bt, restrictbutton_r_lay_fn, tselem->id, nullptr); UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); } @@ -1256,7 +1271,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, -1, -1, - NULL); + nullptr); UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); if (!props_active.constraint_enable) { UI_but_flag_enable(bt, UI_BUT_INACTIVE); @@ -1285,7 +1300,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, -1, -1, - NULL); + nullptr); UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); if (!props_active.modifier_show_viewport) { UI_but_flag_enable(bt, UI_BUT_INACTIVE); @@ -1308,7 +1323,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, -1, -1, - NULL); + nullptr); UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); if (!props_active.modifier_show_render) { UI_but_flag_enable(bt, UI_BUT_INACTIVE); @@ -1320,7 +1335,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, bPoseChannel *pchan = (bPoseChannel *)te->directdata; Bone *bone = pchan->bone; Object *ob = (Object *)tselem->id; - bArmature *arm = ob->data; + bArmature *arm = reinterpret_cast<bArmature *>(ob->data); RNA_pointer_create(&arm->id, &RNA_Bone, bone, &ptr); @@ -1342,7 +1357,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, -1, TIP_("Restrict visibility in the 3D View\n" "* Shift to set children")); - UI_but_func_set(bt, restrictbutton_bone_visibility_fn, bone, NULL); + UI_but_func_set(bt, restrictbutton_bone_visibility_fn, bone, nullptr); UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); UI_but_drawflag_enable(bt, UI_BUT_ICON_REVERSE); } @@ -1470,11 +1485,12 @@ static void outliner_draw_restrictbuts(uiBlock *block, scene, te, &collection_ptr, &layer_collection_ptr, &props, &props_active)) { LayerCollection *layer_collection = (tselem->type == TSE_LAYER_COLLECTION) ? - te->directdata : - NULL; + reinterpret_cast<LayerCollection *>( + te->directdata) : + nullptr; Collection *collection = outliner_collection_from_tree_element(te); - if (layer_collection != NULL) { + if (layer_collection != nullptr) { if (space_outliner->show_restrict_flags & SO_RESTRICT_ENABLE) { bt = uiDefIconButR_prop(block, UI_BTYPE_ICON_TOGGLE, @@ -1491,7 +1507,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, 0, 0, 0, - NULL); + nullptr); UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); } @@ -1605,7 +1621,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, TIP_("Globally disable in viewports\n" "* Ctrl to isolate collection\n" "* Shift to set inside collections and objects")); - if (layer_collection != NULL) { + if (layer_collection != nullptr) { UI_but_func_set(bt, view_layer__collection_set_flag_recursive_fn, layer_collection, @@ -1642,7 +1658,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, TIP_("Globally disable in renders\n" "* Ctrl to isolate collection\n" "* Shift to set inside collections and objects")); - if (layer_collection != NULL) { + if (layer_collection != nullptr) { UI_but_func_set(bt, view_layer__collection_set_flag_recursive_fn, layer_collection, @@ -1677,7 +1693,7 @@ static void outliner_draw_restrictbuts(uiBlock *block, TIP_("Disable selection in viewport\n" "* Ctrl to isolate collection\n" "* Shift to set inside collections and objects")); - if (layer_collection != NULL) { + if (layer_collection != nullptr) { UI_but_func_set(bt, view_layer__collection_set_flag_recursive_fn, layer_collection, @@ -1721,7 +1737,7 @@ static void outliner_draw_userbuts(uiBlock *block, if (tselem->type == TSE_SOME_ID) { uiBut *bt; ID *id = tselem->id; - const char *tip = NULL; + const char *tip = nullptr; char buf[16] = ""; int but_flag = UI_BUT_DRAG_LOCK; @@ -1738,7 +1754,7 @@ static void outliner_draw_userbuts(uiBlock *block, te->ys, UI_UNIT_X, UI_UNIT_Y, - NULL, + nullptr, 0.0, 0.0, 0, @@ -1767,7 +1783,7 @@ static void outliner_draw_userbuts(uiBlock *block, 0, 0, tip); - UI_but_func_set(bt, restrictbutton_id_user_toggle, id, NULL); + UI_but_func_set(bt, restrictbutton_id_user_toggle, id, nullptr); UI_but_flag_enable(bt, but_flag); } } @@ -1791,7 +1807,7 @@ static bool outliner_draw_overrides_buts(uiBlock *block, const bool do_draw = (te->ys + 2 * UI_UNIT_Y >= region->v2d.cur.ymin && te->ys <= region->v2d.cur.ymax); int but_flag = UI_BUT_DRAG_LOCK; - const char *tip = NULL; + const char *tip = nullptr; TreeStoreElem *tselem = TREESTORE(te); switch (tselem->type) { @@ -1838,7 +1854,7 @@ static bool outliner_draw_overrides_buts(uiBlock *block, if (do_draw && (item_has_warnings || (any_child_has_warnings && !TSELEM_OPEN(tselem, space_outliner)))) { - if (tip == NULL) { + if (tip == nullptr) { tip = TIP_("Some sub-items require attention"); } uiBut *bt = uiDefIconBut(block, @@ -1849,7 +1865,7 @@ static bool outliner_draw_overrides_buts(uiBlock *block, te->ys, UI_UNIT_X, UI_UNIT_Y, - NULL, + nullptr, 0.0, 0.0, 0.0, @@ -1894,20 +1910,20 @@ static void outliner_draw_rnacols(ARegion *region, int sizex) static void outliner_draw_rnabuts( uiBlock *block, ARegion *region, SpaceOutliner *space_outliner, int sizex, ListBase *lb) { - PointerRNA *ptr; + PointerRNA ptr; PropertyRNA *prop; 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 == TSE_RNA_PROPERTY) { - ptr = &te->rnaptr; - prop = te->directdata; + if (TreeElementRNAProperty *te_rna_prop = tree_element_cast<TreeElementRNAProperty>(te)) { + ptr = te_rna_prop->getPointerRNA(); + prop = te_rna_prop->getPropertyRNA(); if (!TSELEM_OPEN(tselem, space_outliner)) { if (RNA_property_type(prop) == PROP_POINTER) { uiBut *but = uiDefAutoButR(block, - ptr, + &ptr, prop, -1, "", @@ -1920,10 +1936,10 @@ static void outliner_draw_rnabuts( } else if (RNA_property_type(prop) == PROP_ENUM) { uiDefAutoButR(block, - ptr, + &ptr, prop, -1, - NULL, + nullptr, ICON_NONE, sizex, te->ys, @@ -1932,7 +1948,7 @@ static void outliner_draw_rnabuts( } else { uiDefAutoButR(block, - ptr, + &ptr, prop, -1, "", @@ -1944,12 +1960,13 @@ static void outliner_draw_rnabuts( } } } - else if (tselem->type == TSE_RNA_ARRAY_ELEM) { - ptr = &te->rnaptr; - prop = te->directdata; + else if (TreeElementRNAArrayElement *te_rna_array_elem = + tree_element_cast<TreeElementRNAArrayElement>(te)) { + ptr = te_rna_array_elem->getPointerRNA(); + prop = te_rna_array_elem->getPropertyRNA(); uiDefAutoButR(block, - ptr, + &ptr, prop, te->index, "", @@ -1983,13 +2000,13 @@ static void outliner_buttons(const bContext *C, /* If we add support to rename Sequence, need change this. */ if (tselem->type == TSE_EBONE) { - len = sizeof(((EditBone *)0)->name); + len = sizeof(((EditBone *)nullptr)->name); } else if (tselem->type == TSE_MODIFIER) { - len = sizeof(((ModifierData *)0)->name); + len = sizeof(((ModifierData *)nullptr)->name); } else if (tselem->id && GS(tselem->id->name) == ID_LI) { - len = sizeof(((Library *)0)->filepath); + len = sizeof(((Library *)nullptr)->filepath); } else { len = MAX_ID_NAME - 2; @@ -2019,7 +2036,7 @@ static void outliner_buttons(const bContext *C, tselem->flag &= ~TSE_TEXTBUT; /* Bad! (notifier within draw) without this, we don't get a refresh. */ - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, nullptr); } } @@ -2036,7 +2053,7 @@ static void outliner_mode_toggle_fn(bContext *C, void *tselem_poin, void *UNUSED } /* Check that the item is actually an object. */ - BLI_assert(tselem->id != NULL && GS(tselem->id->name) == ID_OB); + BLI_assert(tselem->id != nullptr && GS(tselem->id->name) == ID_OB); Object *ob = (Object *)tselem->id; const bool object_data_shared = (ob->data == tvc.obact->data); @@ -2105,13 +2122,13 @@ static void outliner_draw_mode_column_toggle(uiBlock *block, te->ys, UI_UNIT_X, UI_UNIT_Y, - NULL, + nullptr, 0.0, 0.0, 0.0, 0.0, tip); - UI_but_func_set(but, outliner_mode_toggle_fn, tselem, NULL); + UI_but_func_set(but, outliner_mode_toggle_fn, tselem, nullptr); UI_but_flag_enable(but, UI_BUT_DRAG_LOCK); /* Mode toggling handles its own undo state because undo steps need to be grouped. */ UI_but_flag_disable(but, UI_BUT_UNDO); @@ -2143,12 +2160,86 @@ static void outliner_draw_mode_column(const bContext *C, } } +/* Returns `true` if some warning was drawn for that element or one of its sub-elements (if it is + * not open). */ +static bool outliner_draw_warning_tree_element(uiBlock *block, + SpaceOutliner *space_outliner, + TreeElement *te, + TreeStoreElem *tselem, + const bool use_mode_column, + const int te_ys) +{ + if ((te->flag & TE_HAS_WARNING) == 0) { + /* If given element has no warning, recursively try to display the first sub-elements' warning. + */ + if (!TSELEM_OPEN(tselem, space_outliner)) { + LISTBASE_FOREACH (TreeElement *, sub_te, &te->subtree) { + TreeStoreElem *sub_tselem = TREESTORE(sub_te); + + if (outliner_draw_warning_tree_element( + block, space_outliner, sub_te, sub_tselem, use_mode_column, te_ys)) { + return true; + } + } + } + return false; + } + + int icon = ICON_NONE; + const char *tip = ""; + const bool has_warning = tree_element_warnings_get(te, &icon, &tip); + BLI_assert(has_warning); + UNUSED_VARS_NDEBUG(has_warning); + + /* Move the warnings a unit left in view layer mode. */ + const short mode_column_offset = (use_mode_column && (space_outliner->outlinevis == SO_SCENES)) ? + UI_UNIT_X : + 0; + + UI_block_emboss_set(block, UI_EMBOSS_NONE_OR_STATUS); + uiBut *but = uiDefIconBut(block, + UI_BTYPE_ICON_TOGGLE, + 0, + icon, + mode_column_offset, + te_ys, + UI_UNIT_X, + UI_UNIT_Y, + nullptr, + 0.0, + 0.0, + 0.0, + 0.0, + tip); + /* No need for undo here, this is a pure info widget. */ + UI_but_flag_disable(but, UI_BUT_UNDO); + + return true; +} + +static void outliner_draw_warning_column(const bContext *C, + uiBlock *block, + SpaceOutliner *space_outliner, + const bool use_mode_column, + ListBase *tree) +{ + LISTBASE_FOREACH (TreeElement *, te, tree) { + TreeStoreElem *tselem = TREESTORE(te); + + outliner_draw_warning_tree_element(block, space_outliner, te, tselem, use_mode_column, te->ys); + + if (TSELEM_OPEN(tselem, space_outliner)) { + outliner_draw_warning_column(C, block, space_outliner, use_mode_column, &te->subtree); + } + } +} + /* ****************************************************** */ /* Normal Drawing... */ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) { - TreeElementIcon data = {0}; + TreeElementIcon data = {nullptr}; if (tselem->type != TSE_SOME_ID) { switch (tselem->type) { @@ -2182,7 +2273,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) data.drag_id = tselem->id; break; case TSE_CONSTRAINT: { - bConstraint *con = te->directdata; + bConstraint *con = reinterpret_cast<bConstraint *>(te->directdata); data.drag_id = tselem->id; switch ((eBConstraint_Types)con->type) { case CONSTRAINT_TYPE_CAMERASOLVER: @@ -2295,9 +2386,11 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) data.drag_id = tselem->id; if (ob->type != OB_GPENCIL) { - ModifierData *md = BLI_findlink(&ob->modifiers, tselem->nr); - const ModifierTypeInfo *modifier_type = BKE_modifier_get_info(md->type); - if (modifier_type != NULL) { + ModifierData *md = reinterpret_cast<ModifierData *>( + BLI_findlink(&ob->modifiers, tselem->nr)); + const ModifierTypeInfo *modifier_type = reinterpret_cast<const ModifierTypeInfo *>( + BKE_modifier_get_info((ModifierType)md->type)); + if (modifier_type != nullptr) { data.icon = modifier_type->icon; } else { @@ -2306,7 +2399,8 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) } else { /* grease pencil modifiers */ - GpencilModifierData *md = BLI_findlink(&ob->greasepencil_modifiers, tselem->nr); + GpencilModifierData *md = reinterpret_cast<GpencilModifierData *>( + BLI_findlink(&ob->greasepencil_modifiers, tselem->nr)); switch ((GpencilModifierType)md->type) { case eGpencilModifierType_Noise: data.icon = ICON_MOD_NOISE; @@ -2462,22 +2556,26 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) case TSE_SEQUENCE_DUP: data.icon = ICON_SEQ_STRIP_DUPLICATE; break; - case TSE_RNA_STRUCT: - if (RNA_struct_is_ID(te->rnaptr.type)) { - data.drag_id = (ID *)te->rnaptr.data; - data.icon = RNA_struct_ui_icon(te->rnaptr.type); + case TSE_RNA_STRUCT: { + const TreeElementRNAStruct *te_rna_struct = tree_element_cast<TreeElementRNAStruct>(te); + const PointerRNA &ptr = te_rna_struct->getPointerRNA(); + + if (RNA_struct_is_ID(ptr.type)) { + data.drag_id = reinterpret_cast<ID *>(ptr.data); + data.icon = RNA_struct_ui_icon(ptr.type); } else { - data.icon = RNA_struct_ui_icon(te->rnaptr.type); + data.icon = RNA_struct_ui_icon(ptr.type); } break; + } case TSE_LAYER_COLLECTION: case TSE_SCENE_COLLECTION_BASE: case TSE_VIEW_COLLECTION_BASE: { Collection *collection = outliner_collection_from_tree_element(te); if (collection && !(collection->flag & COLLECTION_IS_MASTER)) { data.drag_id = tselem->id; - data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : NULL; + data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : nullptr; } data.icon = ICON_OUTLINER_COLLECTION; @@ -2499,7 +2597,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) } else if (tselem->id) { data.drag_id = tselem->id; - data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : NULL; + data.drag_parent = (data.drag_id && te->parent) ? TREESTORE(te->parent)->id : nullptr; if (GS(tselem->id->name) == ID_OB) { Object *ob = (Object *)tselem->id; @@ -2639,7 +2737,7 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te) break; case ID_TXT: { Text *text = (Text *)tselem->id; - if (text->filepath == NULL || (text->flags & TXT_ISMEM)) { + if (text->filepath == nullptr || (text->flags & TXT_ISMEM)) { data.icon = ICON_FILE_TEXT; } else { @@ -2772,7 +2870,7 @@ static void tselem_draw_icon(uiBlock *block, UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, color, true); } else { - UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, NULL, false); + UI_icon_draw_ex(x, y, data.icon, U.inv_dpi_fac, alpha, 0.0f, nullptr, false); } } else { @@ -2784,7 +2882,7 @@ static void tselem_draw_icon(uiBlock *block, y, UI_UNIT_X, UI_UNIT_Y, - NULL, + nullptr, 0.0, 0.0, 1.0, @@ -2805,18 +2903,15 @@ static void outliner_draw_iconrow_number(const uiFontStyle *fstyle, const float color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; float ufac = 0.25f * UI_UNIT_X; float offset_x = (float)offsx + UI_UNIT_X * 0.35f; + rctf rect{}; + BLI_rctf_init(&rect, + offset_x + ufac, + offset_x + UI_UNIT_X - ufac, + (float)ys - UI_UNIT_Y * 0.2f + ufac, + (float)ys - UI_UNIT_Y * 0.2f + UI_UNIT_Y - ufac); UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_aa( - &(const rctf){ - .xmin = offset_x + ufac, - .xmax = offset_x + UI_UNIT_X - ufac, - .ymin = (float)ys - UI_UNIT_Y * 0.2f + ufac, - .ymax = (float)ys - UI_UNIT_Y * 0.2f + UI_UNIT_Y - ufac, - }, - true, - (float)UI_UNIT_Y / 2.0f - ufac, - color); + UI_draw_roundbox_aa(&rect, true, (float)UI_UNIT_Y / 2.0f - ufac, color); /* Now the numbers. */ uchar text_col[4]; @@ -2829,7 +2924,7 @@ static void outliner_draw_iconrow_number(const uiFontStyle *fstyle, /* We treat +99 as 4 digits to make sure the (eyeballed) alignment looks nice. */ int num_digits = 4; - char number_text[4] = "+99\0"; + char number_text[4] = "+99"; if (num_elements < 100) { BLI_snprintf(number_text, sizeof(number_text), "%d", num_elements); num_digits = num_elements < 10 ? 1 : 2; @@ -2864,28 +2959,12 @@ static void outliner_draw_active_indicator(const float minx, { const float ufac = UI_UNIT_X / 20.0f; const float radius = UI_UNIT_Y / 4.0f; + rctf rect{}; + BLI_rctf_init(&rect, minx, maxx, miny + ufac, maxy - ufac); UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_aa( - &(const rctf){ - .xmin = minx, - .xmax = maxx, - .ymin = miny + ufac, - .ymax = maxy - ufac, - }, - true, - radius, - icon_color); - UI_draw_roundbox_aa( - &(const rctf){ - .xmin = minx, - .xmax = maxx, - .ymin = miny + ufac, - .ymax = maxy - ufac, - }, - false, - radius, - icon_border); + UI_draw_roundbox_aa(&rect, true, radius, icon_color); + UI_draw_roundbox_aa(&rect, false, radius, icon_border); GPU_blend(GPU_BLEND_ALPHA); /* Roundbox disables. */ } @@ -2952,11 +3031,11 @@ int tree_element_id_type_to_index(TreeElement *te) return id_index + OB_TYPE_MAX; } -typedef struct MergedIconRow { +struct MergedIconRow { eOLDrawState active[INDEX_ID_MAX + OB_TYPE_MAX]; int num_elements[INDEX_ID_MAX + OB_TYPE_MAX]; TreeElement *tree_element[INDEX_ID_MAX + OB_TYPE_MAX]; -} MergedIconRow; +}; static void outliner_draw_iconrow(bContext *C, uiBlock *block, @@ -3014,7 +3093,7 @@ static void outliner_draw_iconrow(bContext *C, else { const int index = tree_element_id_type_to_index(te); merged->num_elements[index]++; - if ((merged->tree_element[index] == NULL) || (active > merged->active[index])) { + if ((merged->tree_element[index] == nullptr) || (active > merged->active[index])) { merged->tree_element[index] = te; } merged->active[index] = MAX2(active, merged->active[index]); @@ -3091,7 +3170,7 @@ static bool element_should_draw_faded(const TreeViewContext *tvc, const Base *base = (te->directdata) ? (const Base *)te->directdata : BKE_view_layer_base_find( (ViewLayer *)tvc->view_layer, (Object *)ob); - const bool is_visible = (base != NULL) && (base->flag & BASE_VISIBLE_VIEWLAYER); + const bool is_visible = (base != nullptr) && (base->flag & BASE_VISIBLE_VIEWLAYER); if (!is_visible) { return true; } @@ -3140,7 +3219,7 @@ static void outliner_draw_tree_element(bContext *C, const float alpha_fac = element_should_draw_faded(tvc, te, tselem) ? 0.5f : 1.0f; int xmax = region->v2d.cur.xmax; - if ((tselem->flag & TSE_TEXTBUT) && (*te_edit == NULL)) { + if ((tselem->flag & TSE_TEXTBUT) && (*te_edit == nullptr)) { *te_edit = te; } @@ -3157,7 +3236,7 @@ static void outliner_draw_tree_element(bContext *C, Object *ob = (Object *)tselem->id; Base *base = (te->directdata) ? (Base *)te->directdata : BKE_view_layer_base_find(tvc->view_layer, ob); - const bool is_selected = (base != NULL) && ((base->flag & BASE_SELECTED) != 0); + const bool is_selected = (base != nullptr) && ((base->flag & BASE_SELECTED) != 0); if (ob == tvc->obact) { active = OL_DRAWSEL_ACTIVE; @@ -3246,9 +3325,10 @@ static void outliner_draw_tree_element(bContext *C, offsx += 2 * ufac; } + const TreeElementRNAStruct *te_rna_struct = tree_element_cast<TreeElementRNAStruct>(te); 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); + (te_rna_struct && RNA_struct_is_ID(te_rna_struct->getPointerRNA().type))) { + const BIFIconID lib_icon = (BIFIconID)UI_icon_from_library(tselem->id); if (lib_icon != ICON_NONE) { UI_icon_draw_alpha( (float)startx + offsx + 2 * ufac, (float)*starty + 2 * ufac, lib_icon, alpha_fac); @@ -3281,7 +3361,7 @@ static void outliner_draw_tree_element(bContext *C, GPU_blend(GPU_BLEND_ALPHA); - MergedIconRow merged = {{0}}; + MergedIconRow merged{}; outliner_draw_iconrow(C, block, fstyle, @@ -3352,7 +3432,7 @@ static void outliner_draw_hierarchy_line( /* Small vertical padding. */ const short line_padding = UI_UNIT_Y / 4.0f; - /* >= is 1.0 for undashed lines. */ + /* >= is 1.0 for un-dashed lines. */ immUniform1f("dash_factor", draw_dashed ? 0.5f : 1.0f); immBegin(GPU_PRIM_LINES, 2); @@ -3612,17 +3692,22 @@ static void outliner_draw_tree(bContext *C, SpaceOutliner *space_outliner, const float restrict_column_width, const bool use_mode_column, + const bool use_warning_column, TreeElement **te_edit) { const uiFontStyle *fstyle = UI_FSTYLE_WIDGET; int starty, startx; /* Move the tree a unit left in view layer mode */ - short mode_column_offset = (use_mode_column && (space_outliner->outlinevis == SO_SCENES)) ? - UI_UNIT_X : - 0; + short columns_offset = (use_mode_column && (space_outliner->outlinevis == SO_SCENES)) ? + UI_UNIT_X : + 0; if (!use_mode_column && (space_outliner->outlinevis == SO_VIEW_LAYER)) { - mode_column_offset -= UI_UNIT_X; + columns_offset -= UI_UNIT_X; + } + + if (use_warning_column) { + columns_offset += UI_UNIT_X; } GPU_blend(GPU_BLEND_ALPHA); /* Only once. */ @@ -3650,12 +3735,12 @@ static void outliner_draw_tree(bContext *C, /* Draw hierarchy lines for collections and object children. */ starty = (int)region->v2d.tot.ymax - OL_Y_OFFSET; - startx = mode_column_offset + UI_UNIT_X / 2 - (U.pixelsize + 1) / 2; + startx = columns_offset + UI_UNIT_X / 2 - (U.pixelsize + 1) / 2; outliner_draw_hierarchy_lines(space_outliner, &space_outliner->tree, startx, &starty); /* Items themselves. */ starty = (int)region->v2d.tot.ymax - UI_UNIT_Y - OL_Y_OFFSET; - startx = mode_column_offset; + startx = columns_offset; LISTBASE_FOREACH (TreeElement *, te, &space_outliner->tree) { outliner_draw_tree_element(C, block, @@ -3755,7 +3840,7 @@ void draw_outliner(const bContext *C) View2D *v2d = ®ion->v2d; SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); uiBlock *block; - TreeElement *te_edit = NULL; + TreeElement *te_edit = nullptr; TreeViewContext tvc; outliner_viewcontext_init(C, &tvc); @@ -3786,6 +3871,11 @@ void draw_outliner(const bContext *C) const bool use_mode_column = (space_outliner->flag & SO_MODE_COLUMN) && (ELEM(space_outliner->outlinevis, SO_VIEW_LAYER, SO_SCENES)); + const bool use_warning_column = ELEM(space_outliner->outlinevis, + SO_LIBRARIES, + SO_OVERRIDES_LIBRARY) && + space_outliner->runtime->tree_display->hasWarnings(); + /* Draw outliner stuff (background, hierarchy lines and names). */ const float restrict_column_width = outliner_restrict_columns_width(space_outliner); outliner_back(region); @@ -3797,6 +3887,7 @@ void draw_outliner(const bContext *C) space_outliner, restrict_column_width, use_mode_column, + use_warning_column, &te_edit); /* Compute outliner dimensions after it has been drawn. */ @@ -3841,6 +3932,11 @@ void draw_outliner(const bContext *C) outliner_draw_mode_column(C, block, &tvc, space_outliner, &space_outliner->tree); } + /* Draw warning icons */ + if (use_warning_column) { + outliner_draw_warning_column(C, block, space_outliner, use_mode_column, &space_outliner->tree); + } + UI_block_emboss_set(block, UI_EMBOSS); /* Draw edit buttons if necessary. */ diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.cc index 9d4b14a1f57..b41b260b14a 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.cc @@ -21,7 +21,7 @@ * \ingroup spoutliner */ -#include <string.h> +#include <cstring> #include "MEM_guardedalloc.h" @@ -38,6 +38,7 @@ #include "BLT_translation.h" +#include "BKE_action.h" #include "BKE_animsys.h" #include "BKE_appdir.h" #include "BKE_armature.h" @@ -48,6 +49,7 @@ #include "BKE_lib_query.h" #include "BKE_lib_remap.h" #include "BKE_main.h" +#include "BKE_object.h" #include "BKE_report.h" #include "BKE_workspace.h" @@ -71,7 +73,10 @@ #include "GPU_material.h" -#include "outliner_intern.h" +#include "outliner_intern.hh" +#include "tree/tree_element_rna.hh" + +using namespace blender::ed::outliner; static void outliner_show_active(SpaceOutliner *space_outliner, ARegion *region, @@ -105,11 +110,11 @@ static int outliner_highlight_update(bContext *C, wmOperator *UNUSED(op), const TreeElement *hovered_te = outliner_find_item_at_y( space_outliner, &space_outliner->tree, view_mval[1]); - TreeElement *icon_te = NULL; + TreeElement *icon_te = nullptr; bool is_over_icon = false; if (hovered_te) { icon_te = outliner_find_item_at_x_in_row( - space_outliner, hovered_te, view_mval[0], NULL, &is_over_icon); + space_outliner, hovered_te, view_mval[0], nullptr, &is_over_icon); } bool changed = false; @@ -181,11 +186,11 @@ void outliner_item_openclose(SpaceOutliner *space_outliner, } } -typedef struct OpenCloseData { +struct OpenCloseData { TreeStoreElem *prev_tselem; bool open; int x_location; -} OpenCloseData; +}; static int outliner_item_openclose_modal(bContext *C, wmOperator *op, const wmEvent *event) { @@ -216,7 +221,7 @@ static int outliner_item_openclose_modal(bContext *C, wmOperator *op, const wmEv data->prev_tselem = TREESTORE(te); } else { - data->prev_tselem = NULL; + data->prev_tselem = nullptr; } } else if (event->val == KM_RELEASE) { @@ -256,7 +261,7 @@ static int outliner_item_openclose_invoke(bContext *C, wmOperator *op, const wmE } /* Store last expanded tselem and x coordinate of disclosure triangle */ - OpenCloseData *toggle_data = MEM_callocN(sizeof(OpenCloseData), "open_close_data"); + OpenCloseData *toggle_data = MEM_cnew<OpenCloseData>("open_close_data"); toggle_data->prev_tselem = tselem; toggle_data->open = open; toggle_data->x_location = te->xs; @@ -373,7 +378,7 @@ static TreeElement *outliner_item_rename_find_active(const SpaceOutliner *space_ if (!active_element) { BKE_report(reports, RPT_WARNING, "No active item to rename"); - return NULL; + return nullptr; } return active_element; @@ -391,7 +396,7 @@ static TreeElement *outliner_item_rename_find_hovered(const SpaceOutliner *space return hovered; } - return NULL; + return nullptr; } static int outliner_item_rename(bContext *C, wmOperator *op, const wmEvent *event) @@ -450,12 +455,12 @@ static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeSto Main *bmain = CTX_data_main(C); ID *id = tselem->id; - BLI_assert(id != NULL); + BLI_assert(id != nullptr); 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) { + if (te->idcode == ID_LI && ((Library *)id)->parent != nullptr) { BKE_reportf(reports, RPT_WARNING, "Cannot delete indirectly linked library '%s'", id->name); return; } @@ -481,7 +486,7 @@ static void id_delete(bContext *C, ReportList *reports, TreeElement *te, TreeSto BKE_id_delete(bmain, id); - WM_event_add_notifier(C, NC_WINDOW, NULL); + WM_event_add_notifier(C, NC_WINDOW, nullptr); } void id_delete_fn(bContext *C, @@ -573,13 +578,13 @@ static int outliner_id_remap_exec(bContext *C, wmOperator *op) SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); const short id_type = (short)RNA_enum_get(op->ptr, "id_type"); - ID *old_id = BLI_findlink(which_libbase(CTX_data_main(C), id_type), - RNA_enum_get(op->ptr, "old_id")); - ID *new_id = BLI_findlink(which_libbase(CTX_data_main(C), id_type), - RNA_enum_get(op->ptr, "new_id")); + ID *old_id = reinterpret_cast<ID *>( + BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "old_id"))); + ID *new_id = reinterpret_cast<ID *>( + BLI_findlink(which_libbase(CTX_data_main(C), id_type), RNA_enum_get(op->ptr, "new_id"))); /* check for invalid states */ - if (space_outliner == NULL) { + if (space_outliner == nullptr) { return OPERATOR_CANCELLED; } @@ -612,7 +617,7 @@ static int outliner_id_remap_exec(bContext *C, wmOperator *op) * such as lights so freeing correctly refreshes. */ GPU_materials_free(bmain); - WM_event_add_notifier(C, NC_WINDOW, NULL); + WM_event_add_notifier(C, NC_WINDOW, nullptr); return OPERATOR_FINISHED; } @@ -627,8 +632,6 @@ static bool outliner_id_remap_find_tree_element(bContext *C, TreeStoreElem *tselem = TREESTORE(te); 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)); RNA_enum_set_identifier(C, op->ptr, "new_id", tselem->id->name + 2); RNA_enum_set_identifier(C, op->ptr, "old_id", tselem->id->name + 2); @@ -654,7 +657,7 @@ static int outliner_id_remap_invoke(bContext *C, wmOperator *op, const wmEvent * outliner_id_remap_find_tree_element(C, op, &space_outliner->tree, fmval[1]); } - return WM_operator_props_dialog_popup(C, op, 200); + return WM_operator_props_dialog_popup(C, op, 400); } static const EnumPropertyItem *outliner_id_itemf(bContext *C, @@ -662,18 +665,18 @@ static const EnumPropertyItem *outliner_id_itemf(bContext *C, PropertyRNA *UNUSED(prop), bool *r_free) { - if (C == NULL) { + if (C == nullptr) { return DummyRNA_NULL_items; } - EnumPropertyItem item_tmp = {0}, *item = NULL; + EnumPropertyItem item_tmp = {0}, *item = nullptr; int totitem = 0; int i = 0; short id_type = (short)RNA_enum_get(ptr, "id_type"); - ID *id = which_libbase(CTX_data_main(C), id_type)->first; + ID *id = reinterpret_cast<ID *>(which_libbase(CTX_data_main(C), id_type)->first); - for (; id; id = id->next) { + for (; id; id = reinterpret_cast<ID *>(id->next)) { item_tmp.identifier = item_tmp.name = id->name + 2; item_tmp.value = i++; RNA_enum_item_add(&item, &totitem, &item_tmp); @@ -703,10 +706,13 @@ void OUTLINER_OT_id_remap(wmOperatorType *ot) prop = RNA_def_enum(ot->srna, "id_type", rna_enum_id_type_items, ID_OB, "ID Type", ""); RNA_def_property_translation_context(prop, BLT_I18NCONTEXT_ID_ID); + /* Changing ID type wont make sense, would return early with "Invalid old/new ID pair" anyways. + */ + RNA_def_property_flag(prop, PROP_HIDDEN); prop = RNA_def_enum(ot->srna, "old_id", DummyRNA_NULL_items, 0, "Old ID", "Old ID to replace"); - RNA_def_property_enum_funcs_runtime(prop, NULL, NULL, outliner_id_itemf); - RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE | PROP_HIDDEN); + RNA_def_property_enum_funcs_runtime(prop, nullptr, nullptr, outliner_id_itemf); + RNA_def_property_flag(prop, (PropertyFlag)(PROP_ENUM_NO_TRANSLATE | PROP_HIDDEN)); ot->prop = RNA_def_enum(ot->srna, "new_id", @@ -714,7 +720,7 @@ void OUTLINER_OT_id_remap(wmOperatorType *ot) 0, "New ID", "New ID to remap all selected IDs' users to"); - RNA_def_property_enum_funcs_runtime(ot->prop, NULL, NULL, outliner_id_itemf); + RNA_def_property_enum_funcs_runtime(ot->prop, nullptr, nullptr, outliner_id_itemf); RNA_def_property_flag(ot->prop, PROP_ENUM_NO_TRANSLATE); } @@ -729,7 +735,7 @@ void id_remap_fn(bContext *C, wmOperatorType *ot = WM_operatortype_find("OUTLINER_OT_id_remap", false); PointerRNA op_props; - BLI_assert(tselem->id != NULL); + BLI_assert(tselem->id != nullptr); WM_operator_properties_create_ptr(&op_props, ot); @@ -826,7 +832,7 @@ static int outliner_id_paste_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - WM_event_add_notifier(C, NC_WINDOW, NULL); + WM_event_add_notifier(C, NC_WINDOW, nullptr); BKE_reportf(op->reports, RPT_INFO, "%d data-block(s) pasted", num_pasted); @@ -860,7 +866,7 @@ static int lib_relocate( PointerRNA op_props; int ret = 0; - BLI_assert(te->idcode == ID_LI && tselem->id != NULL); + BLI_assert(te->idcode == ID_LI && tselem->id != nullptr); UNUSED_VARS_NDEBUG(te); WM_operator_properties_create_ptr(&op_props, ot); @@ -1252,17 +1258,18 @@ static TreeElement *outliner_show_active_get_element(bContext *C, Object *obact = OBACT(view_layer); if (!obact) { - return NULL; + return nullptr; } te = outliner_find_id(space_outliner, &space_outliner->tree, &obact->id); - if (te != NULL && obact->type == OB_ARMATURE) { + if (te != nullptr && obact->type == OB_ARMATURE) { /* traverse down the bone hierarchy in case of armature */ TreeElement *te_obact = te; if (obact->mode & OB_MODE_POSE) { - bPoseChannel *pchan = CTX_data_active_pose_bone(C); + Object *obpose = BKE_object_pose_armature_get(obact); + bPoseChannel *pchan = BKE_pose_channel_active(obpose, false); if (pchan) { te = outliner_find_posechannel(&te_obact->subtree, pchan); } @@ -1385,7 +1392,7 @@ void OUTLINER_OT_scroll_page(wmOperatorType *ot) ot->poll = ED_operator_outliner_active; /* properties */ - prop = RNA_def_boolean(ot->srna, "up", 0, "Up", "Scroll up one page"); + prop = RNA_def_boolean(ot->srna, "up", false, "Up", "Scroll up one page"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); } @@ -1429,14 +1436,14 @@ static TreeElement *outliner_find_name( } /* nothing valid found */ - return NULL; + return nullptr; } static void outliner_find_panel( Scene *UNUSED(scene), ARegion *region, SpaceOutliner *space_outliner, int again, int flags) { - ReportList *reports = NULL; /* CTX_wm_reports(C); */ - TreeElement *te = NULL; + ReportList *reports = nullptr; /* CTX_wm_reports(C); */ + TreeElement *te = nullptr; TreeElement *last_find; TreeStoreElem *tselem; int ytop, xdelta, prevFound = 0; @@ -1453,7 +1460,7 @@ static void outliner_find_panel( /* try to find matching element */ te = outliner_find_name(space_outliner, &space_outliner->tree, name, flags, last_find, &prevFound); - if (te == NULL) { + if (te == nullptr) { /* no more matches after previous, start from beginning again */ prevFound = 1; te = outliner_find_name(space_outliner, &space_outliner->tree, name, flags, last_find, &prevFound); @@ -1462,10 +1469,10 @@ static void outliner_find_panel( else { /* pop up panel - no previous, or user didn't want search after previous */ name[0] = '\0'; - /* XXX if (sbutton(name, 0, sizeof(name) - 1, "Find: ") && name[0]) { */ - /* te = outliner_find_name(space_outliner, &space_outliner->tree, name, flags, NULL, &prevFound); */ - /* } */ - /* else return; XXX RETURN! XXX */ + // XXX if (sbutton(name, 0, sizeof(name) - 1, "Find: ") && name[0]) { + // te = outliner_find_name(space_outliner, &space_outliner->tree, name, flags, nullptr, &prevFound); + // } + // else return; XXX RETURN! XXX } /* do selection and reveal */ @@ -1481,7 +1488,7 @@ static void outliner_find_panel( outliner_flag_set(space_outliner, &space_outliner->tree, TSE_SELECTED, 0); tselem->flag |= TSE_SELECTED; - /* make te->ys center of view */ + /* Make `te->ys` center of view. */ ytop = (int)(te->ys + BLI_rctf_size_y(®ion->v2d.mask) / 2); if (ytop > 0) { ytop = 0; @@ -1489,7 +1496,7 @@ static void outliner_find_panel( region->v2d.cur.ymax = (float)ytop; region->v2d.cur.ymin = (float)(ytop - BLI_rctf_size_y(®ion->v2d.mask)); - /* make te->xs ==> te->xend center of view */ + /* Make `te->xs` ==> `te->xend` center of view. */ xdelta = (int)(te->xs - region->v2d.cur.xmin); region->v2d.cur.xmin += xdelta; region->v2d.cur.xmax += xdelta; @@ -1582,7 +1589,7 @@ void OUTLINER_OT_show_one_level(wmOperatorType *ot) /* no undo or registry, UI option */ /* properties */ - prop = RNA_def_boolean(ot->srna, "open", 1, "Open", "Expand all entries one level deep"); + prop = RNA_def_boolean(ot->srna, "open", true, "Open", "Expand all entries one level deep"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); } @@ -1694,7 +1701,7 @@ static bool ed_operator_outliner_datablocks_active(bContext *C) SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); return (space_outliner->outlinevis == SO_DATA_API); } - return 0; + return false; } /* Helper func to extract an RNA path from selected tree element @@ -1709,13 +1716,8 @@ static void tree_element_to_path(TreeElement *te, short *flag, short *UNUSED(groupmode)) { - ListBase hierarchy = {NULL, NULL}; - LinkData *ld; - TreeElement *tem, *temnext; - TreeStoreElem *tse /* , *tsenext */ /* UNUSED */; - PointerRNA *ptr, *nextptr; - PropertyRNA *prop; - char *newpath = NULL; + ListBase hierarchy = {nullptr, nullptr}; + char *newpath = nullptr; /* optimize tricks: * - Don't do anything if the selected item is a 'struct', but arrays are allowed @@ -1734,20 +1736,19 @@ static void tree_element_to_path(TreeElement *te, */ /* step 1: flatten out hierarchy of parents into a flat chain */ - for (tem = te->parent; tem; tem = tem->parent) { - ld = MEM_callocN(sizeof(LinkData), "LinkData for tree_element_to_path()"); + for (TreeElement *tem = te->parent; tem; tem = tem->parent) { + LinkData *ld = MEM_cnew<LinkData>("LinkData for tree_element_to_path()"); ld->data = tem; BLI_addhead(&hierarchy, ld); } /* step 2: step down hierarchy building the path * (NOTE: addhead in previous loop was needed so that we can loop like this) */ - for (ld = hierarchy.first; ld; ld = ld->next) { + LISTBASE_FOREACH (LinkData *, ld, &hierarchy) { /* get data */ - tem = (TreeElement *)ld->data; - tse = TREESTORE(tem); - ptr = &tem->rnaptr; - prop = tem->directdata; + TreeElement *tem = (TreeElement *)ld->data; + TreeElementRNACommon *tem_rna = tree_element_cast<TreeElementRNACommon>(tem); + PointerRNA ptr = tem_rna->getPointerRNA(); /* check if we're looking for first ID, or appending to path */ if (*id) { @@ -1755,23 +1756,23 @@ static void tree_element_to_path(TreeElement *te, * - to prevent memory leaks, we must write to newpath not path, * then free old path + swap them. */ - if (tse->type == TSE_RNA_PROPERTY) { + if (TreeElementRNAProperty *tem_rna_prop = tree_element_cast<TreeElementRNAProperty>(tem)) { + PropertyRNA *prop = tem_rna_prop->getPropertyRNA(); + if (RNA_property_type(prop) == PROP_POINTER) { /* for pointer we just append property name */ - newpath = RNA_path_append(*path, ptr, prop, 0, NULL); + newpath = RNA_path_append(*path, &ptr, prop, 0, nullptr); } else if (RNA_property_type(prop) == PROP_COLLECTION) { char buf[128], *name; - temnext = (TreeElement *)(ld->next->data); - // tsenext = TREESTORE(temnext); /* UNUSED */ - - nextptr = &temnext->rnaptr; - name = RNA_struct_name_get_alloc(nextptr, buf, sizeof(buf), NULL); + TreeElement *temnext = (TreeElement *)(ld->next->data); + PointerRNA nextptr = tree_element_cast<TreeElementRNACommon>(temnext)->getPointerRNA(); + name = RNA_struct_name_get_alloc(&nextptr, buf, sizeof(buf), nullptr); if (name) { /* if possible, use name as a key in the path */ - newpath = RNA_path_append(*path, NULL, prop, 0, name); + newpath = RNA_path_append(*path, nullptr, prop, 0, name); if (name != buf) { MEM_freeN(name); @@ -1785,8 +1786,9 @@ static void tree_element_to_path(TreeElement *te, if (temsub == temnext) { break; } + index++; } - newpath = RNA_path_append(*path, NULL, prop, index, NULL); + newpath = RNA_path_append(*path, nullptr, prop, index, nullptr); } ld = ld->next; @@ -1798,22 +1800,22 @@ static void tree_element_to_path(TreeElement *te, MEM_freeN(*path); } *path = newpath; - newpath = NULL; + newpath = nullptr; } } else { /* no ID, so check if entry is RNA-struct, * and if that RNA-struct is an ID datablock to extract info from. */ - if (tse->type == TSE_RNA_STRUCT) { + if (tree_element_cast<TreeElementRNAStruct>(tem)) { /* ptr->data not ptr->owner_id seems to be the one we want, * since ptr->data is sometimes the owner of this ID? */ - if (RNA_struct_is_ID(ptr->type)) { - *id = ptr->data; + if (RNA_struct_is_ID(ptr.type)) { + *id = reinterpret_cast<ID *>(ptr.data); /* clear path */ if (*path) { MEM_freeN(*path); - path = NULL; + path = nullptr; } } } @@ -1823,8 +1825,7 @@ static void tree_element_to_path(TreeElement *te, /* step 3: if we've got an ID, add the current item to the path */ if (*id) { /* add the active property to the path */ - ptr = &te->rnaptr; - prop = te->directdata; + PropertyRNA *prop = tree_element_cast<TreeElementRNACommon>(te)->getPropertyRNA(); /* array checks */ if (tselem->type == TSE_RNA_ARRAY_ELEM) { @@ -1837,7 +1838,7 @@ static void tree_element_to_path(TreeElement *te, } /* path */ - newpath = RNA_path_append(*path, NULL, prop, 0, NULL); + newpath = RNA_path_append(*path, nullptr, prop, 0, nullptr); if (*path) { MEM_freeN(*path); } @@ -1876,15 +1877,18 @@ static void do_outliner_drivers_editop(SpaceOutliner *space_outliner, /* if item is selected, perform operation */ if (tselem->flag & TSE_SELECTED) { - ID *id = NULL; - char *path = NULL; + ID *id = nullptr; + char *path = nullptr; int array_index = 0; short flag = 0; short groupmode = KSP_GROUP_KSNAME; + TreeElementRNACommon *te_rna = tree_element_cast<TreeElementRNACommon>(te); + PointerRNA ptr = te_rna ? te_rna->getPointerRNA() : PointerRNA_NULL; + PropertyRNA *prop = te_rna ? te_rna->getPropertyRNA() : nullptr; + /* check if RNA-property described by this selected element is an animatable prop */ - if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM) && - RNA_property_animateable(&te->rnaptr, te->directdata)) { + if (prop && RNA_property_animateable(&ptr, prop)) { /* get id + path + index info from the selected element */ tree_element_to_path(te, tselem, &id, &path, &array_index, &flag, &groupmode); } @@ -1897,7 +1901,7 @@ static void do_outliner_drivers_editop(SpaceOutliner *space_outliner, /* array checks */ if (flag & KSP_FLAG_WHOLE_ARRAY) { /* entire array was selected, so add drivers for all */ - arraylen = RNA_property_array_length(&te->rnaptr, te->directdata); + arraylen = RNA_property_array_length(&ptr, prop); } else { arraylen = array_index; @@ -1948,7 +1952,7 @@ static int outliner_drivers_addsel_exec(bContext *C, wmOperator *op) SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); /* check for invalid states */ - if (space_outliner == NULL) { + if (space_outliner == nullptr) { return OPERATOR_CANCELLED; } @@ -1957,7 +1961,7 @@ static int outliner_drivers_addsel_exec(bContext *C, wmOperator *op) space_outliner, &space_outliner->tree, op->reports, DRIVERS_EDITMODE_ADD); /* send notifiers */ - WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, NULL); /* XXX */ + WM_event_add_notifier(C, NC_ANIMATION | ND_FCURVES_ORDER, nullptr); /* XXX */ return OPERATOR_FINISHED; } @@ -1988,7 +1992,7 @@ static int outliner_drivers_deletesel_exec(bContext *C, wmOperator *op) SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); /* check for invalid states */ - if (space_outliner == NULL) { + if (space_outliner == nullptr) { return OPERATOR_CANCELLED; } @@ -1997,7 +2001,7 @@ static int outliner_drivers_deletesel_exec(bContext *C, wmOperator *op) space_outliner, &space_outliner->tree, op->reports, DRIVERS_EDITMODE_REMOVE); /* send notifiers */ - WM_event_add_notifier(C, ND_KEYS, NULL); /* XXX */ + WM_event_add_notifier(C, ND_KEYS, nullptr); /* XXX */ return OPERATOR_FINISHED; } @@ -2038,22 +2042,23 @@ enum { /* TODO: should this be an API func? */ static KeyingSet *verify_active_keyingset(Scene *scene, short add) { - KeyingSet *ks = NULL; + KeyingSet *ks = nullptr; /* sanity check */ - if (scene == NULL) { - return NULL; + if (scene == nullptr) { + return nullptr; } /* try to find one from scene */ if (scene->active_keyingset > 0) { - ks = BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1); + ks = reinterpret_cast<KeyingSet *>( + BLI_findlink(&scene->keyingsets, scene->active_keyingset - 1)); } /* Add if none found */ /* XXX the default settings have yet to evolve. */ - if ((add) && (ks == NULL)) { - ks = BKE_keyingset_add(&scene->keyingsets, NULL, NULL, KEYINGSET_ABSOLUTE, 0); + if ((add) && (ks == nullptr)) { + ks = BKE_keyingset_add(&scene->keyingsets, nullptr, nullptr, KEYINGSET_ABSOLUTE, 0); scene->active_keyingset = BLI_listbase_count(&scene->keyingsets); } @@ -2071,15 +2076,17 @@ static void do_outliner_keyingset_editop(SpaceOutliner *space_outliner, /* if item is selected, perform operation */ if (tselem->flag & TSE_SELECTED) { - ID *id = NULL; - char *path = NULL; + ID *id = nullptr; + char *path = nullptr; int array_index = 0; short flag = 0; short groupmode = KSP_GROUP_KSNAME; /* check if RNA-property described by this selected element is an animatable prop */ - if (ELEM(tselem->type, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM) && - RNA_property_animateable(&te->rnaptr, te->directdata)) { + const TreeElementRNACommon *te_rna = tree_element_cast<TreeElementRNACommon>(te); + PointerRNA ptr = te_rna->getPointerRNA(); + if (te_rna && te_rna->getPropertyRNA() && + RNA_property_animateable(&ptr, te_rna->getPropertyRNA())) { /* get id + path + index info from the selected element */ tree_element_to_path(te, tselem, &id, &path, &array_index, &flag, &groupmode); } @@ -2092,13 +2099,13 @@ static void do_outliner_keyingset_editop(SpaceOutliner *space_outliner, /* add a new path with the information obtained (only if valid) */ /* TODO: what do we do with group name? * for now, we don't supply one, and just let this use the KeyingSet name */ - BKE_keyingset_add_path(ks, id, NULL, path, array_index, flag, groupmode); + BKE_keyingset_add_path(ks, id, nullptr, path, array_index, flag, groupmode); ks->active_path = BLI_listbase_count(&ks->paths); break; } case KEYINGSET_EDITMODE_REMOVE: { /* find the relevant path, then remove it from the KeyingSet */ - KS_Path *ksp = BKE_keyingset_find_path(ks, id, NULL, path, array_index, groupmode); + KS_Path *ksp = BKE_keyingset_find_path(ks, id, nullptr, path, array_index, groupmode); if (ksp) { /* free path's data */ @@ -2135,11 +2142,11 @@ static int outliner_keyingset_additems_exec(bContext *C, wmOperator *op) KeyingSet *ks = verify_active_keyingset(scene, 1); /* check for invalid states */ - if (ks == NULL) { + if (ks == nullptr) { BKE_report(op->reports, RPT_ERROR, "Operation requires an active keying set"); return OPERATOR_CANCELLED; } - if (space_outliner == NULL) { + if (space_outliner == nullptr) { return OPERATOR_CANCELLED; } @@ -2147,7 +2154,7 @@ static int outliner_keyingset_additems_exec(bContext *C, wmOperator *op) do_outliner_keyingset_editop(space_outliner, ks, &space_outliner->tree, KEYINGSET_EDITMODE_ADD); /* send notifiers */ - WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, NULL); + WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, nullptr); return OPERATOR_FINISHED; } @@ -2180,7 +2187,7 @@ static int outliner_keyingset_removeitems_exec(bContext *C, wmOperator *UNUSED(o KeyingSet *ks = verify_active_keyingset(scene, 1); /* check for invalid states */ - if (space_outliner == NULL) { + if (space_outliner == nullptr) { return OPERATOR_CANCELLED; } @@ -2189,7 +2196,7 @@ static int outliner_keyingset_removeitems_exec(bContext *C, wmOperator *UNUSED(o space_outliner, ks, &space_outliner->tree, KEYINGSET_EDITMODE_REMOVE); /* send notifiers */ - WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, NULL); + WM_event_add_notifier(C, NC_SCENE | ND_KEYINGSET, nullptr); return OPERATOR_FINISHED; } @@ -2218,7 +2225,7 @@ void OUTLINER_OT_keyingset_remove_selected(wmOperatorType *ot) static bool ed_operator_outliner_id_orphans_active(bContext *C) { ScrArea *area = CTX_wm_area(C); - if (area != NULL && area->spacetype == SPACE_OUTLINER) { + if (area != nullptr && area->spacetype == SPACE_OUTLINER) { SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); return (space_outliner->outlinevis == SO_ID_ORPHANS); } @@ -2303,14 +2310,14 @@ static int outliner_orphans_purge_exec(bContext *C, wmOperator *op) * outliner several mouse events can be handled in one cycle without * handling notifiers/redraw which leads to deleting the same object twice. * cleanup tree here to prevent such cases. */ - if ((area != NULL) && (area->spacetype == SPACE_OUTLINER)) { + if ((area != nullptr) && (area->spacetype == SPACE_OUTLINER)) { outliner_cleanup_tree(space_outliner); } DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_ID | NA_REMOVED, NULL); + WM_event_add_notifier(C, NC_ID | NA_REMOVED, nullptr); /* Force full redraw of the UI. */ - WM_main_add_notifier(NC_WINDOW, NULL); + WM_main_add_notifier(NC_WINDOW, nullptr); return OPERATOR_FINISHED; } @@ -2332,7 +2339,7 @@ void OUTLINER_OT_orphans_purge(wmOperatorType *ot) /* properties */ PropertyRNA *prop = RNA_def_int(ot->srna, "num_deleted", 0, 0, INT_MAX, "", "", 0, INT_MAX); - RNA_def_property_flag(prop, PROP_SKIP_SAVE | PROP_HIDDEN); + RNA_def_property_flag(prop, (PropertyFlag)(PROP_SKIP_SAVE | PROP_HIDDEN)); RNA_def_boolean(ot->srna, "do_local_ids", diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.hh index 3439e4fa219..9db1d73dc76 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.hh @@ -23,8 +23,13 @@ #pragma once +#include <memory> + #include "RNA_types.h" +/* Needed for `tree_element_cast()`. */ +#include "tree/tree_element.hh" + #ifdef __cplusplus extern "C" { #endif @@ -47,15 +52,25 @@ struct bPoseChannel; struct wmKeyConfig; struct wmOperatorType; -typedef struct SpaceOutliner_Runtime { - /** Internal C++ object to create and manage the tree for a specific display type (View Layers, - * Scenes, Blender File, etc.). */ - struct TreeDisplay *tree_display; +namespace blender::ed::outliner { +class AbstractTreeDisplay; +class AbstractTreeElement; +} // namespace blender::ed::outliner + +struct SpaceOutliner_Runtime { + /** Object to create and manage the tree for a specific display type (View Layers, Scenes, + * Blender File, etc.). */ + std::unique_ptr<blender::ed::outliner::AbstractTreeDisplay> tree_display; /** Pointers to tree-store elements, grouped by `(id, type, nr)` * in hash-table for faster searching. */ struct GHash *treehash; -} SpaceOutliner_Runtime; + + SpaceOutliner_Runtime() = default; + /** Used for copying runtime data to a duplicated space. */ + SpaceOutliner_Runtime(const SpaceOutliner_Runtime &); + ~SpaceOutliner_Runtime(); +}; typedef enum TreeElementInsertType { TE_INSERT_BEFORE, @@ -82,7 +97,7 @@ typedef struct TreeElement { * #TreeElement. Step by step, data should be moved to it and operations based on the type should * become virtual methods of the class hierarchy. */ - struct TreeElementType *type; + std::unique_ptr<blender::ed::outliner::AbstractTreeElement> type; ListBase subtree; int xs, ys; /* Do selection. */ @@ -92,8 +107,7 @@ typedef struct TreeElement { short idcode; /* From TreeStore id. */ short xend; /* Width of item display, for select. */ const char *name; - void *directdata; /* Armature Bones, Base, Sequence, Strip... */ - PointerRNA rnaptr; /* RNA Pointer. */ + void *directdata; /* Armature Bones, Base, ... */ } TreeElement; typedef struct TreeElementIcon { @@ -158,6 +172,8 @@ enum { /* Child elements of the same type in the icon-row are drawn merged as one icon. * This flag is set for an element that is part of these merged child icons. */ TE_ICONROW_MERGED = (1 << 7), + /* This element has some warning to be displayed. */ + TE_HAS_WARNING = (1 << 8), }; /* button events */ @@ -211,7 +227,7 @@ typedef enum { * - not searching into RNA items helps but isn't the complete solution */ -#define SEARCHING_OUTLINER(sov) (sov->search_flags & SO_SEARCH_RECURSIVE) +#define SEARCHING_OUTLINER(sov) ((sov)->search_flags & SO_SEARCH_RECURSIVE) /* is the current element open? if so we also show children */ #define TSELEM_OPEN(telm, sv) \ @@ -267,6 +283,10 @@ void outliner_build_tree(struct Main *mainvar, struct SpaceOutliner *space_outliner, struct ARegion *region); +struct TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner, + struct Collection *collection, + TreeElement *ten); + bool outliner_requires_rebuild_on_select_or_active_change( const struct SpaceOutliner *space_outliner); /** @@ -296,7 +316,7 @@ void outliner_collection_isolate_flag(struct Scene *scene, struct Collection *collection, struct PropertyRNA *layer_or_collection_prop, const char *propname, - const bool value); + bool value); /** * Return the index to use based on the TreeElement ID and object type @@ -314,7 +334,7 @@ void tree_element_type_active_set(struct bContext *C, const TreeViewContext *tvc, TreeElement *te, TreeStoreElem *tselem, - const eOLSetState set, + eOLSetState set, bool recursive); /** * Generic call for non-id data to check the active state in UI. @@ -329,8 +349,8 @@ eOLDrawState tree_element_type_active_state_get(const struct bContext *C, void tree_element_activate(struct bContext *C, const TreeViewContext *tvc, TreeElement *te, - const eOLSetState set, - const bool handle_all_types); + eOLSetState set, + bool handle_all_types); eOLDrawState tree_element_active_state_get(const TreeViewContext *tvc, const TreeElement *te, const TreeStoreElem *tselem); @@ -343,7 +363,7 @@ struct bPoseChannel *outliner_find_parent_bone(TreeElement *te, TreeElement **r_ void outliner_item_select(struct bContext *C, struct SpaceOutliner *space_outliner, struct TreeElement *te, - const short select_flag); + short select_flag); /** * Find if x coordinate is over an icon or name. @@ -366,7 +386,7 @@ bool outliner_is_co_within_mode_column(SpaceOutliner *space_outliner, const floa void outliner_item_mode_toggle(struct bContext *C, TreeViewContext *tvc, TreeElement *te, - const bool do_extend); + bool do_extend); /* outliner_edit.c ---------------------------------------------- */ typedef void (*outliner_operation_fn)(struct bContext *C, @@ -396,7 +416,7 @@ void outliner_do_object_operation(struct bContext *C, struct ListBase *lb, outliner_operation_fn operation_fn); -int outliner_flag_is_any_test(ListBase *lb, short flag, const int curlevel); +int outliner_flag_is_any_test(ListBase *lb, short flag, int curlevel); /** * Set or unset \a flag for all outliner elements in \a lb and sub-trees. * \return if any flag was modified. @@ -592,7 +612,7 @@ TreeElement *outliner_find_item_at_x_in_row(const SpaceOutliner *space_outliner, bool *r_is_merged_icon, bool *r_is_over_icon); /** - * `tse` is not in the treestore, we use its contents to find a match. + * `tse` is not in the tree-store, we use its contents to find a match. */ TreeElement *outliner_find_tse(struct SpaceOutliner *space_outliner, const TreeStoreElem *tse); /** @@ -606,7 +626,7 @@ TreeElement *outliner_find_parent_element(ListBase *lb, TreeElement *parent_te, const TreeElement *child_te); /** - * Find treestore that refers to given ID. + * Find tree-store that refers to given ID. */ TreeElement *outliner_find_id(struct SpaceOutliner *space_outliner, ListBase *lb, @@ -631,7 +651,7 @@ bool outliner_tree_traverse(const SpaceOutliner *space_outliner, void *customdata); float outliner_restrict_columns_width(const struct SpaceOutliner *space_outliner); /** - * Find first tree element in tree with matching treestore flag. + * Find first tree element in tree with matching tree-store flag. */ TreeElement *outliner_find_element_with_flag(const ListBase *lb, short flag); /** @@ -668,3 +688,19 @@ int outliner_context(const struct bContext *C, #ifdef __cplusplus } #endif + +namespace blender::ed::outliner { + +/** + * Helper to safely "cast" a #TreeElement to its new C++ #AbstractTreeElement, if possible. + * \return nullptr if the tree-element doesn't match the requested type \a TreeElementT or the + * element doesn't hold a C++ #AbstractTreeElement pendant yet. + */ +template<typename TreeElementT> TreeElementT *tree_element_cast(const TreeElement *te) +{ + static_assert(std::is_base_of_v<AbstractTreeElement, TreeElementT>, + "Requested tree-element type must be an AbstractTreeElement"); + return dynamic_cast<TreeElementT *>(te->type.get()); +} + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.cc index 7e5b0c90714..4664a3150a1 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.cc @@ -25,7 +25,7 @@ #include "ED_screen.h" -#include "outliner_intern.h" +#include "outliner_intern.hh" /* ************************** registration **********************************/ diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.cc index 855975eb2dc..3ff8b9e973f 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.cc @@ -21,7 +21,7 @@ * \ingroup spoutliner */ -#include <stdlib.h> +#include <cstdlib> #include "MEM_guardedalloc.h" @@ -79,7 +79,10 @@ #include "RNA_access.h" #include "RNA_define.h" -#include "outliner_intern.h" +#include "outliner_intern.hh" +#include "tree/tree_element_seq.hh" + +using namespace blender::ed::outliner; /** * \note changes to selection are by convention and not essential. @@ -96,14 +99,14 @@ static void do_outliner_item_editmode_toggle(bContext *C, Scene *scene, Base *ba changed = ED_object_editmode_exit_ex(bmain, scene, ob, EM_FREEDATA); if (changed) { ED_object_base_select(base, BA_DESELECT); - WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL); + WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, nullptr); } } else { changed = ED_object_editmode_enter_ex(CTX_data_main(C), scene, ob, EM_NO_CONTEXT); if (changed) { ED_object_base_select(base, BA_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL); + WM_event_add_notifier(C, NC_SCENE | ND_MODE, nullptr); } } @@ -134,14 +137,14 @@ static void do_outliner_item_posemode_toggle(bContext *C, Scene *scene, Base *ba changed = ED_object_posemode_exit_ex(bmain, ob); if (changed) { ED_object_base_select(base, BA_DESELECT); - WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, NULL); + WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_OBJECT, nullptr); } } else { changed = ED_object_posemode_enter_ex(bmain, ob); if (changed) { ED_object_base_select(base, BA_SELECT); - WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_POSE, NULL); + WM_event_add_notifier(C, NC_SCENE | ND_MODE | NS_MODE_POSE, nullptr); } } @@ -165,7 +168,7 @@ static void do_outliner_item_posemode_toggle(bContext *C, Scene *scene, Base *ba */ static void do_outliner_item_mode_toggle_generic(bContext *C, TreeViewContext *tvc, Base *base) { - const int active_mode = tvc->obact->mode; + const eObjectMode active_mode = (eObjectMode)tvc->obact->mode; ED_undo_group_begin(C); if (ED_object_mode_set(C, OB_MODE_OBJECT)) { @@ -222,13 +225,13 @@ static void tree_element_viewlayer_activate(bContext *C, TreeElement *te) return; } - ViewLayer *view_layer = te->directdata; + ViewLayer *view_layer = reinterpret_cast<ViewLayer *>(te->directdata); wmWindow *win = CTX_wm_window(C); Scene *scene = WM_window_get_active_scene(win); if (BLI_findindex(&scene->view_layers, view_layer) != -1) { WM_window_set_active_view_layer(win, view_layer); - WM_event_add_notifier(C, NC_SCREEN | ND_LAYER, NULL); + WM_event_add_notifier(C, NC_SCREEN | ND_LAYER, nullptr); } } @@ -241,7 +244,7 @@ static void do_outliner_object_select_recursive(ViewLayer *view_layer, { Base *base; - for (base = FIRSTBASE(view_layer); base; base = base->next) { + for (base = reinterpret_cast<Base *>(FIRSTBASE(view_layer)); base; base = base->next) { Object *ob = base->object; if ((((base->flag & BASE_VISIBLE_DEPSGRAPH) != 0) && BKE_object_is_child_recursive(ob_parent, ob))) { @@ -252,8 +255,7 @@ static void do_outliner_object_select_recursive(ViewLayer *view_layer, static void do_outliner_bone_select_recursive(bArmature *arm, Bone *bone_parent, bool select) { - Bone *bone; - for (bone = bone_parent->childbase.first; bone; bone = bone->next) { + LISTBASE_FOREACH (Bone *, bone, &bone_parent->childbase) { if (select && PBONE_SELECTABLE(arm, bone)) { bone->flag |= BONE_SELECTED; } @@ -287,11 +289,11 @@ static void tree_element_object_activate(bContext *C, bool recursive) { TreeStoreElem *tselem = TREESTORE(te); - TreeStoreElem *parent_tselem = NULL; - TreeElement *parent_te = NULL; + TreeStoreElem *parent_tselem = nullptr; + TreeElement *parent_te = nullptr; Scene *sce; Base *base; - Object *ob = NULL; + Object *ob = nullptr; /* if id is not object, we search back */ if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { @@ -309,7 +311,7 @@ static void tree_element_object_activate(bContext *C, } } } - if (ob == NULL) { + if (ob == nullptr) { return; } @@ -323,9 +325,9 @@ static void tree_element_object_activate(bContext *C, base = BKE_view_layer_base_find(view_layer, ob); if (scene->toolsettings->object_flag & SCE_OBJECT_MODE_LOCK) { - if (base != NULL) { + if (base != nullptr) { Object *obact = OBACT(view_layer); - const eObjectMode object_mode = obact ? obact->mode : OB_MODE_OBJECT; + const eObjectMode object_mode = obact ? (eObjectMode)obact->mode : OB_MODE_OBJECT; if (base && !BKE_object_is_mode_compat(base->object, object_mode)) { if (object_mode == OB_MODE_OBJECT) { struct Main *bmain = CTX_data_main(C); @@ -333,7 +335,7 @@ static void tree_element_object_activate(bContext *C, ED_object_mode_generic_exit(bmain, depsgraph, scene, base->object); } if (!BKE_object_is_mode_compat(base->object, object_mode)) { - base = NULL; + base = nullptr; } } } @@ -356,7 +358,7 @@ static void tree_element_object_activate(bContext *C, } } else { - /* deleselect all */ + /* De-select all. */ /* Only in object mode so we can switch the active object, * keeping all objects in the current 'mode' selected, useful for multi-pose/edit mode. @@ -390,8 +392,8 @@ static void tree_element_material_activate(bContext *C, ViewLayer *view_layer, T { /* we search for the object parent */ Object *ob = (Object *)outliner_search_back(te, ID_OB); - /* Note : ob->matbits can be NULL when a local object points to a library mesh. */ - if (ob == NULL || ob != OBACT(view_layer) || ob->matbits == NULL) { + /* Note : ob->matbits can be nullptr when a local object points to a library mesh. */ + if (ob == nullptr || ob != OBACT(view_layer) || ob->matbits == nullptr) { return; /* just paranoia */ } @@ -411,7 +413,7 @@ static void tree_element_material_activate(bContext *C, ViewLayer *view_layer, T * for render views to update. See T42973. * Note that RNA material update does it too, see e.g. rna_MaterialSlot_update(). */ DEG_id_tag_update((ID *)ob, ID_RECALC_TRANSFORM); - WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, NULL); + WM_event_add_notifier(C, NC_MATERIAL | ND_SHADING_LINKS, nullptr); } static void tree_element_camera_activate(bContext *C, Scene *scene, TreeElement *te) @@ -421,17 +423,17 @@ static void tree_element_camera_activate(bContext *C, Scene *scene, TreeElement scene->camera = ob; Main *bmain = CTX_data_main(C); - wmWindowManager *wm = bmain->wm.first; + wmWindowManager *wm = reinterpret_cast<wmWindowManager *>(bmain->wm.first); WM_windows_scene_data_sync(&wm->windows, scene); DEG_id_tag_update(&scene->id, ID_RECALC_COPY_ON_WRITE); DEG_relations_tag_update(bmain); - WM_event_add_notifier(C, NC_SCENE | NA_EDITED, NULL); + WM_event_add_notifier(C, NC_SCENE | NA_EDITED, nullptr); } static void tree_element_world_activate(bContext *C, Scene *scene, TreeElement *te) { - Scene *sce = NULL; + Scene *sce = nullptr; TreeElement *tep = te->parent; if (tep) { @@ -461,7 +463,7 @@ static void tree_element_defgroup_activate(bContext *C, TreeElement *te, TreeSto static void tree_element_gplayer_activate(bContext *C, TreeElement *te, TreeStoreElem *tselem) { bGPdata *gpd = (bGPdata *)tselem->id; - bGPDlayer *gpl = te->directdata; + bGPDlayer *gpl = reinterpret_cast<bGPDlayer *>(te->directdata); /* We can only have a single "active" layer at a time * and there must always be an active layer... */ @@ -489,30 +491,29 @@ static void tree_element_posechannel_activate(bContext *C, bool recursive) { Object *ob = (Object *)tselem->id; - bArmature *arm = ob->data; - bPoseChannel *pchan = te->directdata; + bArmature *arm = reinterpret_cast<bArmature *>(ob->data); + bPoseChannel *pchan = reinterpret_cast<bPoseChannel *>(te->directdata); if (!(pchan->bone->flag & BONE_HIDDEN_P)) { if (set != OL_SETSEL_EXTEND) { /* Single select forces all other bones to get unselected. */ uint objects_len = 0; - Object **objects = BKE_object_pose_array_get_unique(view_layer, NULL, &objects_len); + Object **objects = BKE_object_pose_array_get_unique(view_layer, nullptr, &objects_len); for (uint object_index = 0; object_index < objects_len; object_index++) { Object *ob_iter = BKE_object_pose_armature_get(objects[object_index]); /* Sanity checks. */ - if (ELEM(NULL, ob_iter, ob_iter->pose, ob_iter->data)) { + if (ELEM(nullptr, ob_iter, ob_iter->pose, ob_iter->data)) { continue; } - bPoseChannel *pchannel; - for (pchannel = ob_iter->pose->chanbase.first; pchannel; pchannel = pchannel->next) { + LISTBASE_FOREACH (bPoseChannel *, pchannel, &ob_iter->pose->chanbase) { pchannel->bone->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); } if (ob != ob_iter) { - DEG_id_tag_update(ob_iter->data, ID_RECALC_SELECT); + DEG_id_tag_update(reinterpret_cast<ID *>(ob_iter->data), ID_RECALC_SELECT); } } MEM_freeN(objects); @@ -545,14 +546,14 @@ static void tree_element_bone_activate(bContext *C, bool recursive) { bArmature *arm = (bArmature *)tselem->id; - Bone *bone = te->directdata; + Bone *bone = reinterpret_cast<Bone *>(te->directdata); if (!(bone->flag & BONE_HIDDEN_P)) { Object *ob = OBACT(view_layer); if (ob) { if (set != OL_SETSEL_EXTEND) { /* single select forces all other bones to get unselected */ - for (Bone *bone_iter = arm->bonebase.first; bone_iter != NULL; + for (Bone *bone_iter = reinterpret_cast<Bone *>(arm->bonebase.first); bone_iter != nullptr; bone_iter = bone_iter->next) { bone_iter->flag &= ~(BONE_TIPSEL | BONE_SELECTED | BONE_ROOTSEL); do_outliner_bone_select_recursive(arm, bone_iter, false); @@ -594,13 +595,18 @@ static void tree_element_ebone_activate(bContext *C, bool recursive) { bArmature *arm = (bArmature *)tselem->id; - EditBone *ebone = te->directdata; + EditBone *ebone = reinterpret_cast<EditBone *>(te->directdata); if (set == OL_SETSEL_NORMAL) { if (!(ebone->flag & BONE_HIDDEN_A)) { uint bases_len = 0; - Base **bases = BKE_view_layer_array_from_bases_in_edit_mode_unique_data( - view_layer, NULL, &bases_len); + + ObjectsInModeParams ob_params{}; + ob_params.object_mode = OB_MODE_EDIT; + ob_params.no_dup_data = true; + + Base **bases = BKE_view_layer_array_from_bases_in_mode_params( + view_layer, nullptr, &bases_len, &ob_params); ED_armature_edit_deselect_all_multi_ex(bases, bases_len); MEM_freeN(bases); @@ -673,12 +679,13 @@ static void tree_element_sequence_activate(bContext *C, TreeElement *te, const eOLSetState set) { - Sequence *seq = (Sequence *)te->directdata; + const TreeElementSequence *te_seq = tree_element_cast<TreeElementSequence>(te); + Sequence *seq = &te_seq->getSequence(); Editing *ed = SEQ_editing_get(scene); if (BLI_findindex(ed->seqbasep, seq) != -1) { if (set == OL_SETSEL_EXTEND) { - SEQ_select_active_set(scene, NULL); + SEQ_select_active_set(scene, nullptr); } ED_sequencer_deselect_all(scene); @@ -701,7 +708,7 @@ static void tree_element_sequence_dup_activate(Scene *scene, TreeElement *UNUSED #if 0 select_single_seq(seq, 1); #endif - Sequence *p = ed->seqbasep->first; + Sequence *p = reinterpret_cast<Sequence *>(ed->seqbasep->first); while (p) { if ((!p->strip) || (!p->strip->stripdata) || (p->strip->stripdata->name[0] == '\0')) { p = p->next; @@ -720,22 +727,23 @@ static void tree_element_sequence_dup_activate(Scene *scene, TreeElement *UNUSED static void tree_element_master_collection_activate(const bContext *C) { ViewLayer *view_layer = CTX_data_view_layer(C); - LayerCollection *layer_collection = view_layer->layer_collections.first; + LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>( + view_layer->layer_collections.first); BKE_layer_collection_activate(view_layer, layer_collection); /* A very precise notifier - ND_LAYER alone is quite vague, we want to avoid unnecessary work * when only the active collection changes. */ - WM_main_add_notifier(NC_SCENE | ND_LAYER | NS_LAYER_COLLECTION | NA_ACTIVATED, NULL); + WM_main_add_notifier(NC_SCENE | ND_LAYER | NS_LAYER_COLLECTION | NA_ACTIVATED, nullptr); } static void tree_element_layer_collection_activate(bContext *C, TreeElement *te) { Scene *scene = CTX_data_scene(C); - LayerCollection *layer_collection = te->directdata; + LayerCollection *layer_collection = reinterpret_cast<LayerCollection *>(te->directdata); ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, layer_collection); BKE_layer_collection_activate(view_layer, layer_collection); /* A very precise notifier - ND_LAYER alone is quite vague, we want to avoid unnecessary work * when only the active collection changes. */ - WM_main_add_notifier(NC_SCENE | ND_LAYER | NS_LAYER_COLLECTION | NA_ACTIVATED, NULL); + WM_main_add_notifier(NC_SCENE | ND_LAYER | NS_LAYER_COLLECTION | NA_ACTIVATED, nullptr); } static void tree_element_text_activate(bContext *C, TreeElement *te) @@ -854,7 +862,7 @@ static eOLDrawState tree_element_bone_state_get(const ViewLayer *view_layer, const TreeStoreElem *tselem) { const bArmature *arm = (const bArmature *)tselem->id; - const Bone *bone = te->directdata; + const Bone *bone = reinterpret_cast<Bone *>(te->directdata); const Object *ob = OBACT(view_layer); if (ob && ob->data == arm) { if (bone->flag & BONE_SELECTED) { @@ -866,7 +874,7 @@ static eOLDrawState tree_element_bone_state_get(const ViewLayer *view_layer, static eOLDrawState tree_element_ebone_state_get(const TreeElement *te) { - const EditBone *ebone = te->directdata; + const EditBone *ebone = reinterpret_cast<EditBone *>(te->directdata); if (ebone->flag & BONE_SELECTED) { return OL_DRAWSEL_NORMAL; } @@ -894,7 +902,7 @@ static eOLDrawState tree_element_pose_state_get(const ViewLayer *view_layer, const Object *ob = (const Object *)tselem->id; /* This will just lookup in a cache, it will not change the arguments. */ const Base *base = BKE_view_layer_base_find((ViewLayer *)view_layer, (Object *)ob); - if (base == NULL) { + if (base == nullptr) { /* Armature not instantiated in current scene (e.g. inside an appended group). */ return OL_DRAWSEL_NONE; } @@ -910,7 +918,7 @@ static eOLDrawState tree_element_posechannel_state_get(const Object *ob_pose, const TreeStoreElem *tselem) { const Object *ob = (const Object *)tselem->id; - const bPoseChannel *pchan = te->directdata; + const bPoseChannel *pchan = reinterpret_cast<bPoseChannel *>(te->directdata); if (ob == ob_pose && ob->pose) { if (pchan->bone->flag & BONE_SELECTED) { return OL_DRAWSEL_NORMAL; @@ -926,7 +934,7 @@ static eOLDrawState tree_element_viewlayer_state_get(const bContext *C, const Tr return OL_DRAWSEL_NONE; } - const ViewLayer *view_layer = te->directdata; + const ViewLayer *view_layer = reinterpret_cast<ViewLayer *>(te->directdata); if (CTX_data_view_layer(C) == view_layer) { return OL_DRAWSEL_NORMAL; @@ -950,7 +958,8 @@ static eOLDrawState tree_element_posegroup_state_get(const ViewLayer *view_layer static eOLDrawState tree_element_sequence_state_get(const Scene *scene, const TreeElement *te) { - const Sequence *seq = (const Sequence *)te->directdata; + const TreeElementSequence *te_seq = tree_element_cast<TreeElementSequence>(te); + const Sequence *seq = &te_seq->getSequence(); const Editing *ed = scene->ed; if (ed && ed->act_seq == seq && seq->flag & SELECT) { @@ -961,7 +970,9 @@ static eOLDrawState tree_element_sequence_state_get(const Scene *scene, const Tr static eOLDrawState tree_element_sequence_dup_state_get(const TreeElement *te) { - const Sequence *seq = (const Sequence *)te->directdata; + const TreeElementSequenceStripDuplicate *te_dup = + tree_element_cast<TreeElementSequenceStripDuplicate>(te); + const Sequence *seq = &te_dup->getSequence(); if (seq->flag & SELECT) { return OL_DRAWSEL_NORMAL; } @@ -1002,8 +1013,8 @@ static eOLDrawState tree_element_active_material_get(const ViewLayer *view_layer { /* we search for the object parent */ const Object *ob = (const Object *)outliner_search_back((TreeElement *)te, ID_OB); - /* Note : ob->matbits can be NULL when a local object points to a library mesh. */ - if (ob == NULL || ob != OBACT(view_layer) || ob->matbits == NULL) { + /* Note : ob->matbits can be nullptr when a local object points to a library mesh. */ + if (ob == nullptr || ob != OBACT(view_layer) || ob->matbits == nullptr) { return OL_DRAWSEL_NONE; /* just paranoia */ } @@ -1042,7 +1053,7 @@ static eOLDrawState tree_element_active_scene_get(const TreeViewContext *tvc, static eOLDrawState tree_element_active_world_get(const Scene *scene, const TreeElement *te) { const TreeElement *tep = te->parent; - if (tep == NULL) { + if (tep == nullptr) { return OL_DRAWSEL_NORMAL; } @@ -1138,7 +1149,7 @@ bPoseChannel *outliner_find_parent_bone(TreeElement *te, TreeElement **r_bone_te te = te->parent; } - return NULL; + return nullptr; } static void outliner_sync_to_properties_editors(const bContext *C, @@ -1161,7 +1172,7 @@ static void outliner_sync_to_properties_editors(const bContext *C, static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreElem *tselem) { - PointerRNA ptr = {0}; + PointerRNA ptr = {nullptr}; int context = 0; /* ID Types */ @@ -1209,7 +1220,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE break; case TSE_CONSTRAINT_BASE: case TSE_CONSTRAINT: { - TreeElement *bone_te = NULL; + TreeElement *bone_te = nullptr; bPoseChannel *pchan = outliner_find_parent_bone(te, &bone_te); if (pchan) { @@ -1223,7 +1234,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE /* Expand the selected constraint in the properties editor. */ if (tselem->type != TSE_CONSTRAINT_BASE) { - BKE_constraint_panel_expand(te->directdata); + BKE_constraint_panel_expand(reinterpret_cast<bConstraint *>(te->directdata)); } break; } @@ -1236,7 +1247,8 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE Object *ob = (Object *)tselem->id; if (ob->type == OB_GPENCIL) { - BKE_gpencil_modifier_panel_expand(te->directdata); + BKE_gpencil_modifier_panel_expand( + reinterpret_cast<GpencilModifierData *>(te->directdata)); } else { ModifierData *md = (ModifierData *)te->directdata; @@ -1269,12 +1281,12 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE context = BCONTEXT_SHADERFX; if (tselem->type != TSE_GPENCIL_EFFECT_BASE) { - BKE_shaderfx_panel_expand(te->directdata); + BKE_shaderfx_panel_expand(reinterpret_cast<ShaderFxData *>(te->directdata)); } break; case TSE_BONE: { bArmature *arm = (bArmature *)tselem->id; - Bone *bone = te->directdata; + Bone *bone = reinterpret_cast<Bone *>(te->directdata); RNA_pointer_create(&arm->id, &RNA_Bone, bone, &ptr); context = BCONTEXT_BONE; @@ -1282,7 +1294,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE } case TSE_EBONE: { bArmature *arm = (bArmature *)tselem->id; - EditBone *ebone = te->directdata; + EditBone *ebone = reinterpret_cast<EditBone *>(te->directdata); RNA_pointer_create(&arm->id, &RNA_EditBone, ebone, &ptr); context = BCONTEXT_BONE; @@ -1290,8 +1302,8 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE } case TSE_POSE_CHANNEL: { Object *ob = (Object *)tselem->id; - bArmature *arm = ob->data; - bPoseChannel *pchan = te->directdata; + bArmature *arm = reinterpret_cast<bArmature *>(ob->data); + bPoseChannel *pchan = reinterpret_cast<bPoseChannel *>(te->directdata); RNA_pointer_create(&arm->id, &RNA_PoseBone, pchan, &ptr); context = BCONTEXT_BONE; @@ -1299,7 +1311,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE } case TSE_POSE_BASE: { Object *ob = (Object *)tselem->id; - bArmature *arm = ob->data; + bArmature *arm = reinterpret_cast<bArmature *>(ob->data); RNA_pointer_create(&arm->id, &RNA_Armature, arm, &ptr); context = BCONTEXT_DATA; @@ -1307,7 +1319,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE } case TSE_R_LAYER_BASE: case TSE_R_LAYER: { - ViewLayer *view_layer = te->directdata; + ViewLayer *view_layer = reinterpret_cast<ViewLayer *>(te->directdata); RNA_pointer_create(tselem->id, &RNA_ViewLayer, view_layer, &ptr); context = BCONTEXT_VIEW_LAYER; @@ -1316,7 +1328,7 @@ static void outliner_set_properties_tab(bContext *C, TreeElement *te, TreeStoreE case TSE_POSEGRP_BASE: case TSE_POSEGRP: { Object *ob = (Object *)tselem->id; - bArmature *arm = ob->data; + bArmature *arm = reinterpret_cast<bArmature *>(ob->data); RNA_pointer_create(&arm->id, &RNA_Armature, arm, &ptr); context = BCONTEXT_DATA; @@ -1392,7 +1404,7 @@ static void do_outliner_item_activate_tree_element(bContext *C, Collection *gr = (Collection *)tselem->id; if (extend) { - int sel = BA_SELECT; + eObjectSelect_Mode sel = BA_SELECT; FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (gr, object) { Base *base = BKE_view_layer_base_find(tvc->view_layer, object); if (base && (base->flag & BASE_SELECTED)) { @@ -1416,7 +1428,7 @@ static void do_outliner_item_activate_tree_element(bContext *C, FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (gr, object) { Base *base = BKE_view_layer_base_find(tvc->view_layer, object); /* Object may not be in this scene */ - if (base != NULL) { + if (base != nullptr) { if ((base->flag & BASE_SELECTED) == 0) { ED_object_base_select(base, BA_SELECT); } @@ -1730,7 +1742,7 @@ static int outliner_box_select_exec(bContext *C, wmOperator *op) ARegion *region = CTX_wm_region(C); rctf rectf; - const eSelectOp sel_op = RNA_enum_get(op->ptr, "mode"); + const eSelectOp sel_op = (eSelectOp)RNA_enum_get(op->ptr, "mode"); const bool select = (sel_op != SEL_OP_SUB); if (SEL_OP_USE_PRE_DESELECT(sel_op)) { outliner_flag_set(&space_outliner->tree, TSE_SELECTED, 0); @@ -1816,7 +1828,7 @@ static TreeElement *outliner_find_rightmost_visible_child(SpaceOutliner *space_o { while (te->subtree.last) { if (TSELEM_OPEN(TREESTORE(te), space_outliner)) { - te = te->subtree.last; + te = reinterpret_cast<TreeElement *>(te->subtree.last); } else { break; @@ -1860,7 +1872,7 @@ static TreeElement *outliner_find_next_element(SpaceOutliner *space_outliner, Tr TreeStoreElem *tselem = TREESTORE(te); if (TSELEM_OPEN(tselem, space_outliner) && te->subtree.first) { - te = te->subtree.first; + te = reinterpret_cast<TreeElement *>(te->subtree.first); } else if (te->next) { te = te->next; @@ -1897,7 +1909,7 @@ static TreeElement *outliner_walk_right(SpaceOutliner *space_outliner, /* Only walk down a level if the element is open and not toggling expand */ if (!toggle_all && TSELEM_OPEN(tselem, space_outliner) && !BLI_listbase_is_empty(&te->subtree)) { - te = te->subtree.first; + te = reinterpret_cast<TreeElement *>(te->subtree.first); } else { outliner_item_openclose(space_outliner, te, true, toggle_all); @@ -1948,7 +1960,7 @@ static TreeElement *find_walk_select_start_element(SpaceOutliner *space_outliner /* If no active element exists, use the first element in the tree */ if (!active_te) { - active_te = space_outliner->tree.first; + active_te = reinterpret_cast<TreeElement *>(space_outliner->tree.first); *changed = true; } diff --git a/source/blender/editors/space_outliner/outliner_sync.c b/source/blender/editors/space_outliner/outliner_sync.cc index d95a0dde858..74416024b03 100644 --- a/source/blender/editors/space_outliner/outliner_sync.c +++ b/source/blender/editors/space_outliner/outliner_sync.cc @@ -21,7 +21,7 @@ * \ingroup spoutliner */ -#include <stdio.h> +#include <cstdio> #include "DNA_armature_types.h" #include "DNA_layer_types.h" @@ -50,7 +50,7 @@ #include "WM_api.h" #include "WM_types.h" -#include "outliner_intern.h" +#include "outliner_intern.hh" void ED_outliner_select_sync_from_object_tag(bContext *C) { @@ -93,7 +93,8 @@ void ED_outliner_select_sync_flag_outliners(const bContext *C) Main *bmain = CTX_data_main(C); wmWindowManager *wm = CTX_wm_manager(C); - for (bScreen *screen = bmain->screens.first; screen; screen = screen->id.next) { + for (bScreen *screen = reinterpret_cast<bScreen *>(bmain->screens.first); screen; + screen = reinterpret_cast<bScreen *>(screen->id.next)) { LISTBASE_FOREACH (ScrArea *, area, &screen->areabase) { LISTBASE_FOREACH (SpaceLink *, sl, &area->spacedata) { if (sl->spacetype == SPACE_OUTLINER) { @@ -114,12 +115,12 @@ void ED_outliner_select_sync_flag_outliners(const bContext *C) * outliner display mode also needs to be considered. This stores the types of data * to sync to increase code clarity. */ -typedef struct SyncSelectTypes { +struct SyncSelectTypes { bool object; bool edit_bone; bool pose_bone; bool sequence; -} SyncSelectTypes; +}; /** * Set which types of data to sync when syncing selection from the outliner based on object @@ -173,11 +174,11 @@ static bool outliner_sync_select_to_outliner_set_types(const bContext *C, * Stores items selected from a sync from the outliner. Prevents syncing the selection * state of the last instance of an object linked in multiple collections. */ -typedef struct SelectedItems { +struct SelectedItems { GSet *objects; GSet *edit_bones; GSet *pose_bones; -} SelectedItems; +}; static void selected_items_init(SelectedItems *selected_items) { @@ -188,9 +189,9 @@ static void selected_items_init(SelectedItems *selected_items) static void selected_items_free(SelectedItems *selected_items) { - BLI_gset_free(selected_items->objects, NULL); - BLI_gset_free(selected_items->edit_bones, NULL); - BLI_gset_free(selected_items->pose_bones, NULL); + BLI_gset_free(selected_items->objects, nullptr); + BLI_gset_free(selected_items->edit_bones, nullptr); + BLI_gset_free(selected_items->pose_bones, nullptr); } /* Check if an instance of this object been selected by the sync */ @@ -274,7 +275,7 @@ static void outliner_select_sync_to_pose_bone(TreeElement *te, GSet *selected_pbones) { Object *ob = (Object *)tselem->id; - bArmature *arm = ob->data; + bArmature *arm = reinterpret_cast<bArmature *>(ob->data); bPoseChannel *pchan = (bPoseChannel *)te->directdata; short bone_flag = pchan->bone->flag; @@ -403,7 +404,7 @@ static void outliner_select_sync_from_object(ViewLayer *view_layer, Object *ob = (Object *)tselem->id; Base *base = (te->directdata) ? (Base *)te->directdata : BKE_view_layer_base_find(view_layer, ob); - const bool is_selected = (base != NULL) && ((base->flag & BASE_SELECTED) != 0); + const bool is_selected = (base != nullptr) && ((base->flag & BASE_SELECTED) != 0); if (base && (ob == obact)) { tselem->flag |= TSE_ACTIVE; @@ -486,12 +487,12 @@ static void outliner_select_sync_from_sequence(Sequence *sequence_active, TreeSt * Contains active object, bones, and sequence for syncing to prevent getting active data * repeatedly throughout syncing to the outliner. */ -typedef struct SyncSelectActiveData { +struct SyncSelectActiveData { Object *object; EditBone *edit_bone; bPoseChannel *pose_channel; Sequence *sequence; -} SyncSelectActiveData; +}; /** Sync select and active flags from active view layer, bones, and sequences to the outliner. */ static void outliner_sync_selection_to_outliner(ViewLayer *view_layer, @@ -561,7 +562,7 @@ void outliner_sync_selection(const bContext *C, SpaceOutliner *space_outliner) outliner_sync_selection_to_outliner( view_layer, space_outliner, &space_outliner->tree, &active_data, &sync_types); - /* Keep any unsynced data in the dirty flag */ + /* Keep any un-synced data in the dirty flag. */ if (sync_types.object) { space_outliner->sync_select_dirty &= ~WM_OUTLINER_SYNC_SELECT_FROM_OBJECT; } diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.cc index 01f0feec771..fa31025b550 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.cc @@ -95,10 +95,14 @@ #include "SEQ_relations.h" #include "SEQ_sequencer.h" -#include "outliner_intern.h" +#include "outliner_intern.hh" +#include "tree/tree_element_rna.hh" +#include "tree/tree_element_seq.hh" static CLG_LogRef LOG = {"ed.outliner.tools"}; +using namespace blender::ed::outliner; + /* -------------------------------------------------------------------- */ /** \name ID/Library/Data Set/Un-link Utilities * \{ */ @@ -208,7 +212,7 @@ static bool outliner_operation_tree_element_poll(bContext *C) } SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); TreeElement *te = get_target_element(space_outliner); - if (te == NULL) { + if (te == nullptr) { return false; } @@ -223,8 +227,8 @@ static void unlink_action_fn(bContext *C, TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data)) { - /* just set action to NULL */ - BKE_animdata_set_action(CTX_wm_reports(C), tsep->id, NULL); + /* just set action to nullptr */ + BKE_animdata_set_action(CTX_wm_reports(C), tsep->id, nullptr); } static void unlink_material_fn(bContext *UNUSED(C), @@ -235,7 +239,7 @@ static void unlink_material_fn(bContext *UNUSED(C), TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data)) { - Material **matar = NULL; + Material **matar = nullptr; int a, totcol = 0; if (GS(tsep->id->name) == ID_OB) { @@ -277,11 +281,11 @@ static void unlink_material_fn(bContext *UNUSED(C), BLI_assert(0); } - if (LIKELY(matar != NULL)) { + if (LIKELY(matar != nullptr)) { for (a = 0; a < totcol; a++) { if (a == te->index && matar[a]) { id_us_min(&matar[a]->id); - matar[a] = NULL; + matar[a] = nullptr; } } } @@ -295,7 +299,7 @@ static void unlink_texture_fn(bContext *UNUSED(C), TreeStoreElem *UNUSED(tselem), void *UNUSED(user_data)) { - MTex **mtex = NULL; + MTex **mtex = nullptr; int a; if (GS(tsep->id->name) == ID_LS) { @@ -310,7 +314,7 @@ static void unlink_texture_fn(bContext *UNUSED(C), if (a == te->index && mtex[a]) { if (mtex[a]->tex) { id_us_min(&mtex[a]->tex->id); - mtex[a]->tex = NULL; + mtex[a]->tex = nullptr; } } } @@ -330,7 +334,7 @@ static void unlink_collection_fn(bContext *C, if (tsep) { if (GS(tsep->id->name) == ID_OB) { Object *ob = (Object *)tsep->id; - ob->instance_collection = NULL; + ob->instance_collection = nullptr; DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM); DEG_relations_tag_update(bmain); } @@ -369,7 +373,7 @@ static void unlink_object_fn(bContext *C, TreeElement *te_parent = te->parent; while (tsep && GS(tsep->id->name) == ID_OB) { te_parent = te_parent->parent; - tsep = te_parent ? TREESTORE(te_parent) : NULL; + tsep = te_parent ? TREESTORE(te_parent) : nullptr; } } @@ -404,7 +408,7 @@ static void unlink_world_fn(bContext *UNUSED(C), /* need to use parent scene not just scene, otherwise may end up getting wrong one */ id_us_min(&wo->id); - parscene->world = NULL; + parscene->world = nullptr; } static void outliner_do_libdata_operation(bContext *C, @@ -420,7 +424,7 @@ static void outliner_do_libdata_operation(bContext *C, if (tselem->flag & TSE_SELECTED) { if (((tselem->type == TSE_SOME_ID) && (te->idcode != 0)) || tselem->type == TSE_LAYER_COLLECTION) { - TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL; + TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : nullptr; operation_fn(C, reports, scene, te, tsep, tselem, user_data); } } @@ -437,13 +441,13 @@ static void outliner_do_libdata_operation(bContext *C, /** \name Scene Menu Operator * \{ */ -typedef enum eOutliner_PropSceneOps { +enum eOutliner_PropSceneOps { OL_SCENE_OP_DELETE = 1, -} eOutliner_PropSceneOps; +}; static const EnumPropertyItem prop_scene_op_types[] = { {OL_SCENE_OP_DELETE, "DELETE", ICON_X, "Delete", ""}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; static bool outliner_do_scene_operation( @@ -488,7 +492,7 @@ static bool scene_fn(bContext *C, static int outliner_scene_operation_exec(bContext *C, wmOperator *op) { SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); - const eOutliner_PropSceneOps event = RNA_enum_get(op->ptr, "type"); + const eOutliner_PropSceneOps event = (eOutliner_PropSceneOps)RNA_enum_get(op->ptr, "type"); if (outliner_do_scene_operation(C, event, &space_outliner->tree, scene_fn) == false) { return OPERATOR_CANCELLED; @@ -534,10 +538,10 @@ void OUTLINER_OT_scene_operation(wmOperatorType *ot) * the merged select popup menu. The sub-tree of the parent is searched and * the child is needed to only show elements of the same type in the popup. */ -typedef struct MergedSearchData { +struct MergedSearchData { TreeElement *parent_element; TreeElement *select_element; -} MergedSearchData; +}; static void merged_element_search_fn_recursive( const ListBase *tree, short tselem_type, short type, const char *str, uiSearchItems *items) @@ -615,13 +619,13 @@ static uiBlock *merged_element_search_menu(bContext *C, ARegion *region, void *d but = uiDefSearchBut( block, search, 0, ICON_VIEWZOOM, sizeof(search), 10, 10, menu_width, UI_UNIT_Y, 0, 0, ""); UI_but_func_search_set(but, - NULL, + nullptr, merged_element_search_update_fn, data, false, - NULL, + nullptr, merged_element_search_exec_fn, - NULL); + nullptr); UI_but_flag_enable(but, UI_BUT_ACTIVATE_ON_INIT); /* Fake button to hold space for search items */ @@ -633,15 +637,16 @@ static uiBlock *merged_element_search_menu(bContext *C, ARegion *region, void *d 10 - UI_searchbox_size_y(), menu_width, UI_searchbox_size_y(), - NULL, + nullptr, 0, 0, 0, 0, - NULL); + nullptr); /* Center the menu on the cursor */ - UI_block_bounds_set_popup(block, 6, (const int[2]){-(menu_width / 2), 0}); + const int offset[2] = {-(menu_width / 2), 0}; + UI_block_bounds_set_popup(block, 6, offset); return block; } @@ -650,7 +655,7 @@ void merged_element_search_menu_invoke(bContext *C, TreeElement *parent_te, TreeElement *activate_te) { - MergedSearchData *select_data = MEM_callocN(sizeof(MergedSearchData), "merge_search_data"); + MergedSearchData *select_data = MEM_cnew<MergedSearchData>("merge_search_data"); select_data->parent_element = parent_te; select_data->select_element = activate_te; @@ -773,7 +778,7 @@ static void object_proxy_to_override_convert_fn(bContext *C, Object *ob_proxy = (Object *)id_proxy; Scene *scene = CTX_data_scene(C); - if (ob_proxy->proxy == NULL) { + if (ob_proxy->proxy == nullptr) { return; } @@ -788,17 +793,17 @@ static void object_proxy_to_override_convert_fn(bContext *C, } DEG_id_tag_update(&scene->id, ID_RECALC_BASE_FLAGS | ID_RECALC_COPY_ON_WRITE); - WM_event_add_notifier(C, NC_WINDOW, NULL); + WM_event_add_notifier(C, NC_WINDOW, nullptr); } -typedef struct OutlinerLibOverrideData { +struct OutlinerLibOverrideData { bool do_hierarchy; /** * For resync operation, force keeping newly created override IDs (or original linked IDs) * instead of re-applying relevant existing ID pointer property override operations. Helps * solving broken overrides while not losing *all* of your overrides. */ bool do_resync_hierarchy_enforce; -} OutlinerLibOverrideData; +}; static void id_override_library_create_fn(bContext *C, ReportList *reports, @@ -810,14 +815,14 @@ static void id_override_library_create_fn(bContext *C, { BLI_assert(TSE_IS_REAL_ID(tselem)); ID *id_root = tselem->id; - OutlinerLibOverrideData *data = user_data; + OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data); const bool do_hierarchy = data->do_hierarchy; bool success = false; - ID *id_reference = NULL; + ID *id_reference = nullptr; bool is_override_instancing_object = false; - if (tsep != NULL && tsep->type == TSE_SOME_ID && tsep->id != NULL && - GS(tsep->id->name) == ID_OB) { + if (tsep != nullptr && tsep->type == TSE_SOME_ID && tsep->id != nullptr && + GS(tsep->id->name) == ID_OB && !ID_IS_OVERRIDE_LIBRARY(tsep->id)) { Object *ob = (Object *)tsep->id; if (ob->type == OB_EMPTY && &ob->instance_collection->id == id_root) { BLI_assert(GS(id_root->name) == ID_GR); @@ -847,7 +852,7 @@ static void id_override_library_create_fn(bContext *C, if (do_hierarchy) { /* Tag all linked parents in tree hierarchy to be also overridden. */ - while ((te = te->parent) != NULL) { + while ((te = te->parent) != nullptr) { if (!TSE_IS_REAL_ID(te->store_elem)) { continue; } @@ -869,10 +874,10 @@ static void id_override_library_create_fn(bContext *C, } success = BKE_lib_override_library_create( - bmain, CTX_data_scene(C), CTX_data_view_layer(C), id_root, id_reference, NULL); + bmain, CTX_data_scene(C), CTX_data_view_layer(C), id_root, id_reference, nullptr); } else if (ID_IS_OVERRIDABLE_LIBRARY(id_root)) { - success = BKE_lib_override_library_create_from_id(bmain, id_root, true) != NULL; + success = BKE_lib_override_library_create_from_id(bmain, id_root, true) != nullptr; /* Cleanup. */ BKE_main_id_newptr_and_tag_clear(bmain); @@ -903,7 +908,7 @@ static void id_override_library_reset_fn(bContext *C, { BLI_assert(TSE_IS_REAL_ID(tselem)); ID *id_root = tselem->id; - OutlinerLibOverrideData *data = user_data; + OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data); const bool do_hierarchy = data->do_hierarchy; if (ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) { @@ -916,8 +921,8 @@ static void id_override_library_reset_fn(bContext *C, BKE_lib_override_library_id_reset(bmain, id_root); } - WM_event_add_notifier(C, NC_WM | ND_DATACHANGED, NULL); - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, NULL); + WM_event_add_notifier(C, NC_WM | ND_DATACHANGED, nullptr); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_VIEW3D, nullptr); } else { CLOG_WARN(&LOG, "Could not reset library override of data block '%s'", id_root->name); @@ -934,7 +939,7 @@ static void id_override_library_resync_fn(bContext *C, { BLI_assert(TSE_IS_REAL_ID(tselem)); ID *id_root = tselem->id; - OutlinerLibOverrideData *data = user_data; + OutlinerLibOverrideData *data = reinterpret_cast<OutlinerLibOverrideData *>(user_data); const bool do_hierarchy_enforce = data->do_resync_hierarchy_enforce; if (ID_IS_OVERRIDE_LIBRARY_REAL(id_root)) { @@ -943,7 +948,7 @@ static void id_override_library_resync_fn(bContext *C, id_root->tag |= LIB_TAG_DOIT; /* Tag all linked parents in tree hierarchy to be also overridden. */ - while ((te = te->parent) != NULL) { + while ((te = te->parent) != nullptr) { if (!TSE_IS_REAL_ID(te->store_elem)) { continue; } @@ -953,16 +958,12 @@ static void id_override_library_resync_fn(bContext *C, te->store_elem->id->tag |= LIB_TAG_DOIT; } - BKE_lib_override_library_resync(bmain, - scene, - CTX_data_view_layer(C), - id_root, - NULL, - do_hierarchy_enforce, - true, - &(struct BlendFileReadReport){.reports = reports}); + BlendFileReadReport report{}; + report.reports = reports; + BKE_lib_override_library_resync( + bmain, scene, CTX_data_view_layer(C), id_root, nullptr, do_hierarchy_enforce, &report); - WM_event_add_notifier(C, NC_WINDOW, NULL); + WM_event_add_notifier(C, NC_WINDOW, nullptr); } else { CLOG_WARN(&LOG, "Could not resync library override of data block '%s'", id_root->name); @@ -986,7 +987,7 @@ static void id_override_library_delete_fn(bContext *C, id_root->tag |= LIB_TAG_DOIT; /* Tag all linked parents in tree hierarchy to be also overridden. */ - while ((te = te->parent) != NULL) { + while ((te = te->parent) != nullptr) { if (!TSE_IS_REAL_ID(te->store_elem)) { continue; } @@ -998,7 +999,7 @@ static void id_override_library_delete_fn(bContext *C, BKE_lib_override_library_delete(bmain, id_root); - WM_event_add_notifier(C, NC_WINDOW, NULL); + WM_event_add_notifier(C, NC_WINDOW, nullptr); } else { CLOG_WARN(&LOG, "Could not delete library override of data block '%s'", id_root->name); @@ -1062,7 +1063,7 @@ static void singleuser_action_fn(bContext *C, if (id) { IdAdtTemplate *iat = (IdAdtTemplate *)tsep->id; - PointerRNA ptr = {NULL}; + PointerRNA ptr = {nullptr}; PropertyRNA *prop; RNA_pointer_create(&iat->id, &RNA_AnimData, iat->adt, &ptr); @@ -1085,7 +1086,7 @@ static void singleuser_world_fn(bContext *C, /* need to use parent scene not just scene, otherwise may end up getting wrong one */ if (id) { Scene *parscene = (Scene *)tsep->id; - PointerRNA ptr = {NULL}; + PointerRNA ptr = {nullptr}; PropertyRNA *prop; RNA_id_pointer_create(&parscene->id, &ptr); @@ -1115,10 +1116,10 @@ void outliner_do_object_operation_ex(bContext *C, WM_window_set_active_scene(CTX_data_main(C), C, CTX_wm_window(C), scene_owner); } /* Important to use 'scene_owner' not scene_act else deleting objects can crash. - * only use 'scene_act' when 'scene_owner' is NULL, which can happen when the + * only use 'scene_act' when 'scene_owner' is nullptr, which can happen when the * outliner isn't showing scenes: Visible Layer draw mode for eg. */ operation_fn( - C, reports, scene_owner ? scene_owner : scene_act, te, NULL, tselem, user_data); + C, reports, scene_owner ? scene_owner : scene_act, te, nullptr, tselem, user_data); select_handled = true; } } @@ -1130,7 +1131,7 @@ void outliner_do_object_operation_ex(bContext *C, space_outliner, &te->subtree, operation_fn, - NULL, + nullptr, recurse_selected); } } @@ -1145,7 +1146,7 @@ void outliner_do_object_operation(bContext *C, outliner_operation_fn operation_fn) { outliner_do_object_operation_ex( - C, reports, scene_act, space_outliner, lb, operation_fn, NULL, true); + C, reports, scene_act, space_outliner, lb, operation_fn, nullptr, true); } /** \} */ @@ -1168,8 +1169,8 @@ static void unlinkact_animdata_fn(int UNUSED(event), TreeStoreElem *tselem, void *UNUSED(arg)) { - /* just set action to NULL */ - BKE_animdata_set_action(NULL, tselem->id, NULL); + /* just set action to nullptr */ + BKE_animdata_set_action(nullptr, tselem->id, nullptr); DEG_id_tag_update(tselem->id, ID_RECALC_ANIMATION); } @@ -1209,25 +1210,25 @@ static void refreshdrivers_animdata_fn(int UNUSED(event), /** \name Object Operation Utilities * \{ */ -typedef enum eOutliner_PropDataOps { +enum eOutliner_PropDataOps { OL_DOP_SELECT = 1, OL_DOP_DESELECT, OL_DOP_HIDE, OL_DOP_UNHIDE, OL_DOP_SELECT_LINKED, -} eOutliner_PropDataOps; +}; -typedef enum eOutliner_PropConstraintOps { +enum eOutliner_PropConstraintOps { OL_CONSTRAINTOP_ENABLE = 1, OL_CONSTRAINTOP_DISABLE, OL_CONSTRAINTOP_DELETE, -} eOutliner_PropConstraintOps; +}; -typedef enum eOutliner_PropModifierOps { +enum eOutliner_PropModifierOps { OL_MODIFIER_OP_TOGVIS = 1, OL_MODIFIER_OP_TOGREN, OL_MODIFIER_OP_DELETE, -} eOutliner_PropModifierOps; +}; static void pchan_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg)) { @@ -1288,7 +1289,8 @@ static void ebone_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), static void sequence_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *scene_ptr) { - Sequence *seq = (Sequence *)te->directdata; + TreeElementSequence *te_seq = tree_element_cast<TreeElementSequence>(te); + Sequence *seq = &te_seq->getSequence(); Scene *scene = (Scene *)scene_ptr; Editing *ed = SEQ_editing_get(scene); if (BLI_findindex(ed->seqbasep, seq) != -1) { @@ -1339,10 +1341,16 @@ static void data_select_linked_fn(int event, TreeStoreElem *UNUSED(tselem), void *C_v) { + const TreeElementRNAStruct *te_rna_struct = tree_element_cast<TreeElementRNAStruct>(te); + if (!te_rna_struct) { + return; + } + if (event == OL_DOP_SELECT_LINKED) { - if (RNA_struct_is_ID(te->rnaptr.type)) { + const PointerRNA &ptr = te_rna_struct->getPointerRNA(); + if (RNA_struct_is_ID(ptr.type)) { bContext *C = (bContext *)C_v; - ID *id = te->rnaptr.data; + ID *id = reinterpret_cast<ID *>(ptr.data); ED_object_select_linked_by_id(C, id); } @@ -1351,7 +1359,7 @@ static void data_select_linked_fn(int event, static void constraint_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *C_v) { - bContext *C = C_v; + bContext *C = reinterpret_cast<bContext *>(C_v); Main *bmain = CTX_data_main(C); bConstraint *constraint = (bConstraint *)te->directdata; Object *ob = (Object *)outliner_search_back(te, ID_OB); @@ -1367,7 +1375,7 @@ static void constraint_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tsel WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob); } else if (event == OL_CONSTRAINTOP_DELETE) { - ListBase *lb = NULL; + ListBase *lb = nullptr; if (TREESTORE(te->parent->parent)->type == TSE_POSE_CHANNEL) { lb = &((bPoseChannel *)te->parent->parent->directdata)->constraints; @@ -1378,7 +1386,7 @@ static void constraint_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tsel if (BKE_constraint_remove_ex(lb, ob, constraint, true)) { /* there's no active constraint now, so make sure this is the case */ - BKE_constraints_active_set(&ob->constraints, NULL); + BKE_constraints_active_set(&ob->constraints, nullptr); /* needed to set the flags on posebones correctly */ ED_object_constraint_update(bmain, ob); @@ -1408,7 +1416,7 @@ static void modifier_fn(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob); } else if (event == OL_MODIFIER_OP_DELETE) { - ED_object_modifier_remove(NULL, bmain, scene, ob, md); + ED_object_modifier_remove(nullptr, bmain, scene, ob, md); WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER | NA_REMOVED, ob); te->store_elem->flag &= ~TSE_SELECTED; } @@ -1442,11 +1450,12 @@ static Base *outliner_batch_delete_hierarchy( Object *object, *parent; if (!base) { - return NULL; + return nullptr; } object = base->object; - for (child_base = view_layer->object_bases.first; child_base; child_base = base_next) { + for (child_base = reinterpret_cast<Base *>(view_layer->object_bases.first); child_base; + child_base = base_next) { base_next = child_base->next; for (parent = child_base->object->parent; parent && (parent != object); parent = parent->parent) { @@ -1540,7 +1549,7 @@ static const EnumPropertyItem prop_object_op_types[] = { 0, "Convert Proxy to Override", "Convert a Proxy object to a full library override, including all its dependencies"}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; static int outliner_object_operation_exec(bContext *C, wmOperator *op) @@ -1550,11 +1559,11 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) wmWindow *win = CTX_wm_window(C); SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); int event; - const char *str = NULL; + const char *str = nullptr; bool selection_changed = false; /* check for invalid states */ - if (space_outliner == NULL) { + if (space_outliner == nullptr) { return OPERATOR_CANCELLED; } @@ -1579,7 +1588,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) space_outliner, &space_outliner->tree, object_select_hierarchy_fn, - NULL, + nullptr, false); if (scene != sce) { WM_window_set_active_scene(bmain, C, win, sce); @@ -1595,7 +1604,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) } else if (event == OL_OP_REMAP) { outliner_do_libdata_operation( - C, op->reports, scene, space_outliner, &space_outliner->tree, id_remap_fn, NULL); + C, op->reports, scene, space_outliner, &space_outliner->tree, id_remap_fn, nullptr); /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth * trick does not work here). */ } @@ -1624,7 +1633,7 @@ static int outliner_object_operation_exec(bContext *C, wmOperator *op) ED_outliner_select_sync_from_object_tag(C); } - if (str != NULL) { + if (str != nullptr) { ED_undo_push(C, str); } @@ -1653,13 +1662,13 @@ void OUTLINER_OT_object_operation(wmOperatorType *ot) /** \name Delete Object/Collection Operator * \{ */ -typedef void (*OutlinerDeleteFunc)(bContext *C, ReportList *reports, Scene *scene, Object *ob); +using OutlinerDeleteFn = void (*)(bContext *C, ReportList *reports, Scene *scene, Object *ob); static void outliner_do_object_delete(bContext *C, ReportList *reports, Scene *scene, GSet *objects_to_delete, - OutlinerDeleteFunc delete_fn) + OutlinerDeleteFn delete_fn) { GSetIterator objects_to_delete_iter; GSET_ITER (objects_to_delete_iter, objects_to_delete) { @@ -1678,7 +1687,8 @@ static TreeTraversalAction outliner_find_objects_to_delete(TreeElement *te, void return TRAVERSE_CONTINUE; } - if ((tselem->type != TSE_SOME_ID) || (tselem->id == NULL) || (GS(tselem->id->name) != ID_OB)) { + if ((tselem->type != TSE_SOME_ID) || (tselem->id == nullptr) || + (GS(tselem->id->name) != ID_OB)) { return TRAVERSE_SKIP_CHILDS; } @@ -1687,6 +1697,8 @@ static TreeTraversalAction outliner_find_objects_to_delete(TreeElement *te, void return TRAVERSE_CONTINUE; } +/* FIXME: See comment above #WM_msg_publish_rna_prop(). */ +extern "C" { static int outliner_delete_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); @@ -1720,7 +1732,7 @@ static int outliner_delete_exec(bContext *C, wmOperator *op) outliner_do_object_delete(C, op->reports, scene, objects_to_delete, outliner_object_delete_fn); } - BLI_gset_free(objects_to_delete, NULL); + BLI_gset_free(objects_to_delete, nullptr); outliner_collection_delete(C, bmain, scene, op->reports, delete_hierarchy); @@ -1746,6 +1758,7 @@ static int outliner_delete_exec(bContext *C, wmOperator *op) return OPERATOR_FINISHED; } +} void OUTLINER_OT_delete(wmOperatorType *ot) { @@ -1773,7 +1786,7 @@ void OUTLINER_OT_delete(wmOperatorType *ot) /** \name ID-Data Menu Operator * \{ */ -typedef enum eOutlinerIdOpTypes { +enum eOutlinerIdOpTypes { OUTLINER_IDOP_INVALID = 0, OUTLINER_IDOP_UNLINK, @@ -1798,7 +1811,7 @@ typedef enum eOutlinerIdOpTypes { OUTLINER_IDOP_RENAME, OUTLINER_IDOP_SELECT_LINKED, -} eOutlinerIdOpTypes; +}; /* TODO: implement support for changing the ID-block used. */ static const EnumPropertyItem prop_id_op_types[] = { @@ -1811,7 +1824,7 @@ static const EnumPropertyItem prop_id_op_types[] = { 0, "Remap Users", "Make all users of selected data-blocks to use instead current (clicked) one"}, - {0, "", 0, NULL, NULL}, + {0, "", 0, nullptr, nullptr}, {OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE, "OVERRIDE_LIBRARY_CREATE", 0, @@ -1856,10 +1869,10 @@ static const EnumPropertyItem prop_id_op_types[] = { "Delete Library Override Hierarchy", "Delete this local override (including its hierarchy of override dependencies) and relink " "its usages to the linked data-blocks"}, - {0, "", 0, NULL, NULL}, + {0, "", 0, nullptr, nullptr}, {OUTLINER_IDOP_COPY, "COPY", ICON_COPYDOWN, "Copy", ""}, {OUTLINER_IDOP_PASTE, "PASTE", ICON_PASTEDOWN, "Paste", ""}, - {0, "", 0, NULL, NULL}, + {0, "", 0, nullptr, nullptr}, {OUTLINER_IDOP_FAKE_ADD, "ADD_FAKE", 0, @@ -1869,7 +1882,7 @@ static const EnumPropertyItem prop_id_op_types[] = { {OUTLINER_IDOP_FAKE_CLEAR, "CLEAR_FAKE", 0, "Clear Fake User", ""}, {OUTLINER_IDOP_RENAME, "RENAME", 0, "Rename", ""}, {OUTLINER_IDOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; static bool outliner_id_operation_item_poll(bContext *C, @@ -1903,7 +1916,7 @@ static bool outliner_id_operation_item_poll(bContext *C, if (GS(tselem->id->name) == ID_OB) { Object *ob = (Object *)tselem->id; - if ((ob != NULL) && (ob->proxy != NULL)) { + if ((ob != nullptr) && (ob->proxy != nullptr)) { return true; } } @@ -1935,13 +1948,13 @@ static const EnumPropertyItem *outliner_id_operation_itemf(bContext *C, PropertyRNA *prop, bool *r_free) { - EnumPropertyItem *items = NULL; + EnumPropertyItem *items = nullptr; int totitem = 0; - if ((C == NULL) || (ED_operator_outliner_active(C) == false)) { + if ((C == nullptr) || (ED_operator_outliner_active(C) == false)) { return prop_id_op_types; } - for (const EnumPropertyItem *it = prop_id_op_types; it->identifier != NULL; it++) { + for (const EnumPropertyItem *it = prop_id_op_types; it->identifier != nullptr; it++) { if (!outliner_id_operation_item_poll(C, ptr, prop, it->value)) { continue; } @@ -1961,22 +1974,27 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; /* check for invalid states */ - if (space_outliner == NULL) { + if (space_outliner == nullptr) { return OPERATOR_CANCELLED; } TreeElement *te = get_target_element(space_outliner); get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel); - eOutlinerIdOpTypes event = RNA_enum_get(op->ptr, "type"); + eOutlinerIdOpTypes event = (eOutlinerIdOpTypes)RNA_enum_get(op->ptr, "type"); switch (event) { case OUTLINER_IDOP_UNLINK: { /* unlink datablock from its parent */ if (objectlevel) { - outliner_do_libdata_operation( - C, op->reports, scene, space_outliner, &space_outliner->tree, unlink_object_fn, NULL); - - WM_event_add_notifier(C, NC_SCENE | ND_LAYER, NULL); + outliner_do_libdata_operation(C, + op->reports, + scene, + space_outliner, + &space_outliner->tree, + unlink_object_fn, + nullptr); + + WM_event_add_notifier(C, NC_SCENE | ND_LAYER, nullptr); ED_undo_push(C, "Unlink Object"); break; } @@ -1989,9 +2007,9 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) space_outliner, &space_outliner->tree, unlink_action_fn, - NULL); + nullptr); - WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, nullptr); ED_undo_push(C, "Unlink action"); break; case ID_MA: @@ -2001,9 +2019,9 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) space_outliner, &space_outliner->tree, unlink_material_fn, - NULL); + nullptr); - WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, nullptr); ED_undo_push(C, "Unlink material"); break; case ID_TE: @@ -2013,16 +2031,21 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) space_outliner, &space_outliner->tree, unlink_texture_fn, - NULL); + nullptr); - WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, NULL); + WM_event_add_notifier(C, NC_OBJECT | ND_OB_SHADING, nullptr); ED_undo_push(C, "Unlink texture"); break; case ID_WO: - outliner_do_libdata_operation( - C, op->reports, scene, space_outliner, &space_outliner->tree, unlink_world_fn, NULL); + outliner_do_libdata_operation(C, + op->reports, + scene, + space_outliner, + &space_outliner->tree, + unlink_world_fn, + nullptr); - WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL); + WM_event_add_notifier(C, NC_SCENE | ND_WORLD, nullptr); ED_undo_push(C, "Unlink world"); break; case ID_GR: @@ -2032,9 +2055,9 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) space_outliner, &space_outliner->tree, unlink_collection_fn, - NULL); + nullptr); - WM_event_add_notifier(C, NC_SCENE | ND_LAYER, NULL); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER, nullptr); ED_undo_push(C, "Unlink Collection"); break; default: @@ -2046,29 +2069,32 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) case OUTLINER_IDOP_LOCAL: { /* make local */ outliner_do_libdata_operation( - C, op->reports, scene, space_outliner, &space_outliner->tree, id_local_fn, NULL); + C, op->reports, scene, space_outliner, &space_outliner->tree, id_local_fn, nullptr); ED_undo_push(C, "Localized Data"); break; } case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE: { + OutlinerLibOverrideData override_data{}; outliner_do_libdata_operation(C, op->reports, scene, space_outliner, &space_outliner->tree, id_override_library_create_fn, - &(OutlinerLibOverrideData){.do_hierarchy = false}); + &override_data); ED_undo_push(C, "Overridden Data"); break; } case OUTLINER_IDOP_OVERRIDE_LIBRARY_CREATE_HIERARCHY: { + OutlinerLibOverrideData override_data{}; + override_data.do_hierarchy = true; outliner_do_libdata_operation(C, op->reports, scene, space_outliner, &space_outliner->tree, id_override_library_create_fn, - &(OutlinerLibOverrideData){.do_hierarchy = true}); + &override_data); ED_undo_push(C, "Overridden Data Hierarchy"); break; } @@ -2083,58 +2109,67 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) break; } case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET: { + OutlinerLibOverrideData override_data{}; outliner_do_libdata_operation(C, op->reports, scene, space_outliner, &space_outliner->tree, id_override_library_reset_fn, - &(OutlinerLibOverrideData){.do_hierarchy = false}); + &override_data); ED_undo_push(C, "Reset Overridden Data"); break; } case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESET_HIERARCHY: { + OutlinerLibOverrideData override_data{}; + override_data.do_hierarchy = true; outliner_do_libdata_operation(C, op->reports, scene, space_outliner, &space_outliner->tree, id_override_library_reset_fn, - &(OutlinerLibOverrideData){.do_hierarchy = true}); + &override_data); ED_undo_push(C, "Reset Overridden Data Hierarchy"); break; } case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY: { + OutlinerLibOverrideData override_data{}; + override_data.do_hierarchy = true; outliner_do_libdata_operation(C, op->reports, scene, space_outliner, &space_outliner->tree, id_override_library_resync_fn, - &(OutlinerLibOverrideData){.do_hierarchy = true}); + &override_data); ED_undo_push(C, "Resync Overridden Data Hierarchy"); break; } case OUTLINER_IDOP_OVERRIDE_LIBRARY_RESYNC_HIERARCHY_ENFORCE: { - outliner_do_libdata_operation( - C, - op->reports, - scene, - space_outliner, - &space_outliner->tree, - id_override_library_resync_fn, - &(OutlinerLibOverrideData){.do_hierarchy = true, .do_resync_hierarchy_enforce = true}); + OutlinerLibOverrideData override_data{}; + override_data.do_hierarchy = true; + override_data.do_resync_hierarchy_enforce = true; + outliner_do_libdata_operation(C, + op->reports, + scene, + space_outliner, + &space_outliner->tree, + id_override_library_resync_fn, + &override_data); ED_undo_push(C, "Resync Overridden Data Hierarchy"); break; } case OUTLINER_IDOP_OVERRIDE_LIBRARY_DELETE_HIERARCHY: { + OutlinerLibOverrideData override_data{}; + override_data.do_hierarchy = true; outliner_do_libdata_operation(C, op->reports, scene, space_outliner, &space_outliner->tree, id_override_library_delete_fn, - &(OutlinerLibOverrideData){.do_hierarchy = true}); + &override_data); ED_undo_push(C, "Delete Overridden Data Hierarchy"); break; } @@ -2148,9 +2183,9 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) space_outliner, &space_outliner->tree, singleuser_action_fn, - NULL); + nullptr); - WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, nullptr); ED_undo_push(C, "Single-User Action"); break; @@ -2161,9 +2196,9 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) space_outliner, &space_outliner->tree, singleuser_world_fn, - NULL); + nullptr); - WM_event_add_notifier(C, NC_SCENE | ND_WORLD, NULL); + WM_event_add_notifier(C, NC_SCENE | ND_WORLD, nullptr); ED_undo_push(C, "Single-User World"); break; @@ -2176,7 +2211,7 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) case OUTLINER_IDOP_DELETE: { if (idlevel > 0) { outliner_do_libdata_operation( - C, op->reports, scene, space_outliner, &space_outliner->tree, id_delete_fn, NULL); + C, op->reports, scene, space_outliner, &space_outliner->tree, id_delete_fn, nullptr); ED_undo_push(C, "Delete"); } break; @@ -2184,7 +2219,7 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) case OUTLINER_IDOP_REMAP: { if (idlevel > 0) { outliner_do_libdata_operation( - C, op->reports, scene, space_outliner, &space_outliner->tree, id_remap_fn, NULL); + C, op->reports, scene, space_outliner, &space_outliner->tree, id_remap_fn, nullptr); /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth * trick does not work here). */ } @@ -2192,14 +2227,14 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) } case OUTLINER_IDOP_COPY: { wm->op_undo_depth++; - WM_operator_name_call(C, "OUTLINER_OT_id_copy", WM_OP_INVOKE_DEFAULT, NULL); + WM_operator_name_call(C, "OUTLINER_OT_id_copy", WM_OP_INVOKE_DEFAULT, nullptr); wm->op_undo_depth--; /* No need for undo, this operation does not change anything... */ break; } case OUTLINER_IDOP_PASTE: { wm->op_undo_depth++; - WM_operator_name_call(C, "OUTLINER_OT_id_paste", WM_OP_INVOKE_DEFAULT, NULL); + WM_operator_name_call(C, "OUTLINER_OT_id_paste", WM_OP_INVOKE_DEFAULT, nullptr); wm->op_undo_depth--; ED_outliner_select_sync_from_all_tag(C); ED_undo_push(C, "Paste"); @@ -2207,10 +2242,15 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) } case OUTLINER_IDOP_FAKE_ADD: { /* set fake user */ - outliner_do_libdata_operation( - C, op->reports, scene, space_outliner, &space_outliner->tree, id_fake_user_set_fn, NULL); + outliner_do_libdata_operation(C, + op->reports, + scene, + space_outliner, + &space_outliner->tree, + id_fake_user_set_fn, + nullptr); - WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); + WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr); ED_undo_push(C, "Add Fake User"); break; } @@ -2222,24 +2262,29 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) space_outliner, &space_outliner->tree, id_fake_user_clear_fn, - NULL); + nullptr); - WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); + WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr); ED_undo_push(C, "Clear Fake User"); break; } case OUTLINER_IDOP_RENAME: { /* rename */ outliner_do_libdata_operation( - C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn, NULL); + C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn, nullptr); - WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); + WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr); ED_undo_push(C, "Rename"); break; } case OUTLINER_IDOP_SELECT_LINKED: - outliner_do_libdata_operation( - C, op->reports, scene, space_outliner, &space_outliner->tree, id_select_linked_fn, NULL); + outliner_do_libdata_operation(C, + op->reports, + scene, + space_outliner, + &space_outliner->tree, + id_select_linked_fn, + nullptr); ED_outliner_select_sync_from_all_tag(C); ED_undo_push(C, "Select"); break; @@ -2250,10 +2295,10 @@ static int outliner_id_operation_exec(bContext *C, wmOperator *op) } /* wrong notifier still... */ - WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); + WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr); /* XXX: this is just so that outliner is always up to date. */ - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, nullptr); return OPERATOR_FINISHED; } @@ -2281,14 +2326,14 @@ void OUTLINER_OT_id_operation(wmOperatorType *ot) /** \name Library Menu Operator * \{ */ -typedef enum eOutlinerLibOpTypes { +enum eOutlinerLibOpTypes { OL_LIB_INVALID = 0, OL_LIB_RENAME, OL_LIB_DELETE, OL_LIB_RELOCATE, OL_LIB_RELOAD, -} eOutlinerLibOpTypes; +}; static const EnumPropertyItem outliner_lib_op_type_items[] = { {OL_LIB_RENAME, "RENAME", 0, "Rename", ""}, @@ -2304,7 +2349,7 @@ static const EnumPropertyItem outliner_lib_op_type_items[] = { "Relocate", "Select a new path for this library, and reload all its data"}, {OL_LIB_RELOAD, "RELOAD", ICON_FILE_REFRESH, "Reload", "Reload all data from this library"}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; static int outliner_lib_operation_exec(bContext *C, wmOperator *op) @@ -2314,39 +2359,39 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op) int scenelevel = 0, objectlevel = 0, idlevel = 0, datalevel = 0; /* check for invalid states */ - if (space_outliner == NULL) { + if (space_outliner == nullptr) { return OPERATOR_CANCELLED; } TreeElement *te = get_target_element(space_outliner); get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel); - eOutlinerLibOpTypes event = RNA_enum_get(op->ptr, "type"); + eOutlinerLibOpTypes event = (eOutlinerLibOpTypes)RNA_enum_get(op->ptr, "type"); switch (event) { case OL_LIB_RENAME: { outliner_do_libdata_operation( - C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn, NULL); + C, op->reports, scene, space_outliner, &space_outliner->tree, item_rename_fn, nullptr); - WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); + WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr); ED_undo_push(C, "Rename Library"); break; } case OL_LIB_DELETE: { outliner_do_libdata_operation( - C, op->reports, scene, space_outliner, &space_outliner->tree, id_delete_fn, NULL); + C, op->reports, scene, space_outliner, &space_outliner->tree, id_delete_fn, nullptr); ED_undo_push(C, "Delete Library"); break; } case OL_LIB_RELOCATE: { outliner_do_libdata_operation( - C, op->reports, scene, space_outliner, &space_outliner->tree, lib_relocate_fn, NULL); + C, op->reports, scene, space_outliner, &space_outliner->tree, lib_relocate_fn, nullptr); /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth * trick does not work here). */ break; } case OL_LIB_RELOAD: { outliner_do_libdata_operation( - C, op->reports, scene, space_outliner, &space_outliner->tree, lib_reload_fn, NULL); + C, op->reports, scene, space_outliner, &space_outliner->tree, lib_reload_fn, nullptr); /* No undo push here, operator does it itself (since it's a modal one, the op_undo_depth * trick does not work here). */ break; @@ -2357,10 +2402,10 @@ static int outliner_lib_operation_exec(bContext *C, wmOperator *op) } /* wrong notifier still... */ - WM_event_add_notifier(C, NC_ID | NA_EDITED, NULL); + WM_event_add_notifier(C, NC_ID | NA_EDITED, nullptr); /* XXX: this is just so that outliner is always up to date */ - WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, NULL); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_OUTLINER, nullptr); return OPERATOR_FINISHED; } @@ -2397,7 +2442,7 @@ static void outliner_do_id_set_operation( TreeStoreElem *tselem = TREESTORE(te); if (tselem->flag & TSE_SELECTED) { if (tselem->type == type) { - TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : NULL; + TreeStoreElem *tsep = te->parent ? TREESTORE(te->parent) : nullptr; operation_fn(te, tselem, tsep, newid); } } @@ -2416,14 +2461,14 @@ static void actionset_id_fn(TreeElement *UNUSED(te), if (tselem->type == TSE_ANIM_DATA) { /* "animation" entries - action is child of this */ - BKE_animdata_set_action(NULL, tselem->id, act); + BKE_animdata_set_action(nullptr, tselem->id, act); } /* TODO: if any other "expander" channels which own actions need to support this menu, * add: tselem->type = ... */ else if (tsep && (tsep->type == TSE_ANIM_DATA)) { /* "animation" entries case again */ - BKE_animdata_set_action(NULL, tsep->id, act); + BKE_animdata_set_action(nullptr, tsep->id, act); } /* TODO: other cases not supported yet. */ } @@ -2439,9 +2484,10 @@ static int outliner_action_set_exec(bContext *C, wmOperator *op) get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel); /* get action to use */ - act = BLI_findlink(&bmain->actions, RNA_enum_get(op->ptr, "action")); + act = reinterpret_cast<bAction *>( + BLI_findlink(&bmain->actions, RNA_enum_get(op->ptr, "action"))); - if (act == NULL) { + if (act == nullptr) { BKE_report(op->reports, RPT_ERROR, "No valid action to add"); return OPERATOR_CANCELLED; } @@ -2470,7 +2516,7 @@ static int outliner_action_set_exec(bContext *C, wmOperator *op) } /* set notifier that things have changed */ - WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, nullptr); ED_undo_push(C, "Set action"); /* done */ @@ -2508,7 +2554,7 @@ void OUTLINER_OT_action_set(wmOperatorType *ot) /** \name Animation Menu Operator * \{ */ -typedef enum eOutliner_AnimDataOps { +enum eOutliner_AnimDataOps { OUTLINER_ANIMOP_INVALID = 0, OUTLINER_ANIMOP_CLEAR_ADT, @@ -2518,7 +2564,7 @@ typedef enum eOutliner_AnimDataOps { OUTLINER_ANIMOP_REFRESH_DRV, OUTLINER_ANIMOP_CLEAR_DRV -} eOutliner_AnimDataOps; +}; static const EnumPropertyItem prop_animdata_op_types[] = { {OUTLINER_ANIMOP_CLEAR_ADT, @@ -2530,7 +2576,7 @@ static const EnumPropertyItem prop_animdata_op_types[] = { {OUTLINER_ANIMOP_CLEAR_ACT, "CLEAR_ACT", 0, "Unlink Action", ""}, {OUTLINER_ANIMOP_REFRESH_DRV, "REFRESH_DRIVERS", 0, "Refresh Drivers", ""}, {OUTLINER_ANIMOP_CLEAR_DRV, "CLEAR_DRIVERS", 0, "Clear Drivers", ""}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; static int outliner_animdata_operation_exec(bContext *C, wmOperator *op) @@ -2546,21 +2592,21 @@ static int outliner_animdata_operation_exec(bContext *C, wmOperator *op) } /* perform the core operation */ - eOutliner_AnimDataOps event = RNA_enum_get(op->ptr, "type"); + eOutliner_AnimDataOps event = (eOutliner_AnimDataOps)RNA_enum_get(op->ptr, "type"); switch (event) { case OUTLINER_ANIMOP_CLEAR_ADT: /* Remove Animation Data - this may remove the active action, in some cases... */ outliner_do_data_operation( - space_outliner, datalevel, event, &space_outliner->tree, clear_animdata_fn, NULL); + space_outliner, datalevel, event, &space_outliner->tree, clear_animdata_fn, nullptr); - WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, nullptr); ED_undo_push(C, "Clear Animation Data"); break; case OUTLINER_ANIMOP_SET_ACT: /* delegate once again... */ wm->op_undo_depth++; - WM_operator_name_call(C, "OUTLINER_OT_action_set", WM_OP_INVOKE_REGION_WIN, NULL); + WM_operator_name_call(C, "OUTLINER_OT_action_set", WM_OP_INVOKE_REGION_WIN, nullptr); wm->op_undo_depth--; ED_undo_push(C, "Set active action"); break; @@ -2568,9 +2614,9 @@ static int outliner_animdata_operation_exec(bContext *C, wmOperator *op) case OUTLINER_ANIMOP_CLEAR_ACT: /* clear active action - using standard rules */ outliner_do_data_operation( - space_outliner, datalevel, event, &space_outliner->tree, unlinkact_animdata_fn, NULL); + space_outliner, datalevel, event, &space_outliner->tree, unlinkact_animdata_fn, nullptr); - WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_NLA_ACTCHANGE, nullptr); ED_undo_push(C, "Unlink action"); break; @@ -2580,17 +2626,21 @@ static int outliner_animdata_operation_exec(bContext *C, wmOperator *op) event, &space_outliner->tree, refreshdrivers_animdata_fn, - NULL); + nullptr); - WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, nullptr); /* ED_undo_push(C, "Refresh Drivers"); No undo needed - shouldn't have any impact? */ break; case OUTLINER_ANIMOP_CLEAR_DRV: - outliner_do_data_operation( - space_outliner, datalevel, event, &space_outliner->tree, cleardrivers_animdata_fn, NULL); + outliner_do_data_operation(space_outliner, + datalevel, + event, + &space_outliner->tree, + cleardrivers_animdata_fn, + nullptr); - WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, NULL); + WM_event_add_notifier(C, NC_ANIMATION | ND_ANIMCHAN, nullptr); ED_undo_push(C, "Clear Drivers"); break; @@ -2630,13 +2680,13 @@ static const EnumPropertyItem prop_constraint_op_types[] = { {OL_CONSTRAINTOP_ENABLE, "ENABLE", ICON_HIDE_OFF, "Enable", ""}, {OL_CONSTRAINTOP_DISABLE, "DISABLE", ICON_HIDE_ON, "Disable", ""}, {OL_CONSTRAINTOP_DELETE, "DELETE", ICON_X, "Delete", ""}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; static int outliner_constraint_operation_exec(bContext *C, wmOperator *op) { SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); - eOutliner_PropConstraintOps event = RNA_enum_get(op->ptr, "type"); + eOutliner_PropConstraintOps event = (eOutliner_PropConstraintOps)RNA_enum_get(op->ptr, "type"); outliner_do_data_operation( space_outliner, TSE_CONSTRAINT, event, &space_outliner->tree, constraint_fn, C); @@ -2677,13 +2727,13 @@ static const EnumPropertyItem prop_modifier_op_types[] = { {OL_MODIFIER_OP_TOGVIS, "TOGVIS", ICON_RESTRICT_VIEW_OFF, "Toggle Viewport Use", ""}, {OL_MODIFIER_OP_TOGREN, "TOGREN", ICON_RESTRICT_RENDER_OFF, "Toggle Render Use", ""}, {OL_MODIFIER_OP_DELETE, "DELETE", ICON_X, "Delete", ""}, - {0, NULL, 0, NULL, NULL}, + {0, nullptr, 0, nullptr, nullptr}, }; static int outliner_modifier_operation_exec(bContext *C, wmOperator *op) { SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); - eOutliner_PropModifierOps event = RNA_enum_get(op->ptr, "type"); + eOutliner_PropModifierOps event = (eOutliner_PropModifierOps)RNA_enum_get(op->ptr, "type"); outliner_do_data_operation( space_outliner, TSE_MODIFIER, event, &space_outliner->tree, modifier_fn, C); @@ -2726,28 +2776,28 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op) TreeElement *te = get_target_element(space_outliner); get_element_operation_type(te, &scenelevel, &objectlevel, &idlevel, &datalevel); - eOutliner_PropDataOps event = RNA_enum_get(op->ptr, "type"); + eOutliner_PropDataOps event = (eOutliner_PropDataOps)RNA_enum_get(op->ptr, "type"); switch (datalevel) { case TSE_POSE_CHANNEL: { outliner_do_data_operation( - space_outliner, datalevel, event, &space_outliner->tree, pchan_fn, NULL); - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); + space_outliner, datalevel, event, &space_outliner->tree, pchan_fn, nullptr); + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr); ED_undo_push(C, "PoseChannel operation"); break; } case TSE_BONE: { outliner_do_data_operation( - space_outliner, datalevel, event, &space_outliner->tree, bone_fn, NULL); - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); + space_outliner, datalevel, event, &space_outliner->tree, bone_fn, nullptr); + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr); ED_undo_push(C, "Bone operation"); break; } case TSE_EBONE: { outliner_do_data_operation( - space_outliner, datalevel, event, &space_outliner->tree, ebone_fn, NULL); - WM_event_add_notifier(C, NC_OBJECT | ND_POSE, NULL); + space_outliner, datalevel, event, &space_outliner->tree, ebone_fn, nullptr); + WM_event_add_notifier(C, NC_OBJECT | ND_POSE, nullptr); ED_undo_push(C, "EditBone operation"); break; @@ -2763,8 +2813,8 @@ static int outliner_data_operation_exec(bContext *C, wmOperator *op) } case TSE_GP_LAYER: { outliner_do_data_operation( - space_outliner, datalevel, event, &space_outliner->tree, gpencil_layer_fn, NULL); - WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, NULL); + space_outliner, datalevel, event, &space_outliner->tree, gpencil_layer_fn, nullptr); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA, nullptr); ED_undo_push(C, "Grease Pencil Layer operation"); break; @@ -2792,17 +2842,17 @@ static const EnumPropertyItem *outliner_data_op_sets_enum_item_fn(bContext *C, bool *UNUSED(r_free)) { /* Check for invalid states. */ - if (C == NULL) { + if (C == nullptr) { return DummyRNA_DEFAULT_items; } SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); - if (space_outliner == NULL) { + if (space_outliner == nullptr) { return DummyRNA_DEFAULT_items; } TreeElement *te = get_target_element(space_outliner); - if (te == NULL) { + if (te == nullptr) { return DummyRNA_NULL_items; } @@ -2813,10 +2863,11 @@ static const EnumPropertyItem *outliner_data_op_sets_enum_item_fn(bContext *C, {OL_DOP_DESELECT, "DESELECT", 0, "Deselect", ""}, {OL_DOP_HIDE, "HIDE", 0, "Hide", ""}, {OL_DOP_UNHIDE, "UNHIDE", 0, "Unhide", ""}, - {0, NULL, 0, NULL, NULL}}; + {0, nullptr, 0, nullptr, nullptr}}; static const EnumPropertyItem optype_sel_linked[] = { - {OL_DOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""}, {0, NULL, 0, NULL, NULL}}; + {OL_DOP_SELECT_LINKED, "SELECT_LINKED", 0, "Select Linked", ""}, + {0, nullptr, 0, nullptr, nullptr}}; if (tselem->type == TSE_RNA_STRUCT) { return optype_sel_linked; @@ -2851,7 +2902,7 @@ void OUTLINER_OT_data_operation(wmOperatorType *ot) static int outliner_operator_menu(bContext *C, const char *opname) { wmOperatorType *ot = WM_operatortype_find(opname, false); - uiPopupMenu *pup = UI_popup_menu_begin(C, WM_operatortype_name(ot, NULL), ICON_NONE); + uiPopupMenu *pup = UI_popup_menu_begin(C, WM_operatortype_name(ot, nullptr), ICON_NONE); uiLayout *layout = UI_popup_menu_layout(pup); /* set this so the default execution context is the same as submenus */ diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.cc index 3353726de18..eb885eba20d 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.cc @@ -21,8 +21,8 @@ * \ingroup spoutliner */ -#include <math.h> -#include <string.h> +#include <cmath> +#include <cstring> #include "MEM_guardedalloc.h" @@ -74,15 +74,19 @@ #include "RNA_access.h" #include "UI_interface.h" +#include "UI_resources.h" -#include "outliner_intern.h" -#include "tree/tree_display.h" -#include "tree/tree_element.h" +#include "outliner_intern.hh" +#include "tree/common.hh" +#include "tree/tree_display.hh" +#include "tree/tree_element.hh" #ifdef WIN32 # include "BLI_math_base.h" /* M_PI */ #endif +using namespace blender::ed::outliner; + /* prototypes */ static int outliner_exclude_filter_get(const SpaceOutliner *space_outliner); @@ -101,7 +105,7 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner) BLI_mempool_iter iter; BLI_mempool_iternew(ts, &iter); - while ((tselem = BLI_mempool_iterstep(&iter))) { + while ((tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) { tselem->used = 0; } @@ -111,8 +115,8 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner) space_outliner->storeflag &= ~SO_TREESTORE_CLEANUP; BLI_mempool_iternew(ts, &iter); - while ((tselem = BLI_mempool_iterstep(&iter))) { - if (tselem->id == NULL) { + while ((tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) { + if (tselem->id == nullptr) { unused++; } } @@ -120,10 +124,10 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner) if (unused) { if (BLI_mempool_len(ts) == unused) { BLI_mempool_destroy(ts); - space_outliner->treestore = NULL; + space_outliner->treestore = nullptr; if (space_outliner->runtime->treehash) { BKE_outliner_treehash_free(space_outliner->runtime->treehash); - space_outliner->runtime->treehash = NULL; + space_outliner->runtime->treehash = nullptr; } } else { @@ -131,9 +135,9 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner) BLI_mempool *new_ts = BLI_mempool_create( sizeof(TreeStoreElem), BLI_mempool_len(ts) - unused, 512, BLI_MEMPOOL_ALLOW_ITER); BLI_mempool_iternew(ts, &iter); - while ((tselem = BLI_mempool_iterstep(&iter))) { + while ((tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) { if (tselem->id) { - tsenew = BLI_mempool_alloc(new_ts); + tsenew = reinterpret_cast<TreeStoreElem *>(BLI_mempool_alloc(new_ts)); *tsenew = *tselem; } } @@ -156,14 +160,14 @@ static void outliner_storage_cleanup(SpaceOutliner *space_outliner) static void check_persistent( SpaceOutliner *space_outliner, TreeElement *te, ID *id, short type, short nr) { - if (space_outliner->treestore == NULL) { + if (space_outliner->treestore == nullptr) { /* if treestore was not created in readfile.c, create it here */ space_outliner->treestore = BLI_mempool_create( sizeof(TreeStoreElem), 1, 512, BLI_MEMPOOL_ALLOW_ITER); } - if (space_outliner->runtime->treehash == NULL) { - space_outliner->runtime->treehash = BKE_outliner_treehash_create_from_treestore( - space_outliner->treestore); + if (space_outliner->runtime->treehash == nullptr) { + space_outliner->runtime->treehash = reinterpret_cast<GHash *>( + BKE_outliner_treehash_create_from_treestore(space_outliner->treestore)); } /* find any unused tree element in treestore and mark it as used @@ -177,7 +181,7 @@ static void check_persistent( } /* add 1 element to treestore */ - tselem = BLI_mempool_alloc(space_outliner->treestore); + tselem = reinterpret_cast<TreeStoreElem *>(BLI_mempool_alloc(space_outliner->treestore)); tselem->type = type; tselem->nr = type ? nr : 0; tselem->id = id; @@ -213,8 +217,8 @@ void outliner_free_tree_element(TreeElement *element, ListBase *parent_subtree) if (element->flag & TE_FREE_NAME) { MEM_freeN((void *)element->name); } - outliner_tree_element_type_free(&element->type); - MEM_freeN(element); + element->type = nullptr; + MEM_delete(element); } /* ********************************************************* */ @@ -253,14 +257,6 @@ static void outliner_add_bone(SpaceOutliner *space_outliner, } } -bool outliner_animdata_test(const AnimData *adt) -{ - if (adt) { - return (adt->action || adt->drivers.first || adt->nla_tracks.first); - } - return false; -} - #ifdef WITH_FREESTYLE static void outliner_add_line_styles(SpaceOutliner *space_outliner, ListBase *lb, @@ -313,13 +309,13 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner, outliner_add_element(space_outliner, &te->subtree, ob->data, te, TSE_SOME_ID, 0); if (ob->pose) { - bArmature *arm = ob->data; + bArmature *arm = reinterpret_cast<bArmature *>(ob->data); TreeElement *tenla = outliner_add_element( space_outliner, &te->subtree, ob, te, TSE_POSE_BASE, 0); tenla->name = IFACE_("Pose"); /* channels undefined in editmode, but we want the 'tenla' pose icon itself */ - if ((arm->edbo == NULL) && (ob->mode & OB_MODE_POSE)) { + if ((arm->edbo == nullptr) && (ob->mode & OB_MODE_POSE)) { int const_index = 1000; /* ensure unique id for bone constraints */ int a; LISTBASE_FOREACH_INDEX (bPoseChannel *, pchan, &ob->pose->chanbase, a) { @@ -359,7 +355,7 @@ static void outliner_add_object_contents(SpaceOutliner *space_outliner, } } /* make hierarchy */ - TreeElement *ten = tenla->subtree.first; + TreeElement *ten = reinterpret_cast<TreeElement *>(tenla->subtree.first); while (ten) { TreeElement *nten = ten->next, *par; tselem = TREESTORE(ten); @@ -714,13 +710,15 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, ebone->temp.p = ten; } /* make hierarchy */ - TreeElement *ten = arm->edbo->first ? ((EditBone *)arm->edbo->first)->temp.p : NULL; + TreeElement *ten = arm->edbo->first ? reinterpret_cast<TreeElement *>( + ((EditBone *)arm->edbo->first)->temp.p) : + nullptr; while (ten) { TreeElement *nten = ten->next, *par; EditBone *ebone = (EditBone *)ten->directdata; if (ebone->parent) { BLI_remlink(&te->subtree, ten); - par = ebone->parent->temp.p; + par = reinterpret_cast<TreeElement *>(ebone->parent->temp.p); BLI_addtail(&par->subtree, ten); ten->parent = par; } @@ -812,6 +810,8 @@ static void outliner_add_id_contents(SpaceOutliner *space_outliner, } } +namespace blender::ed::outliner { + TreeElement *outliner_add_element(SpaceOutliner *space_outliner, ListBase *lb, void *idv, @@ -819,16 +819,16 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, short type, short index) { - ID *id = idv; + ID *id = reinterpret_cast<ID *>(idv); if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { id = ((PointerRNA *)idv)->owner_id; if (!id) { - id = ((PointerRNA *)idv)->data; + id = reinterpret_cast<ID *>(((PointerRNA *)idv)->data); } } else if (type == TSE_GP_LAYER) { - /* idv is the layer its self */ + /* idv is the layer itself */ id = TREESTORE(parent)->id; } @@ -836,8 +836,8 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, if (type == TSE_ID_BASE) { /* pass */ } - else if (id == NULL) { - return NULL; + else if (id == nullptr) { + return nullptr; } if (type == 0) { @@ -845,7 +845,7 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, BLI_assert(TREESTORE_ID_TYPE(id)); } - TreeElement *te = MEM_callocN(sizeof(TreeElement), __func__); + TreeElement *te = MEM_new<TreeElement>(__func__); /* add to the visual tree */ BLI_addtail(lb, te); /* add to the storage */ @@ -860,12 +860,12 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, te->parent = parent; te->index = index; /* For data arrays. */ - /* New C++ based type handle (`TreeElementType` in C, `AbstractTreeElement` in C++). Only some - * support this, eventually this should replace `TreeElement` entirely. */ - te->type = outliner_tree_element_type_create(type, te, idv); + /* New C++ based type handle. Only some support this, eventually this should replace + * `TreeElement` entirely. */ + te->type = AbstractTreeElement::createFromType(type, *te, idv); if (te->type) { /* Element types ported to the new design are expected to have their name set at this point! */ - BLI_assert(te->name != NULL); + BLI_assert(te->name != nullptr); } if (ELEM(type, TSE_SEQUENCE, TSE_SEQ_STRIP, TSE_SEQUENCE_DUP)) { @@ -909,14 +909,14 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, te->idcode = GS(id->name); } - if (te->type && outliner_tree_element_type_is_expand_valid(te->type)) { - outliner_tree_element_type_expand(te->type, space_outliner); + if (te->type && te->type->isExpandValid()) { + tree_element_expand(*te->type, *space_outliner); } 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)) { + if (te->type->expandPoll(*space_outliner)) { outliner_add_id_contents(space_outliner, te, tselem, id); - outliner_tree_element_type_post_expand(te->type, space_outliner); + te->type->postExpand(*space_outliner); } } else if (ELEM(type, @@ -925,199 +925,25 @@ TreeElement *outliner_add_element(SpaceOutliner *space_outliner, TSE_NLA, TSE_NLA_ACTION, TSE_NLA_TRACK, - TSE_GP_LAYER)) { - /* Should already use new AbstractTreeElement design. */ - BLI_assert(0); - } - else if (type == TSE_SEQUENCE) { - Sequence *seq = (Sequence *)idv; - - /* - * The idcode is a little hack, but the outliner - * only check te->idcode if te->type is equal to zero, - * so this is "safe". - */ - te->idcode = seq->type; - te->directdata = seq; - te->name = seq->name + 2; - - if (!(seq->type & SEQ_TYPE_EFFECT)) { - /* - * This work like the sequence. - * If the sequence have a name (not default name) - * show it, in other case put the filename. - */ - - if (seq->type == SEQ_TYPE_META) { - LISTBASE_FOREACH (Sequence *, p, &seq->seqbase) { - outliner_add_element(space_outliner, &te->subtree, (void *)p, te, TSE_SEQUENCE, index); - } - } - else { - outliner_add_element( - space_outliner, &te->subtree, (void *)seq->strip, te, TSE_SEQ_STRIP, index); - } - } + TSE_GP_LAYER, + TSE_RNA_STRUCT, + TSE_RNA_PROPERTY, + TSE_RNA_ARRAY_ELEM, + TSE_SEQUENCE, + TSE_SEQ_STRIP, + TSE_SEQUENCE_DUP)) { + BLI_assert_msg(false, "Element type should already use new AbstractTreeElement design"); } - else if (type == TSE_SEQ_STRIP) { - Strip *strip = (Strip *)idv; - - if (strip->dir[0] != '\0') { - te->name = strip->dir; - } - else { - te->name = IFACE_("Strip None"); - } - te->directdata = strip; - } - else if (type == TSE_SEQUENCE_DUP) { - Sequence *seq = (Sequence *)idv; - - te->idcode = seq->type; - te->directdata = seq; - te->name = seq->strip->stripdata->name; - } - else if (ELEM(type, TSE_RNA_STRUCT, TSE_RNA_PROPERTY, TSE_RNA_ARRAY_ELEM)) { - PointerRNA *ptr = (PointerRNA *)idv; - - /* Don't display arrays larger, weak but index is stored as a short, - * also the outliner isn't intended for editing such large data-sets. */ - BLI_STATIC_ASSERT(sizeof(te->index) == 2, "Index is no longer short!") - const int tot_limit = SHRT_MAX; - - /* we do lazy build, for speed and to avoid infinite recursion */ - - if (ptr->data == NULL) { - te->name = IFACE_("(empty)"); - } - else if (type == TSE_RNA_STRUCT) { - /* struct */ - te->name = RNA_struct_name_get_alloc(ptr, NULL, 0, NULL); - - if (te->name) { - te->flag |= TE_FREE_NAME; - } - else { - te->name = RNA_struct_ui_name(ptr->type); - } - - /* If searching don't expand RNA entries */ - if (SEARCHING_OUTLINER(space_outliner) && BLI_strcasecmp("RNA", te->name) == 0) { - tselem->flag &= ~TSE_CHILDSEARCH; - } - - PropertyRNA *iterprop = RNA_struct_iterator_property(ptr->type); - int tot = RNA_property_collection_length(ptr, iterprop); - CLAMP_MAX(tot, tot_limit); - - /* auto open these cases */ - if (!parent || (RNA_property_type(parent->directdata)) == PROP_POINTER) { - if (!tselem->used) { - tselem->flag &= ~TSE_CLOSED; - } - } - - if (TSELEM_OPEN(tselem, space_outliner)) { - for (int a = 0; a < tot; a++) { - PointerRNA propptr; - RNA_property_collection_lookup_int(ptr, iterprop, a, &propptr); - if (!(RNA_property_flag(propptr.data) & PROP_HIDDEN)) { - outliner_add_element( - space_outliner, &te->subtree, (void *)ptr, te, TSE_RNA_PROPERTY, a); - } - } - } - else if (tot) { - te->flag |= TE_LAZY_CLOSED; - } - - te->rnaptr = *ptr; - } - else if (type == TSE_RNA_PROPERTY) { - /* property */ - PointerRNA propptr; - PropertyRNA *iterprop = RNA_struct_iterator_property(ptr->type); - RNA_property_collection_lookup_int(ptr, iterprop, index, &propptr); - PropertyRNA *prop = propptr.data; - PropertyType proptype = RNA_property_type(prop); - - te->name = RNA_property_ui_name(prop); - te->directdata = prop; - te->rnaptr = *ptr; - - /* If searching don't expand RNA entries */ - if (SEARCHING_OUTLINER(space_outliner) && BLI_strcasecmp("RNA", te->name) == 0) { - tselem->flag &= ~TSE_CHILDSEARCH; - } - - if (proptype == PROP_POINTER) { - PointerRNA pptr = RNA_property_pointer_get(ptr, prop); - - if (pptr.data) { - if (TSELEM_OPEN(tselem, space_outliner)) { - outliner_add_element( - space_outliner, &te->subtree, (void *)&pptr, te, TSE_RNA_STRUCT, -1); - } - else { - te->flag |= TE_LAZY_CLOSED; - } - } - } - else if (proptype == PROP_COLLECTION) { - int tot = RNA_property_collection_length(ptr, prop); - CLAMP_MAX(tot, tot_limit); - - if (TSELEM_OPEN(tselem, space_outliner)) { - for (int a = 0; a < tot; a++) { - PointerRNA pptr; - RNA_property_collection_lookup_int(ptr, prop, a, &pptr); - outliner_add_element( - space_outliner, &te->subtree, (void *)&pptr, te, TSE_RNA_STRUCT, a); - } - } - else if (tot) { - te->flag |= TE_LAZY_CLOSED; - } - } - else if (ELEM(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) { - int tot = RNA_property_array_length(ptr, prop); - CLAMP_MAX(tot, tot_limit); - - if (TSELEM_OPEN(tselem, space_outliner)) { - for (int a = 0; a < tot; a++) { - outliner_add_element( - space_outliner, &te->subtree, (void *)ptr, te, TSE_RNA_ARRAY_ELEM, a); - } - } - else if (tot) { - te->flag |= TE_LAZY_CLOSED; - } - } - } - else if (type == TSE_RNA_ARRAY_ELEM) { - PropertyRNA *prop = parent->directdata; - - te->directdata = prop; - te->rnaptr = *ptr; - te->index = index; - - char c = RNA_property_array_item_char(prop, index); - - te->name = MEM_callocN(sizeof(char[20]), "OutlinerRNAArrayName"); - if (c) { - sprintf((char *)te->name, " %c", c); - } - else { - sprintf((char *)te->name, " %d", index + 1); - } - te->flag |= TE_FREE_NAME; - } + if (tree_element_warnings_get(te, nullptr, nullptr)) { + te->flag |= TE_HAS_WARNING; } return te; } +} // namespace blender::ed::outliner + /* ======================================================= */ BLI_INLINE void outliner_add_collection_init(TreeElement *te, Collection *collection) @@ -1157,43 +983,20 @@ TreeElement *outliner_add_collection_recursive(SpaceOutliner *space_outliner, /* ======================================================= */ /* Generic Tree Building helpers - order these are called is top to bottom */ -/* Hierarchy --------------------------------------------- */ - -void outliner_make_object_parent_hierarchy(ListBase *lb) -{ - /* build hierarchy */ - /* XXX also, set extents here... */ - TreeElement *te = lb->first; - while (te) { - TreeElement *ten = te->next; - TreeStoreElem *tselem = TREESTORE(te); - - 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); - TreeElement *tep = (TreeElement *)ob->parent->id.newid; - BLI_addtail(&tep->subtree, te); - te->parent = tep; - } - } - te = ten; - } -} - /* Sorting ------------------------------------------------------ */ -typedef struct tTreeSort { +struct tTreeSort { TreeElement *te; ID *id; const char *name; short idcode; -} tTreeSort; +}; /* alphabetical comparator, trying to put objects first */ static int treesort_alpha_ob(const void *v1, const void *v2) { - const tTreeSort *x1 = v1, *x2 = v2; + const tTreeSort *x1 = reinterpret_cast<const tTreeSort *>(v1); + const tTreeSort *x2 = reinterpret_cast<const tTreeSort *>(v2); /* first put objects last (hierarchy) */ int comp = (x1->idcode == ID_OB); @@ -1231,7 +1034,8 @@ static int treesort_alpha_ob(const void *v1, const void *v2) /* Move children that are not in the collection to the end of the list. */ static int treesort_child_not_in_collection(const void *v1, const void *v2) { - const tTreeSort *x1 = v1, *x2 = v2; + const tTreeSort *x1 = reinterpret_cast<const tTreeSort *>(v1); + const tTreeSort *x2 = reinterpret_cast<const tTreeSort *>(v2); /* Among objects first come the ones in the collection, followed by the ones not on it. * This way we can have the dashed lines in a separate style connecting the former. */ @@ -1244,7 +1048,8 @@ static int treesort_child_not_in_collection(const void *v1, const void *v2) /* alphabetical comparator */ static int treesort_alpha(const void *v1, const void *v2) { - const tTreeSort *x1 = v1, *x2 = v2; + const tTreeSort *x1 = reinterpret_cast<const tTreeSort *>(v1); + const tTreeSort *x2 = reinterpret_cast<const tTreeSort *>(v2); int comp = BLI_strcasecmp_natural(x1->name, x2->name); @@ -1301,24 +1106,25 @@ static int treesort_obtype_alpha(const void *v1, const void *v2) /* sort happens on each subtree individual */ static void outliner_sort(ListBase *lb) { - TreeElement *te = lb->last; - if (te == NULL) { + TreeElement *last_te = reinterpret_cast<TreeElement *>(lb->last); + if (last_te == nullptr) { return; } - TreeStoreElem *tselem = TREESTORE(te); + TreeStoreElem *last_tselem = TREESTORE(last_te); /* Sorting rules; only object lists, ID lists, or deform-groups. */ - if (ELEM(tselem->type, TSE_DEFGROUP, TSE_ID_BASE) || - ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB))) { + if (ELEM(last_tselem->type, TSE_DEFGROUP, TSE_ID_BASE) || + ((last_tselem->type == TSE_SOME_ID) && (last_te->idcode == ID_OB))) { int totelem = BLI_listbase_count(lb); if (totelem > 1) { - tTreeSort *tear = MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array"); + tTreeSort *tear = reinterpret_cast<tTreeSort *>( + MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array")); tTreeSort *tp = tear; int skip = 0; - for (te = lb->first; te; te = te->next, tp++) { - tselem = TREESTORE(te); + LISTBASE_FOREACH (TreeElement *, te, lb) { + TreeStoreElem *tselem = TREESTORE(te); tp->te = te; tp->name = te->name; tp->idcode = te->idcode; @@ -1331,6 +1137,7 @@ static void outliner_sort(ListBase *lb) } tp->id = tselem->id; + tp++; } /* just sort alphabetically */ @@ -1367,26 +1174,28 @@ static void outliner_sort(ListBase *lb) static void outliner_collections_children_sort(ListBase *lb) { - TreeElement *te = lb->last; - if (te == NULL) { + TreeElement *last_te = reinterpret_cast<TreeElement *>(lb->last); + if (last_te == nullptr) { return; } - TreeStoreElem *tselem = TREESTORE(te); + TreeStoreElem *last_tselem = TREESTORE(last_te); /* Sorting rules: only object lists. */ - if ((tselem->type == TSE_SOME_ID) && (te->idcode == ID_OB)) { + if ((last_tselem->type == TSE_SOME_ID) && (last_te->idcode == ID_OB)) { int totelem = BLI_listbase_count(lb); if (totelem > 1) { - tTreeSort *tear = MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array"); + tTreeSort *tear = reinterpret_cast<tTreeSort *>( + MEM_mallocN(totelem * sizeof(tTreeSort), "tree sort array")); tTreeSort *tp = tear; - for (te = lb->first; te; te = te->next, tp++) { - tselem = TREESTORE(te); + LISTBASE_FOREACH (TreeElement *, te, lb) { + TreeStoreElem *tselem = TREESTORE(te); tp->te = te; tp->name = te->name; tp->idcode = te->idcode; tp->id = tselem->id; + tp++; } qsort(tear, totelem, sizeof(tTreeSort), treesort_child_not_in_collection); @@ -1408,10 +1217,10 @@ static void outliner_collections_children_sort(ListBase *lb) /* Filtering ----------------------------------------------- */ -typedef struct OutlinerTreeElementFocus { +struct OutlinerTreeElementFocus { TreeStoreElem *tselem; int ys; -} OutlinerTreeElementFocus; +}; /** * Bring the outliner scrolling back to where it was in relation to the original focus element @@ -1423,12 +1232,12 @@ static void outliner_restore_scrolling_position(SpaceOutliner *space_outliner, { View2D *v2d = ®ion->v2d; - if (focus->tselem != NULL) { + if (focus->tselem != nullptr) { outliner_set_coordinates(region, space_outliner); TreeElement *te_new = outliner_find_tree_element(&space_outliner->tree, focus->tselem); - if (te_new != NULL) { + if (te_new != nullptr) { int ys_new = te_new->ys; int ys_old = focus->ys; @@ -1466,17 +1275,16 @@ static TreeElement *outliner_find_first_desired_element_at_y_recursive( } if (TSELEM_OPEN(te->store_elem, space_outliner)) { - TreeElement *te_iter, *te_sub; - for (te_iter = te->subtree.first; te_iter; te_iter = te_iter->next) { - te_sub = outliner_find_first_desired_element_at_y_recursive( + LISTBASE_FOREACH (TreeElement *, te_iter, &te->subtree) { + TreeElement *te_sub = outliner_find_first_desired_element_at_y_recursive( space_outliner, te_iter, limit, callback_test); - if (te_sub != NULL) { + if (te_sub != nullptr) { return te_sub; } } } - return NULL; + return nullptr; } /** @@ -1487,7 +1295,7 @@ static TreeElement *outliner_find_first_desired_element_at_y_recursive( * * Basically we keep going up and down the outliner tree from that point forward, until we find * what we are looking for. If we are past the visible range and we can't find a valid element - * we return NULL. + * we return nullptr. */ static TreeElement *outliner_find_first_desired_element_at_y(const SpaceOutliner *space_outliner, const float view_co, @@ -1504,15 +1312,15 @@ static TreeElement *outliner_find_first_desired_element_at_y(const SpaceOutliner callback_test = test_collection_callback; } - while (te != NULL) { + while (te != nullptr) { TreeElement *te_sub = outliner_find_first_desired_element_at_y_recursive( space_outliner, te, view_co_limit, callback_test); - if (te_sub != NULL) { + if (te_sub != nullptr) { /* Skip the element if it was not visible to start with. */ if (te->ys + UI_UNIT_Y > view_co_limit) { return te_sub; } - return NULL; + return nullptr; } if (te->next) { @@ -1520,7 +1328,7 @@ static TreeElement *outliner_find_first_desired_element_at_y(const SpaceOutliner continue; } - if (te->parent == NULL) { + if (te->parent == nullptr) { break; } @@ -1533,7 +1341,7 @@ static TreeElement *outliner_find_first_desired_element_at_y(const SpaceOutliner } } - return NULL; + return nullptr; } /** @@ -1554,12 +1362,12 @@ static void outliner_store_scrolling_position(SpaceOutliner *space_outliner, TreeElement *te = outliner_find_first_desired_element_at_y( space_outliner, region->v2d.cur.ymax, limit); - if (te != NULL) { + if (te != nullptr) { focus->tselem = TREESTORE(te); focus->ys = te->ys; } else { - focus->tselem = NULL; + focus->tselem = nullptr; } } @@ -1617,7 +1425,7 @@ static bool outliner_element_visible_get(ViewLayer *view_layer, Object *ob = (Object *)tselem->id; Base *base = (Base *)te->directdata; - BLI_assert((base == NULL) || (base->object == ob)); + BLI_assert((base == nullptr) || (base->object == ob)); if (exclude_filter & SO_FILTER_OB_TYPE) { switch (ob->type) { @@ -1655,10 +1463,10 @@ static bool outliner_element_visible_get(ViewLayer *view_layer, } if (exclude_filter & SO_FILTER_OB_STATE) { - if (base == NULL) { + if (base == nullptr) { base = BKE_view_layer_base_find(view_layer, ob); - if (base == NULL) { + if (base == nullptr) { return false; } } @@ -1693,14 +1501,14 @@ static bool outliner_element_visible_get(ViewLayer *view_layer, return is_visible; } - if ((te->parent != NULL) && (TREESTORE(te->parent)->type == TSE_SOME_ID) && + if ((te->parent != nullptr) && (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 == TSE_SOME_ID) && + else if ((te->parent != nullptr) && (TREESTORE(te->parent)->type == TSE_SOME_ID) && (te->parent->idcode == ID_OB)) { if (exclude_filter & SO_FILTER_NO_OB_CONTENT) { return false; @@ -1743,8 +1551,9 @@ static TreeElement *outliner_extract_children_from_subtree(TreeElement *element, TreeElement *te_next = element->next; if (outliner_element_is_collection_or_object(element)) { - TreeElement *te_prev = NULL; - for (TreeElement *te = element->subtree.last; te; te = te_prev) { + TreeElement *te_prev = nullptr; + for (TreeElement *te = reinterpret_cast<TreeElement *>(element->subtree.last); te; + te = te_prev) { te_prev = te->prev; if (!outliner_element_is_collection_or_object(te)) { @@ -1771,7 +1580,7 @@ static int outliner_filter_subtree(SpaceOutliner *space_outliner, TreeElement *te, *te_next; TreeStoreElem *tselem; - for (te = lb->first; te; te = te_next) { + for (te = reinterpret_cast<TreeElement *>(lb->first); te; te = te_next) { te_next = te->next; if ((outliner_element_visible_get(view_layer, te, exclude_filter) == false)) { /* Don't free the tree, but extract the children from the parent and add to this tree. */ @@ -1824,7 +1633,7 @@ static int outliner_filter_subtree(SpaceOutliner *space_outliner, static void outliner_filter_tree(SpaceOutliner *space_outliner, ViewLayer *view_layer) { - char search_buff[sizeof(((struct SpaceOutliner *)NULL)->search_string) + 2]; + char search_buff[sizeof(((struct SpaceOutliner *)nullptr)->search_string) + 2]; char *search_string; const int exclude_filter = outliner_exclude_filter_get(space_outliner); @@ -1850,7 +1659,7 @@ static void outliner_clear_newid_from_main(Main *bmain) { ID *id_iter; FOREACH_MAIN_ID_BEGIN (bmain, id_iter) { - id_iter->newid = NULL; + id_iter->newid = nullptr; } FOREACH_MAIN_ID_END; } @@ -1890,17 +1699,15 @@ void outliner_build_tree(Main *mainvar, outliner_free_tree(&space_outliner->tree); outliner_storage_cleanup(space_outliner); - outliner_tree_display_destroy(&space_outliner->runtime->tree_display); - space_outliner->runtime->tree_display = outliner_tree_display_create(space_outliner->outlinevis, - space_outliner); + space_outliner->runtime->tree_display = AbstractTreeDisplay::createFromDisplayMode( + space_outliner->outlinevis, *space_outliner); /* All tree displays should be created as sub-classes of AbstractTreeDisplay. */ - BLI_assert(space_outliner->runtime->tree_display != NULL); + BLI_assert(space_outliner->runtime->tree_display != nullptr); - TreeSourceData source_data = {.bmain = mainvar, .scene = scene, .view_layer = view_layer}; - space_outliner->tree = outliner_tree_display_build_tree(space_outliner->runtime->tree_display, - &source_data); + TreeSourceData source_data{*mainvar, *scene, *view_layer}; + space_outliner->tree = space_outliner->runtime->tree_display->buildTree(source_data); if ((space_outliner->flag & SO_SKIP_SORT_ALPHA) == 0) { outliner_sort(&space_outliner->tree); diff --git a/source/blender/editors/space_outliner/outliner_utils.c b/source/blender/editors/space_outliner/outliner_utils.cc index d370d508198..86b56a7ec12 100644 --- a/source/blender/editors/space_outliner/outliner_utils.c +++ b/source/blender/editors/space_outliner/outliner_utils.cc @@ -21,7 +21,7 @@ * \ingroup spoutliner */ -#include <string.h> +#include <cstring> #include "BLI_listbase.h" #include "BLI_utildefines.h" @@ -42,7 +42,7 @@ #include "UI_interface.h" #include "UI_view2d.h" -#include "outliner_intern.h" +#include "outliner_intern.hh" /* -------------------------------------------------------------------- */ /** \name Tree View Context @@ -58,7 +58,7 @@ void outliner_viewcontext_init(const bContext *C, TreeViewContext *tvc) /* Objects. */ tvc->obact = OBACT(tvc->view_layer); - if (tvc->obact != NULL) { + if (tvc->obact != nullptr) { tvc->ob_edit = OBEDIT_FROM_OBACT(tvc->obact); if ((tvc->obact->type == OB_ARMATURE) || @@ -104,14 +104,14 @@ TreeElement *outliner_find_item_at_y(const SpaceOutliner *space_outliner, } } - return NULL; + return nullptr; } static TreeElement *outliner_find_item_at_x_in_row_recursive(const TreeElement *parent_te, float view_co_x, bool *r_is_merged_icon) { - TreeElement *child_te = parent_te->subtree.first; + TreeElement *child_te = reinterpret_cast<TreeElement *>(parent_te->subtree.first); while (child_te) { const bool over_element = (view_co_x > child_te->xs) && (view_co_x < child_te->xend); @@ -168,7 +168,7 @@ TreeElement *outliner_find_tree_element(ListBase *lb, const TreeStoreElem *store return tes; } } - return NULL; + return nullptr; } TreeElement *outliner_find_parent_element(ListBase *lb, @@ -185,25 +185,25 @@ TreeElement *outliner_find_parent_element(ListBase *lb, return find_te; } } - return NULL; + return nullptr; } TreeElement *outliner_find_tse(SpaceOutliner *space_outliner, const TreeStoreElem *tse) { TreeStoreElem *tselem; - if (tse->id == NULL) { - return NULL; + if (tse->id == nullptr) { + return nullptr; } - /* check if 'tse' is in treestore */ + /* Check if 'tse' is in tree-store. */ tselem = BKE_outliner_treehash_lookup_any( space_outliner->runtime->treehash, tse->type, tse->nr, tse->id); if (tselem) { return outliner_find_tree_element(&space_outliner->tree, tselem); } - return NULL; + return nullptr; } TreeElement *outliner_find_id(SpaceOutliner *space_outliner, ListBase *lb, const ID *id) @@ -221,7 +221,7 @@ TreeElement *outliner_find_id(SpaceOutliner *space_outliner, ListBase *lb, const return tes; } } - return NULL; + return nullptr; } TreeElement *outliner_find_posechannel(ListBase *lb, const bPoseChannel *pchan) @@ -239,7 +239,7 @@ TreeElement *outliner_find_posechannel(ListBase *lb, const bPoseChannel *pchan) } } } - return NULL; + return nullptr; } TreeElement *outliner_find_editbone(ListBase *lb, const EditBone *ebone) @@ -257,7 +257,7 @@ TreeElement *outliner_find_editbone(ListBase *lb, const EditBone *ebone) } } } - return NULL; + return nullptr; } TreeElement *outliner_search_back_te(TreeElement *te, short idcode) @@ -272,7 +272,7 @@ TreeElement *outliner_search_back_te(TreeElement *te, short idcode) } te = te->parent; } - return NULL; + return nullptr; } ID *outliner_search_back(TreeElement *te, short idcode) @@ -285,7 +285,7 @@ ID *outliner_search_back(TreeElement *te, short idcode) tselem = TREESTORE(search_te); return tselem->id; } - return NULL; + return nullptr; } bool outliner_tree_traverse(const SpaceOutliner *space_outliner, @@ -295,7 +295,8 @@ bool outliner_tree_traverse(const SpaceOutliner *space_outliner, TreeTraversalFunc func, void *customdata) { - for (TreeElement *te = tree->first, *te_next; te; te = te_next) { + for (TreeElement *te = reinterpret_cast<TreeElement *>(tree->first), *te_next; te; + te = te_next) { TreeTraversalAction func_retval = TRAVERSE_CONTINUE; /* in case te is freed in callback */ TreeStoreElem *tselem = TREESTORE(te); @@ -382,7 +383,7 @@ TreeElement *outliner_find_element_with_flag(const ListBase *lb, short flag) return active_element; } } - return NULL; + return nullptr; } bool outliner_is_element_visible(const TreeElement *te) @@ -467,7 +468,7 @@ Base *ED_outliner_give_base_under_cursor(bContext *C, const int mval[2]) ViewLayer *view_layer = CTX_data_view_layer(C); SpaceOutliner *space_outliner = CTX_wm_space_outliner(C); TreeElement *te; - Base *base = NULL; + Base *base = nullptr; float view_mval[2]; UI_view2d_region_to_view(®ion->v2d, mval[0], mval[1], &view_mval[0], &view_mval[1]); diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.cc index 6c45d39e0d8..0fb17fa3f47 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.cc @@ -21,8 +21,8 @@ * \ingroup spoutliner */ -#include <stdio.h> -#include <string.h> +#include <cstdio> +#include <cstring> #include "MEM_guardedalloc.h" @@ -31,6 +31,7 @@ #include "BLI_utildefines.h" #include "BKE_context.h" +#include "BKE_lib_remap.h" #include "BKE_outliner_treehash.h" #include "BKE_screen.h" @@ -49,8 +50,20 @@ #include "UI_resources.h" #include "UI_view2d.h" -#include "outliner_intern.h" -#include "tree/tree_display.h" +#include "outliner_intern.hh" +#include "tree/tree_display.hh" + +SpaceOutliner_Runtime::SpaceOutliner_Runtime(const SpaceOutliner_Runtime & /*other*/) + : tree_display(nullptr), treehash(nullptr) +{ +} + +SpaceOutliner_Runtime::~SpaceOutliner_Runtime() +{ + if (treehash) { + BKE_outliner_treehash_free(treehash); + } +} static void outliner_main_region_init(wmWindowManager *wm, ARegion *region) { @@ -92,7 +105,7 @@ static void outliner_main_region_draw(const bContext *C, ARegion *region) UI_view2d_view_restore(C); /* scrollers */ - UI_view2d_scrollers_draw(v2d, NULL); + UI_view2d_scrollers_draw(v2d, nullptr); } static void outliner_main_region_free(ARegion *UNUSED(region)) @@ -104,7 +117,7 @@ static void outliner_main_region_listener(const wmRegionListenerParams *params) ScrArea *area = params->area; ARegion *region = params->region; wmNotifier *wmn = params->notifier; - SpaceOutliner *space_outliner = area->spacedata.first; + SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first); /* context changes */ switch (wmn->category) { @@ -262,23 +275,25 @@ static void outliner_main_region_listener(const wmRegionListenerParams *params) } } +/* FIXME: See comment above #WM_msg_publish_rna_prop(). */ +extern "C" { static void outliner_main_region_message_subscribe(const wmRegionMessageSubscribeParams *params) { struct wmMsgBus *mbus = params->message_bus; ScrArea *area = params->area; ARegion *region = params->region; - SpaceOutliner *space_outliner = area->spacedata.first; + SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first); - wmMsgSubscribeValue msg_sub_value_region_tag_redraw = { - .owner = region, - .user_data = region, - .notify = ED_region_do_msg_notify_tag_redraw, - }; + wmMsgSubscribeValue msg_sub_value_region_tag_redraw{}; + msg_sub_value_region_tag_redraw.owner = region; + msg_sub_value_region_tag_redraw.user_data = region; + msg_sub_value_region_tag_redraw.notify = ED_region_do_msg_notify_tag_redraw; if (ELEM(space_outliner->outlinevis, SO_VIEW_LAYER, SO_SCENES, SO_OVERRIDES_LIBRARY)) { WM_msg_subscribe_rna_anon_prop(mbus, Window, view_layer, &msg_sub_value_region_tag_redraw); } } +} /* ************************ header outliner area region *********************** */ @@ -324,7 +339,7 @@ static SpaceLink *outliner_create(const ScrArea *UNUSED(area), const Scene *UNUS ARegion *region; SpaceOutliner *space_outliner; - space_outliner = MEM_callocN(sizeof(SpaceOutliner), "initoutliner"); + space_outliner = MEM_cnew<SpaceOutliner>("initoutliner"); space_outliner->spacetype = SPACE_OUTLINER; space_outliner->filter_id_type = ID_GR; space_outliner->show_restrict_flags = SO_RESTRICT_ENABLE | SO_RESTRICT_HIDE | SO_RESTRICT_RENDER; @@ -334,14 +349,14 @@ static SpaceLink *outliner_create(const ScrArea *UNUSED(area), const Scene *UNUS space_outliner->filter = SO_FILTER_NO_VIEW_LAYERS; /* header */ - region = MEM_callocN(sizeof(ARegion), "header for outliner"); + region = MEM_cnew<ARegion>("header for outliner"); BLI_addtail(&space_outliner->regionbase, region); region->regiontype = RGN_TYPE_HEADER; region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_BOTTOM : RGN_ALIGN_TOP; /* main region */ - region = MEM_callocN(sizeof(ARegion), "main region for outliner"); + region = MEM_cnew<ARegion>("main region for outliner"); BLI_addtail(&space_outliner->regionbase, region); region->regiontype = RGN_TYPE_WINDOW; @@ -359,84 +374,81 @@ static void outliner_free(SpaceLink *sl) BLI_mempool_destroy(space_outliner->treestore); } - if (space_outliner->runtime) { - outliner_tree_display_destroy(&space_outliner->runtime->tree_display); - if (space_outliner->runtime->treehash) { - BKE_outliner_treehash_free(space_outliner->runtime->treehash); - } - MEM_freeN(space_outliner->runtime); - } + MEM_delete(space_outliner->runtime); } /* spacetype; init callback */ static void outliner_init(wmWindowManager *UNUSED(wm), ScrArea *area) { - SpaceOutliner *space_outliner = area->spacedata.first; + SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first); - if (space_outliner->runtime == NULL) { - space_outliner->runtime = MEM_callocN(sizeof(*space_outliner->runtime), - "SpaceOutliner_Runtime"); + if (space_outliner->runtime == nullptr) { + space_outliner->runtime = MEM_new<SpaceOutliner_Runtime>("SpaceOutliner_Runtime"); } } static SpaceLink *outliner_duplicate(SpaceLink *sl) { SpaceOutliner *space_outliner = (SpaceOutliner *)sl; - SpaceOutliner *space_outliner_new = MEM_dupallocN(space_outliner); + SpaceOutliner *space_outliner_new = MEM_new<SpaceOutliner>(__func__, *space_outliner); BLI_listbase_clear(&space_outliner_new->tree); - space_outliner_new->treestore = NULL; + space_outliner_new->treestore = nullptr; space_outliner_new->sync_select_dirty = WM_OUTLINER_SYNC_SELECT_FROM_ALL; if (space_outliner->runtime) { - space_outliner_new->runtime = MEM_dupallocN(space_outliner->runtime); - space_outliner_new->runtime->tree_display = NULL; - space_outliner_new->runtime->treehash = NULL; + /* Copy constructor handles details. */ + space_outliner_new->runtime = MEM_new<SpaceOutliner_Runtime>("SpaceOutliner_runtime dup", + *space_outliner->runtime); } return (SpaceLink *)space_outliner_new; } -static void outliner_id_remap(ScrArea *area, SpaceLink *slink, ID *old_id, ID *new_id) +static void outliner_id_remap(ScrArea *area, SpaceLink *slink, const struct IDRemapper *mappings) { SpaceOutliner *space_outliner = (SpaceOutliner *)slink; - /* Some early out checks. */ - if (!TREESTORE_ID_TYPE(old_id)) { - return; /* ID type is not used by outliner. */ - } + BKE_id_remapper_apply(mappings, (ID **)&space_outliner->search_tse.id, ID_REMAP_APPLY_DEFAULT); - if (space_outliner->search_tse.id == old_id) { - space_outliner->search_tse.id = new_id; + if (!space_outliner->treestore) { + return; } - if (space_outliner->treestore) { - TreeStoreElem *tselem; - BLI_mempool_iter iter; - bool changed = false; - - BLI_mempool_iternew(space_outliner->treestore, &iter); - while ((tselem = BLI_mempool_iterstep(&iter))) { - if (tselem->id == old_id) { - tselem->id = new_id; + TreeStoreElem *tselem; + BLI_mempool_iter iter; + bool changed = false; + bool unassigned = false; + + BLI_mempool_iternew(space_outliner->treestore, &iter); + while ((tselem = static_cast<TreeStoreElem *>(BLI_mempool_iterstep(&iter)))) { + switch (BKE_id_remapper_apply(mappings, &tselem->id, ID_REMAP_APPLY_DEFAULT)) { + case ID_REMAP_RESULT_SOURCE_REMAPPED: changed = true; - } + break; + case ID_REMAP_RESULT_SOURCE_UNASSIGNED: + changed = true; + unassigned = true; + break; + case ID_REMAP_RESULT_SOURCE_UNAVAILABLE: + case ID_REMAP_RESULT_SOURCE_NOT_MAPPABLE: + break; } + } - /* Note that the Outliner may not be the active editor of the area, and hence not initialized. - * So runtime data might not have been created yet. */ - if (space_outliner->runtime && space_outliner->runtime->treehash && changed) { - /* rebuild hash table, because it depends on ids too */ - /* postpone a full rebuild because this can be called many times on-free */ - space_outliner->storeflag |= SO_TREESTORE_REBUILD; - - if (new_id == NULL) { - /* Redraw is needed when removing data for multiple outlines show the same data. - * without this, the stale data won't get fully flushed when this outliner - * is not the active outliner the user is interacting with. See T85976. */ - ED_area_tag_redraw(area); - } + /* Note that the Outliner may not be the active editor of the area, and hence not initialized. + * So runtime data might not have been created yet. */ + if (space_outliner->runtime && space_outliner->runtime->treehash && changed) { + /* rebuild hash table, because it depends on ids too */ + /* postpone a full rebuild because this can be called many times on-free */ + space_outliner->storeflag |= SO_TREESTORE_REBUILD; + + if (unassigned) { + /* Redraw is needed when removing data for multiple outlines show the same data. + * without this, the stale data won't get fully flushed when this outliner + * is not the active outliner the user is interacting with. See T85976. */ + ED_area_tag_redraw(area); } } } @@ -444,14 +456,14 @@ static void outliner_id_remap(ScrArea *area, SpaceLink *slink, ID *old_id, ID *n static void outliner_deactivate(struct ScrArea *area) { /* Remove hover highlights */ - SpaceOutliner *space_outliner = area->spacedata.first; + SpaceOutliner *space_outliner = reinterpret_cast<SpaceOutliner *>(area->spacedata.first); outliner_flag_set(&space_outliner->tree, TSE_HIGHLIGHTED_ANY, false); ED_region_tag_redraw_no_rebuild(BKE_area_find_region_type(area, RGN_TYPE_WINDOW)); } void ED_spacetype_outliner(void) { - SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype time"); + SpaceType *st = MEM_cnew<SpaceType>("spacetype time"); ARegionType *art; st->spaceid = SPACE_OUTLINER; @@ -469,7 +481,7 @@ void ED_spacetype_outliner(void) st->context = outliner_context; /* regions: main window */ - art = MEM_callocN(sizeof(ARegionType), "spacetype outliner region"); + art = MEM_cnew<ARegionType>("spacetype outliner region"); art->regionid = RGN_TYPE_WINDOW; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D; @@ -481,7 +493,7 @@ void ED_spacetype_outliner(void) BLI_addhead(&st->regiontypes, art); /* regions: header */ - art = MEM_callocN(sizeof(ARegionType), "spacetype outliner header region"); + art = MEM_cnew<ARegionType>("spacetype outliner header region"); art->regionid = RGN_TYPE_HEADER; art->prefsizey = HEADERY; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D | ED_KEYMAP_HEADER; diff --git a/source/blender/editors/space_outliner/tree/common.cc b/source/blender/editors/space_outliner/tree/common.cc index 306d59288f4..c6b5ee3b7ef 100644 --- a/source/blender/editors/space_outliner/tree/common.cc +++ b/source/blender/editors/space_outliner/tree/common.cc @@ -20,10 +20,18 @@ * Functions and helpers shared between tree-display types or other tree related code. */ +#include "BLI_listbase.h" + #include "BKE_idtype.h" +#include "DNA_anim_types.h" +#include "DNA_object_types.h" +#include "DNA_outliner_types.h" + #include "RNA_access.h" +#include "../outliner_intern.hh" +#include "common.hh" #include "tree_display.hh" /* -------------------------------------------------------------------- */ @@ -38,3 +46,33 @@ const char *outliner_idcode_to_plural(short idcode) } /** \} */ + +void outliner_make_object_parent_hierarchy(ListBase *lb) +{ + /* build hierarchy */ + /* XXX also, set extents here... */ + TreeElement *te = reinterpret_cast<TreeElement *>(lb->first); + while (te) { + TreeElement *ten = te->next; + TreeStoreElem *tselem = TREESTORE(te); + + 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); + TreeElement *tep = (TreeElement *)ob->parent->id.newid; + BLI_addtail(&tep->subtree, te); + te->parent = tep; + } + } + te = ten; + } +} + +bool outliner_animdata_test(const AnimData *adt) +{ + if (adt) { + return (adt->action || adt->drivers.first || adt->nla_tracks.first); + } + return false; +} diff --git a/source/blender/editors/space_node/node_toolbar.cc b/source/blender/editors/space_outliner/tree/common.hh index c32dcbef91b..1745bfa436e 100644 --- a/source/blender/editors/space_node/node_toolbar.cc +++ b/source/blender/editors/space_outliner/tree/common.hh @@ -12,28 +12,17 @@ * 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) 2012 Blender Foundation. - * All rights reserved. */ /** \file - * \ingroup nodes + * \ingroup spoutliner */ -#include "BLI_utildefines.h" - -#include "DNA_node_types.h" - -#include "BKE_context.h" -#include "BKE_screen.h" - -#include "WM_api.h" +#pragma once -#include "node_intern.hh" /* own include */ +struct ListBase; -/* ******************* node toolbar registration ************** */ +const char *outliner_idcode_to_plural(short idcode); -void node_toolbar_register(ARegionType *UNUSED(art)) -{ -} +void outliner_make_object_parent_hierarchy(ListBase *lb); +bool outliner_animdata_test(const struct AnimData *adt); diff --git a/source/blender/editors/space_outliner/tree/tree_display.cc b/source/blender/editors/space_outliner/tree/tree_display.cc index 003afd5bdec..d2b6fff6996 100644 --- a/source/blender/editors/space_outliner/tree/tree_display.cc +++ b/source/blender/editors/space_outliner/tree/tree_display.cc @@ -19,50 +19,41 @@ */ #include "DNA_listBase.h" +#include "DNA_space_types.h" #include "tree_display.hh" using namespace blender::ed::outliner; -TreeDisplay *outliner_tree_display_create(eSpaceOutliner_Mode mode, SpaceOutliner *space_outliner) -{ - AbstractTreeDisplay *tree_display = nullptr; +namespace blender::ed::outliner { - switch (mode) { +std::unique_ptr<AbstractTreeDisplay> AbstractTreeDisplay::createFromDisplayMode( + int /*eSpaceOutliner_Mode*/ mode, SpaceOutliner &space_outliner) +{ + switch ((eSpaceOutliner_Mode)mode) { case SO_SCENES: - tree_display = new TreeDisplayScenes(*space_outliner); - break; + return std::make_unique<TreeDisplayScenes>(space_outliner); case SO_LIBRARIES: - tree_display = new TreeDisplayLibraries(*space_outliner); - break; + return std::make_unique<TreeDisplayLibraries>(space_outliner); case SO_SEQUENCE: - tree_display = new TreeDisplaySequencer(*space_outliner); - break; + return std::make_unique<TreeDisplaySequencer>(space_outliner); case SO_DATA_API: - tree_display = new TreeDisplayDataAPI(*space_outliner); - break; + return std::make_unique<TreeDisplayDataAPI>(space_outliner); case SO_ID_ORPHANS: - tree_display = new TreeDisplayIDOrphans(*space_outliner); - break; + return std::make_unique<TreeDisplayIDOrphans>(space_outliner); case SO_OVERRIDES_LIBRARY: - tree_display = new TreeDisplayOverrideLibrary(*space_outliner); - break; + return std::make_unique<TreeDisplayOverrideLibrary>(space_outliner); case SO_VIEW_LAYER: + /* FIXME(Julian): this should not be the default! Return nullptr and handle that as valid + * case. */ default: - tree_display = new TreeDisplayViewLayer(*space_outliner); - break; + return std::make_unique<TreeDisplayViewLayer>(space_outliner); } - - return reinterpret_cast<TreeDisplay *>(tree_display); } -void outliner_tree_display_destroy(TreeDisplay **tree_display) +bool AbstractTreeDisplay::hasWarnings() const { - delete reinterpret_cast<AbstractTreeDisplay *>(*tree_display); - *tree_display = nullptr; + return has_warnings; } -ListBase outliner_tree_display_build_tree(TreeDisplay *tree_display, TreeSourceData *source_data) -{ - return reinterpret_cast<AbstractTreeDisplay *>(tree_display)->buildTree(*source_data); -} +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_display.h b/source/blender/editors/space_outliner/tree/tree_display.h deleted file mode 100644 index b6dc33ba7b7..00000000000 --- a/source/blender/editors/space_outliner/tree/tree_display.h +++ /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. - */ - -/** \file - * \ingroup spoutliner - * - * C-API for the Tree-Display types. - */ - -#pragma once - -#include "DNA_space_types.h" - -struct ListBase; - -#ifdef __cplusplus -extern "C" { -#endif - -/** C alias for an #AbstractTreeDisplay handle. */ -typedef struct TreeDisplay TreeDisplay; - -/** - * \brief The data to build the tree from. - */ -typedef struct TreeSourceData { - struct Main *bmain; - struct Scene *scene; - struct ViewLayer *view_layer; -} TreeSourceData; - -TreeDisplay *outliner_tree_display_create(eSpaceOutliner_Mode mode, SpaceOutliner *space_outliner); -void outliner_tree_display_destroy(TreeDisplay **tree_display); - -ListBase outliner_tree_display_build_tree(TreeDisplay *tree_display, TreeSourceData *source_data); - -/* The following functions are needed to build the tree. They are calls back into C; the way - * elements are created should be refactored and ported to C++ with a new design/API too. */ -/** - * TODO: this function needs to be split up! It's getting a bit too large... - * - * \note "ID" is not always a real ID. - * \note If child items are only added to the tree if the item is open, - * the `TSE_` type _must_ be added to #outliner_element_needs_rebuild_on_open_change(). - */ -struct TreeElement *outliner_add_element(SpaceOutliner *space_outliner, - ListBase *lb, - void *idv, - struct TreeElement *parent, - short type, - short index); -/* make sure elements are correctly nested */ -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); - -#ifdef __cplusplus -} -#endif diff --git a/source/blender/editors/space_outliner/tree/tree_display.hh b/source/blender/editors/space_outliner/tree/tree_display.hh index 54e64655b18..68f0f9c562d 100644 --- a/source/blender/editors/space_outliner/tree/tree_display.hh +++ b/source/blender/editors/space_outliner/tree/tree_display.hh @@ -34,16 +34,35 @@ #pragma once -#include "tree_display.h" +#include <memory> +struct ID; +struct LayerCollection; +struct Library; struct ListBase; struct Main; +struct Scene; +struct Sequence; struct SpaceOutliner; struct TreeElement; -struct TreeSourceData; +struct ViewLayer; namespace blender::ed::outliner { +/** + * \brief The data to build the tree from. + */ +struct TreeSourceData { + Main *bmain; + Scene *scene; + ViewLayer *view_layer; + + TreeSourceData(Main &bmain, Scene &scene, ViewLayer &view_layer) + : bmain(&bmain), scene(&scene), view_layer(&view_layer) + { + } +}; + /* -------------------------------------------------------------------- */ /* Tree-Display Interface */ @@ -59,13 +78,21 @@ class AbstractTreeDisplay { } virtual ~AbstractTreeDisplay() = default; + static std::unique_ptr<AbstractTreeDisplay> createFromDisplayMode( + int /*eSpaceOutliner_Mode*/ mode, SpaceOutliner &space_outliner); + /** * Build a tree for this display mode with the Blender context data given in \a source_data and * the view settings in \a space_outliner. */ virtual ListBase buildTree(const TreeSourceData &source_data) = 0; + /** Accessor to whether given tree has some warnings to display. */ + bool hasWarnings() const; + protected: + bool has_warnings = false; + /** All derived classes will need a handle to this, so storing it in the base for convenience. */ SpaceOutliner &space_outliner_; }; @@ -105,7 +132,7 @@ class TreeDisplayLibraries final : public AbstractTreeDisplay { ListBase buildTree(const TreeSourceData &source_data) override; private: - TreeElement *add_library_contents(Main &, ListBase &, Library *) const; + TreeElement *add_library_contents(Main &, ListBase &, Library *); bool library_id_filter_poll(const Library *lib, ID *id) const; short id_filter_get() const; }; @@ -123,7 +150,7 @@ class TreeDisplayOverrideLibrary final : public AbstractTreeDisplay { ListBase buildTree(const TreeSourceData &source_data) override; private: - TreeElement *add_library_contents(Main &, ListBase &, Library *) const; + TreeElement *add_library_contents(Main &, ListBase &, Library *); bool override_library_id_filter_poll(const Library *lib, ID *id) const; short id_filter_get() const; }; diff --git a/source/blender/editors/space_outliner/tree/tree_display_data.cc b/source/blender/editors/space_outliner/tree/tree_display_data.cc index 8a5c2e7d9f3..5c88e88bd37 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_data.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_data.cc @@ -21,10 +21,13 @@ #include "BLI_listbase.h" #include "BLI_mempool.h" +#include "DNA_space_types.h" + #include "RNA_access.h" -#include "../outliner_intern.h" +#include "../outliner_intern.hh" #include "tree_display.hh" +#include "tree_element.hh" namespace blender::ed::outliner { 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 836f0937cf4..1d77e82612d 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_libraries.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_libraries.cc @@ -25,11 +25,14 @@ #include "BKE_main.h" #include "DNA_collection_types.h" +#include "DNA_space_types.h" #include "BLT_translation.h" -#include "../outliner_intern.h" +#include "../outliner_intern.hh" +#include "common.hh" #include "tree_display.hh" +#include "tree_element.hh" namespace blender::ed::outliner { @@ -104,9 +107,7 @@ ListBase TreeDisplayLibraries::buildTree(const TreeSourceData &source_data) return tree; } -TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar, - ListBase &lb, - Library *lib) const +TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar, ListBase &lb, Library *lib) { const short filter_id_type = id_filter_get(); @@ -149,6 +150,9 @@ TreeElement *TreeDisplayLibraries::add_library_contents(Main &mainvar, tenlib = outliner_add_element(&space_outliner_, &lb, &mainvar, nullptr, TSE_ID_BASE, 0); tenlib->name = IFACE_("Current File"); } + if (tenlib->flag & TE_HAS_WARNING) { + has_warnings = true; + } } /* Create data-block list parent element on demand. */ 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 eeb3ca6893a..587f807c40c 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_orphaned.cc @@ -19,6 +19,7 @@ */ #include "DNA_ID.h" +#include "DNA_space_types.h" #include "BLI_listbase.h" #include "BLI_listbase_wrapper.hh" @@ -26,8 +27,10 @@ #include "BKE_main.h" -#include "../outliner_intern.h" +#include "../outliner_intern.hh" +#include "common.hh" #include "tree_display.hh" +#include "tree_element.hh" namespace blender::ed::outliner { diff --git a/source/blender/editors/space_outliner/tree/tree_display_override_library.cc b/source/blender/editors/space_outliner/tree/tree_display_override_library.cc index 943e182277c..d9a0661d3b4 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_override_library.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_override_library.cc @@ -25,11 +25,14 @@ #include "BKE_main.h" #include "DNA_collection_types.h" +#include "DNA_space_types.h" #include "BLT_translation.h" -#include "../outliner_intern.h" +#include "../outliner_intern.hh" +#include "common.hh" #include "tree_display.hh" +#include "tree_element.hh" namespace blender::ed::outliner { @@ -112,7 +115,7 @@ ListBase TreeDisplayOverrideLibrary::buildTree(const TreeSourceData &source_data TreeElement *TreeDisplayOverrideLibrary::add_library_contents(Main &mainvar, ListBase &lb, - Library *lib) const + Library *lib) { const short filter_id_type = id_filter_get(); @@ -152,6 +155,9 @@ TreeElement *TreeDisplayOverrideLibrary::add_library_contents(Main &mainvar, tenlib = outliner_add_element(&space_outliner_, &lb, &mainvar, nullptr, TSE_ID_BASE, 0); tenlib->name = IFACE_("Current File"); } + if (tenlib->flag & TE_HAS_WARNING) { + has_warnings = true; + } } /* Create data-block list parent element on demand. */ 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 29442aace37..ad66e8a7ee5 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_scenes.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_scenes.cc @@ -18,14 +18,18 @@ * \ingroup spoutliner */ +#include "DNA_space_types.h" + #include "BLI_listbase.h" #include "BLI_listbase_wrapper.hh" #include "BLI_mempool.h" #include "BKE_main.h" -#include "../outliner_intern.h" +#include "../outliner_intern.hh" +#include "common.hh" #include "tree_display.hh" +#include "tree_element.hh" namespace blender::ed::outliner { diff --git a/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc b/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc index aa28b164584..7c5137a72dd 100644 --- a/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc +++ b/source/blender/editors/space_outliner/tree/tree_display_sequencer.cc @@ -24,10 +24,14 @@ #include "BLI_listbase_wrapper.hh" #include "BLI_utildefines.h" +#include "DNA_sequence_types.h" +#include "DNA_space_types.h" + #include "SEQ_sequencer.h" -#include "../outliner_intern.h" +#include "../outliner_intern.hh" #include "tree_display.hh" +#include "tree_element.hh" namespace blender::ed::outliner { 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 ebbc9baaa9f..73990b45562 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 @@ -22,6 +22,7 @@ #include "DNA_collection_types.h" #include "DNA_scene_types.h" +#include "DNA_space_types.h" #include "BKE_layer.h" @@ -32,8 +33,10 @@ #include "BLT_translation.h" -#include "../outliner_intern.h" +#include "../outliner_intern.hh" +#include "common.hh" #include "tree_display.hh" +#include "tree_element.hh" namespace blender::ed::outliner { diff --git a/source/blender/editors/space_outliner/tree/tree_element.cc b/source/blender/editors/space_outliner/tree/tree_element.cc index 36da7fe1944..5685d8964f5 100644 --- a/source/blender/editors/space_outliner/tree/tree_element.cc +++ b/source/blender/editors/space_outliner/tree/tree_element.cc @@ -20,6 +20,11 @@ #include "DNA_anim_types.h" #include "DNA_listBase.h" +#include "DNA_space_types.h" + +#include "UI_resources.h" + +#include "BLT_translation.h" #include "tree_element_anim_data.hh" #include "tree_element_collection.hh" @@ -28,15 +33,19 @@ #include "tree_element_id.hh" #include "tree_element_nla.hh" #include "tree_element_overrides.hh" +#include "tree_element_rna.hh" #include "tree_element_scene_objects.hh" +#include "tree_element_seq.hh" #include "tree_element_view_layer.hh" -#include "tree_element.h" +#include "../outliner_intern.hh" #include "tree_element.hh" namespace blender::ed::outliner { -static AbstractTreeElement *tree_element_create(int type, TreeElement &legacy_te, void *idv) +std::unique_ptr<AbstractTreeElement> AbstractTreeElement::createFromType(const int type, + TreeElement &legacy_te, + void *idv) { ID &id = *static_cast<ID *>(idv); @@ -56,28 +65,46 @@ static AbstractTreeElement *tree_element_create(int type, TreeElement &legacy_te case TSE_SOME_ID: return TreeElementID::createFromID(legacy_te, id); case TSE_ANIM_DATA: - return new TreeElementAnimData(legacy_te, *reinterpret_cast<IdAdtTemplate &>(id).adt); + return std::make_unique<TreeElementAnimData>(legacy_te, + *reinterpret_cast<IdAdtTemplate &>(id).adt); case TSE_DRIVER_BASE: - return new TreeElementDriverBase(legacy_te, *static_cast<AnimData *>(idv)); + return std::make_unique<TreeElementDriverBase>(legacy_te, *static_cast<AnimData *>(idv)); case TSE_NLA: - return new TreeElementNLA(legacy_te, *static_cast<AnimData *>(idv)); + return std::make_unique<TreeElementNLA>(legacy_te, *static_cast<AnimData *>(idv)); case TSE_NLA_TRACK: - return new TreeElementNLATrack(legacy_te, *static_cast<NlaTrack *>(idv)); + return std::make_unique<TreeElementNLATrack>(legacy_te, *static_cast<NlaTrack *>(idv)); case TSE_NLA_ACTION: - return new TreeElementNLAAction(legacy_te, *static_cast<bAction *>(idv)); + return std::make_unique<TreeElementNLAAction>(legacy_te, *static_cast<bAction *>(idv)); case TSE_GP_LAYER: - return new TreeElementGPencilLayer(legacy_te, *static_cast<bGPDlayer *>(idv)); + return std::make_unique<TreeElementGPencilLayer>(legacy_te, *static_cast<bGPDlayer *>(idv)); case TSE_R_LAYER_BASE: - return new TreeElementViewLayerBase(legacy_te, *static_cast<Scene *>(idv)); + return std::make_unique<TreeElementViewLayerBase>(legacy_te, *static_cast<Scene *>(idv)); case TSE_SCENE_COLLECTION_BASE: - return new TreeElementCollectionBase(legacy_te, *static_cast<Scene *>(idv)); + return std::make_unique<TreeElementCollectionBase>(legacy_te, *static_cast<Scene *>(idv)); case TSE_SCENE_OBJECTS_BASE: - return new TreeElementSceneObjectsBase(legacy_te, *static_cast<Scene *>(idv)); + return std::make_unique<TreeElementSceneObjectsBase>(legacy_te, *static_cast<Scene *>(idv)); case TSE_LIBRARY_OVERRIDE_BASE: - return new TreeElementOverridesBase(legacy_te, id); + return std::make_unique<TreeElementOverridesBase>(legacy_te, id); case TSE_LIBRARY_OVERRIDE: - return new TreeElementOverridesProperty(legacy_te, - *static_cast<TreeElementOverridesData *>(idv)); + return std::make_unique<TreeElementOverridesProperty>( + legacy_te, *static_cast<TreeElementOverridesData *>(idv)); + case TSE_RNA_STRUCT: + return std::make_unique<TreeElementRNAStruct>(legacy_te, + *reinterpret_cast<PointerRNA *>(idv)); + case TSE_RNA_PROPERTY: + return std::make_unique<TreeElementRNAProperty>( + legacy_te, *reinterpret_cast<PointerRNA *>(idv), legacy_te.index); + case TSE_RNA_ARRAY_ELEM: + return std::make_unique<TreeElementRNAArrayElement>( + legacy_te, *reinterpret_cast<PointerRNA *>(idv), legacy_te.index); + case TSE_SEQUENCE: + return std::make_unique<TreeElementSequence>(legacy_te, *reinterpret_cast<Sequence *>(idv)); + case TSE_SEQ_STRIP: + return std::make_unique<TreeElementSequenceStrip>(legacy_te, + *reinterpret_cast<Strip *>(idv)); + case TSE_SEQUENCE_DUP: + return std::make_unique<TreeElementSequenceStripDuplicate>( + legacy_te, *reinterpret_cast<Sequence *>(idv)); default: break; } @@ -85,14 +112,7 @@ static AbstractTreeElement *tree_element_create(int type, TreeElement &legacy_te return nullptr; } -static void tree_element_free(AbstractTreeElement **tree_element) -{ - delete *tree_element; - *tree_element = nullptr; -} - -static void tree_element_expand(const AbstractTreeElement &tree_element, - SpaceOutliner &space_outliner) +void tree_element_expand(const 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 @@ -104,58 +124,39 @@ static void tree_element_expand(const AbstractTreeElement &tree_element, 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(const AbstractTreeElement &tree_element, - SpaceOutliner &space_outliner) +bool tree_element_warnings_get(TreeElement *te, int *r_icon, const char **r_message) { - 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(const AbstractTreeElement &tree_element, - const SpaceOutliner &space_outliner) -{ - return tree_element.expandPoll(space_outliner); -} + TreeStoreElem *tselem = te->store_elem; -} // namespace blender::ed::outliner - -namespace outliner = blender::ed::outliner; - -TreeElementType *outliner_tree_element_type_create(int type, TreeElement *legacy_te, void *idv) -{ - outliner::AbstractTreeElement *element = outliner::tree_element_create(type, *legacy_te, idv); - return reinterpret_cast<TreeElementType *>(element); -} + if (tselem->type != TSE_SOME_ID) { + return false; + } + if (te->idcode != ID_LI) { + return false; + } -void outliner_tree_element_type_expand(TreeElementType *type, SpaceOutliner *space_outliner) -{ - 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); + Library *library = (Library *)tselem->id; + if (library->tag & LIBRARY_TAG_RESYNC_REQUIRED) { + if (r_icon) { + *r_icon = ICON_ERROR; + } + if (r_message) { + *r_message = TIP_( + "Contains linked library overrides that need to be resynced, updating the library is " + "recommended"); + } + return true; + } + if (library->id.tag & LIB_TAG_MISSING) { + if (r_icon) { + *r_icon = ICON_ERROR; + } + if (r_message) { + *r_message = TIP_("Missing library"); + } + return true; + } + return false; } -void outliner_tree_element_type_free(TreeElementType **type) -{ - outliner::tree_element_free(reinterpret_cast<outliner::AbstractTreeElement **>(type)); -} +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element.h b/source/blender/editors/space_outliner/tree/tree_element.h deleted file mode 100644 index 8e5b02278cc..00000000000 --- a/source/blender/editors/space_outliner/tree/tree_element.h +++ /dev/null @@ -1,48 +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. - */ - -/** \file - * \ingroup spoutliner - * - * C-API for the Tree-Element types. - * This API shouldn't stay for long. All tree building should eventually be done through C++ types, - * with more type safety and an easier to reason about design. - */ - -#pragma once - -#include "DNA_space_types.h" - -struct TreeElement; - -#ifdef __cplusplus -extern "C" { -#endif - -/** C alias for an #AbstractTreeElement handle. */ -typedef struct TreeElementType TreeElementType; - -TreeElementType *outliner_tree_element_type_create(int type, TreeElement *legacy_te, void *idv); -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 -} -#endif diff --git a/source/blender/editors/space_outliner/tree/tree_element.hh b/source/blender/editors/space_outliner/tree/tree_element.hh index 09bd0eec05d..aca5738b91a 100644 --- a/source/blender/editors/space_outliner/tree/tree_element.hh +++ b/source/blender/editors/space_outliner/tree/tree_element.hh @@ -20,7 +20,11 @@ #pragma once -#include "tree_element.h" +#include <memory> + +struct ListBase; +struct SpaceOutliner; +struct TreeElement; namespace blender::ed::outliner { @@ -39,6 +43,10 @@ class AbstractTreeElement { public: virtual ~AbstractTreeElement() = default; + static std::unique_ptr<AbstractTreeElement> createFromType(int type, + TreeElement &legacy_te, + void *idv); + /** * Check if the type is expandable in current context. */ @@ -46,12 +54,6 @@ class AbstractTreeElement { { return true; } - /** - * Let the type add its own children. - */ - virtual void expand(SpaceOutliner &) const - { - } virtual void postExpand(SpaceOutliner &) const { } @@ -65,11 +67,46 @@ class AbstractTreeElement { return true; } + friend void tree_element_expand(const AbstractTreeElement &tree_element, + SpaceOutliner &space_outliner); + protected: /* Pseudo-abstract: Only allow creation through derived types. */ AbstractTreeElement(TreeElement &legacy_te) : legacy_te_(legacy_te) { } + + /** + * Let the type add its own children. + */ + virtual void expand(SpaceOutliner &) const + { + } }; +/** + * TODO: this function needs to be split up! It's getting a bit too large... + * + * \note "ID" is not always a real ID. + * \note If child items are only added to the tree if the item is open, + * the `TSE_` type _must_ be added to #outliner_element_needs_rebuild_on_open_change(). + */ +struct TreeElement *outliner_add_element(SpaceOutliner *space_outliner, + ListBase *lb, + void *idv, + struct TreeElement *parent, + short type, + short index); + +void tree_element_expand(const AbstractTreeElement &tree_element, SpaceOutliner &space_outliner); + +/** + * Get actual warning data of a tree element, if any. + * + * \param r_icon The icon to display as warning. + * \param r_message The message to display as warning. + * \return true if there is a warning, false otherwise. + */ +bool tree_element_warnings_get(struct TreeElement *te, int *r_icon, const char **r_message); + } // 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 c0fef7c98e2..41212f61d5d 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 @@ -22,11 +22,11 @@ #include "DNA_anim_types.h" #include "DNA_listBase.h" +#include "DNA_outliner_types.h" #include "BLT_translation.h" -#include "../outliner_intern.h" -#include "tree_display.h" +#include "../outliner_intern.hh" #include "tree_element_anim_data.hh" diff --git a/source/blender/editors/space_outliner/tree/tree_element_collection.cc b/source/blender/editors/space_outliner/tree/tree_element_collection.cc index 1add61db7f1..0a7ee21df15 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_collection.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_collection.cc @@ -19,11 +19,12 @@ */ #include "DNA_listBase.h" +#include "DNA_outliner_types.h" +#include "DNA_scene_types.h" #include "BLT_translation.h" -#include "../outliner_intern.h" -#include "tree_display.h" +#include "../outliner_intern.hh" #include "tree_element_collection.hh" diff --git a/source/blender/editors/space_outliner/tree/tree_element_driver.cc b/source/blender/editors/space_outliner/tree/tree_element_driver.cc index 42f51908eaa..49d7f91b557 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_driver.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_driver.cc @@ -24,11 +24,11 @@ #include "DNA_anim_types.h" #include "DNA_listBase.h" +#include "DNA_space_types.h" #include "BLT_translation.h" -#include "../outliner_intern.h" -#include "tree_display.h" +#include "../outliner_intern.hh" #include "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 index 91e6fdcde4b..ead83ad6931 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_gpencil_layer.cc @@ -21,8 +21,9 @@ #include "BLI_utildefines.h" #include "DNA_gpencil_types.h" +#include "DNA_space_types.h" -#include "../outliner_intern.h" +#include "../outliner_intern.hh" #include "tree_element_gpencil_layer.hh" diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.cc b/source/blender/editors/space_outliner/tree/tree_element_id.cc index 7ff5a3285f1..afbbd171cf4 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_id.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_id.cc @@ -19,6 +19,7 @@ */ #include "DNA_ID.h" +#include "DNA_space_types.h" #include "BLI_listbase_wrapper.hh" #include "BLI_utildefines.h" @@ -29,8 +30,8 @@ #include "RNA_access.h" -#include "../outliner_intern.h" -#include "tree_display.h" +#include "../outliner_intern.hh" +#include "common.hh" #include "tree_element_id_library.hh" #include "tree_element_id_scene.hh" @@ -38,13 +39,13 @@ namespace blender::ed::outliner { -TreeElementID *TreeElementID::createFromID(TreeElement &legacy_te, ID &id) +std::unique_ptr<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); + return std::make_unique<TreeElementIDLibrary>(legacy_te, (Library &)id); case ID_SCE: - return new TreeElementIDScene(legacy_te, (Scene &)id); + return std::make_unique<TreeElementIDScene>(legacy_te, (Scene &)id); case ID_OB: case ID_ME: case ID_CU: @@ -82,7 +83,7 @@ TreeElementID *TreeElementID::createFromID(TreeElement &legacy_te, ID &id) case ID_PAL: case ID_PC: case ID_CF: - return new TreeElementID(legacy_te, id); + return std::make_unique<TreeElementID>(legacy_te, id); /* Deprecated */ case ID_IP: BLI_assert_msg(0, "Outliner trying to build tree-element for deprecated ID type"); diff --git a/source/blender/editors/space_outliner/tree/tree_element_id.hh b/source/blender/editors/space_outliner/tree/tree_element_id.hh index b3b5ca2770c..9b5b955be0b 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_id.hh +++ b/source/blender/editors/space_outliner/tree/tree_element_id.hh @@ -24,6 +24,9 @@ #include "tree_element.hh" +struct AnimData; +struct ID; + namespace blender::ed::outliner { class TreeElementID : public AbstractTreeElement { @@ -33,7 +36,7 @@ class TreeElementID : public AbstractTreeElement { public: TreeElementID(TreeElement &legacy_te, ID &id); - static TreeElementID *createFromID(TreeElement &legacy_te, ID &id); + static std::unique_ptr<TreeElementID> createFromID(TreeElement &legacy_te, ID &id); void postExpand(SpaceOutliner &) const override; bool expandPoll(const SpaceOutliner &) const override; 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 index 36f536c9845..b5fd67d4807 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_id_library.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_id_library.cc @@ -18,9 +18,10 @@ * \ingroup spoutliner */ +#include "DNA_ID.h" #include "DNA_listBase.h" -#include "../outliner_intern.h" +#include "../outliner_intern.hh" #include "tree_element_id_library.hh" 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 index 88660cd8aa9..ce128b1a5ff 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_id_library.hh +++ b/source/blender/editors/space_outliner/tree/tree_element_id_library.hh @@ -22,6 +22,8 @@ #include "tree_element_id.hh" +struct Library; + namespace blender::ed::outliner { class TreeElementIDLibrary final : public TreeElementID { 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 index ae81b44a1e4..c71d6786c6e 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_id_scene.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_id_scene.cc @@ -19,9 +19,10 @@ */ #include "DNA_listBase.h" +#include "DNA_outliner_types.h" +#include "DNA_scene_types.h" -#include "../outliner_intern.h" -#include "tree_display.h" +#include "../outliner_intern.hh" #include "tree_element_id_scene.hh" diff --git a/source/blender/editors/space_outliner/tree/tree_element_nla.cc b/source/blender/editors/space_outliner/tree/tree_element_nla.cc index 65832e8f981..89ebee49192 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_nla.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_nla.cc @@ -22,11 +22,11 @@ #include "DNA_anim_types.h" #include "DNA_listBase.h" +#include "DNA_space_types.h" #include "BLT_translation.h" -#include "../outliner_intern.h" -#include "tree_display.h" +#include "../outliner_intern.hh" #include "tree_element_nla.hh" diff --git a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc index 731beb3956e..ba1471625b9 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_overrides.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_overrides.cc @@ -27,10 +27,11 @@ #include "BLT_translation.h" +#include "DNA_space_types.h" + #include "RNA_access.h" -#include "../outliner_intern.h" -#include "tree_display.h" +#include "../outliner_intern.hh" #include "tree_element_overrides.hh" diff --git a/source/blender/editors/space_outliner/tree/tree_element_rna.cc b/source/blender/editors/space_outliner/tree/tree_element_rna.cc new file mode 100644 index 00000000000..7a9f1b6f0fa --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_rna.cc @@ -0,0 +1,268 @@ +/* + * 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 <climits> +#include <iostream> + +#include "BLI_listbase.h" +#include "BLI_string.h" + +#include "BLT_translation.h" + +#include "DNA_outliner_types.h" +#include "DNA_space_types.h" + +#include "MEM_guardedalloc.h" + +#include "RNA_access.h" + +#include "../outliner_intern.hh" + +#include "tree_element_rna.hh" + +namespace blender::ed::outliner { + +/* Don't display arrays larger, weak but index is stored as a short, + * also the outliner isn't intended for editing such large data-sets. */ +BLI_STATIC_ASSERT(sizeof(TreeElement::index) == 2, "Index is no longer short!") + +/* -------------------------------------------------------------------- */ +/* Common functionality (#TreeElementRNACommon Base Class) */ + +TreeElementRNACommon::TreeElementRNACommon(TreeElement &legacy_te, PointerRNA &rna_ptr) + : AbstractTreeElement(legacy_te), rna_ptr_(rna_ptr) +{ + /* Create an empty tree-element. */ + if (!isRNAValid()) { + legacy_te_.name = IFACE_("(empty)"); + return; + } +} + +bool TreeElementRNACommon::isExpandValid() const +{ + return true; +} + +bool TreeElementRNACommon::isRNAValid() const +{ + return rna_ptr_.data != nullptr; +} + +bool TreeElementRNACommon::expandPoll(const SpaceOutliner &) const +{ + return isRNAValid(); +} + +const PointerRNA &TreeElementRNACommon::getPointerRNA() const +{ + return rna_ptr_; +} + +PropertyRNA *TreeElementRNACommon::getPropertyRNA() const +{ + return nullptr; +} + +/* -------------------------------------------------------------------- */ +/* RNA Struct */ + +TreeElementRNAStruct::TreeElementRNAStruct(TreeElement &legacy_te, PointerRNA &rna_ptr) + : TreeElementRNACommon(legacy_te, rna_ptr) +{ + BLI_assert(legacy_te.store_elem->type == TSE_RNA_STRUCT); + + if (!isRNAValid()) { + return; + } + + legacy_te_.name = RNA_struct_name_get_alloc(&rna_ptr, nullptr, 0, nullptr); + if (legacy_te_.name) { + legacy_te_.flag |= TE_FREE_NAME; + } + else { + legacy_te_.name = RNA_struct_ui_name(rna_ptr.type); + } +} + +void TreeElementRNAStruct::expand(SpaceOutliner &space_outliner) const +{ + TreeStoreElem &tselem = *TREESTORE(&legacy_te_); + PointerRNA ptr = rna_ptr_; + + /* If searching don't expand RNA entries */ + if (SEARCHING_OUTLINER(&space_outliner) && BLI_strcasecmp("RNA", legacy_te_.name) == 0) { + tselem.flag &= ~TSE_CHILDSEARCH; + } + + PropertyRNA *iterprop = RNA_struct_iterator_property(ptr.type); + int tot = RNA_property_collection_length(&ptr, iterprop); + CLAMP_MAX(tot, max_index); + + TreeElementRNAProperty *parent_prop_te = legacy_te_.parent ? + tree_element_cast<TreeElementRNAProperty>( + legacy_te_.parent) : + nullptr; + /* auto open these cases */ + if (!parent_prop_te || (RNA_property_type(parent_prop_te->getPropertyRNA()) == PROP_POINTER)) { + if (!tselem.used) { + tselem.flag &= ~TSE_CLOSED; + } + } + + if (TSELEM_OPEN(&tselem, &space_outliner)) { + for (int index = 0; index < tot; index++) { + PointerRNA propptr; + RNA_property_collection_lookup_int(&ptr, iterprop, index, &propptr); + if (!(RNA_property_flag(reinterpret_cast<PropertyRNA *>(propptr.data)) & PROP_HIDDEN)) { + outliner_add_element( + &space_outliner, &legacy_te_.subtree, &ptr, &legacy_te_, TSE_RNA_PROPERTY, index); + } + } + } + else if (tot) { + legacy_te_.flag |= TE_LAZY_CLOSED; + } +} + +/* -------------------------------------------------------------------- */ +/* RNA Property */ + +TreeElementRNAProperty::TreeElementRNAProperty(TreeElement &legacy_te, + PointerRNA &rna_ptr, + const int index) + : TreeElementRNACommon(legacy_te, rna_ptr) +{ + BLI_assert(legacy_te.store_elem->type == TSE_RNA_PROPERTY); + + if (!isRNAValid()) { + return; + } + + PointerRNA propptr; + PropertyRNA *iterprop = RNA_struct_iterator_property(rna_ptr.type); + RNA_property_collection_lookup_int(&rna_ptr, iterprop, index, &propptr); + + PropertyRNA *prop = reinterpret_cast<PropertyRNA *>(propptr.data); + + legacy_te_.name = RNA_property_ui_name(prop); + rna_prop_ = prop; +} + +void TreeElementRNAProperty::expand(SpaceOutliner &space_outliner) const +{ + TreeStoreElem &tselem = *TREESTORE(&legacy_te_); + PointerRNA rna_ptr = rna_ptr_; + PropertyType proptype = RNA_property_type(rna_prop_); + + /* If searching don't expand RNA entries */ + if (SEARCHING_OUTLINER(&space_outliner) && BLI_strcasecmp("RNA", legacy_te_.name) == 0) { + tselem.flag &= ~TSE_CHILDSEARCH; + } + + if (proptype == PROP_POINTER) { + PointerRNA pptr = RNA_property_pointer_get(&rna_ptr, rna_prop_); + + if (pptr.data) { + if (TSELEM_OPEN(&tselem, &space_outliner)) { + outliner_add_element( + &space_outliner, &legacy_te_.subtree, &pptr, &legacy_te_, TSE_RNA_STRUCT, -1); + } + else { + legacy_te_.flag |= TE_LAZY_CLOSED; + } + } + } + else if (proptype == PROP_COLLECTION) { + int tot = RNA_property_collection_length(&rna_ptr, rna_prop_); + CLAMP_MAX(tot, max_index); + + if (TSELEM_OPEN(&tselem, &space_outliner)) { + for (int index = 0; index < tot; index++) { + PointerRNA pptr; + RNA_property_collection_lookup_int(&rna_ptr, rna_prop_, index, &pptr); + outliner_add_element( + &space_outliner, &legacy_te_.subtree, &pptr, &legacy_te_, TSE_RNA_STRUCT, index); + } + } + else if (tot) { + legacy_te_.flag |= TE_LAZY_CLOSED; + } + } + else if (ELEM(proptype, PROP_BOOLEAN, PROP_INT, PROP_FLOAT)) { + int tot = RNA_property_array_length(&rna_ptr, rna_prop_); + CLAMP_MAX(tot, max_index); + + if (TSELEM_OPEN(&tselem, &space_outliner)) { + for (int index = 0; index < tot; index++) { + outliner_add_element(&space_outliner, + &legacy_te_.subtree, + &rna_ptr, + &legacy_te_, + TSE_RNA_ARRAY_ELEM, + index); + } + } + else if (tot) { + legacy_te_.flag |= TE_LAZY_CLOSED; + } + } +} + +PropertyRNA *TreeElementRNAProperty::getPropertyRNA() const +{ + return rna_prop_; +} + +/* -------------------------------------------------------------------- */ +/* RNA Array Element */ + +TreeElementRNAArrayElement::TreeElementRNAArrayElement(TreeElement &legacy_te, + PointerRNA &rna_ptr, + const int index) + : TreeElementRNACommon(legacy_te, rna_ptr) +{ + BLI_assert(legacy_te.store_elem->type == TSE_RNA_ARRAY_ELEM); + + BLI_assert(legacy_te.parent && (legacy_te.parent->store_elem->type == TSE_RNA_PROPERTY)); + legacy_te_.index = index; + + char c = RNA_property_array_item_char(TreeElementRNAArrayElement::getPropertyRNA(), index); + + legacy_te_.name = reinterpret_cast<char *>( + MEM_callocN(sizeof(char[20]), "OutlinerRNAArrayName")); + if (c) { + sprintf((char *)legacy_te_.name, " %c", c); + } + else { + sprintf((char *)legacy_te_.name, " %d", index + 1); + } + legacy_te_.flag |= TE_FREE_NAME; +} + +PropertyRNA *TreeElementRNAArrayElement::getPropertyRNA() const +{ + /* Forward query to the parent (which is expected to be a #TreeElementRNAProperty). */ + const TreeElementRNAProperty *parent_prop_te = tree_element_cast<TreeElementRNAProperty>( + legacy_te_.parent); + return parent_prop_te ? parent_prop_te->getPropertyRNA() : nullptr; +} + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_rna.hh b/source/blender/editors/space_outliner/tree/tree_element_rna.hh new file mode 100644 index 00000000000..1f107ddbf88 --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_rna.hh @@ -0,0 +1,86 @@ +/* + * 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 <limits> + +#include "RNA_types.h" + +#include "tree_element.hh" + +struct PointerRNA; + +namespace blender::ed::outliner { + +/** + * Base class for common behavior of RNA tree elements. + */ +class TreeElementRNACommon : public AbstractTreeElement { + protected: + constexpr static int max_index = std::numeric_limits<short>::max(); + PointerRNA rna_ptr_; + + public: + TreeElementRNACommon(TreeElement &legacy_te, PointerRNA &rna_ptr); + bool isExpandValid() const override; + bool expandPoll(const SpaceOutliner &) const override; + + const PointerRNA &getPointerRNA() const; + /** + * If this element represents a property or is part of a property (array element), this returns + * the property. Otherwise nullptr. + */ + virtual PropertyRNA *getPropertyRNA() const; + + bool isRNAValid() const; +}; + +/* -------------------------------------------------------------------- */ + +class TreeElementRNAStruct : public TreeElementRNACommon { + public: + TreeElementRNAStruct(TreeElement &legacy_te, PointerRNA &rna_ptr); + void expand(SpaceOutliner &space_outliner) const override; +}; + +/* -------------------------------------------------------------------- */ + +class TreeElementRNAProperty : public TreeElementRNACommon { + private: + PropertyRNA *rna_prop_ = nullptr; + + public: + TreeElementRNAProperty(TreeElement &legacy_te, PointerRNA &rna_ptr, int index); + void expand(SpaceOutliner &space_outliner) const override; + + PropertyRNA *getPropertyRNA() const override; +}; + +/* -------------------------------------------------------------------- */ + +class TreeElementRNAArrayElement : public TreeElementRNACommon { + public: + TreeElementRNAArrayElement(TreeElement &legacy_te, PointerRNA &rna_ptr, int index); + + PropertyRNA *getPropertyRNA() const override; +}; + +} // 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 index a46e8de1bdd..dad03d392fb 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.cc @@ -24,8 +24,10 @@ #include "BLT_translation.h" -#include "../outliner_intern.h" -#include "tree_display.h" +#include "DNA_outliner_types.h" + +#include "../outliner_intern.hh" +#include "common.hh" #include "tree_element_scene_objects.hh" 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 index a2aa29c4a33..7ce5a404f5c 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh +++ b/source/blender/editors/space_outliner/tree/tree_element_scene_objects.hh @@ -22,6 +22,8 @@ #include "tree_element.hh" +struct Scene; + namespace blender::ed::outliner { class TreeElementSceneObjectsBase final : public AbstractTreeElement { diff --git a/source/blender/editors/space_outliner/tree/tree_element_seq.cc b/source/blender/editors/space_outliner/tree/tree_element_seq.cc new file mode 100644 index 00000000000..8d0b4c140c7 --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_seq.cc @@ -0,0 +1,111 @@ +/* + * 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_outliner_types.h" +#include "DNA_sequence_types.h" + +#include "BLI_listbase.h" + +#include "BLT_translation.h" + +#include "../outliner_intern.hh" +#include "tree_element_seq.hh" + +namespace blender::ed::outliner { + +TreeElementSequence::TreeElementSequence(TreeElement &legacy_te, Sequence &sequence) + : AbstractTreeElement(legacy_te), sequence_(sequence) +{ + BLI_assert(legacy_te.store_elem->type == TSE_SEQUENCE); + + /* + * The idcode is a little hack, but the outliner + * only check te->idcode if te->type is equal to zero, + * so this is "safe". + */ + legacy_te.idcode = sequence_.type; + legacy_te.name = sequence_.name + 2; +} + +bool TreeElementSequence::expandPoll(const SpaceOutliner & /*space_outliner*/) const +{ + return !(sequence_.type & SEQ_TYPE_EFFECT); +} + +void TreeElementSequence::expand(SpaceOutliner &space_outliner) const +{ + /* + * This work like the sequence. + * If the sequence have a name (not default name) + * show it, in other case put the filename. + */ + + if (sequence_.type == SEQ_TYPE_META) { + LISTBASE_FOREACH (Sequence *, child, &sequence_.seqbase) { + outliner_add_element( + &space_outliner, &legacy_te_.subtree, child, &legacy_te_, TSE_SEQUENCE, 0); + } + } + else { + outliner_add_element( + &space_outliner, &legacy_te_.subtree, sequence_.strip, &legacy_te_, TSE_SEQ_STRIP, 0); + } +} + +Sequence &TreeElementSequence::getSequence() const +{ + return sequence_; +} + +/* -------------------------------------------------------------------- */ +/* Strip */ + +TreeElementSequenceStrip::TreeElementSequenceStrip(TreeElement &legacy_te, Strip &strip) + : AbstractTreeElement(legacy_te) +{ + BLI_assert(legacy_te.store_elem->type == TSE_SEQ_STRIP); + + if (strip.dir[0] != '\0') { + legacy_te_.name = strip.dir; + } + else { + legacy_te_.name = IFACE_("Strip None"); + } +} + +/* -------------------------------------------------------------------- */ +/* Strip Duplicate */ + +TreeElementSequenceStripDuplicate::TreeElementSequenceStripDuplicate(TreeElement &legacy_te, + Sequence &sequence) + : AbstractTreeElement(legacy_te), sequence_(sequence) +{ + BLI_assert(legacy_te.store_elem->type == TSE_SEQUENCE_DUP); + + legacy_te_.idcode = sequence.type; + legacy_te_.name = sequence.strip->stripdata->name; +} + +Sequence &TreeElementSequenceStripDuplicate::getSequence() const +{ + return sequence_; +} + +} // namespace blender::ed::outliner diff --git a/source/blender/editors/space_outliner/tree/tree_element_seq.hh b/source/blender/editors/space_outliner/tree/tree_element_seq.hh new file mode 100644 index 00000000000..2b334b5b7fa --- /dev/null +++ b/source/blender/editors/space_outliner/tree/tree_element_seq.hh @@ -0,0 +1,60 @@ +/* + * 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 Sequence; +struct Strip; + +namespace blender::ed::outliner { + +class TreeElementSequence : public AbstractTreeElement { + Sequence &sequence_; + + public: + TreeElementSequence(TreeElement &legacy_te, Sequence &sequence); + + bool expandPoll(const SpaceOutliner &) const override; + void expand(SpaceOutliner &) const override; + + Sequence &getSequence() const; +}; + +/* -------------------------------------------------------------------- */ + +class TreeElementSequenceStrip : public AbstractTreeElement { + public: + TreeElementSequenceStrip(TreeElement &legacy_te, Strip &strip); +}; + +/* -------------------------------------------------------------------- */ + +class TreeElementSequenceStripDuplicate : public AbstractTreeElement { + Sequence &sequence_; + + public: + TreeElementSequenceStripDuplicate(TreeElement &legacy_te, Sequence &sequence); + + Sequence &getSequence() const; +}; + +} // 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 index 7bb9405147e..65786ac89ed 100644 --- a/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc +++ b/source/blender/editors/space_outliner/tree/tree_element_view_layer.cc @@ -19,13 +19,14 @@ */ #include "DNA_layer_types.h" +#include "DNA_scene_types.h" +#include "DNA_space_types.h" #include "BLI_listbase_wrapper.hh" #include "BLT_translation.h" -#include "../outliner_intern.h" -#include "tree_display.h" +#include "../outliner_intern.hh" #include "tree_element_view_layer.hh" diff --git a/source/blender/editors/space_sequencer/sequencer_add.c b/source/blender/editors/space_sequencer/sequencer_add.c index 616953e720a..72c39839739 100644 --- a/source/blender/editors/space_sequencer/sequencer_add.c +++ b/source/blender/editors/space_sequencer/sequencer_add.c @@ -59,6 +59,7 @@ #include "SEQ_add.h" #include "SEQ_effects.h" +#include "SEQ_iterator.h" #include "SEQ_proxy.h" #include "SEQ_relations.h" #include "SEQ_render.h" @@ -601,35 +602,48 @@ static IMB_Proxy_Size seq_get_proxy_size_flags(bContext *C) return proxy_sizes; } -static void seq_build_proxy(bContext *C, Sequence *seq) +static void seq_build_proxy(bContext *C, SeqCollection *movie_strips) { if (U.sequencer_proxy_setup != USER_SEQ_PROXY_SETUP_AUTOMATIC) { return; } - /* Enable and set proxy size. */ - SEQ_proxy_set(seq, true); - seq->strip->proxy->build_size_flags = seq_get_proxy_size_flags(C); - seq->strip->proxy->build_flags |= SEQ_PROXY_SKIP_EXISTING; - - /* Build proxy. */ - GSet *file_list = BLI_gset_new(BLI_ghashutil_strhash_p, BLI_ghashutil_strcmp, "file list"); wmJob *wm_job = ED_seq_proxy_wm_job_get(C); ProxyJob *pj = ED_seq_proxy_job_get(C, wm_job); - SEQ_proxy_rebuild_context(pj->main, pj->depsgraph, pj->scene, seq, file_list, &pj->queue); - BLI_gset_free(file_list, MEM_freeN); + + Sequence *seq; + SEQ_ITERATOR_FOREACH (seq, movie_strips) { + /* Enable and set proxy size. */ + SEQ_proxy_set(seq, true); + seq->strip->proxy->build_size_flags = seq_get_proxy_size_flags(C); + seq->strip->proxy->build_flags |= SEQ_PROXY_SKIP_EXISTING; + SEQ_proxy_rebuild_context(pj->main, pj->depsgraph, pj->scene, seq, NULL, &pj->queue, true); + } if (!WM_jobs_is_running(wm_job)) { G.is_break = false; WM_jobs_start(CTX_wm_manager(C), wm_job); } - ED_area_tag_redraw(CTX_wm_area(C)); } +static void sequencer_add_movie_clamp_sound_strip_length(Scene *scene, + ListBase *seqbase, + Sequence *seq_movie, + Sequence *seq_sound) +{ + if (ELEM(NULL, seq_movie, seq_sound) || seq_sound->len <= seq_movie->len) { + return; + } + + SEQ_transform_set_right_handle_frame(seq_sound, SEQ_transform_get_right_handle_frame(seq_movie)); + SEQ_time_update_sequence(scene, seqbase, seq_sound); +} + static void sequencer_add_movie_multiple_strips(bContext *C, wmOperator *op, - SeqLoadData *load_data) + SeqLoadData *load_data, + SeqCollection *r_movie_strips) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); @@ -689,15 +703,19 @@ static void sequencer_add_movie_multiple_strips(bContext *C, else { load_data->start_frame += seq_movie->enddisp - seq_movie->startdisp; } + sequencer_add_movie_clamp_sound_strip_length(scene, ed->seqbasep, seq_movie, seq_sound); seq_load_apply_generic_options(C, op, seq_sound); seq_load_apply_generic_options(C, op, seq_movie); - seq_build_proxy(C, seq_movie); + SEQ_collection_append_strip(seq_movie, r_movie_strips); } } RNA_END; } -static bool sequencer_add_movie_single_strip(bContext *C, wmOperator *op, SeqLoadData *load_data) +static bool sequencer_add_movie_single_strip(bContext *C, + wmOperator *op, + SeqLoadData *load_data, + SeqCollection *r_movie_strips) { Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); @@ -740,9 +758,10 @@ static bool sequencer_add_movie_single_strip(bContext *C, wmOperator *op, SeqLoa load_data->start_frame += audio_frame_offset; seq_sound = SEQ_add_sound_strip(bmain, scene, ed->seqbasep, load_data, audio_skip); } + sequencer_add_movie_clamp_sound_strip_length(scene, ed->seqbasep, seq_movie, seq_sound); seq_load_apply_generic_options(C, op, seq_sound); seq_load_apply_generic_options(C, op, seq_movie); - seq_build_proxy(C, seq_movie); + SEQ_collection_append_strip(seq_movie, r_movie_strips); return true; } @@ -759,21 +778,25 @@ static int sequencer_add_movie_strip_exec(bContext *C, wmOperator *op) ED_sequencer_deselect_all(scene); } + SeqCollection *movie_strips = SEQ_collection_create(__func__); const int tot_files = RNA_property_collection_length(op->ptr, RNA_struct_find_property(op->ptr, "files")); if (tot_files > 1) { - sequencer_add_movie_multiple_strips(C, op, &load_data); + sequencer_add_movie_multiple_strips(C, op, &load_data, movie_strips); } else { - if (!sequencer_add_movie_single_strip(C, op, &load_data)) { - sequencer_add_cancel(C, op); - return OPERATOR_CANCELLED; - } + sequencer_add_movie_single_strip(C, op, &load_data, movie_strips); + } + + if (SEQ_collection_len(movie_strips) == 0) { + SEQ_collection_free(movie_strips); + return OPERATOR_CANCELLED; } /* Free custom data. */ sequencer_add_cancel(C, op); + seq_build_proxy(C, movie_strips); DEG_relations_tag_update(bmain); DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index e814530d1e2..6dffc0bc2a4 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -2262,28 +2262,15 @@ void sequencer_draw_preview(const bContext *C, seq_prefetch_wm_notify(C, scene); } -/* Draw backdrop in sequencer timeline. */ -static void draw_seq_backdrop(View2D *v2d) +static void draw_seq_timeline_channels(View2D *v2d) { - int i; - uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); - - /* View backdrop. */ - immUniformThemeColor(TH_BACK); - immRectf(pos, v2d->cur.xmin, v2d->cur.ymin, v2d->cur.xmax, v2d->cur.ymax); - - /* Darker overlay over the view backdrop. */ - immUniformThemeColorShade(TH_BACK, -10); - immRectf(pos, v2d->cur.xmin, -1.0, v2d->cur.xmax, 1.0); - - /* Alternating horizontal stripes. */ - i = max_ii(1, ((int)v2d->cur.ymin) - 1); - GPU_blend(GPU_BLEND_ALPHA); immUniformThemeColor(TH_ROW_ALTERNATE); + /* Alternating horizontal stripes. */ + int i = max_ii(1, ((int)v2d->cur.ymin) - 1); while (i < v2d->cur.ymax) { if (i & 1) { immRectf(pos, v2d->cur.xmin, i, v2d->cur.xmax, i + 1); @@ -2295,6 +2282,14 @@ static void draw_seq_backdrop(View2D *v2d) immUnbindProgram(); } +static void draw_seq_timeline_channel_numbers(ARegion *region) +{ + View2D *v2d = ®ion->v2d; + rcti rect; + BLI_rcti_init(&rect, 0, 15 * UI_DPI_FAC, 15 * UI_DPI_FAC, region->winy - UI_TIME_SCRUB_MARGIN_Y); + UI_view2d_draw_scale_y__block(region, v2d, &rect, TH_SCROLL_TEXT); +} + static void draw_seq_strips(const bContext *C, Editing *ed, ARegion *region) { Scene *scene = CTX_data_scene(C); @@ -2718,7 +2713,7 @@ void draw_timeline_seq(const bContext *C, ARegion *region) } UI_view2d_view_ortho(v2d); - draw_seq_backdrop(v2d); + draw_seq_timeline_channels(v2d); if ((sseq->flag & SEQ_SHOW_OVERLAY) && (sseq->timeline_overlay.flag & SEQ_TIMELINE_SHOW_GRID)) { U.v2d_min_gridsize *= 3; UI_view2d_draw_lines_x__discrete_frames_or_seconds( @@ -2776,13 +2771,7 @@ void draw_timeline_seq(const bContext *C, ARegion *region) UI_view2d_view_restore(C); ED_time_scrub_draw(region, scene, !(sseq->flag & SEQ_DRAWFRAMES), true); - /* Draw channel numbers. */ - { - rcti rect; - BLI_rcti_init( - &rect, 0, 15 * UI_DPI_FAC, 15 * UI_DPI_FAC, region->winy - UI_TIME_SCRUB_MARGIN_Y); - UI_view2d_draw_scale_y__block(region, v2d, &rect, TH_SCROLL_TEXT); - } + draw_seq_timeline_channel_numbers(region); } void draw_timeline_seq_display(const bContext *C, ARegion *region) diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index e9f37fa6838..3b5e16d84a9 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -39,6 +39,7 @@ #include "DNA_sound_types.h" #include "BKE_context.h" +#include "BKE_fcurve.h" #include "BKE_global.h" #include "BKE_lib_id.h" #include "BKE_main.h" @@ -46,6 +47,7 @@ #include "BKE_sound.h" #include "SEQ_add.h" +#include "SEQ_animation.h" #include "SEQ_clipboard.h" #include "SEQ_edit.h" #include "SEQ_effects.h" @@ -66,6 +68,7 @@ #include "RNA_enum_types.h" /* For menu, popup, icons, etc. */ +#include "ED_keyframing.h" #include "ED_numinput.h" #include "ED_outliner.h" #include "ED_screen.h" @@ -1558,7 +1561,7 @@ static int sequencer_split_invoke(bContext *C, wmOperator *op, const wmEvent *ev } RNA_int_set(op->ptr, "channel", mouseloc[1]); RNA_enum_set(op->ptr, "side", split_side); - /*RNA_enum_set(op->ptr, "type", split_hard); */ + // RNA_enum_set(op->ptr, "type", split_hard); return sequencer_split_exec(C, op); } @@ -1655,6 +1658,35 @@ void SEQUENCER_OT_split(struct wmOperatorType *ot) /** \name Duplicate Strips Operator * \{ */ +static void sequencer_backup_original_animation(Scene *scene, ListBase *list) +{ + if (scene->adt == NULL || scene->adt->action == NULL || + BLI_listbase_is_empty(&scene->adt->action->curves)) { + return; + } + + BLI_movelisttolist(list, &scene->adt->action->curves); +} + +static void sequencer_restore_original_animation(Scene *scene, ListBase *list) +{ + if (scene->adt == NULL || scene->adt->action == NULL || BLI_listbase_is_empty(list)) { + return; + } + + BLI_movelisttolist(&scene->adt->action->curves, list); +} + +static void sequencer_duplicate_animation(Scene *scene, Sequence *seq, ListBase *curves_backup) +{ + GSet *fcurves = SEQ_fcurves_by_strip_get(seq, curves_backup); + GSET_FOREACH_BEGIN (FCurve *, fcu, fcurves) { + FCurve *fcu_cpy = BKE_fcurve_copy(fcu); + BLI_addtail(&scene->adt->action->curves, fcu_cpy); + } + GSET_FOREACH_END(); +} + static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) { Scene *scene = CTX_data_scene(C); @@ -1665,32 +1697,44 @@ static int sequencer_add_duplicate_exec(bContext *C, wmOperator *UNUSED(op)) } Sequence *active_seq = SEQ_select_active_get(scene); - ListBase duplicated = {NULL, NULL}; + ListBase duplicated_strips = {NULL, NULL}; - SEQ_sequence_base_dupli_recursive(scene, scene, &duplicated, ed->seqbasep, 0, 0); + SEQ_sequence_base_dupli_recursive(scene, scene, &duplicated_strips, ed->seqbasep, 0, 0); ED_sequencer_deselect_all(scene); - if (duplicated.first) { - Sequence *seq = duplicated.first; - /* Rely on the nseqbase list being added at the end. - * Their UUIDs has been re-generated by the SEQ_sequence_base_dupli_recursive(), */ - BLI_movelisttolist(ed->seqbasep, &duplicated); - - /* Handle duplicated strips: set active, select, ensure unique name and duplicate animation - * data. */ - for (; seq; seq = seq->next) { - if (active_seq != NULL && STREQ(seq->name, active_seq->name)) { - SEQ_select_active_set(scene, seq); - } - seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL + SEQ_LOCK); - SEQ_ensure_unique_name(seq, scene); - } + if (duplicated_strips.first == NULL) { + return OPERATOR_CANCELLED; + } - WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); - return OPERATOR_FINISHED; + /* Duplicate animation. + * First backup original curves from scene and duplicate strip curves from backup into scene. + * This way, when pasted strips are renamed, curves are renamed with them. Finally, restore + * original curves from backup. + */ + ListBase fcurves_original_backup = {NULL, NULL}; + sequencer_backup_original_animation(scene, &fcurves_original_backup); + + Sequence *seq = duplicated_strips.first; + + /* Rely on the nseqbase list being added at the end. + * Their UUIDs has been re-generated by the SEQ_sequence_base_dupli_recursive(), */ + BLI_movelisttolist(ed->seqbasep, &duplicated_strips); + + /* Handle duplicated strips: set active, select, ensure unique name and duplicate animation + * data. */ + for (; seq; seq = seq->next) { + if (active_seq != NULL && STREQ(seq->name, active_seq->name)) { + SEQ_select_active_set(scene, seq); + } + seq->flag &= ~(SEQ_LEFTSEL + SEQ_RIGHTSEL + SEQ_LOCK); + sequencer_duplicate_animation(scene, seq, &fcurves_original_backup); + SEQ_ensure_unique_name(seq, scene); } - return OPERATOR_CANCELLED; + sequencer_restore_original_animation(scene, &fcurves_original_backup); + + WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); + return OPERATOR_FINISHED; } void SEQUENCER_OT_duplicate(wmOperatorType *ot) @@ -1905,7 +1949,7 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op) } seq_next = seq->next; - SEQ_sequence_free(scene, seq, true); + SEQ_edit_flag_for_removal(scene, seqbase, seq); seq = seq_next; } else { @@ -1913,6 +1957,8 @@ static int sequencer_separate_images_exec(bContext *C, wmOperator *op) } } + SEQ_edit_remove_flagged_sequences(scene, seqbase); + SEQ_sort(seqbase); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); @@ -1950,6 +1996,8 @@ static int sequencer_meta_toggle_exec(bContext *C, wmOperator *UNUSED(op)) Editing *ed = SEQ_editing_get(scene); Sequence *active_seq = SEQ_select_active_get(scene); + SEQ_prefetch_stop(scene); + if (active_seq && active_seq->type == SEQ_TYPE_META && active_seq->flag & SELECT) { /* Enter meta-strip. */ SEQ_meta_stack_alloc(ed, active_seq); @@ -2439,6 +2487,22 @@ static void seq_copy_del_sound(Scene *scene, Sequence *seq) } } +static void sequencer_copy_animation(Scene *scene, Sequence *seq) +{ + if (scene->adt == NULL || scene->adt->action == NULL || + BLI_listbase_is_empty(&scene->adt->action->curves)) { + return; + } + + GSet *fcurves = SEQ_fcurves_by_strip_get(seq, &scene->adt->action->curves); + + GSET_FOREACH_BEGIN (FCurve *, fcu, fcurves) { + BLI_addtail(&fcurves_clipboard, BKE_fcurve_copy(fcu)); + } + GSET_FOREACH_END(); + BLI_gset_free(fcurves, NULL); +} + static int sequencer_copy_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); @@ -2465,8 +2529,10 @@ static int sequencer_copy_exec(bContext *C, wmOperator *op) seqbase_clipboard_frame = scene->r.cfra; SEQ_clipboard_active_seq_name_store(scene); - /* Remove anything that references the current scene. */ LISTBASE_FOREACH (Sequence *, seq, &seqbase_clipboard) { + /* Copy curves. */ + sequencer_copy_animation(scene, seq); + /* Remove anything that references the current scene. */ seq_copy_del_sound(scene, seq); } @@ -2511,6 +2577,29 @@ void ED_sequencer_deselect_all(Scene *scene) } } +static void sequencer_paste_animation(bContext *C) +{ + if (BLI_listbase_is_empty(&fcurves_clipboard)) { + return; + } + + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); + bAction *act; + + if (scene->adt != NULL && scene->adt->action != NULL) { + act = scene->adt->action; + } + else { + /* get action to add F-Curve+keyframe to */ + act = ED_id_action_ensure(bmain, &scene->id); + } + + LISTBASE_FOREACH (FCurve *, fcu, &fcurves_clipboard) { + BLI_addtail(&act->curves, BKE_fcurve_copy(fcu)); + } +} + static int sequencer_paste_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); @@ -2540,6 +2629,17 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op) ofs = scene->r.cfra - min_seq_startdisp; } + /* Paste animation. + * Note: Only fcurves are copied. Drivers and NLA action strips are not copied. + * First backup original curves from scene and move curves from clipboard into scene. This way, + * when pasted strips are renamed, pasted fcurves are renamed with them. Finally restore original + * curves from backup. + */ + + ListBase fcurves_original_backup = {NULL, NULL}; + sequencer_backup_original_animation(scene, &fcurves_original_backup); + sequencer_paste_animation(C); + /* Copy strips, temporarily restoring pointers to actual data-blocks. This * must happen on the clipboard itself, so that copying does user counting * on the actual data-blocks. */ @@ -2569,6 +2669,8 @@ static int sequencer_paste_exec(bContext *C, wmOperator *op) } } + sequencer_restore_original_animation(scene, &fcurves_original_backup); + DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS); DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER, scene); diff --git a/source/blender/editors/space_sequencer/sequencer_intern.h b/source/blender/editors/space_sequencer/sequencer_intern.h index cb33c648b0a..7143a1fa1ca 100644 --- a/source/blender/editors/space_sequencer/sequencer_intern.h +++ b/source/blender/editors/space_sequencer/sequencer_intern.h @@ -33,13 +33,13 @@ struct ARegionType; struct Depsgraph; struct Main; struct Scene; -struct Sequence; struct SeqCollection; +struct Sequence; struct SpaceSeq; struct StripElem; +struct View2D; struct bContext; struct rctf; -struct View2D; struct wmOperator; #define OVERLAP_ALPHA 180 @@ -57,12 +57,12 @@ void sequencer_draw_preview(const struct bContext *C, bool draw_backdrop); void color3ubv_from_seq(const struct Scene *curscene, const struct Sequence *seq, - const bool show_strip_color_tag, + bool show_strip_color_tag, uchar r_col[3]); void sequencer_special_update_set(Sequence *seq); /* Get handle width in 2d-View space. */ -float sequence_handle_size_get_clamped(struct Sequence *seq, const float pixelx); +float sequence_handle_size_get_clamped(struct Sequence *seq, float pixelx); /* UNUSED */ /* void seq_reset_imageofs(struct SpaceSeq *sseq); */ diff --git a/source/blender/editors/space_sequencer/sequencer_proxy.c b/source/blender/editors/space_sequencer/sequencer_proxy.c index 0a8eb7cb88f..fb561025da2 100644 --- a/source/blender/editors/space_sequencer/sequencer_proxy.c +++ b/source/blender/editors/space_sequencer/sequencer_proxy.c @@ -85,7 +85,7 @@ static void seq_proxy_build_job(const bContext *C, ReportList *reports) } bool success = SEQ_proxy_rebuild_context( - pj->main, pj->depsgraph, pj->scene, seq, file_list, &pj->queue); + pj->main, pj->depsgraph, pj->scene, seq, file_list, &pj->queue, false); if (!success && (seq->strip->proxy->build_flags & SEQ_PROXY_SKIP_EXISTING) != 0) { BKE_reportf(reports, RPT_WARNING, "Overwrite is not checked for %s, skipping", seq->name); @@ -137,7 +137,7 @@ static int sequencer_rebuild_proxy_exec(bContext *C, wmOperator *UNUSED(op)) short stop = 0, do_update; float progress; - SEQ_proxy_rebuild_context(bmain, depsgraph, scene, seq, file_list, &queue); + SEQ_proxy_rebuild_context(bmain, depsgraph, scene, seq, file_list, &queue, false); for (link = queue.first; link; link = link->next) { struct SeqIndexBuildContext *context = link->data; diff --git a/source/blender/editors/space_sequencer/sequencer_thumbnails.c b/source/blender/editors/space_sequencer/sequencer_thumbnails.c index c6fecdb1fc6..82ba17d4db1 100644 --- a/source/blender/editors/space_sequencer/sequencer_thumbnails.c +++ b/source/blender/editors/space_sequencer/sequencer_thumbnails.c @@ -66,7 +66,7 @@ typedef struct ThumbDataItem { static void thumbnail_hash_data_free(void *val) { ThumbDataItem *item = val; - SEQ_sequence_free(item->scene, item->seq_dupli, 0); + SEQ_sequence_free(item->scene, item->seq_dupli); MEM_freeN(val); } diff --git a/source/blender/editors/space_sequencer/space_sequencer.c b/source/blender/editors/space_sequencer/space_sequencer.c index b93f421ff5c..b294fdf4820 100644 --- a/source/blender/editors/space_sequencer/space_sequencer.c +++ b/source/blender/editors/space_sequencer/space_sequencer.c @@ -39,6 +39,7 @@ #include "BKE_context.h" #include "BKE_global.h" #include "BKE_lib_id.h" +#include "BKE_lib_remap.h" #include "BKE_screen.h" #include "BKE_sequencer_offscreen.h" @@ -988,19 +989,12 @@ static void sequencer_buttons_region_listener(const wmRegionListenerParams *para } } -static void sequencer_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id) +static void sequencer_id_remap(ScrArea *UNUSED(area), + SpaceLink *slink, + const struct IDRemapper *mappings) { SpaceSeq *sseq = (SpaceSeq *)slink; - - if (!ELEM(GS(old_id->name), ID_GD)) { - return; - } - - if ((ID *)sseq->gpd == old_id) { - sseq->gpd = (bGPdata *)new_id; - id_us_min(old_id); - id_us_plus(new_id); - } + BKE_id_remapper_apply(mappings, (ID **)&sseq->gpd, ID_REMAP_APPLY_DEFAULT); } /* ************************************* */ diff --git a/source/blender/editors/space_spreadsheet/CMakeLists.txt b/source/blender/editors/space_spreadsheet/CMakeLists.txt index 27446fe1a94..f1db8dedf1a 100644 --- a/source/blender/editors/space_spreadsheet/CMakeLists.txt +++ b/source/blender/editors/space_spreadsheet/CMakeLists.txt @@ -49,7 +49,6 @@ set(SRC spreadsheet_row_filter_ui.cc spreadsheet_cache.hh - spreadsheet_cell_value.hh spreadsheet_column.hh spreadsheet_column_values.hh spreadsheet_context.hh diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc index 0cb4a52eb2f..18f383d45fb 100644 --- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc +++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc @@ -18,6 +18,7 @@ #include "BLI_listbase.h" +#include "BKE_lib_remap.h" #include "BKE_screen.h" #include "ED_screen.h" @@ -60,15 +61,14 @@ using namespace blender::ed::spreadsheet; static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *UNUSED(scene)) { - SpaceSpreadsheet *spreadsheet_space = (SpaceSpreadsheet *)MEM_callocN(sizeof(SpaceSpreadsheet), - "spreadsheet space"); + SpaceSpreadsheet *spreadsheet_space = MEM_cnew<SpaceSpreadsheet>("spreadsheet space"); spreadsheet_space->spacetype = SPACE_SPREADSHEET; spreadsheet_space->filter_flag = SPREADSHEET_FILTER_ENABLE; { /* Header. */ - ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet header"); + ARegion *region = MEM_cnew<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; @@ -76,7 +76,7 @@ static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *U { /* Footer. */ - ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet footer region"); + ARegion *region = MEM_cnew<ARegion>("spreadsheet footer region"); BLI_addtail(&spreadsheet_space->regionbase, region); region->regiontype = RGN_TYPE_FOOTER; region->alignment = (U.uiflag & USER_HEADER_BOTTOM) ? RGN_ALIGN_TOP : RGN_ALIGN_BOTTOM; @@ -84,16 +84,15 @@ static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *U { /* Dataset Region */ - ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet dataset region"); + ARegion *region = MEM_cnew<ARegion>("spreadsheet dataset region"); BLI_addtail(&spreadsheet_space->regionbase, region); - region->regiontype = RGN_TYPE_CHANNELS; + region->regiontype = RGN_TYPE_TOOLS; region->alignment = RGN_ALIGN_LEFT; - region->v2d.scroll = (V2D_SCROLL_RIGHT | V2D_SCROLL_BOTTOM); } { /* Properties region. */ - ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet right region"); + ARegion *region = MEM_cnew<ARegion>("spreadsheet right region"); BLI_addtail(&spreadsheet_space->regionbase, region); region->regiontype = RGN_TYPE_UI; region->alignment = RGN_ALIGN_RIGHT; @@ -102,7 +101,7 @@ static SpaceLink *spreadsheet_create(const ScrArea *UNUSED(area), const Scene *U { /* Main window. */ - ARegion *region = (ARegion *)MEM_callocN(sizeof(ARegion), "spreadsheet main region"); + ARegion *region = MEM_cnew<ARegion>("spreadsheet main region"); BLI_addtail(&spreadsheet_space->regionbase, region); region->regiontype = RGN_TYPE_WINDOW; } @@ -114,7 +113,7 @@ static void spreadsheet_free(SpaceLink *sl) { SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)sl; - delete sspreadsheet->runtime; + MEM_delete(sspreadsheet->runtime); LISTBASE_FOREACH_MUTABLE (SpreadsheetRowFilter *, row_filter, &sspreadsheet->row_filters) { spreadsheet_row_filter_free(row_filter); @@ -131,7 +130,7 @@ static void spreadsheet_init(wmWindowManager *UNUSED(wm), ScrArea *area) { SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)area->spacedata.first; if (sspreadsheet->runtime == nullptr) { - sspreadsheet->runtime = new SpaceSpreadsheet_Runtime(); + sspreadsheet->runtime = MEM_new<SpaceSpreadsheet_Runtime>(__func__); } } @@ -140,10 +139,11 @@ static SpaceLink *spreadsheet_duplicate(SpaceLink *sl) const SpaceSpreadsheet *sspreadsheet_old = (SpaceSpreadsheet *)sl; SpaceSpreadsheet *sspreadsheet_new = (SpaceSpreadsheet *)MEM_dupallocN(sspreadsheet_old); if (sspreadsheet_old->runtime) { - sspreadsheet_new->runtime = new SpaceSpreadsheet_Runtime(*sspreadsheet_old->runtime); + sspreadsheet_new->runtime = MEM_new<SpaceSpreadsheet_Runtime>(__func__, + *sspreadsheet_old->runtime); } else { - sspreadsheet_new->runtime = new SpaceSpreadsheet_Runtime(); + sspreadsheet_new->runtime = MEM_new<SpaceSpreadsheet_Runtime>(__func__); } BLI_listbase_clear(&sspreadsheet_new->row_filters); @@ -172,21 +172,23 @@ static void spreadsheet_keymap(wmKeyConfig *keyconf) WM_keymap_ensure(keyconf, "Spreadsheet Generic", SPACE_SPREADSHEET, 0); } -static void spreadsheet_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id) +static void spreadsheet_id_remap(ScrArea *UNUSED(area), + SpaceLink *slink, + const IDRemapper *mappings) { SpaceSpreadsheet *sspreadsheet = (SpaceSpreadsheet *)slink; LISTBASE_FOREACH (SpreadsheetContext *, context, &sspreadsheet->context_path) { - if (context->type == SPREADSHEET_CONTEXT_OBJECT) { - SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context; - if ((ID *)object_context->object == old_id) { - if (new_id && GS(new_id->name) == ID_OB) { - object_context->object = (Object *)new_id; - } - else { - object_context->object = nullptr; - } - } + if (context->type != SPREADSHEET_CONTEXT_OBJECT) { + continue; + } + SpreadsheetContextObject *object_context = (SpreadsheetContextObject *)context; + + if (object_context->object != nullptr && GS(object_context->object->id.name) != ID_OB) { + object_context->object = nullptr; + continue; } + + BKE_id_remapper_apply(mappings, ((ID **)&object_context->object), ID_REMAP_APPLY_DEFAULT); } } @@ -323,6 +325,8 @@ static float get_default_column_width(const ColumnValues &values) return 8.0f; case SPREADSHEET_VALUE_TYPE_STRING: return 5.0f; + case SPREADSHEET_VALUE_TYPE_UNKNOWN: + return 2.0f; } return float_width; } @@ -619,7 +623,7 @@ static void spreadsheet_right_region_listener(const wmRegionListenerParams *UNUS void ED_spacetype_spreadsheet() { - SpaceType *st = (SpaceType *)MEM_callocN(sizeof(SpaceType), "spacetype spreadsheet"); + SpaceType *st = MEM_cnew<SpaceType>("spacetype spreadsheet"); ARegionType *art; st->spaceid = SPACE_SPREADSHEET; @@ -634,7 +638,7 @@ void ED_spacetype_spreadsheet() st->id_remap = spreadsheet_id_remap; /* regions: main window */ - art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet region"); + art = MEM_cnew<ARegionType>("spacetype spreadsheet region"); art->regionid = RGN_TYPE_WINDOW; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D; @@ -644,7 +648,7 @@ void ED_spacetype_spreadsheet() BLI_addhead(&st->regiontypes, art); /* regions: header */ - art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet header region"); + art = MEM_cnew<ARegionType>("spacetype spreadsheet header region"); art->regionid = RGN_TYPE_HEADER; art->prefsizey = HEADERY; art->keymapflag = 0; @@ -657,7 +661,7 @@ void ED_spacetype_spreadsheet() BLI_addhead(&st->regiontypes, art); /* regions: footer */ - art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet footer region"); + art = MEM_cnew<ARegionType>("spacetype spreadsheet footer region"); art->regionid = RGN_TYPE_FOOTER; art->prefsizey = HEADERY; art->keymapflag = 0; @@ -670,7 +674,7 @@ void ED_spacetype_spreadsheet() BLI_addhead(&st->regiontypes, art); /* regions: right panel buttons */ - art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spacetype spreadsheet right region"); + art = MEM_cnew<ARegionType>("spacetype spreadsheet right region"); art->regionid = RGN_TYPE_UI; art->prefsizex = UI_SIDEBAR_PANEL_WIDTH; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_FRAMES; @@ -685,10 +689,10 @@ void ED_spacetype_spreadsheet() register_row_filter_panels(*art); /* regions: channels */ - art = (ARegionType *)MEM_callocN(sizeof(ARegionType), "spreadsheet dataset region"); - art->regionid = RGN_TYPE_CHANNELS; + art = MEM_cnew<ARegionType>("spreadsheet dataset region"); + art->regionid = RGN_TYPE_TOOLS; art->prefsizex = 150 + V2D_SCROLL_WIDTH; - art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D; + art->keymapflag = ED_KEYMAP_UI; art->init = ED_region_panels_init; art->draw = spreadsheet_dataset_region_draw; art->listener = spreadsheet_dataset_region_listener; diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh b/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh deleted file mode 100644 index c11b4a2b23d..00000000000 --- a/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh +++ /dev/null @@ -1,64 +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 <optional> - -#include "BLI_color.hh" -#include "BLI_float2.hh" -#include "BLI_float3.hh" - -struct Collection; -struct Object; - -namespace blender::ed::spreadsheet { - -struct ObjectCellValue { - const Object *object; -}; - -struct CollectionCellValue { - const Collection *collection; -}; - -struct GeometrySetCellValue { - const GeometrySet *geometry_set; -}; - -/** - * This is a type that can hold the value of a cell in a spreadsheet. This type allows us to - * decouple the drawing of individual cells from the code that generates the data to be displayed. - */ -class CellValue { - public: - /* The implementation just uses a bunch of `std::option` for now. Unfortunately, we cannot use - * `std::variant` yet, due to missing compiler support. This type can really be optimized more, - * but it does not really matter too much currently. */ - - std::optional<int> value_int; - std::optional<float> value_float; - std::optional<bool> value_bool; - std::optional<float2> value_float2; - std::optional<float3> value_float3; - std::optional<ColorGeometry4f> value_color; - std::optional<ObjectCellValue> value_object; - std::optional<CollectionCellValue> value_collection; - std::optional<GeometrySetCellValue> value_geometry_set; - std::optional<std::string> value_string; -}; - -} // namespace blender::ed::spreadsheet diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc index ee08c86b29f..ede8756a9da 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_column.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_column.cc @@ -18,18 +18,54 @@ #include "MEM_guardedalloc.h" +#include "BLI_color.hh" #include "BLI_hash.hh" +#include "BLI_math_vec_types.hh" #include "BLI_string.h" #include "BLI_string_ref.hh" +#include "BKE_geometry_set.hh" + +#include "FN_cpp_type.hh" + #include "spreadsheet_column.hh" +#include "spreadsheet_column_values.hh" namespace blender::ed::spreadsheet { +eSpreadsheetColumnValueType cpp_type_to_column_type(const fn::CPPType &type) +{ + if (type.is<bool>()) { + return SPREADSHEET_VALUE_TYPE_BOOL; + } + if (type.is<int>()) { + return SPREADSHEET_VALUE_TYPE_INT32; + } + if (type.is<float>()) { + return SPREADSHEET_VALUE_TYPE_FLOAT; + } + if (type.is<float2>()) { + return SPREADSHEET_VALUE_TYPE_FLOAT2; + } + if (type.is<float3>()) { + return SPREADSHEET_VALUE_TYPE_FLOAT3; + } + if (type.is<ColorGeometry4f>()) { + return SPREADSHEET_VALUE_TYPE_COLOR; + } + if (type.is<std::string>()) { + return SPREADSHEET_VALUE_TYPE_STRING; + } + if (type.is<InstanceReference>()) { + return SPREADSHEET_VALUE_TYPE_INSTANCES; + } + + return SPREADSHEET_VALUE_TYPE_UNKNOWN; +} + SpreadsheetColumnID *spreadsheet_column_id_new() { - SpreadsheetColumnID *column_id = (SpreadsheetColumnID *)MEM_callocN(sizeof(SpreadsheetColumnID), - __func__); + SpreadsheetColumnID *column_id = MEM_cnew<SpreadsheetColumnID>(__func__); return column_id; } @@ -50,8 +86,7 @@ void spreadsheet_column_id_free(SpreadsheetColumnID *column_id) SpreadsheetColumn *spreadsheet_column_new(SpreadsheetColumnID *column_id) { - SpreadsheetColumn *column = (SpreadsheetColumn *)MEM_callocN(sizeof(SpreadsheetColumn), - __func__); + SpreadsheetColumn *column = MEM_cnew<SpreadsheetColumn>(__func__); column->id = column_id; return column; } diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column.hh b/source/blender/editors/space_spreadsheet/spreadsheet_column.hh index 1a03278acad..7dad505c21b 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_column.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_column.hh @@ -44,7 +44,7 @@ void spreadsheet_column_id_free(SpreadsheetColumnID *column_id); SpreadsheetColumn *spreadsheet_column_new(SpreadsheetColumnID *column_id); SpreadsheetColumn *spreadsheet_column_copy(const SpreadsheetColumn *src_column); void spreadsheet_column_assign_runtime_data(SpreadsheetColumn *column, - const eSpreadsheetColumnValueType data_type, + eSpreadsheetColumnValueType data_type, const StringRefNull display_name); void spreadsheet_column_free(SpreadsheetColumn *column); diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh b/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh index 877651d6530..83e3217e5c8 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_column_values.hh @@ -20,33 +20,36 @@ #include "BLI_string_ref.hh" -#include "spreadsheet_cell_value.hh" +#include "FN_generic_virtual_array.hh" namespace blender::ed::spreadsheet { +struct CellDrawParams; + +eSpreadsheetColumnValueType cpp_type_to_column_type(const fn::CPPType &type); + /** * This represents a column in a spreadsheet. It has a name and provides a value for all the cells * in the column. */ -class ColumnValues { +class ColumnValues final { protected: - eSpreadsheetColumnValueType type_; std::string name_; - int size_; + + fn::GVArray data_; public: - ColumnValues(const eSpreadsheetColumnValueType type, std::string name, const int size) - : type_(type), name_(std::move(name)), size_(size) + ColumnValues(std::string name, fn::GVArray data) : name_(std::move(name)), data_(std::move(data)) { + /* The array should not be empty. */ + BLI_assert(data_); } virtual ~ColumnValues() = default; - virtual void get_value(int index, CellValue &r_cell_value) const = 0; - eSpreadsheetColumnValueType type() const { - return type_; + return cpp_type_to_column_type(data_.type()); } StringRefNull name() const @@ -56,45 +59,16 @@ class ColumnValues { int size() const { - return size_; + return data_.size(); } - /* The default width of newly created columns, in UI units. */ - float default_width = 0.0f; -}; - -/* Utility class for the function below. */ -template<typename GetValueF> class LambdaColumnValues : public ColumnValues { - private: - GetValueF get_value_; - - public: - LambdaColumnValues(const eSpreadsheetColumnValueType type, - std::string name, - int size, - GetValueF get_value) - : ColumnValues(type, std::move(name), size), get_value_(std::move(get_value)) + const fn::GVArray &data() const { + return data_; } - void get_value(int index, CellValue &r_cell_value) const final - { - get_value_(index, r_cell_value); - } + /* The default width of newly created columns, in UI units. */ + float default_width = 0.0f; }; -/* Utility function that simplifies creating a spreadsheet column from a lambda function. */ -template<typename GetValueF> -std::unique_ptr<ColumnValues> column_values_from_function(const eSpreadsheetColumnValueType type, - std::string name, - const int size, - GetValueF get_value, - const float default_width = 0.0f) -{ - std::unique_ptr<ColumnValues> column_values = std::make_unique<LambdaColumnValues<GetValueF>>( - type, std::move(name), size, std::move(get_value)); - column_values->default_width = default_width; - return column_values; -} - } // namespace blender::ed::spreadsheet diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_context.cc b/source/blender/editors/space_spreadsheet/spreadsheet_context.cc index e55a7cae6a6..5cec016b727 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_context.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_context.cc @@ -50,8 +50,7 @@ namespace blender::ed::spreadsheet { static SpreadsheetContextObject *spreadsheet_context_object_new() { - SpreadsheetContextObject *context = (SpreadsheetContextObject *)MEM_callocN( - sizeof(SpreadsheetContextObject), __func__); + SpreadsheetContextObject *context = MEM_cnew<SpreadsheetContextObject>(__func__); context->base.type = SPREADSHEET_CONTEXT_OBJECT; return context; } @@ -77,8 +76,7 @@ static void spreadsheet_context_object_free(SpreadsheetContextObject *context) static SpreadsheetContextModifier *spreadsheet_context_modifier_new() { - SpreadsheetContextModifier *context = (SpreadsheetContextModifier *)MEM_callocN( - sizeof(SpreadsheetContextModifier), __func__); + SpreadsheetContextModifier *context = MEM_cnew<SpreadsheetContextModifier>(__func__); context->base.type = SPREADSHEET_CONTEXT_MODIFIER; return context; } @@ -111,8 +109,7 @@ static void spreadsheet_context_modifier_free(SpreadsheetContextModifier *contex static SpreadsheetContextNode *spreadsheet_context_node_new() { - SpreadsheetContextNode *context = (SpreadsheetContextNode *)MEM_callocN( - sizeof(SpreadsheetContextNode), __func__); + SpreadsheetContextNode *context = MEM_cnew<SpreadsheetContextNode>(__func__); context->base.type = SPREADSHEET_CONTEXT_NODE; return context; } diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc index 173ef43bfb6..b9b03732a40 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc @@ -14,8 +14,11 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "BLI_virtual_array.hh" + #include "BKE_context.h" #include "BKE_editmesh.h" +#include "BKE_global.h" #include "BKE_lib_id.h" #include "BKE_mesh.h" #include "BKE_mesh_wrapper.h" @@ -51,30 +54,6 @@ using blender::fn::GField; namespace blender::ed::spreadsheet { -static std::optional<eSpreadsheetColumnValueType> cpp_type_to_column_value_type( - const fn::CPPType &type) -{ - if (type.is<bool>()) { - return SPREADSHEET_VALUE_TYPE_BOOL; - } - if (type.is<int>()) { - return SPREADSHEET_VALUE_TYPE_INT32; - } - if (type.is<float>()) { - return SPREADSHEET_VALUE_TYPE_FLOAT; - } - if (type.is<float2>()) { - return SPREADSHEET_VALUE_TYPE_FLOAT2; - } - if (type.is<float3>()) { - return SPREADSHEET_VALUE_TYPE_FLOAT3; - } - if (type.is<ColorGeometry4f>()) { - return SPREADSHEET_VALUE_TYPE_COLOR; - } - return std::nullopt; -} - void ExtraColumns::foreach_default_column_ids( FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const { @@ -92,39 +71,7 @@ std::unique_ptr<ColumnValues> ExtraColumns::get_column_values( if (values == nullptr) { return {}; } - eSpreadsheetColumnValueType column_type = *cpp_type_to_column_value_type(values->type()); - return column_values_from_function(column_type, - column_id.name, - values->size(), - [column_type, values](int index, CellValue &r_cell_value) { - const void *value = (*values)[index]; - switch (column_type) { - case SPREADSHEET_VALUE_TYPE_BOOL: - r_cell_value.value_bool = *(const bool *)value; - break; - case SPREADSHEET_VALUE_TYPE_INT32: - r_cell_value.value_int = *(const int *)value; - break; - case SPREADSHEET_VALUE_TYPE_FLOAT: - r_cell_value.value_float = *(const float *)value; - break; - case SPREADSHEET_VALUE_TYPE_FLOAT2: - r_cell_value.value_float2 = *(const float2 *)value; - break; - case SPREADSHEET_VALUE_TYPE_FLOAT3: - r_cell_value.value_float3 = *(const float3 *)value; - break; - case SPREADSHEET_VALUE_TYPE_COLOR: - r_cell_value.value_color = *( - const ColorGeometry4f *)value; - break; - case SPREADSHEET_VALUE_TYPE_STRING: - r_cell_value.value_string = *(const std::string *)value; - break; - case SPREADSHEET_VALUE_TYPE_INSTANCES: - break; - } - }); + return std::make_unique<ColumnValues>(column_id.name, fn::GVArray::ForSpan(*values)); } void GeometryDataSource::foreach_default_column_ids( @@ -157,6 +104,20 @@ void GeometryDataSource::foreach_default_column_ids( fn({(char *)"Rotation"}, false); fn({(char *)"Scale"}, false); } + else if (G.debug_value == 4001 && component_->type() == GEO_COMPONENT_TYPE_MESH) { + if (domain_ == ATTR_DOMAIN_EDGE) { + fn({(char *)"Vertex 1"}, false); + fn({(char *)"Vertex 2"}, false); + } + else if (domain_ == ATTR_DOMAIN_FACE) { + fn({(char *)"Corner Start"}, false); + fn({(char *)"Corner Size"}, false); + } + else if (domain_ == ATTR_DOMAIN_CORNER) { + fn({(char *)"Vertex"}, false); + fn({(char *)"Edge"}, false); + } + } } std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( @@ -179,52 +140,72 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( if (STREQ(column_id.name, "Name")) { Span<int> reference_handles = instances.instance_reference_handles(); Span<InstanceReference> references = instances.references(); - std::unique_ptr<ColumnValues> values = column_values_from_function( - SPREADSHEET_VALUE_TYPE_INSTANCES, - "Name", - domain_size, - [reference_handles, references](int index, CellValue &r_cell_value) { - const InstanceReference &reference = references[reference_handles[index]]; - switch (reference.type()) { - case InstanceReference::Type::Object: { - Object &object = reference.object(); - r_cell_value.value_object = ObjectCellValue{&object}; - break; - } - case InstanceReference::Type::Collection: { - Collection &collection = reference.collection(); - r_cell_value.value_collection = CollectionCellValue{&collection}; - break; - } - case InstanceReference::Type::GeometrySet: { - const GeometrySet &geometry_set = reference.geometry_set(); - r_cell_value.value_geometry_set = GeometrySetCellValue{&geometry_set}; - break; - } - case InstanceReference::Type::None: { - break; - } - } - }); - return values; + return std::make_unique<ColumnValues>( + column_id.name, + VArray<InstanceReference>::ForFunc(domain_size, + [reference_handles, references](int64_t index) { + return references[reference_handles[index]]; + })); } Span<float4x4> transforms = instances.instance_transforms(); if (STREQ(column_id.name, "Rotation")) { - return column_values_from_function( - SPREADSHEET_VALUE_TYPE_FLOAT3, - column_id.name, - domain_size, - [transforms](int index, CellValue &r_cell_value) { - r_cell_value.value_float3 = transforms[index].to_euler(); - }); + return std::make_unique<ColumnValues>( + column_id.name, VArray<float3>::ForFunc(domain_size, [transforms](int64_t index) { + return transforms[index].to_euler(); + })); } if (STREQ(column_id.name, "Scale")) { - return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT3, - column_id.name, - domain_size, - [transforms](int index, CellValue &r_cell_value) { - r_cell_value.value_float3 = transforms[index].scale(); - }); + return std::make_unique<ColumnValues>( + column_id.name, VArray<float3>::ForFunc(domain_size, [transforms](int64_t index) { + return transforms[index].scale(); + })); + } + } + else if (G.debug_value == 4001 && component_->type() == GEO_COMPONENT_TYPE_MESH) { + const MeshComponent &component = static_cast<const MeshComponent &>(*component_); + if (const Mesh *mesh = component.get_for_read()) { + if (domain_ == ATTR_DOMAIN_EDGE) { + if (STREQ(column_id.name, "Vertex 1")) { + return std::make_unique<ColumnValues>( + column_id.name, VArray<int>::ForFunc(mesh->totedge, [mesh](int64_t index) { + return mesh->medge[index].v1; + })); + } + if (STREQ(column_id.name, "Vertex 2")) { + return std::make_unique<ColumnValues>( + column_id.name, VArray<int>::ForFunc(mesh->totedge, [mesh](int64_t index) { + return mesh->medge[index].v2; + })); + } + } + else if (domain_ == ATTR_DOMAIN_FACE) { + if (STREQ(column_id.name, "Corner Start")) { + return std::make_unique<ColumnValues>( + column_id.name, VArray<int>::ForFunc(mesh->totpoly, [mesh](int64_t index) { + return mesh->mpoly[index].loopstart; + })); + } + if (STREQ(column_id.name, "Corner Size")) { + return std::make_unique<ColumnValues>( + column_id.name, VArray<int>::ForFunc(mesh->totpoly, [mesh](int64_t index) { + return mesh->mpoly[index].totloop; + })); + } + } + else if (domain_ == ATTR_DOMAIN_CORNER) { + if (STREQ(column_id.name, "Vertex")) { + return std::make_unique<ColumnValues>( + column_id.name, VArray<int>::ForFunc(mesh->totloop, [mesh](int64_t index) { + return mesh->mloop[index].v; + })); + } + if (STREQ(column_id.name, "Edge")) { + return std::make_unique<ColumnValues>( + column_id.name, VArray<int>::ForFunc(mesh->totloop, [mesh](int64_t index) { + return mesh->mloop[index].e; + })); + } + } } } @@ -237,71 +218,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values( return {}; } - const CustomDataType type = bke::cpp_type_to_custom_data_type(varray.type()); - switch (type) { - case CD_PROP_FLOAT: - return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT, - column_id.name, - domain_size, - [varray](int index, CellValue &r_cell_value) { - float value; - varray.get(index, &value); - r_cell_value.value_float = value; - }); - case CD_PROP_INT32: - return column_values_from_function( - SPREADSHEET_VALUE_TYPE_INT32, - column_id.name, - domain_size, - [varray](int index, CellValue &r_cell_value) { - int value; - varray.get(index, &value); - r_cell_value.value_int = value; - }, - STREQ(column_id.name, "id") ? 5.5f : 0.0f); - case CD_PROP_BOOL: - return column_values_from_function(SPREADSHEET_VALUE_TYPE_BOOL, - column_id.name, - domain_size, - [varray](int index, CellValue &r_cell_value) { - bool value; - varray.get(index, &value); - r_cell_value.value_bool = value; - }); - case CD_PROP_FLOAT2: { - return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT2, - column_id.name, - domain_size, - [varray](int index, CellValue &r_cell_value) { - float2 value; - varray.get(index, &value); - r_cell_value.value_float2 = value; - }); - } - case CD_PROP_FLOAT3: { - return column_values_from_function(SPREADSHEET_VALUE_TYPE_FLOAT3, - column_id.name, - domain_size, - [varray](int index, CellValue &r_cell_value) { - float3 value; - varray.get(index, &value); - r_cell_value.value_float3 = value; - }); - } - case CD_PROP_COLOR: { - return column_values_from_function(SPREADSHEET_VALUE_TYPE_COLOR, - column_id.name, - domain_size, - [varray](int index, CellValue &r_cell_value) { - ColorGeometry4f value; - varray.get(index, &value); - r_cell_value.value_color = value; - }); - } - default: - break; - } - return {}; + return std::make_unique<ColumnValues>(column_id.name, std::move(varray)); } int GeometryDataSource::tot_rows() const @@ -309,90 +226,9 @@ int GeometryDataSource::tot_rows() const return component_->attribute_domain_size(domain_); } -using IsVertexSelectedFn = FunctionRef<bool(int vertex_index)>; - -static void get_selected_vertex_indices(const Mesh &mesh, - const IsVertexSelectedFn is_vertex_selected_fn, - MutableSpan<bool> selection) -{ - for (const int i : IndexRange(mesh.totvert)) { - if (!selection[i]) { - continue; - } - if (!is_vertex_selected_fn(i)) { - selection[i] = false; - } - } -} - -static void get_selected_corner_indices(const Mesh &mesh, - const IsVertexSelectedFn is_vertex_selected_fn, - MutableSpan<bool> selection) -{ - for (const int i : IndexRange(mesh.totloop)) { - const MLoop &loop = mesh.mloop[i]; - if (!selection[i]) { - continue; - } - if (!is_vertex_selected_fn(loop.v)) { - selection[i] = false; - } - } -} - -static void get_selected_face_indices(const Mesh &mesh, - const IsVertexSelectedFn is_vertex_selected_fn, - MutableSpan<bool> selection) -{ - for (const int poly_index : IndexRange(mesh.totpoly)) { - if (!selection[poly_index]) { - continue; - } - const MPoly &poly = mesh.mpoly[poly_index]; - for (const int loop_index : IndexRange(poly.loopstart, poly.totloop)) { - const MLoop &loop = mesh.mloop[loop_index]; - if (!is_vertex_selected_fn(loop.v)) { - selection[poly_index] = false; - break; - } - } - } -} - -static void get_selected_edge_indices(const Mesh &mesh, - const IsVertexSelectedFn is_vertex_selected_fn, - MutableSpan<bool> selection) -{ - for (const int i : IndexRange(mesh.totedge)) { - if (!selection[i]) { - continue; - } - const MEdge &edge = mesh.medge[i]; - if (!is_vertex_selected_fn(edge.v1) || !is_vertex_selected_fn(edge.v2)) { - selection[i] = false; - } - } -} - -static void get_selected_indices_on_domain(const Mesh &mesh, - const AttributeDomain domain, - const IsVertexSelectedFn is_vertex_selected_fn, - MutableSpan<bool> selection) -{ - switch (domain) { - case ATTR_DOMAIN_POINT: - return get_selected_vertex_indices(mesh, is_vertex_selected_fn, selection); - case ATTR_DOMAIN_FACE: - return get_selected_face_indices(mesh, is_vertex_selected_fn, selection); - case ATTR_DOMAIN_CORNER: - return get_selected_corner_indices(mesh, is_vertex_selected_fn, selection); - case ATTR_DOMAIN_EDGE: - return get_selected_edge_indices(mesh, is_vertex_selected_fn, selection); - default: - return; - } -} - +/** + * Only data sets corresponding to mesh objects in edit mode currently support selection filtering. + */ bool GeometryDataSource::has_selection_filter() const { Object *object_orig = DEG_get_original_object(object_eval_); @@ -409,7 +245,18 @@ bool GeometryDataSource::has_selection_filter() const return true; } -void GeometryDataSource::apply_selection_filter(MutableSpan<bool> rows_included) const +static IndexMask index_mask_from_bool_array(const VArray<bool> &selection, + Vector<int64_t> &indices) +{ + for (const int i : selection.index_range()) { + if (selection[i]) { + indices.append(i); + } + } + return IndexMask(indices); +} + +IndexMask GeometryDataSource::apply_selection_filter(Vector<int64_t> &indices) const { std::lock_guard lock{mutex_}; @@ -425,27 +272,38 @@ void GeometryDataSource::apply_selection_filter(MutableSpan<bool> rows_included) int *orig_indices = (int *)CustomData_get_layer(&mesh_eval->vdata, CD_ORIGINDEX); if (orig_indices != nullptr) { /* Use CD_ORIGINDEX layer if it exists. */ - auto is_vertex_selected = [&](int vertex_index) -> bool { - const int i_orig = orig_indices[vertex_index]; - if (i_orig < 0) { - return false; - } - if (i_orig >= bm->totvert) { - return false; - } - BMVert *vert = bm->vtable[i_orig]; - return BM_elem_flag_test(vert, BM_ELEM_SELECT); - }; - get_selected_indices_on_domain(*mesh_eval, domain_, is_vertex_selected, rows_included); - } - else if (mesh_eval->totvert == bm->totvert) { + VArray<bool> selection = mesh_component->attribute_try_adapt_domain<bool>( + VArray<bool>::ForFunc(mesh_eval->totvert, + [bm, orig_indices](int vertex_index) -> bool { + const int i_orig = orig_indices[vertex_index]; + if (i_orig < 0) { + return false; + } + if (i_orig >= bm->totvert) { + return false; + } + BMVert *vert = bm->vtable[i_orig]; + return BM_elem_flag_test(vert, BM_ELEM_SELECT); + }), + ATTR_DOMAIN_POINT, + domain_); + return index_mask_from_bool_array(selection, indices); + } + + if (mesh_eval->totvert == bm->totvert) { /* Use a simple heuristic to match original vertices to evaluated ones. */ - auto is_vertex_selected = [&](int vertex_index) -> bool { - BMVert *vert = bm->vtable[vertex_index]; - return BM_elem_flag_test(vert, BM_ELEM_SELECT); - }; - get_selected_indices_on_domain(*mesh_eval, domain_, is_vertex_selected, rows_included); - } + VArray<bool> selection = mesh_component->attribute_try_adapt_domain<bool>( + VArray<bool>::ForFunc(mesh_eval->totvert, + [bm](int vertex_index) -> bool { + BMVert *vert = bm->vtable[vertex_index]; + return BM_elem_flag_test(vert, BM_ELEM_SELECT); + }), + ATTR_DOMAIN_POINT, + domain_); + return index_mask_from_bool_array(selection, indices); + } + + return IndexMask(mesh_eval->totvert); } void VolumeDataSource::foreach_default_column_ids( @@ -472,50 +330,36 @@ std::unique_ptr<ColumnValues> VolumeDataSource::get_column_values( #ifdef WITH_OPENVDB const int size = this->tot_rows(); if (STREQ(column_id.name, "Grid Name")) { - return column_values_from_function( - SPREADSHEET_VALUE_TYPE_STRING, - IFACE_("Grid Name"), - size, - [volume](int index, CellValue &r_cell_value) { + return std::make_unique<ColumnValues>( + IFACE_("Grid Name"), VArray<std::string>::ForFunc(size, [volume](int64_t index) { const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, index); - r_cell_value.value_string = BKE_volume_grid_name(volume_grid); - }, - 6.0f); + return BKE_volume_grid_name(volume_grid); + })); } if (STREQ(column_id.name, "Data Type")) { - return column_values_from_function( - SPREADSHEET_VALUE_TYPE_STRING, - IFACE_("Type"), - size, - [volume](int index, CellValue &r_cell_value) { + return std::make_unique<ColumnValues>( + IFACE_("Data Type"), VArray<std::string>::ForFunc(size, [volume](int64_t index) { const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, index); const VolumeGridType type = BKE_volume_grid_type(volume_grid); const char *name = nullptr; RNA_enum_name_from_value(rna_enum_volume_grid_data_type_items, type, &name); - r_cell_value.value_string = IFACE_(name); - }, - 5.0f); + return IFACE_(name); + })); } if (STREQ(column_id.name, "Class")) { - return column_values_from_function( - SPREADSHEET_VALUE_TYPE_STRING, - IFACE_("Class"), - size, - [volume](int index, CellValue &r_cell_value) { + return std::make_unique<ColumnValues>( + IFACE_("Class"), VArray<std::string>::ForFunc(size, [volume](int64_t index) { const VolumeGrid *volume_grid = BKE_volume_grid_get_for_read(volume, index); openvdb::GridBase::ConstPtr grid = BKE_volume_grid_openvdb_for_read(volume, volume_grid); openvdb::GridClass grid_class = grid->getGridClass(); if (grid_class == openvdb::GridClass::GRID_FOG_VOLUME) { - r_cell_value.value_string = IFACE_("Fog Volume"); - } - else if (grid_class == openvdb::GridClass::GRID_LEVEL_SET) { - r_cell_value.value_string = IFACE_("Level Set"); + return IFACE_("Fog Volume"); } - else { - r_cell_value.value_string = IFACE_("Unknown"); + if (grid_class == openvdb::GridClass::GRID_LEVEL_SET) { + return IFACE_("Level Set"); } - }, - 5.0f); + return IFACE_("Unknown"); + })); } #else UNUSED_VARS(column_id); diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh index 23207734d2b..b5105050d2b 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.hh @@ -87,7 +87,7 @@ class GeometryDataSource : public DataSource { * filtering. */ bool has_selection_filter() const override; - void apply_selection_filter(MutableSpan<bool> rows_included) const; + IndexMask apply_selection_filter(Vector<int64_t> &indices) const; void foreach_default_column_ids( FunctionRef<void(const SpreadsheetColumnID &, bool is_extra)> fn) const override; diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh b/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh index e62835d5792..df23a27aa22 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_intern.hh @@ -36,10 +36,10 @@ struct SpaceSpreadsheet_Runtime { } }; -struct bContext; struct ARegionType; +struct bContext; -void spreadsheet_operatortypes(void); +void spreadsheet_operatortypes(); void spreadsheet_update_context_path(const bContext *C); Object *spreadsheet_get_object_eval(const SpaceSpreadsheet *sspreadsheet, const Depsgraph *depsgraph); diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc index 202523c0e64..f4b5ff819ed 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc @@ -17,8 +17,15 @@ #include <iomanip> #include <sstream> +#include "BLI_math_vec_types.hh" + +#include "BKE_geometry_set.hh" + +#include "spreadsheet_column_values.hh" #include "spreadsheet_layout.hh" +#include "DNA_collection_types.h" +#include "DNA_object_types.h" #include "DNA_userdef_types.h" #include "UI_interface.h" @@ -92,13 +99,14 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer { { const int real_index = spreadsheet_layout_.row_indices[row_index]; const ColumnValues &column = *spreadsheet_layout_.columns[column_index].values; - CellValue cell_value; - if (real_index < column.size()) { - column.get_value(real_index, cell_value); + if (real_index > column.size()) { + return; } - if (cell_value.value_int.has_value()) { - const int value = *cell_value.value_int; + const fn::GVArray &data = column.data(); + + if (data.type().is<int>()) { + const int value = data.get<int>(real_index); const std::string value_str = std::to_string(value); uiBut *but = uiDefIconTextBut(params.block, UI_BTYPE_LABEL, @@ -119,8 +127,8 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer { UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT); UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT); } - else if (cell_value.value_float.has_value()) { - const float value = *cell_value.value_float; + else if (data.type().is<float>()) { + const float value = data.get<float>(real_index); std::stringstream ss; ss << std::fixed << std::setprecision(3) << value; const std::string value_str = ss.str(); @@ -143,8 +151,8 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer { UI_but_drawflag_disable(but, UI_BUT_TEXT_LEFT); UI_but_drawflag_enable(but, UI_BUT_TEXT_RIGHT); } - else if (cell_value.value_bool.has_value()) { - const bool value = *cell_value.value_bool; + else if (data.type().is<bool>()) { + const bool value = data.get<bool>(real_index); const int icon = value ? ICON_CHECKBOX_HLT : ICON_CHECKBOX_DEHLT; uiBut *but = uiDefIconTextBut(params.block, UI_BTYPE_LABEL, @@ -163,87 +171,81 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer { nullptr); UI_but_drawflag_disable(but, UI_BUT_ICON_LEFT); } - else if (cell_value.value_float2.has_value()) { - const float2 value = *cell_value.value_float2; + else if (data.type().is<float2>()) { + const float2 value = data.get<float2>(real_index); this->draw_float_vector(params, Span(&value.x, 2)); } - else if (cell_value.value_float3.has_value()) { - const float3 value = *cell_value.value_float3; + else if (data.type().is<float3>()) { + const float3 value = data.get<float3>(real_index); this->draw_float_vector(params, Span(&value.x, 3)); } - else if (cell_value.value_color.has_value()) { - const ColorGeometry4f value = *cell_value.value_color; + else if (data.type().is<ColorGeometry4f>()) { + const ColorGeometry4f value = data.get<ColorGeometry4f>(real_index); this->draw_float_vector(params, Span(&value.r, 4)); } - else if (cell_value.value_object.has_value()) { - const ObjectCellValue value = *cell_value.value_object; - uiDefIconTextBut(params.block, - UI_BTYPE_LABEL, - 0, - ICON_OBJECT_DATA, - reinterpret_cast<const ID *const>(value.object)->name + 2, - params.xmin, - params.ymin, - params.width, - params.height, - nullptr, - 0, - 0, - 0, - 0, - nullptr); - } - else if (cell_value.value_collection.has_value()) { - const CollectionCellValue value = *cell_value.value_collection; - uiDefIconTextBut(params.block, - UI_BTYPE_LABEL, - 0, - ICON_OUTLINER_COLLECTION, - reinterpret_cast<const ID *const>(value.collection)->name + 2, - params.xmin, - params.ymin, - params.width, - params.height, - nullptr, - 0, - 0, - 0, - 0, - nullptr); - } - else if (cell_value.value_geometry_set.has_value()) { - uiDefIconTextBut(params.block, - UI_BTYPE_LABEL, - 0, - ICON_MESH_DATA, - "Geometry", - params.xmin, - params.ymin, - params.width, - params.height, - nullptr, - 0, - 0, - 0, - 0, - nullptr); - } - else if (cell_value.value_string.has_value()) { - uiDefIconTextBut(params.block, - UI_BTYPE_LABEL, - 0, - ICON_NONE, - cell_value.value_string->c_str(), - params.xmin, - params.ymin, - params.width, - params.height, - nullptr, - 0, - 0, - 0, - 0, - nullptr); + else if (data.type().is<InstanceReference>()) { + const InstanceReference value = data.get<InstanceReference>(real_index); + switch (value.type()) { + case InstanceReference::Type::Object: { + const Object &object = value.object(); + uiDefIconTextBut(params.block, + UI_BTYPE_LABEL, + 0, + ICON_OBJECT_DATA, + object.id.name + 2, + params.xmin, + params.ymin, + params.width, + params.height, + nullptr, + 0, + 0, + 0, + 0, + nullptr); + break; + } + case InstanceReference::Type::Collection: { + Collection &collection = value.collection(); + uiDefIconTextBut(params.block, + UI_BTYPE_LABEL, + 0, + ICON_OUTLINER_COLLECTION, + collection.id.name + 2, + params.xmin, + params.ymin, + params.width, + params.height, + nullptr, + 0, + 0, + 0, + 0, + nullptr); + break; + } + case InstanceReference::Type::GeometrySet: { + uiDefIconTextBut(params.block, + UI_BTYPE_LABEL, + 0, + ICON_MESH_DATA, + "Geometry", + params.xmin, + params.ymin, + params.width, + params.height, + nullptr, + 0, + 0, + 0, + 0, + nullptr); + break; + } + case InstanceReference::Type::None: { + break; + } + } } } diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh b/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh index 1768af6ae09..f996cd99dad 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.hh @@ -32,7 +32,7 @@ struct ColumnLayout { /* Layout information for the entire spreadsheet. */ struct SpreadsheetLayout { Vector<ColumnLayout> columns; - Span<int64_t> row_indices; + IndexMask row_indices; int index_column_width = 100; }; diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc b/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc index 854c3d4aba6..db8265a33ce 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_panels.cc @@ -25,7 +25,7 @@ namespace blender::ed::spreadsheet { void spreadsheet_data_set_region_panels_register(ARegionType ®ion_type) { - PanelType *panel_type = (PanelType *)MEM_callocN(sizeof(PanelType), __func__); + PanelType *panel_type = MEM_cnew<PanelType>(__func__); strcpy(panel_type->idname, "SPREADSHEET_PT_data_set"); strcpy(panel_type->label, N_("Data Set")); strcpy(panel_type->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc index 1e46fef8d71..556c0b0d5ca 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc @@ -18,7 +18,6 @@ #include "BLI_listbase.h" -#include "DNA_collection_types.h" #include "DNA_screen_types.h" #include "DNA_space_types.h" @@ -38,238 +37,193 @@ namespace blender::ed::spreadsheet { -template<typename OperationFn> -static void apply_filter_operation(const ColumnValues &values, +template<typename T, typename OperationFn> +static void apply_filter_operation(const VArray<T> &data, OperationFn check_fn, - MutableSpan<bool> rows_included) + const IndexMask mask, + Vector<int64_t> &new_indices) { - for (const int i : rows_included.index_range()) { - if (!rows_included[i]) { - continue; - } - CellValue cell_value; - values.get_value(i, cell_value); - if (!check_fn(cell_value)) { - rows_included[i] = false; + for (const int64_t i : mask) { + if (check_fn(data[i])) { + new_indices.append(i); } } } -static void apply_row_filter(const SpreadsheetLayout &spreadsheet_layout, - const SpreadsheetRowFilter &row_filter, - MutableSpan<bool> rows_included) +static void apply_row_filter(const SpreadsheetRowFilter &row_filter, + const Map<StringRef, const ColumnValues *> &columns, + const IndexMask prev_mask, + Vector<int64_t> &new_indices) { - for (const ColumnLayout &column : spreadsheet_layout.columns) { - const ColumnValues &values = *column.values; - if (values.name() != row_filter.column_name) { - continue; + const ColumnValues &column = *columns.lookup(row_filter.column_name); + const fn::GVArray &column_data = column.data(); + if (column_data.type().is<float>()) { + const float value = row_filter.value_float; + switch (row_filter.operation) { + case SPREADSHEET_ROW_FILTER_EQUAL: { + const float threshold = row_filter.threshold; + apply_filter_operation( + column_data.typed<float>(), + [&](const float cell) { return std::abs(cell - value) < threshold; }, + prev_mask, + new_indices); + break; + } + case SPREADSHEET_ROW_FILTER_GREATER: { + apply_filter_operation( + column_data.typed<float>(), + [&](const float cell) { return cell > value; }, + prev_mask, + new_indices); + break; + } + case SPREADSHEET_ROW_FILTER_LESS: { + apply_filter_operation( + column_data.typed<float>(), + [&](const float cell) { return cell < value; }, + prev_mask, + new_indices); + break; + } } - - switch (values.type()) { - case SPREADSHEET_VALUE_TYPE_INT32: { - const int value = row_filter.value_int; - switch (row_filter.operation) { - case SPREADSHEET_ROW_FILTER_EQUAL: { - apply_filter_operation( - values, - [value](const CellValue &cell_value) -> bool { - return *cell_value.value_int == value; - }, - rows_included); - break; - } - case SPREADSHEET_ROW_FILTER_GREATER: { - apply_filter_operation( - values, - [value](const CellValue &cell_value) -> bool { - return *cell_value.value_int > value; - }, - rows_included); - break; - } - case SPREADSHEET_ROW_FILTER_LESS: { - apply_filter_operation( - values, - [value](const CellValue &cell_value) -> bool { - return *cell_value.value_int < value; - }, - rows_included); - break; - } - } + } + else if (column_data.type().is<int>()) { + const int value = row_filter.value_int; + switch (row_filter.operation) { + case SPREADSHEET_ROW_FILTER_EQUAL: { + apply_filter_operation( + column_data.typed<int>(), + [&](const int cell) { return cell == value; }, + prev_mask, + new_indices); break; } - case SPREADSHEET_VALUE_TYPE_FLOAT: { - const float value = row_filter.value_float; - switch (row_filter.operation) { - case SPREADSHEET_ROW_FILTER_EQUAL: { - const float threshold = row_filter.threshold; - apply_filter_operation( - values, - [value, threshold](const CellValue &cell_value) -> bool { - return std::abs(*cell_value.value_float - value) < threshold; - }, - rows_included); - break; - } - case SPREADSHEET_ROW_FILTER_GREATER: { - apply_filter_operation( - values, - [value](const CellValue &cell_value) -> bool { - return *cell_value.value_float > value; - }, - rows_included); - break; - } - case SPREADSHEET_ROW_FILTER_LESS: { - apply_filter_operation( - values, - [value](const CellValue &cell_value) -> bool { - return *cell_value.value_float < value; - }, - rows_included); - break; - } - } + case SPREADSHEET_ROW_FILTER_GREATER: { + apply_filter_operation( + column_data.typed<int>(), + [value](const int cell) { return cell > value; }, + prev_mask, + new_indices); break; } - case SPREADSHEET_VALUE_TYPE_FLOAT2: { - const float2 value = row_filter.value_float2; - switch (row_filter.operation) { - case SPREADSHEET_ROW_FILTER_EQUAL: { - const float threshold_squared = row_filter.threshold * row_filter.threshold; - apply_filter_operation( - values, - [value, threshold_squared](const CellValue &cell_value) -> bool { - return float2::distance_squared(*cell_value.value_float2, value) < - threshold_squared; - }, - rows_included); - break; - } - case SPREADSHEET_ROW_FILTER_GREATER: { - apply_filter_operation( - values, - [value](const CellValue &cell_value) -> bool { - return cell_value.value_float2->x > value.x && - cell_value.value_float2->y > value.y; - }, - rows_included); - break; - } - case SPREADSHEET_ROW_FILTER_LESS: { - apply_filter_operation( - values, - [value](const CellValue &cell_value) -> bool { - return cell_value.value_float2->x < value.x && - cell_value.value_float2->y < value.y; - }, - rows_included); - break; - } - } + case SPREADSHEET_ROW_FILTER_LESS: { + apply_filter_operation( + column_data.typed<int>(), + [&](const int cell) { return cell < value; }, + prev_mask, + new_indices); break; } - case SPREADSHEET_VALUE_TYPE_FLOAT3: { - const float3 value = row_filter.value_float3; - switch (row_filter.operation) { - case SPREADSHEET_ROW_FILTER_EQUAL: { - const float threshold_squared = row_filter.threshold * row_filter.threshold; - apply_filter_operation( - values, - [value, threshold_squared](const CellValue &cell_value) -> bool { - return float3::distance_squared(*cell_value.value_float3, value) < - threshold_squared; - }, - rows_included); - break; - } - case SPREADSHEET_ROW_FILTER_GREATER: { - apply_filter_operation( - values, - [value](const CellValue &cell_value) -> bool { - return cell_value.value_float3->x > value.x && - cell_value.value_float3->y > value.y && - cell_value.value_float3->z > value.z; - }, - rows_included); - break; - } - case SPREADSHEET_ROW_FILTER_LESS: { - apply_filter_operation( - values, - [value](const CellValue &cell_value) -> bool { - return cell_value.value_float3->x < value.x && - cell_value.value_float3->y < value.y && - cell_value.value_float3->z < value.z; - }, - rows_included); - break; - } - } + } + } + else if (column_data.type().is<float2>()) { + const float2 value = row_filter.value_float2; + switch (row_filter.operation) { + case SPREADSHEET_ROW_FILTER_EQUAL: { + const float threshold_sq = row_filter.threshold; + apply_filter_operation( + column_data.typed<float2>(), + [&](const float2 cell) { return math::distance_squared(cell, value) > threshold_sq; }, + prev_mask, + new_indices); break; } - case SPREADSHEET_VALUE_TYPE_COLOR: { - const ColorGeometry4f value = row_filter.value_color; - switch (row_filter.operation) { - case SPREADSHEET_ROW_FILTER_EQUAL: { - const float threshold_squared = row_filter.threshold * row_filter.threshold; - apply_filter_operation( - values, - [value, threshold_squared](const CellValue &cell_value) -> bool { - return len_squared_v4v4(value, *cell_value.value_color) < threshold_squared; - }, - rows_included); - break; - } - } + case SPREADSHEET_ROW_FILTER_GREATER: { + apply_filter_operation( + column_data.typed<float2>(), + [&](const float2 cell) { return cell.x > value.x && cell.y > value.y; }, + prev_mask, + new_indices); + break; + } + case SPREADSHEET_ROW_FILTER_LESS: { + apply_filter_operation( + column_data.typed<float2>(), + [&](const float2 cell) { return cell.x < value.x && cell.y < value.y; }, + prev_mask, + new_indices); + break; + } + } + } + else if (column_data.type().is<float3>()) { + const float3 value = row_filter.value_float3; + switch (row_filter.operation) { + case SPREADSHEET_ROW_FILTER_EQUAL: { + const float threshold_sq = row_filter.threshold; + apply_filter_operation( + column_data.typed<float3>(), + [&](const float3 cell) { return math::distance_squared(cell, value) > threshold_sq; }, + prev_mask, + new_indices); break; } - case SPREADSHEET_VALUE_TYPE_BOOL: { - const bool value = (row_filter.flag & SPREADSHEET_ROW_FILTER_BOOL_VALUE) != 0; + case SPREADSHEET_ROW_FILTER_GREATER: { apply_filter_operation( - values, - [value](const CellValue &cell_value) -> bool { - return *cell_value.value_bool == value; + column_data.typed<float3>(), + [&](const float3 cell) { + return cell.x > value.x && cell.y > value.y && cell.z > value.z; }, - rows_included); + prev_mask, + new_indices); break; } - case SPREADSHEET_VALUE_TYPE_INSTANCES: { - const StringRef value = row_filter.value_string; + case SPREADSHEET_ROW_FILTER_LESS: { apply_filter_operation( - values, - [value](const CellValue &cell_value) -> bool { - const ID *id = nullptr; - if (cell_value.value_object) { - id = &cell_value.value_object->object->id; - } - else if (cell_value.value_collection) { - id = &cell_value.value_collection->collection->id; - } - if (id == nullptr) { - return false; - } - - return value == id->name + 2; + column_data.typed<float3>(), + [&](const float3 cell) { + return cell.x < value.x && cell.y < value.y && cell.z < value.z; }, - rows_included); + prev_mask, + new_indices); break; } - default: + } + } + else if (column_data.type().is<ColorGeometry4f>()) { + const ColorGeometry4f value = row_filter.value_color; + switch (row_filter.operation) { + case SPREADSHEET_ROW_FILTER_EQUAL: { + const float threshold_sq = row_filter.threshold; + apply_filter_operation( + column_data.typed<ColorGeometry4f>(), + [&](const ColorGeometry4f cell) { + return len_squared_v4v4(cell, value) > threshold_sq; + }, + prev_mask, + new_indices); break; + } } - - /* Only one column should have this name. */ - break; } -} - -static void index_vector_from_bools(Span<bool> selection, Vector<int64_t> &indices) -{ - for (const int i : selection.index_range()) { - if (selection[i]) { - indices.append(i); + else if (column_data.type().is<InstanceReference>()) { + const StringRef value = row_filter.value_string; + switch (row_filter.operation) { + case SPREADSHEET_ROW_FILTER_EQUAL: { + apply_filter_operation( + column_data.typed<InstanceReference>(), + [&](const InstanceReference cell) { + switch (cell.type()) { + case InstanceReference::Type::Object: { + return value == (reinterpret_cast<ID &>(cell.object()).name + 2); + } + case InstanceReference::Type::Collection: { + return value == (reinterpret_cast<ID &>(cell.collection()).name + 2); + } + case InstanceReference::Type::GeometrySet: { + return false; + } + case InstanceReference::Type::None: { + return false; + } + } + BLI_assert_unreachable(); + return false; + }, + prev_mask, + new_indices); + break; + } } } } @@ -297,10 +251,10 @@ static bool use_selection_filter(const SpaceSpreadsheet &sspreadsheet, return true; } -Span<int64_t> spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet, - const SpreadsheetLayout &spreadsheet_layout, - const DataSource &data_source, - ResourceScope &scope) +IndexMask spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet, + const SpreadsheetLayout &spreadsheet_layout, + const DataSource &data_source, + ResourceScope &scope) { const int tot_rows = data_source.tot_rows(); @@ -309,35 +263,51 @@ Span<int64_t> spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet, /* Avoid allocating an array if no row filtering is necessary. */ if (!(use_filters || use_selection)) { - return IndexRange(tot_rows).as_span(); + return IndexMask(tot_rows); } - Array<bool> rows_included(tot_rows, true); + IndexMask mask(tot_rows); + + Vector<int64_t> mask_indices; + mask_indices.reserve(tot_rows); + + if (use_selection) { + const GeometryDataSource *geometry_data_source = dynamic_cast<const GeometryDataSource *>( + &data_source); + mask = geometry_data_source->apply_selection_filter(mask_indices); + } if (use_filters) { + Map<StringRef, const ColumnValues *> columns; + for (const ColumnLayout &column : spreadsheet_layout.columns) { + columns.add(column.values->name(), column.values); + } + LISTBASE_FOREACH (const SpreadsheetRowFilter *, row_filter, &sspreadsheet.row_filters) { if (row_filter->flag & SPREADSHEET_ROW_FILTER_ENABLED) { - apply_row_filter(spreadsheet_layout, *row_filter, rows_included); + if (!columns.contains(row_filter->column_name)) { + continue; + } + Vector<int64_t> new_indices; + new_indices.reserve(mask_indices.size()); + apply_row_filter(*row_filter, columns, mask, new_indices); + std::swap(new_indices, mask_indices); + mask = IndexMask(mask_indices); } } } - if (use_selection) { - const GeometryDataSource *geometry_data_source = dynamic_cast<const GeometryDataSource *>( - &data_source); - geometry_data_source->apply_selection_filter(rows_included); + if (mask_indices.is_empty()) { + BLI_assert(mask.is_empty() || mask.is_range()); + return mask; } - Vector<int64_t> &indices = scope.construct<Vector<int64_t>>(); - index_vector_from_bools(rows_included, indices); - - return indices; + return IndexMask(scope.add_value(std::move(mask_indices))); } SpreadsheetRowFilter *spreadsheet_row_filter_new() { - SpreadsheetRowFilter *row_filter = (SpreadsheetRowFilter *)MEM_callocN( - sizeof(SpreadsheetRowFilter), __func__); + SpreadsheetRowFilter *row_filter = MEM_cnew<SpreadsheetRowFilter>(__func__); row_filter->flag = (SPREADSHEET_ROW_FILTER_UI_EXPAND | SPREADSHEET_ROW_FILTER_ENABLED); row_filter->operation = SPREADSHEET_ROW_FILTER_LESS; row_filter->threshold = 0.01f; diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh index 0a5783e318d..3788baaa993 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh +++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.hh @@ -23,10 +23,10 @@ namespace blender::ed::spreadsheet { -Span<int64_t> spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet, - const SpreadsheetLayout &spreadsheet_layout, - const DataSource &data_source, - ResourceScope &scope); +IndexMask spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet, + const SpreadsheetLayout &spreadsheet_layout, + const DataSource &data_source, + ResourceScope &scope); SpreadsheetRowFilter *spreadsheet_row_filter_new(); SpreadsheetRowFilter *spreadsheet_row_filter_copy(const SpreadsheetRowFilter *src_row_filter); diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc index a07abac4474..56722104b4f 100644 --- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc +++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter_ui.cc @@ -114,6 +114,8 @@ static std::string value_string(const SpreadsheetRowFilter &row_filter, } case SPREADSHEET_VALUE_TYPE_STRING: return row_filter.value_string; + case SPREADSHEET_VALUE_TYPE_UNKNOWN: + return ""; } BLI_assert_unreachable(); return ""; @@ -238,6 +240,10 @@ static void spreadsheet_filter_panel_draw(const bContext *C, Panel *panel) uiItemR(layout, filter_ptr, "threshold", 0, nullptr, ICON_NONE); break; case SPREADSHEET_VALUE_TYPE_STRING: + uiItemR(layout, filter_ptr, "value_string", 0, IFACE_("Value"), ICON_NONE); + break; + case SPREADSHEET_VALUE_TYPE_UNKNOWN: + uiItemL(layout, IFACE_("Unkown column type"), ICON_ERROR); break; } } @@ -325,7 +331,7 @@ static void set_filter_expand_flag(const bContext *UNUSED(C), Panel *panel, shor void register_row_filter_panels(ARegionType ®ion_type) { { - PanelType *panel_type = (PanelType *)MEM_callocN(sizeof(PanelType), __func__); + PanelType *panel_type = MEM_cnew<PanelType>(__func__); strcpy(panel_type->idname, "SPREADSHEET_PT_row_filters"); strcpy(panel_type->label, N_("Filters")); strcpy(panel_type->category, "Filters"); @@ -336,7 +342,7 @@ void register_row_filter_panels(ARegionType ®ion_type) } { - PanelType *panel_type = (PanelType *)MEM_callocN(sizeof(PanelType), __func__); + PanelType *panel_type = MEM_cnew<PanelType>(__func__); strcpy(panel_type->idname, "SPREADSHEET_PT_filter"); strcpy(panel_type->label, ""); strcpy(panel_type->category, "Filters"); diff --git a/source/blender/editors/space_text/space_text.c b/source/blender/editors/space_text/space_text.c index f449ce50ae3..7339d8248c8 100644 --- a/source/blender/editors/space_text/space_text.c +++ b/source/blender/editors/space_text/space_text.c @@ -32,6 +32,7 @@ #include "BKE_context.h" #include "BKE_global.h" #include "BKE_lib_id.h" +#include "BKE_lib_remap.h" #include "BKE_screen.h" #include "ED_screen.h" @@ -401,18 +402,12 @@ static void text_properties_region_draw(const bContext *C, ARegion *region) } } -static void text_id_remap(ScrArea *UNUSED(area), SpaceLink *slink, ID *old_id, ID *new_id) +static void text_id_remap(ScrArea *UNUSED(area), + SpaceLink *slink, + const struct IDRemapper *mappings) { SpaceText *stext = (SpaceText *)slink; - - if (!ELEM(GS(old_id->name), ID_TXT)) { - return; - } - - if ((ID *)stext->text == old_id) { - stext->text = (Text *)new_id; - id_us_ensure_real(new_id); - } + BKE_id_remapper_apply(mappings, (ID **)&stext->text, ID_REMAP_APPLY_ENSURE_REAL); } /********************* registration ********************/ diff --git a/source/blender/editors/space_text/text_format.h b/source/blender/editors/space_text/text_format.h index 01c40b4ed22..ebccaa54342 100644 --- a/source/blender/editors/space_text/text_format.h +++ b/source/blender/editors/space_text/text_format.h @@ -66,12 +66,12 @@ int text_check_format_len(TextLine *line, unsigned int len); * * \param len: length in bytes of \a fmt_p to fill. */ -void text_format_fill(const char **str_p, char **fmt_p, const char type, const int len); +void text_format_fill(const char **str_p, char **fmt_p, char type, int len); /** * ASCII version of #text_format_fill, * use when we no the text being stepped over is ascii (as is the case for most keywords) */ -void text_format_fill_ascii(const char **str_p, char **fmt_p, const char type, const int len); +void text_format_fill_ascii(const char **str_p, char **fmt_p, char type, int len); /* *** Generalize Formatting *** */ typedef struct TextFormatType { @@ -88,7 +88,7 @@ typedef struct TextFormatType { * * See: FMT_TYPE_ enums below */ - void (*format_line)(SpaceText *st, TextLine *line, const bool do_next); + void (*format_line)(SpaceText *st, TextLine *line, bool do_next); const char **ext; /* NULL terminated extensions */ } TextFormatType; diff --git a/source/blender/editors/space_text/text_intern.h b/source/blender/editors/space_text/text_intern.h index 3cae4188932..0b81cd74a42 100644 --- a/source/blender/editors/space_text/text_intern.h +++ b/source/blender/editors/space_text/text_intern.h @@ -42,7 +42,7 @@ void text_update_character_width(struct SpaceText *st); /** * Takes an area instead of a region, use for listeners. */ -void text_scroll_to_cursor__area(struct SpaceText *st, struct ScrArea *area, const bool center); +void text_scroll_to_cursor__area(struct SpaceText *st, struct ScrArea *area, bool center); void text_update_cursor_moved(struct bContext *C); /* Padding around line numbers in character widths. */ diff --git a/source/blender/editors/space_text/text_ops.c b/source/blender/editors/space_text/text_ops.c index 3c0ffa29bbd..430ffe6d56f 100644 --- a/source/blender/editors/space_text/text_ops.c +++ b/source/blender/editors/space_text/text_ops.c @@ -796,7 +796,7 @@ static int text_run_script(bContext *C, ReportList *reports) /* Don't report error messages while live editing */ if (!is_live) { - /* text may have freed its self */ + /* text may have freed itself */ if (CTX_data_edit_text(C) == text) { if (text->curl != curl_prev || curc_prev != text->curc) { text_update_cursor_moved(C); diff --git a/source/blender/editors/space_topbar/space_topbar.c b/source/blender/editors/space_topbar/space_topbar.c index 41eddd32854..82a0de9b845 100644 --- a/source/blender/editors/space_topbar/space_topbar.c +++ b/source/blender/editors/space_topbar/space_topbar.c @@ -35,6 +35,7 @@ #include "BKE_context.h" #include "BKE_global.h" #include "BKE_screen.h" +#include "BKE_undo_system.h" #include "ED_screen.h" #include "ED_space_api.h" @@ -236,6 +237,64 @@ static void recent_files_menu_register(void) WM_menutype_add(mt); } +static void undo_history_draw_menu(const bContext *C, Menu *menu) +{ + wmWindowManager *wm = CTX_wm_manager(C); + if (wm->undo_stack == NULL) { + return; + } + + int undo_step_count = 0; + int undo_step_count_all = 0; + for (UndoStep *us = wm->undo_stack->steps.last; us; us = us->prev) { + undo_step_count_all += 1; + if (us->skip) { + continue; + } + undo_step_count += 1; + } + + uiLayout *split = uiLayoutSplit(menu->layout, 0.0f, false); + uiLayout *column = NULL; + + const int col_size = 20 + (undo_step_count / 12); + + undo_step_count = 0; + + /* Reverse the order so the most recent state is first in the menu. */ + int i = undo_step_count_all - 1; + for (UndoStep *us = wm->undo_stack->steps.last; us; us = us->prev, i--) { + if (us->skip) { + continue; + } + if (!(undo_step_count % col_size)) { + column = uiLayoutColumn(split, false); + } + const bool is_active = (us == wm->undo_stack->step_active); + uiLayout *row = uiLayoutRow(column, false); + uiLayoutSetEnabled(row, !is_active); + uiItemIntO(row, + IFACE_(us->name), + is_active ? ICON_LAYER_ACTIVE : ICON_NONE, + "ED_OT_undo_history", + "item", + i); + undo_step_count += 1; + } +} + +static void undo_history_menu_register(void) +{ + MenuType *mt; + + mt = MEM_callocN(sizeof(MenuType), __func__); + strcpy(mt->idname, "TOPBAR_MT_undo_history"); + strcpy(mt->label, N_("Undo History")); + strcpy(mt->translation_context, BLT_I18NCONTEXT_DEFAULT_BPYRNA); + mt->draw = undo_history_draw_menu; + WM_menutype_add(mt); +} + void ED_spacetype_topbar(void) { SpaceType *st = MEM_callocN(sizeof(SpaceType), "spacetype topbar"); @@ -278,6 +337,7 @@ void ED_spacetype_topbar(void) BLI_addhead(&st->regiontypes, art); recent_files_menu_register(); + undo_history_menu_register(); BKE_spacetype_register(st); } diff --git a/source/blender/editors/space_userpref/space_userpref.c b/source/blender/editors/space_userpref/space_userpref.c index 1711188fca7..b1ee6da1a33 100644 --- a/source/blender/editors/space_userpref/space_userpref.c +++ b/source/blender/editors/space_userpref/space_userpref.c @@ -113,9 +113,9 @@ static SpaceLink *userpref_duplicate(SpaceLink *sl) /* add handlers, stuff you only do once or on area/region changes */ static void userpref_main_region_init(wmWindowManager *wm, ARegion *region) { - /* do not use here, the properties changed in userprefs do a system-wide refresh, + /* do not use here, the properties changed in user-preferences do a system-wide refresh, * then scroller jumps back */ - /* region->v2d.flag &= ~V2D_IS_INIT; */ + // region->v2d.flag &= ~V2D_IS_INIT; region->v2d.scroll = V2D_SCROLL_RIGHT | V2D_SCROLL_VERTICAL_HIDE; diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 8822ea6af3b..0a5bebac8a8 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -48,6 +48,7 @@ #include "BKE_idprop.h" #include "BKE_lattice.h" #include "BKE_layer.h" +#include "BKE_lib_remap.h" #include "BKE_main.h" #include "BKE_mball.h" #include "BKE_mesh.h" @@ -1813,50 +1814,54 @@ static int view3d_context(const bContext *C, const char *member, bContextDataRes return CTX_RESULT_MEMBER_NOT_FOUND; } -static void view3d_id_remap(ScrArea *area, SpaceLink *slink, ID *old_id, ID *new_id) +static void view3d_id_remap_v3d_ob_centers(View3D *v3d, const struct IDRemapper *mappings) { - View3D *v3d; - ARegion *region; - bool is_local = false; - - if (!ELEM(GS(old_id->name), ID_OB, ID_MA, ID_IM, ID_MC)) { - return; + if (BKE_id_remapper_apply(mappings, (ID **)&v3d->ob_center, ID_REMAP_APPLY_DEFAULT) == + ID_REMAP_RESULT_SOURCE_UNASSIGNED) { + /* Otherwise, bonename may remain valid... + * We could be smart and check this, too? */ + v3d->ob_center_bone[0] = '\0'; } +} - for (v3d = (View3D *)slink; v3d; v3d = v3d->localvd, is_local = true) { - if ((ID *)v3d->camera == old_id) { - v3d->camera = (Object *)new_id; - if (!new_id) { - /* 3D view might be inactive, in that case needs to use slink->regionbase */ - ListBase *regionbase = (slink == area->spacedata.first) ? &area->regionbase : - &slink->regionbase; - for (region = regionbase->first; region; region = region->next) { - if (region->regiontype == RGN_TYPE_WINDOW) { - RegionView3D *rv3d = is_local ? ((RegionView3D *)region->regiondata)->localvd : - region->regiondata; - if (rv3d && (rv3d->persp == RV3D_CAMOB)) { - rv3d->persp = RV3D_PERSP; - } - } +static void view3d_id_remap_v3d(ScrArea *area, + SpaceLink *slink, + View3D *v3d, + const struct IDRemapper *mappings, + const bool is_local) +{ + ARegion *region; + if (BKE_id_remapper_apply(mappings, (ID **)&v3d->camera, ID_REMAP_APPLY_DEFAULT) == + ID_REMAP_RESULT_SOURCE_UNASSIGNED) { + /* 3D view might be inactive, in that case needs to use slink->regionbase */ + ListBase *regionbase = (slink == area->spacedata.first) ? &area->regionbase : + &slink->regionbase; + for (region = regionbase->first; region; region = region->next) { + if (region->regiontype == RGN_TYPE_WINDOW) { + RegionView3D *rv3d = is_local ? ((RegionView3D *)region->regiondata)->localvd : + region->regiondata; + if (rv3d && (rv3d->persp == RV3D_CAMOB)) { + rv3d->persp = RV3D_PERSP; } } } + } +} - /* Values in local-view aren't used, see: T52663 */ - if (is_local == false) { - if ((ID *)v3d->ob_center == old_id) { - v3d->ob_center = (Object *)new_id; - /* Otherwise, bonename may remain valid... - * We could be smart and check this, too? */ - if (new_id == NULL) { - v3d->ob_center_bone[0] = '\0'; - } - } - } +static void view3d_id_remap(ScrArea *area, SpaceLink *slink, const struct IDRemapper *mappings) +{ - if (is_local) { - break; - } + if (!BKE_id_remapper_has_mapping_for( + mappings, FILTER_ID_OB | FILTER_ID_MA | FILTER_ID_IM | FILTER_ID_MC)) { + return; + } + + View3D *view3d = (View3D *)slink; + view3d_id_remap_v3d(area, slink, view3d, mappings, false); + view3d_id_remap_v3d_ob_centers(view3d, mappings); + if (view3d->localvd != NULL) { + /* Object centers in local-view aren't used, see: T52663 */ + view3d_id_remap_v3d(area, slink, view3d->localvd, mappings, true); } } diff --git a/source/blender/editors/space_view3d/view3d_buttons.c b/source/blender/editors/space_view3d/view3d_buttons.c index b79303551a1..243d4033cbc 100644 --- a/source/blender/editors/space_view3d/view3d_buttons.c +++ b/source/blender/editors/space_view3d/view3d_buttons.c @@ -87,7 +87,7 @@ typedef struct { } TransformMedian_Generic; typedef struct { - float location[3], bv_weight, be_weight, skin[2], crease; + float location[3], bv_weight, v_crease, be_weight, skin[2], e_crease; } TransformMedian_Mesh; typedef struct { @@ -319,6 +319,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float BMIter iter; const int cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT); + const int cd_vert_crease_offset = CustomData_get_offset(&bm->vdata, CD_CREASE); const int cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN); const int cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT); const int cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE); @@ -335,6 +336,10 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float median->bv_weight += BM_ELEM_CD_GET_FLOAT(eve, cd_vert_bweight_offset); } + if (cd_vert_crease_offset != -1) { + median->v_crease += BM_ELEM_CD_GET_FLOAT(eve, cd_vert_crease_offset); + } + if (has_skinradius) { MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_skin_offset); add_v2_v2(median->skin, vs->radius); /* Third val not used currently. */ @@ -352,7 +357,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float } if (cd_edge_crease_offset != -1) { - median->crease += BM_ELEM_CD_GET_FLOAT(eed, cd_edge_crease_offset); + median->e_crease += BM_ELEM_CD_GET_FLOAT(eed, cd_edge_crease_offset); } totedgedata++; @@ -489,11 +494,12 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float if (has_meshdata) { TransformMedian_Mesh *median = &median_basis.mesh; if (totedgedata) { - median->crease /= (float)totedgedata; + median->e_crease /= (float)totedgedata; median->be_weight /= (float)totedgedata; } if (tot) { median->bv_weight /= (float)tot; + median->v_crease /= (float)tot; if (has_skinradius) { median->skin[0] /= (float)tot; median->skin[1] /= (float)tot; @@ -683,6 +689,23 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float TIP_("Vertex weight used by Bevel modifier")); UI_but_number_step_size_set(but, 1); UI_but_number_precision_set(but, 2); + /* customdata layer added on demand */ + but = uiDefButF(block, + UI_BTYPE_NUM, + B_TRANSFORM_PANEL_MEDIAN, + tot == 1 ? IFACE_("Vertex Crease:") : IFACE_("Mean Vertex Crease:"), + 0, + yi -= buth + but_margin, + butw, + buth, + &ve_median->v_crease, + 0.0, + 1.0, + 0, + 0, + TIP_("Weight used by the Subdivision Surface modifier")); + UI_but_number_step_size_set(but, 1); + UI_but_number_precision_set(but, 2); } if (has_skinradius) { UI_block_align_begin(block); @@ -761,7 +784,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float yi -= buth + but_margin, butw, buth, - &ve_median->crease, + &ve_median->e_crease, 0.0, 1.0, 0, @@ -958,8 +981,9 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float const bool apply_vcos = (tot == 1) || (len_squared_v3(median_basis.generic.location) != 0.0f); if ((ob->type == OB_MESH) && - (apply_vcos || median_basis.mesh.bv_weight || median_basis.mesh.skin[0] || - median_basis.mesh.skin[1] || median_basis.mesh.be_weight || median_basis.mesh.crease)) { + (apply_vcos || median_basis.mesh.bv_weight || median_basis.mesh.v_crease || + median_basis.mesh.skin[0] || median_basis.mesh.skin[1] || median_basis.mesh.be_weight || + median_basis.mesh.e_crease)) { const TransformMedian_Mesh *median = &median_basis.mesh, *ve_median = &ve_median_basis.mesh; Mesh *me = ob->data; BMEditMesh *em = me->edit_mesh; @@ -969,18 +993,21 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float BMEdge *eed; int cd_vert_bweight_offset = -1; + int cd_vert_crease_offset = -1; int cd_vert_skin_offset = -1; int cd_edge_bweight_offset = -1; int cd_edge_crease_offset = -1; float scale_bv_weight = 1.0f; + float scale_v_crease = 1.0f; float scale_skin[2] = {1.0f, 1.0f}; float scale_be_weight = 1.0f; - float scale_crease = 1.0f; + float scale_e_crease = 1.0f; /* Vertices */ - if (apply_vcos || median->bv_weight || median->skin[0] || median->skin[1]) { + if (apply_vcos || median->bv_weight || median->v_crease || median->skin[0] || + median->skin[1]) { if (median->bv_weight) { BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_VERT_BWEIGHT); cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT); @@ -989,6 +1016,14 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float scale_bv_weight = compute_scale_factor(ve_median->bv_weight, median->bv_weight); } + if (median->v_crease) { + BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_VERT_CREASE); + cd_vert_crease_offset = CustomData_get_offset(&bm->vdata, CD_CREASE); + BLI_assert(cd_vert_crease_offset != -1); + + scale_v_crease = compute_scale_factor(ve_median->v_crease, median->v_crease); + } + for (int i = 0; i < 2; i++) { if (median->skin[i]) { cd_vert_skin_offset = CustomData_get_offset(&bm->vdata, CD_MVERT_SKIN); @@ -1011,6 +1046,11 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float apply_scale_factor_clamp(b_weight, tot, ve_median->bv_weight, scale_bv_weight); } + if (cd_vert_crease_offset != -1) { + float *crease = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_crease_offset); + apply_scale_factor_clamp(crease, tot, ve_median->v_crease, scale_v_crease); + } + if (cd_vert_skin_offset != -1) { MVertSkin *vs = BM_ELEM_CD_GET_VOID_P(eve, cd_vert_skin_offset); @@ -1033,7 +1073,7 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float /* Edges */ - if (median->be_weight || median->crease) { + if (median->be_weight || median->e_crease) { if (median->be_weight) { BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_BWEIGHT); cd_edge_bweight_offset = CustomData_get_offset(&bm->edata, CD_BWEIGHT); @@ -1042,12 +1082,12 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float scale_be_weight = compute_scale_factor(ve_median->be_weight, median->be_weight); } - if (median->crease) { + if (median->e_crease) { BM_mesh_cd_flag_ensure(bm, me, ME_CDFLAG_EDGE_CREASE); cd_edge_crease_offset = CustomData_get_offset(&bm->edata, CD_CREASE); BLI_assert(cd_edge_crease_offset != -1); - scale_crease = compute_scale_factor(ve_median->crease, median->crease); + scale_e_crease = compute_scale_factor(ve_median->e_crease, median->e_crease); } BM_ITER_MESH (eed, &iter, bm, BM_EDGES_OF_MESH) { @@ -1057,9 +1097,9 @@ static void v3d_editvertex_buts(uiLayout *layout, View3D *v3d, Object *ob, float apply_scale_factor_clamp(b_weight, tot, ve_median->be_weight, scale_be_weight); } - if (median->crease != 0.0f) { + if (median->e_crease != 0.0f) { float *crease = BM_ELEM_CD_GET_VOID_P(eed, cd_edge_crease_offset); - apply_scale_factor_clamp(crease, tot, ve_median->crease, scale_crease); + apply_scale_factor_clamp(crease, tot, ve_median->e_crease, scale_e_crease); } } } @@ -1552,7 +1592,7 @@ static void v3d_posearmature_buts(uiLayout *layout, Object *ob) PointerRNA pchanptr; uiLayout *col; - pchan = BKE_pose_channel_active(ob); + pchan = BKE_pose_channel_active_if_layer_visible(ob); if (!pchan) { uiItemL(layout, IFACE_("No Bone Active"), ICON_NONE); diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index a7d170982ed..b1f19581543 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -1581,6 +1581,7 @@ void view3d_main_region_draw(const bContext *C, ARegion *region) view3d_draw_view(C, region); + DRW_cache_free_old_subdiv(); DRW_cache_free_old_batches(bmain); BKE_image_free_old_gputextures(bmain); GPU_pass_cache_garbage_collect(); diff --git a/source/blender/editors/space_view3d/view3d_edit.c b/source/blender/editors/space_view3d/view3d_edit.c index 830f7cbeff1..80089815284 100644 --- a/source/blender/editors/space_view3d/view3d_edit.c +++ b/source/blender/editors/space_view3d/view3d_edit.c @@ -3216,7 +3216,7 @@ static int view_lock_to_active_exec(bContext *C, wmOperator *UNUSED(op)) if (obact->mode & OB_MODE_POSE) { Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); Object *obact_eval = DEG_get_evaluated_object(depsgraph, obact); - bPoseChannel *pcham_act = BKE_pose_channel_active(obact_eval); + bPoseChannel *pcham_act = BKE_pose_channel_active_if_layer_visible(obact_eval); if (pcham_act) { BLI_strncpy(v3d->ob_center_bone, pcham_act->name, sizeof(v3d->ob_center_bone)); } diff --git a/source/blender/editors/space_view3d/view3d_gizmo_armature.c b/source/blender/editors/space_view3d/view3d_gizmo_armature.c index 83d3286c8b3..31ae8a92f81 100644 --- a/source/blender/editors/space_view3d/view3d_gizmo_armature.c +++ b/source/blender/editors/space_view3d/view3d_gizmo_armature.c @@ -134,7 +134,7 @@ static bool WIDGETGROUP_armature_spline_poll(const bContext *C, wmGizmoGroupType if (ob) { const bArmature *arm = ob->data; if (arm->drawtype == ARM_B_BONE) { - bPoseChannel *pchan = BKE_pose_channel_active(ob); + bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob); if (pchan && pchan->bone->segments > 1) { return true; } @@ -148,7 +148,7 @@ static void WIDGETGROUP_armature_spline_setup(const bContext *C, wmGizmoGroup *g { ViewLayer *view_layer = CTX_data_view_layer(C); Object *ob = BKE_object_pose_armature_get(OBACT(view_layer)); - bPoseChannel *pchan = BKE_pose_channel_active(ob); + bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob); const wmGizmoType *gzt_move = WM_gizmotype_find("GIZMO_GT_move_3d", true); @@ -187,7 +187,7 @@ static void WIDGETGROUP_armature_spline_refresh(const bContext *C, wmGizmoGroup } struct BoneSplineWidgetGroup *bspline_group = gzgroup->customdata; - bPoseChannel *pchan = BKE_pose_channel_active(ob); + bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob); /* Handles */ for (int i = 0; i < ARRAY_SIZE(bspline_group->handles); i++) { diff --git a/source/blender/editors/space_view3d/view3d_intern.h b/source/blender/editors/space_view3d/view3d_intern.h index 7388004125c..6a1a09df316 100644 --- a/source/blender/editors/space_view3d/view3d_intern.h +++ b/source/blender/editors/space_view3d/view3d_intern.h @@ -115,8 +115,8 @@ struct wmNDOFMotionData; void view3d_ndof_fly(const struct wmNDOFMotionData *ndof, struct View3D *v3d, struct RegionView3D *rv3d, - const bool use_precision, - const short protectflag, + bool use_precision, + short protectflag, bool *r_has_translate, bool *r_has_rotate); #endif /* WITH_INPUT_NDOF */ @@ -203,13 +203,13 @@ void ED_view3d_smooth_view_ex(const struct Depsgraph *depsgraph, struct ScrArea *area, struct View3D *v3d, struct ARegion *region, - const int smooth_viewtx, + int smooth_viewtx, const V3D_SmoothParams *sview); void ED_view3d_smooth_view(struct bContext *C, struct View3D *v3d, struct ARegion *region, - const int smooth_viewtx, + int smooth_viewtx, const V3D_SmoothParams *sview); /** @@ -274,17 +274,17 @@ struct View3DCameraControl *ED_view3d_cameracontrol_acquire(struct Depsgraph *de * Updates cameras from the `rv3d` values, optionally auto-keyframing. */ void ED_view3d_cameracontrol_update(struct View3DCameraControl *vctrl, - const bool use_autokey, + bool use_autokey, struct bContext *C, - const bool do_rotate, - const bool do_translate); + bool do_rotate, + bool do_translate); /** * Release view control. * * \param restore: Sets the view state to the values that were set * before #ED_view3d_control_acquire was called. */ -void ED_view3d_cameracontrol_release(struct View3DCameraControl *vctrl, const bool restore); +void ED_view3d_cameracontrol_release(struct View3DCameraControl *vctrl, bool restore); /** * Returns the object which is being manipulated or NULL. */ diff --git a/source/blender/editors/space_view3d/view3d_iterators.c b/source/blender/editors/space_view3d/view3d_iterators.c index 16d9b9182cf..990b4fc85b1 100644 --- a/source/blender/editors/space_view3d/view3d_iterators.c +++ b/source/blender/editors/space_view3d/view3d_iterators.c @@ -272,8 +272,7 @@ typedef struct foreachScreenFace_userData { static void meshobject_foreachScreenVert__mapFunc(void *userData, int index, const float co[3], - const float UNUSED(no_f[3]), - const short UNUSED(no_s[3])) + const float UNUSED(no[3])) { foreachScreenObjectVert_userData *data = userData; struct MVert *mv = &((Mesh *)(data->vc.obact->data))->mvert[index]; @@ -322,8 +321,7 @@ void meshobject_foreachScreenVert( static void mesh_foreachScreenVert__mapFunc(void *userData, int index, const float co[3], - const float UNUSED(no_f[3]), - const short UNUSED(no_s[3])) + const float UNUSED(no[3])) { foreachScreenVert_userData *data = userData; BMVert *eve = BM_vert_at_index(data->vc.em->bm, index); diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index cc8aac21a6e..45899880b41 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -4040,7 +4040,9 @@ static bool lattice_circle_select(ViewContext *vc, return data.is_changed; } -/* NOTE: pose-bone case is copied from editbone case... */ +/** + * \note logic is shared with the edit-bone case, see #armature_circle_doSelectJoint. + */ static bool pchan_circle_doSelectJoint(void *userData, bPoseChannel *pchan, const float screen_co[2]) @@ -4137,6 +4139,9 @@ static bool pose_circle_select(ViewContext *vc, return data.is_changed; } +/** + * \note logic is shared with the pose-bone case, see #pchan_circle_doSelectJoint. + */ static bool armature_circle_doSelectJoint(void *userData, EditBone *ebone, const float screen_co[2], diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index 3035d11d0e3..642de550812 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -712,9 +712,9 @@ int transformEnd(struct bContext *C, TransInfo *t); void setTransformViewMatrices(TransInfo *t); void setTransformViewAspect(TransInfo *t, float r_aspect[3]); void convertViewVec(TransInfo *t, float r_vec[3], double dx, double dy); -void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], const eV3DProjTest flag); +void projectIntViewEx(TransInfo *t, const float vec[3], int adr[2], eV3DProjTest flag); void projectIntView(TransInfo *t, const float vec[3], int adr[2]); -void projectFloatViewEx(TransInfo *t, const float vec[3], float adr[2], const eV3DProjTest flag); +void projectFloatViewEx(TransInfo *t, const float vec[3], float adr[2], eV3DProjTest flag); void projectFloatView(TransInfo *t, const float vec[3], float adr[2]); void applyAspectRatio(TransInfo *t, float vec[2]); @@ -770,7 +770,7 @@ typedef enum { } MouseInputMode; void initMouseInput( - TransInfo *t, MouseInput *mi, const float center[2], const int mval[2], const bool precision); + TransInfo *t, MouseInput *mi, const float center[2], const int mval[2], bool precision); void initMouseInputMode(TransInfo *t, MouseInput *mi, MouseInputMode mode); void applyMouseInput(struct TransInfo *t, struct MouseInput *mi, diff --git a/source/blender/editors/transform/transform_convert.c b/source/blender/editors/transform/transform_convert.c index 8f3d13176a3..4107cc3a71c 100644 --- a/source/blender/editors/transform/transform_convert.c +++ b/source/blender/editors/transform/transform_convert.c @@ -914,6 +914,9 @@ void special_aftertrans_update(bContext *C, TransInfo *t) case TC_SEQ_DATA: special_aftertrans_update__sequencer(C, t); break; + case TC_SEQ_IMAGE_DATA: + special_aftertrans_update__sequencer_image(C, t); + break; case TC_TRACKING_DATA: special_aftertrans_update__movieclip(C, t); break; @@ -930,7 +933,6 @@ void special_aftertrans_update(bContext *C, TransInfo *t) case TC_OBJECT_TEXSPACE: case TC_PAINT_CURVE_VERTS: case TC_PARTICLE_VERTS: - case TC_SEQ_IMAGE_DATA: case TC_NONE: default: break; diff --git a/source/blender/editors/transform/transform_convert.h b/source/blender/editors/transform/transform_convert.h index 5ed8182857d..c40f3c28a79 100644 --- a/source/blender/editors/transform/transform_convert.h +++ b/source/blender/editors/transform/transform_convert.h @@ -48,9 +48,9 @@ int special_transform_moving(TransInfo *t); void special_aftertrans_update(struct bContext *C, TransInfo *t); void sort_trans_data_dist(TransInfo *t); void createTransData(struct bContext *C, TransInfo *t); -bool clipUVTransform(TransInfo *t, float vec[2], const bool resize); +bool clipUVTransform(TransInfo *t, float vec[2], bool resize); void clipUVData(TransInfo *t); -void transform_convert_flush_handle2D(TransData *td, TransData2D *td2d, const float y_fac); +void transform_convert_flush_handle2D(TransData *td, TransData2D *td2d, float y_fac); /** * Called for updating while transform acts, once per redraw. */ @@ -83,7 +83,7 @@ void transform_around_single_fallback(TransInfo *t); * but may want to use a different one at times (if caller does not operate on * selection). */ -void posttrans_fcurve_clean(struct FCurve *fcu, const int sel_flag, const bool use_handle); +void posttrans_fcurve_clean(struct FCurve *fcu, int sel_flag, bool use_handle); /** * Little helper function for ObjectToTransData used to give certain * constraints (ChildOf, FollowPath, and others that may be added) @@ -125,8 +125,8 @@ void special_aftertrans_update__actedit(bContext *C, TransInfo *t); * Returns total number of bones with #BONE_TRANSFORM. */ int transform_convert_pose_transflags_update(Object *ob, - const int mode, - const short around, + int mode, + short around, bool has_translate_rotate[2]); /** * When objects array is NULL, use 't->data_container' as is. @@ -208,9 +208,9 @@ struct TransMeshDataCrazySpace { }; void transform_convert_mesh_islands_calc(struct BMEditMesh *em, - const bool calc_single_islands, - const bool calc_island_center, - const bool calc_island_axismtx, + bool calc_single_islands, + bool calc_island_center, + bool calc_island_axismtx, struct TransIslandData *r_island_data); void transform_convert_mesh_islanddata_free(struct TransIslandData *island_data); /** @@ -223,8 +223,8 @@ void transform_convert_mesh_connectivity_distance(struct BMesh *bm, float *dists, int *index); void transform_convert_mesh_mirrordata_calc(struct BMEditMesh *em, - const bool use_select, - const bool use_topology, + bool use_select, + bool use_topology, const bool mirror_axis[3], struct TransMirrorData *r_mirror_data); void transform_convert_mesh_mirrordata_free(struct TransMirrorData *mirror_data); @@ -304,6 +304,7 @@ void special_aftertrans_update__sequencer(bContext *C, TransInfo *t); /* transform_convert_sequencer_image.c */ void createTransSeqImageData(TransInfo *t); void recalcData_sequencer_image(TransInfo *t); +void special_aftertrans_update__sequencer_image(bContext *C, TransInfo *t); /* transform_convert_tracking.c */ void createTransTrackingData(bContext *C, TransInfo *t); diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c index 63aada0f797..5d0a3bd9dd1 100644 --- a/source/blender/editors/transform/transform_convert_armature.c +++ b/source/blender/editors/transform/transform_convert_armature.c @@ -427,7 +427,7 @@ static short pose_grab_with_ik(Main *bmain, Object *ob) /* Rule: allow multiple Bones * (but they must be selected, and only one ik-solver per chain should get added) */ for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) { - if (pchan->bone->layer & arm->layer) { + if (BKE_pose_is_layer_visible(arm, pchan)) { if (pchan->bone->flag & (BONE_SELECTED | BONE_TRANSFORM_MIRROR)) { /* Rule: no IK for solitary (unconnected) bones. */ for (bonec = pchan->bone->childbase.first; bonec; bonec = bonec->next) { diff --git a/source/blender/editors/transform/transform_convert_curve.c b/source/blender/editors/transform/transform_convert_curve.c index 255af3feca2..924e51a2b41 100644 --- a/source/blender/editors/transform/transform_convert_curve.c +++ b/source/blender/editors/transform/transform_convert_curve.c @@ -357,26 +357,6 @@ void createTransCurveVerts(TransInfo *t) for (a = nu->pntsu * nu->pntsv, bp = nu->bp; a > 0; a--, bp++) { if (bp->hide == 0) { if (is_prop_edit || (bp->f1 & SELECT)) { - float axismtx[3][3]; - - if (t->around == V3D_AROUND_LOCAL_ORIGINS) { - if (nu->pntsv == 1) { - float normal[3], plane[3]; - - BKE_nurb_bpoint_calc_normal(nu, bp, normal); - BKE_nurb_bpoint_calc_plane(nu, bp, plane); - - if (createSpaceNormalTangent(axismtx, normal, plane)) { - /* pass */ - } - else { - normalize_v3(normal); - axis_dominant_v3_to_m3(axismtx, normal); - invert_m3(axismtx); - } - } - } - copy_v3_v3(td->iloc, bp->vec); td->loc = bp->vec; copy_v3_v3(td->center, td->loc); @@ -400,9 +380,22 @@ void createTransCurveVerts(TransInfo *t) copy_m3_m3(td->smtx, smtx); copy_m3_m3(td->mtx, mtx); + if (t->around == V3D_AROUND_LOCAL_ORIGINS) { if (nu->pntsv == 1) { - copy_m3_m3(td->axismtx, axismtx); + float normal[3], plane[3]; + + BKE_nurb_bpoint_calc_normal(nu, bp, normal); + BKE_nurb_bpoint_calc_plane(nu, bp, plane); + + if (createSpaceNormalTangent(td->axismtx, normal, plane)) { + /* pass */ + } + else { + normalize_v3(normal); + axis_dominant_v3_to_m3(td->axismtx, normal); + invert_m3(td->axismtx); + } } } diff --git a/source/blender/editors/transform/transform_convert_mask.c b/source/blender/editors/transform/transform_convert_mask.c index 1a25cfd1efb..e26172cd764 100644 --- a/source/blender/editors/transform/transform_convert_mask.c +++ b/source/blender/editors/transform/transform_convert_mask.c @@ -472,12 +472,7 @@ void special_aftertrans_update__mask(bContext *C, TransInfo *t) } if (t->scene->nodetree) { - /* tracks can be used for stabilization nodes, - * flush update for such nodes */ - // if (nodeUpdateID(t->scene->nodetree, &mask->id)) - { - WM_event_add_notifier(C, NC_MASK | ND_DATA, &mask->id); - } + WM_event_add_notifier(C, NC_MASK | ND_DATA, &mask->id); } /* TODO: don't key all masks. */ diff --git a/source/blender/editors/transform/transform_convert_mesh.c b/source/blender/editors/transform/transform_convert_mesh.c index c3d95e1ad98..e00522f0f88 100644 --- a/source/blender/editors/transform/transform_convert_mesh.c +++ b/source/blender/editors/transform/transform_convert_mesh.c @@ -1465,7 +1465,7 @@ static void VertsToTransData(TransInfo *t, td->ext = NULL; td->val = NULL; td->extra = eve; - if (t->mode == TFM_BWEIGHT) { + if (t->mode == TFM_BWEIGHT || t->mode == TFM_VERT_CREASE) { td->val = bweight; td->ival = *bweight; } @@ -1606,10 +1606,15 @@ void createTransEditVerts(TransInfo *t) } int cd_vert_bweight_offset = -1; + int cd_vert_crease_offset = -1; if (t->mode == TFM_BWEIGHT) { BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_BWEIGHT); cd_vert_bweight_offset = CustomData_get_offset(&bm->vdata, CD_BWEIGHT); } + else if (t->mode == TFM_VERT_CREASE) { + BM_mesh_cd_flag_ensure(bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_VERT_CREASE); + cd_vert_crease_offset = CustomData_get_offset(&bm->vdata, CD_CREASE); + } TransData *tob = tc->data; TransDataMirror *td_mirror = tc->data_mirror; @@ -1645,6 +1650,8 @@ void createTransEditVerts(TransInfo *t) else if (prop_mode || BM_elem_flag_test(eve, BM_ELEM_SELECT)) { float *bweight = (cd_vert_bweight_offset != -1) ? BM_ELEM_CD_GET_VOID_P(eve, cd_vert_bweight_offset) : + (cd_vert_crease_offset != -1) ? + BM_ELEM_CD_GET_VOID_P(eve, cd_vert_crease_offset) : NULL; /* Do not use the island center in case we are using islands diff --git a/source/blender/editors/transform/transform_convert_mesh_edge.c b/source/blender/editors/transform/transform_convert_mesh_edge.c index 2db3e259153..2243f66cc7f 100644 --- a/source/blender/editors/transform/transform_convert_mesh_edge.c +++ b/source/blender/editors/transform/transform_convert_mesh_edge.c @@ -86,8 +86,8 @@ void createTransEdge(TransInfo *t) BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_EDGE_BWEIGHT); cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_BWEIGHT); } - else { /* if (t->mode == TFM_CREASE) { */ - BLI_assert(t->mode == TFM_CREASE); + else { /* if (t->mode == TFM_EDGE_CREASE) { */ + BLI_assert(t->mode == TFM_EDGE_CREASE); BM_mesh_cd_flag_ensure(em->bm, BKE_mesh_from_object(tc->obedit), ME_CDFLAG_EDGE_CREASE); cd_edge_float_offset = CustomData_get_offset(&em->bm->edata, CD_CREASE); } diff --git a/source/blender/editors/transform/transform_convert_node.c b/source/blender/editors/transform/transform_convert_node.c index da11666d445..e8cdfaf1f40 100644 --- a/source/blender/editors/transform/transform_convert_node.c +++ b/source/blender/editors/transform/transform_convert_node.c @@ -31,6 +31,7 @@ #include "BKE_context.h" #include "BKE_node.h" +#include "BKE_node_tree_update.h" #include "BKE_report.h" #include "ED_node.h" @@ -246,7 +247,7 @@ void special_aftertrans_update__node(bContext *C, TransInfo *t) nodeRemoveNode(bmain, ntree, node, true); } } - ntreeUpdateTree(bmain, ntree); + ED_node_tree_propagate_change(C, bmain, ntree); } } diff --git a/source/blender/editors/transform/transform_convert_sequencer.c b/source/blender/editors/transform/transform_convert_sequencer.c index 88c01321785..01eae36e846 100644 --- a/source/blender/editors/transform/transform_convert_sequencer.c +++ b/source/blender/editors/transform/transform_convert_sequencer.c @@ -34,6 +34,7 @@ #include "ED_markers.h" +#include "SEQ_animation.h" #include "SEQ_edit.h" #include "SEQ_effects.h" #include "SEQ_iterator.h" @@ -302,7 +303,7 @@ static SeqCollection *extract_standalone_strips(SeqCollection *transformed_strip return collection; } -/* Query strips positioned after left edge of transformed strips boundbox. */ +/* Query strips positioned after left edge of transformed strips bound-box. */ static SeqCollection *query_right_side_strips(ListBase *seqbase, SeqCollection *transformed_strips) { int minframe = MAXFRAME; @@ -351,7 +352,7 @@ static ListBase *seqbase_active_get(const TransInfo *t) return SEQ_active_seqbase_get(ed); } -/* Offset all strips positioned after left edge of transformed strips boundbox by amount equal +/* Offset all strips positioned after left edge of transformed strips bound-box by amount equal * to overlap of transformed strips. */ static void seq_transform_handle_expand_to_fit(TransInfo *t, SeqCollection *transformed_strips) { diff --git a/source/blender/editors/transform/transform_convert_sequencer_image.c b/source/blender/editors/transform/transform_convert_sequencer_image.c index d5a59885014..3a5770c2863 100644 --- a/source/blender/editors/transform/transform_convert_sequencer_image.c +++ b/source/blender/editors/transform/transform_convert_sequencer_image.c @@ -38,8 +38,12 @@ #include "SEQ_transform.h" #include "SEQ_utils.h" +#include "ED_keyframing.h" + #include "UI_view2d.h" +#include "RNA_access.h" + #include "transform.h" #include "transform_convert.h" @@ -215,3 +219,44 @@ void recalcData_sequencer_image(TransInfo *t) SEQ_relations_invalidate_cache_preprocessed(t->scene, seq); } } + +void special_aftertrans_update__sequencer_image(bContext *UNUSED(C), TransInfo *t) +{ + if (t->state == TRANS_CANCEL) { + return; + } + + TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t); + TransData *td = NULL; + TransData2D *td2d = NULL; + int i; + + PointerRNA ptr; + PropertyRNA *prop; + + for (i = 0, td = tc->data, td2d = tc->data_2d; i < tc->data_len; i++, td++, td2d++) { + TransDataSeq *tdseq = td->extra; + Sequence *seq = tdseq->seq; + StripTransform *transform = seq->strip->transform; + Scene *scene = t->scene; + + RNA_pointer_create(&scene->id, &RNA_SequenceTransform, transform, &ptr); + + if (t->mode == TFM_ROTATION) { + prop = RNA_struct_find_property(&ptr, "rotation"); + ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA); + } + if (t->mode == TFM_TRANSLATION) { + prop = RNA_struct_find_property(&ptr, "offset_x"); + ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA); + prop = RNA_struct_find_property(&ptr, "offset_y"); + ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA); + } + if (t->mode == TFM_RESIZE) { + prop = RNA_struct_find_property(&ptr, "scale_x"); + ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA); + prop = RNA_struct_find_property(&ptr, "scale_y"); + ED_autokeyframe_property(t->context, scene, &ptr, prop, -1, CFRA); + } + } +} diff --git a/source/blender/editors/transform/transform_convert_tracking.c b/source/blender/editors/transform/transform_convert_tracking.c index dc37f2796bf..f2d0fb7ac2f 100644 --- a/source/blender/editors/transform/transform_convert_tracking.c +++ b/source/blender/editors/transform/transform_convert_tracking.c @@ -29,8 +29,10 @@ #include "BLI_math.h" #include "BKE_context.h" +#include "BKE_main.h" #include "BKE_movieclip.h" #include "BKE_node.h" +#include "BKE_node_tree_update.h" #include "BKE_tracking.h" #include "ED_clip.h" @@ -793,8 +795,12 @@ void special_aftertrans_update__movieclip(bContext *C, TransInfo *t) /* Tracks can be used for stabilization nodes, * flush update for such nodes. */ - nodeUpdateID(t->scene->nodetree, &clip->id); - WM_event_add_notifier(C, NC_SCENE | ND_NODES, NULL); + if (t->context != NULL) { + Main *bmain = CTX_data_main(C); + BKE_ntree_update_tag_id_changed(bmain, &clip->id); + BKE_ntree_update_main(bmain, NULL); + WM_event_add_notifier(C, NC_SCENE | ND_NODES, NULL); + } } } diff --git a/source/blender/editors/transform/transform_data.h b/source/blender/editors/transform/transform_data.h index 6cfceedb389..a78c2491a1a 100644 --- a/source/blender/editors/transform/transform_data.h +++ b/source/blender/editors/transform/transform_data.h @@ -27,8 +27,8 @@ struct Object; struct bConstraint; #define TRANSDATABASIC \ - /** Extra data (mirrored element pointer, in editmode mesh to BMVert) \ - * (editbone for roll fixing) (...). */ \ + /** Extra data (mirrored element pointer, in edit-mode mesh to #BMVert) \ + * (edit-bone for roll fixing) (...). */ \ void *extra; \ /** Location of the data to transform. */ \ float *loc; \ diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index c2ff095904d..d1cbab9ff8a 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -214,7 +214,8 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve t->flag = 0; - if (obact && ELEM(object_mode, OB_MODE_EDIT, OB_MODE_EDIT_GPENCIL)) { + if (obact && !(t->options & (CTX_CURSOR | CTX_TEXTURE_SPACE)) && + ELEM(object_mode, OB_MODE_EDIT, OB_MODE_EDIT_GPENCIL)) { t->obedit_type = obact->type; } else { @@ -259,7 +260,7 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve } /* Crease needs edge flag */ - if (ELEM(t->mode, TFM_CREASE, TFM_BWEIGHT)) { + if (ELEM(t->mode, TFM_EDGE_CREASE, TFM_BWEIGHT)) { t->options |= CTX_EDGE_DATA; } diff --git a/source/blender/editors/transform/transform_gizmo_extrude_3d.c b/source/blender/editors/transform/transform_gizmo_extrude_3d.c index 6e89c3de197..dee6e7281ef 100644 --- a/source/blender/editors/transform/transform_gizmo_extrude_3d.c +++ b/source/blender/editors/transform/transform_gizmo_extrude_3d.c @@ -82,6 +82,7 @@ typedef struct GizmoExtrudeGroup { float orient_matrix[3][3]; bool constraint_axis[3]; float value[4]; + int orient_type; } redo_xform; /* Depends on object type. */ @@ -310,6 +311,7 @@ static void gizmo_mesh_extrude_refresh(const bContext *C, wmGizmoGroup *gzgroup) RNA_float_get_array(op_xform->ptr, "orient_matrix", &ggd->redo_xform.orient_matrix[0][0]); RNA_boolean_get_array(op_xform->ptr, "constraint_axis", ggd->redo_xform.constraint_axis); RNA_float_get_array(op_xform->ptr, "value", ggd->redo_xform.value); + ggd->redo_xform.orient_type = RNA_enum_get(op_xform->ptr, "orient_type"); /* Set properties for redo. */ for (int i = 0; i < 3; i++) { @@ -435,7 +437,8 @@ static void gizmo_mesh_extrude_invoke_prepare(const bContext *UNUSED(C), if (gz == ggd->adjust[0]) { RNA_boolean_set_array(¯optr, "constraint_axis", ggd->redo_xform.constraint_axis); RNA_float_set_array(¯optr, "orient_matrix", &ggd->redo_xform.orient_matrix[0][0]); - RNA_enum_set(¯optr, "orient_type", V3D_ORIENT_NORMAL); + RNA_enum_set(¯optr, "orient_matrix_type", ggd->redo_xform.orient_type); + RNA_enum_set(¯optr, "orient_type", ggd->redo_xform.orient_type); } RNA_float_set_array(¯optr, "value", ggd->redo_xform.value); } diff --git a/source/blender/editors/transform/transform_mode.c b/source/blender/editors/transform/transform_mode.c index d2e7f9f83df..e1fea62ae54 100644 --- a/source/blender/editors/transform/transform_mode.c +++ b/source/blender/editors/transform/transform_mode.c @@ -1042,7 +1042,7 @@ void ElementResize(const TransInfo *t, applyNumInput(&num_evil, values_final_evil); float ratio = values_final_evil[0]; - *td->val = td->ival * ratio * gps->runtime.multi_frame_falloff; + *td->val = td->ival * fabs(ratio) * gps->runtime.multi_frame_falloff; CLAMP_MIN(*td->val, 0.001f); } } @@ -1135,8 +1135,11 @@ void transform_mode_init(TransInfo *t, wmOperator *op, const int mode) case TFM_PUSHPULL: initPushPull(t); break; - case TFM_CREASE: - initCrease(t); + case TFM_EDGE_CREASE: + initEgdeCrease(t); + break; + case TFM_VERT_CREASE: + initVertCrease(t); break; case TFM_BONESIZE: initBoneSize(t); diff --git a/source/blender/editors/transform/transform_mode.h b/source/blender/editors/transform/transform_mode.h index ec3d5b8d0fe..16b26724c67 100644 --- a/source/blender/editors/transform/transform_mode.h +++ b/source/blender/editors/transform/transform_mode.h @@ -45,7 +45,7 @@ bool transdata_check_local_center(const TransInfo *t, short around); /** * Informs if the mode can be switched during modal. */ -bool transform_mode_is_changeable(const int mode); +bool transform_mode_is_changeable(int mode); void protectedTransBits(short protectflag, float vec[3]); void protectedSizeBits(short protectflag, float size[3]); void constraintTransLim(const TransInfo *t, TransData *td); @@ -69,13 +69,13 @@ void ElementRotation(const TransInfo *t, const TransDataContainer *tc, TransData *td, const float mat[3][3], - const short around); + short around); void headerResize(TransInfo *t, const float vec[3], char *str, int str_size); void ElementResize(const TransInfo *t, const TransDataContainer *tc, TransData *td, const float mat[3][3]); -void transform_mode_init(TransInfo *t, struct wmOperator *op, const int mode); +void transform_mode_init(TransInfo *t, struct wmOperator *op, int mode); /** * When in modal and not set, initializes a default orientation for the mode. */ @@ -106,7 +106,8 @@ void initCurveShrinkFatten(TransInfo *t); void initBevelWeight(TransInfo *t); /* transform_mode_edge_crease.c */ -void initCrease(TransInfo *t); +void initEgdeCrease(TransInfo *t); +void initVertCrease(TransInfo *t); /* transform_mode_edge_rotate_normal.c */ void initNormalRotation(TransInfo *t); diff --git a/source/blender/editors/transform/transform_mode_edge_crease.c b/source/blender/editors/transform/transform_mode_edge_crease.c index debc2a1be3e..60b95a1d2da 100644 --- a/source/blender/editors/transform/transform_mode_edge_crease.c +++ b/source/blender/editors/transform/transform_mode_edge_crease.c @@ -157,9 +157,9 @@ static void applyCrease(TransInfo *t, const int UNUSED(mval[2])) ED_area_status_text(t->area, str); } -void initCrease(TransInfo *t) +static void initCrease_ex(TransInfo *t, int mode) { - t->mode = TFM_CREASE; + t->mode = mode; t->transform = applyCrease; initMouseInputMode(t, &t->mouse, INPUT_SPRING_DELTA); @@ -176,4 +176,13 @@ void initCrease(TransInfo *t) t->flag |= T_NO_CONSTRAINT | T_NO_PROJECT; } +void initEgdeCrease(TransInfo *t) +{ + initCrease_ex(t, TFM_EDGE_CREASE); +} + +void initVertCrease(TransInfo *t) +{ + initCrease_ex(t, TFM_VERT_CREASE); +} /** \} */ diff --git a/source/blender/editors/transform/transform_mode_edge_slide.c b/source/blender/editors/transform/transform_mode_edge_slide.c index 7a0f2743a98..223f2511c72 100644 --- a/source/blender/editors/transform/transform_mode_edge_slide.c +++ b/source/blender/editors/transform/transform_mode_edge_slide.c @@ -195,7 +195,7 @@ static bool bm_loop_calc_opposite_co(BMLoop *l_tmp, const float plane_no[3], flo /* allow some overlap to avoid missing the intersection because of float precision */ if ((fac > -FLT_EPSILON) && (fac < 1.0f + FLT_EPSILON)) { /* likelihood of multiple intersections per ngon is quite low, - * it would have to loop back on its self, but better support it + * it would have to loop back on itself, but better support it * so check for the closest opposite edge */ const float tdist = len_v3v3(l_tmp->v->co, tvec); if (tdist < dist) { diff --git a/source/blender/editors/transform/transform_mode_timetranslate.c b/source/blender/editors/transform/transform_mode_timetranslate.c index 5f2a2e472c5..84ca5d3ae54 100644 --- a/source/blender/editors/transform/transform_mode_timetranslate.c +++ b/source/blender/editors/transform/transform_mode_timetranslate.c @@ -62,27 +62,28 @@ static void headerTimeTranslate(TransInfo *t, char str[UI_MAX_DRAW_STR]) float ival = TRANS_DATA_CONTAINER_FIRST_OK(t)->data->ival; float val = ival + t->values_final[0]; - float snap_val = val; - snapFrameTransform(t, autosnap, ival, val, &snap_val); + snapFrameTransform(t, autosnap, ival, val, &val); + float delta_x = val - ival; if (ELEM(autosnap, SACTSNAP_SECOND, SACTSNAP_TSTEP)) { /* Convert to seconds. */ const Scene *scene = t->scene; const double secf = FPS; - snap_val /= secf; + delta_x /= secf; + val /= secf; } if (autosnap == SACTSNAP_FRAME) { - BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f (%.4f)", snap_val, val); + BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f (%.4f)", delta_x, val); } else if (autosnap == SACTSNAP_SECOND) { - BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f sec (%.4f)", snap_val, val); + BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.2f sec (%.4f)", delta_x, val); } else if (autosnap == SACTSNAP_TSTEP) { - BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f sec", snap_val); + BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f sec", delta_x); } else { - BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", snap_val); + BLI_snprintf(&tvec[0], NUM_STR_REP_LEN, "%.4f", delta_x); } } diff --git a/source/blender/editors/transform/transform_mode_translate.c b/source/blender/editors/transform/transform_mode_translate.c index 19d0c6d39a3..b8b043c650f 100644 --- a/source/blender/editors/transform/transform_mode_translate.c +++ b/source/blender/editors/transform/transform_mode_translate.c @@ -225,11 +225,12 @@ static void headerTranslation(TransInfo *t, const float vec[3], char str[UI_MAX_ if (t->spacetype == SPACE_GRAPH) { /* WORKAROUND: * Special case where snapping is done in #recalData. - * Update the header based on the first element. */ + * Update the header based on the #center_local. */ const short autosnap = getAnimEdit_SnapMode(t); - float ival = TRANS_DATA_CONTAINER_FIRST_OK(t)->data->ival; + float ival = TRANS_DATA_CONTAINER_FIRST_OK(t)->center_local[0]; float val = ival + dvec[0]; - snapFrameTransform(t, autosnap, ival, val, &dvec[0]); + snapFrameTransform(t, autosnap, ival, val, &val); + dvec[0] = val - ival; } if (t->con.mode & CON_APPLY) { diff --git a/source/blender/editors/transform/transform_ops.c b/source/blender/editors/transform/transform_ops.c index 5ed340abf97..80feb934f1a 100644 --- a/source/blender/editors/transform/transform_ops.c +++ b/source/blender/editors/transform/transform_ops.c @@ -78,6 +78,7 @@ static const char OP_BONE_SIZE[] = "TRANSFORM_OT_bbone_resize"; static const char OP_EDGE_SLIDE[] = "TRANSFORM_OT_edge_slide"; static const char OP_VERT_SLIDE[] = "TRANSFORM_OT_vert_slide"; static const char OP_EDGE_CREASE[] = "TRANSFORM_OT_edge_crease"; +static const char OP_VERT_CREASE[] = "TRANSFORM_OT_vert_crease"; static const char OP_EDGE_BWEIGHT[] = "TRANSFORM_OT_edge_bevelweight"; static const char OP_SEQ_SLIDE[] = "TRANSFORM_OT_seq_slide"; static const char OP_NORMAL_ROTATION[] = "TRANSFORM_OT_rotate_normal"; @@ -98,6 +99,7 @@ static void TRANSFORM_OT_bbone_resize(struct wmOperatorType *ot); static void TRANSFORM_OT_edge_slide(struct wmOperatorType *ot); static void TRANSFORM_OT_vert_slide(struct wmOperatorType *ot); static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot); +static void TRANSFORM_OT_vert_crease(struct wmOperatorType *ot); static void TRANSFORM_OT_edge_bevelweight(struct wmOperatorType *ot); static void TRANSFORM_OT_seq_slide(struct wmOperatorType *ot); static void TRANSFORM_OT_rotate_normal(struct wmOperatorType *ot); @@ -118,7 +120,8 @@ static TransformModeItem transform_modes[] = { {OP_BONE_SIZE, TFM_BONESIZE, TRANSFORM_OT_bbone_resize}, {OP_EDGE_SLIDE, TFM_EDGE_SLIDE, TRANSFORM_OT_edge_slide}, {OP_VERT_SLIDE, TFM_VERT_SLIDE, TRANSFORM_OT_vert_slide}, - {OP_EDGE_CREASE, TFM_CREASE, TRANSFORM_OT_edge_crease}, + {OP_EDGE_CREASE, TFM_EDGE_CREASE, TRANSFORM_OT_edge_crease}, + {OP_VERT_CREASE, TFM_VERT_CREASE, TRANSFORM_OT_vert_crease}, {OP_EDGE_BWEIGHT, TFM_BWEIGHT, TRANSFORM_OT_edge_bevelweight}, {OP_SEQ_SLIDE, TFM_SEQ_SLIDE, TRANSFORM_OT_seq_slide}, {OP_NORMAL_ROTATION, TFM_NORMAL_ROTATION, TRANSFORM_OT_rotate_normal}, @@ -139,7 +142,8 @@ const EnumPropertyItem rna_enum_transform_mode_types[] = { {TFM_TILT, "TILT", 0, "Tilt", ""}, {TFM_TRACKBALL, "TRACKBALL", 0, "Trackball", ""}, {TFM_PUSHPULL, "PUSHPULL", 0, "Push/Pull", ""}, - {TFM_CREASE, "CREASE", 0, "Crease", ""}, + {TFM_EDGE_CREASE, "CREASE", 0, "Crease", ""}, + {TFM_VERT_CREASE, "VERTEX_CREASE", 0, "Vertex Crease", ""}, {TFM_MIRROR, "MIRROR", 0, "Mirror", ""}, {TFM_BONESIZE, "BONE_SIZE", 0, "Bone Size", ""}, {TFM_BONE_ENVELOPE, "BONE_ENVELOPE", 0, "Bone Envelope", ""}, @@ -1196,6 +1200,29 @@ static void TRANSFORM_OT_edge_crease(struct wmOperatorType *ot) Transform_Properties(ot, P_SNAP); } +static void TRANSFORM_OT_vert_crease(struct wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Vertex Crease"; + ot->description = "Change the crease of vertices"; + ot->idname = OP_VERT_CREASE; + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_BLOCKING; + + /* api callbacks */ + ot->invoke = transform_invoke; + ot->exec = transform_exec; + ot->modal = transform_modal; + ot->cancel = transform_cancel; + ot->poll = ED_operator_editmesh; + ot->poll_property = transform_poll_property; + + RNA_def_float_factor(ot->srna, "value", 0, -1.0f, 1.0f, "Factor", "", -1.0f, 1.0f); + + WM_operatortype_props_advanced_begin(ot); + + Transform_Properties(ot, P_SNAP); +} + static void TRANSFORM_OT_edge_bevelweight(struct wmOperatorType *ot) { /* identifiers */ diff --git a/source/blender/editors/transform/transform_orientations.c b/source/blender/editors/transform/transform_orientations.c index fa2485c33c2..5ac5bccd69c 100644 --- a/source/blender/editors/transform/transform_orientations.c +++ b/source/blender/editors/transform/transform_orientations.c @@ -513,7 +513,7 @@ short ED_transform_calc_orientation_from_type_ex(const Scene *scene, if (ob) { if (ob->mode & OB_MODE_POSE) { - const bPoseChannel *pchan = BKE_pose_channel_active(ob); + const bPoseChannel *pchan = BKE_pose_channel_active_if_layer_visible(ob); if (pchan && gimbal_axis_pose(ob, pchan, r_mat)) { break; } @@ -1224,7 +1224,7 @@ int getTransformOrientation_ex(ViewLayer *view_layer, float imat[3][3], mat[3][3]; bool ok = false; - if (activeOnly && (pchan = BKE_pose_channel_active(ob))) { + if (activeOnly && (pchan = BKE_pose_channel_active_if_layer_visible(ob))) { add_v3_v3(normal, pchan->pose_mat[2]); add_v3_v3(plane, pchan->pose_mat[1]); ok = true; diff --git a/source/blender/editors/transform/transform_orientations.h b/source/blender/editors/transform/transform_orientations.h index 6e0e3d9f8c7..dd2d5bc86c5 100644 --- a/source/blender/editors/transform/transform_orientations.h +++ b/source/blender/editors/transform/transform_orientations.h @@ -34,8 +34,8 @@ short transform_orientation_matrix_get(struct bContext *C, short orient_index, const float custom[3][3], float r_spacemtx[3][3]); -const char *transform_orientations_spacename_get(struct TransInfo *t, const short orient_type); -void transform_orientations_current_set(struct TransInfo *t, const short orient_index); +const char *transform_orientations_spacename_get(struct TransInfo *t, short orient_type); +void transform_orientations_current_set(struct TransInfo *t, short orient_index); /** * Those two fill in mat and return non-zero on success. @@ -55,7 +55,7 @@ bool createSpaceNormalTangent(float mat[3][3], const float normal[3], const floa struct TransformOrientation *addMatrixSpace(struct bContext *C, float mat[3][3], const char *name, - const bool overwrite); + bool overwrite); void applyTransformOrientation(const struct TransformOrientation *ts, float r_mat[3][3], char r_name[64]); @@ -75,5 +75,5 @@ int getTransformOrientation_ex(ViewLayer *view_layer, struct Object *obedit, float normal[3], float plane[3], - const short around); + short around); int getTransformOrientation(const struct bContext *C, float normal[3], float plane[3]); diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index a09078a8222..40be8e6e641 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -499,13 +499,15 @@ void applySnapping(TransInfo *t, float *vec) /* Time base quirky code to go around find-nearest slowness. */ /* TODO: add exception for object mode, no need to slow it down then. */ if (current - t->tsnap.last >= 0.01) { - t->tsnap.calcSnap(t, vec); + if (t->tsnap.calcSnap) { + t->tsnap.calcSnap(t, vec); + } if (t->tsnap.targetSnap) { t->tsnap.targetSnap(t); } - } - t->tsnap.last = current; + t->tsnap.last = current; + } if (validSnap(t)) { t->tsnap.applySnap(t, vec); @@ -691,6 +693,15 @@ static void initSnappingMode(TransInfo *t) bm_face_is_snap_target, POINTER_FROM_UINT((BM_ELEM_SELECT | BM_ELEM_HIDDEN))); } + else { + /* Ignore hidden geometry in the general case. */ + ED_transform_snap_object_context_set_editmesh_callbacks( + t->tsnap.object_context, + (bool (*)(BMVert *, void *))BM_elem_cb_check_hflag_disabled, + (bool (*)(BMEdge *, void *))BM_elem_cb_check_hflag_disabled, + (bool (*)(BMFace *, void *))BM_elem_cb_check_hflag_disabled, + POINTER_FROM_UINT(BM_ELEM_HIDDEN)); + } } } else if (t->spacetype == SPACE_SEQ) { @@ -783,8 +794,15 @@ static void setSnappingCallback(TransInfo *t) if (t->spacetype == SPACE_VIEW3D) { t->tsnap.calcSnap = snap_calc_view3d_fn; } - else if (t->spacetype == SPACE_IMAGE && t->obedit_type == OB_MESH) { - t->tsnap.calcSnap = snap_calc_uv_fn; + else if (t->spacetype == SPACE_IMAGE) { + SpaceImage *sima = t->area->spacedata.first; + Object *obact = t->view_layer->basact ? t->view_layer->basact->object : NULL; + + const bool is_uv_editor = sima->mode == SI_MODE_UV; + const bool has_edit_object = obact && BKE_object_is_in_editmode(obact); + if (is_uv_editor && has_edit_object) { + t->tsnap.calcSnap = snap_calc_uv_fn; + } } else if (t->spacetype == SPACE_NODE) { t->tsnap.calcSnap = snap_calc_node_fn; @@ -959,7 +977,7 @@ static void snap_calc_view3d_fn(TransInfo *t, float *UNUSED(vec)) static void snap_calc_uv_fn(TransInfo *t, float *UNUSED(vec)) { - BLI_assert(t->spacetype == SPACE_IMAGE && t->obedit_type == OB_MESH); + BLI_assert(t->spacetype == SPACE_IMAGE); if (t->tsnap.mode & SCE_SNAP_MODE_VERTEX) { float co[2]; diff --git a/source/blender/editors/transform/transform_snap.h b/source/blender/editors/transform/transform_snap.h index bc89c7a8cda..389c1441db1 100644 --- a/source/blender/editors/transform/transform_snap.h +++ b/source/blender/editors/transform/transform_snap.h @@ -27,7 +27,7 @@ bool peelObjectsTransform(struct TransInfo *t, const float mval[2], - const bool use_peel_object, + bool use_peel_object, /* return args */ float r_loc[3], float r_no[3], @@ -92,9 +92,9 @@ void transform_snap_sequencer_apply_translate(TransInfo *t, float *vec); */ short getAnimEdit_SnapMode(TransInfo *t); void snapFrameTransform(TransInfo *t, - const eAnimEdit_AutoSnap autosnap, - const float val_initial, - const float val_final, + eAnimEdit_AutoSnap autosnap, + float val_initial, + float val_final, float *r_val_final); /** * This function is used by Animation Editor specific transform functions to do @@ -102,5 +102,5 @@ void snapFrameTransform(TransInfo *t, */ void transform_snap_anim_flush_data(TransInfo *t, TransData *td, - const eAnimEdit_AutoSnap autosnap, + eAnimEdit_AutoSnap autosnap, float *r_val_final); diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 350d3a2676c..9dc8b6cf69d 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -146,26 +146,28 @@ struct SnapObjectContext { * If NULL the BMesh should be used. */ static Mesh *mesh_for_snap(Object *ob_eval, eSnapEditType edit_mode_type, bool *r_use_hide) { - Mesh *me_eval = ob_eval->data; + Mesh *me_eval = BKE_object_get_evaluated_mesh(ob_eval); bool use_hide = false; if (BKE_object_is_in_editmode(ob_eval)) { if (edit_mode_type == SNAP_GEOM_EDIT) { return NULL; } - BMEditMesh *em_eval = BKE_editmesh_from_object(ob_eval); - if ((edit_mode_type == SNAP_GEOM_FINAL) && em_eval->mesh_eval_final) { - if (em_eval->mesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) { + Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob_eval); + Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob_eval); + + if ((edit_mode_type == SNAP_GEOM_FINAL) && editmesh_eval_final) { + if (editmesh_eval_final->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) { return NULL; } - me_eval = em_eval->mesh_eval_final; + me_eval = editmesh_eval_final; use_hide = true; } - else if ((edit_mode_type == SNAP_GEOM_CAGE) && em_eval->mesh_eval_cage) { - if (em_eval->mesh_eval_cage->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) { + else if ((edit_mode_type == SNAP_GEOM_CAGE) && editmesh_eval_cage) { + if (editmesh_eval_cage->runtime.wrapper_type == ME_WRAPPER_TYPE_BMESH) { return NULL; } - me_eval = em_eval->mesh_eval_cage; + me_eval = editmesh_eval_cage; use_hide = true; } } @@ -318,12 +320,14 @@ static SnapObjectData *snap_object_data_mesh_get(SnapObjectContext *sctx, if (sod->treedata_mesh.tree == NULL) { sod->treedata_mesh.vert = me_eval->mvert; + sod->treedata_mesh.vert_normals = BKE_mesh_vertex_normals_ensure(me_eval); sod->treedata_mesh.loop = me_eval->mloop; sod->treedata_mesh.looptri = BKE_mesh_runtime_looptri_ensure(me_eval); BLI_assert(sod->has_looptris == false); } else { BLI_assert(sod->treedata_mesh.vert != NULL); + BLI_assert(sod->treedata_mesh.vert_normals != NULL); BLI_assert(sod->treedata_mesh.loop != NULL); BLI_assert(sod->treedata_mesh.looptri != NULL); sod->has_looptris = true; @@ -343,12 +347,14 @@ static SnapObjectData *snap_object_data_mesh_get(SnapObjectContext *sctx, static struct Mesh_Runtime *snap_object_data_editmesh_runtime_get(Object *ob_eval) { - BMEditMesh *em_eval = BKE_editmesh_from_object(ob_eval); - if (em_eval->mesh_eval_final) { - return &em_eval->mesh_eval_final->runtime; + Mesh *editmesh_eval_final = BKE_object_get_editmesh_eval_final(ob_eval); + if (editmesh_eval_final) { + return &editmesh_eval_final->runtime; } - if (em_eval->mesh_eval_cage) { - return &em_eval->mesh_eval_cage->runtime; + + Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(ob_eval); + if (editmesh_eval_cage) { + return &editmesh_eval_cage->runtime; } return &((Mesh *)ob_eval->data)->runtime; @@ -1195,56 +1201,96 @@ static bool snap_bound_box_check_dist(const float min[3], return true; } -static void cb_mvert_co_get(const int index, const void *user_data, const float **r_co) +/** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Callbacks + * \{ */ + +struct Nearest2dUserData; + +typedef void (*Nearest2DGetVertCoCallback)(const int index, + const struct Nearest2dUserData *data, + const float **r_co); +typedef void (*Nearest2DGetEdgeVertsCallback)(const int index, + const struct Nearest2dUserData *data, + int r_v_index[2]); +typedef void (*Nearest2DGetTriVertsCallback)(const int index, + const struct Nearest2dUserData *data, + int r_v_index[3]); +/* Equal the previous one */ +typedef void (*Nearest2DGetTriEdgesCallback)(const int index, + const struct Nearest2dUserData *data, + int r_e_index[3]); +typedef void (*Nearest2DCopyVertNoCallback)(const int index, + const struct Nearest2dUserData *data, + float r_no[3]); + +typedef struct Nearest2dUserData { + Nearest2DGetVertCoCallback get_vert_co; + Nearest2DGetEdgeVertsCallback get_edge_verts_index; + Nearest2DGetTriVertsCallback get_tri_verts_index; + Nearest2DGetTriEdgesCallback get_tri_edges_index; + Nearest2DCopyVertNoCallback copy_vert_no; + + union { + struct { + struct BMesh *bm; + }; + struct { + const struct MVert *vert; + const float (*vert_normals)[3]; + const struct MEdge *edge; /* only used for #BVHTreeFromMeshEdges */ + const struct MLoop *loop; + const struct MLoopTri *looptri; + }; + }; + + bool is_persp; + bool use_backface_culling; +} Nearest2dUserData; + +static void cb_mvert_co_get(const int index, const Nearest2dUserData *data, const float **r_co) { - const BVHTreeFromMesh *data = user_data; *r_co = data->vert[index].co; } -static void cb_bvert_co_get(const int index, const void *user_data, const float **r_co) +static void cb_bvert_co_get(const int index, const Nearest2dUserData *data, const float **r_co) { - const BMEditMesh *data = user_data; BMVert *eve = BM_vert_at_index(data->bm, index); *r_co = eve->co; } -static void cb_mvert_no_copy(const int index, const void *user_data, float r_no[3]) +static void cb_mvert_no_copy(const int index, const Nearest2dUserData *data, float r_no[3]) { - const BVHTreeFromMesh *data = user_data; - const MVert *vert = data->vert + index; - - normal_short_to_float_v3(r_no, vert->no); + copy_v3_v3(r_no, data->vert_normals[index]); } -static void cb_bvert_no_copy(const int index, const void *user_data, float r_no[3]) +static void cb_bvert_no_copy(const int index, const Nearest2dUserData *data, float r_no[3]) { - const BMEditMesh *data = user_data; BMVert *eve = BM_vert_at_index(data->bm, index); copy_v3_v3(r_no, eve->no); } -static void cb_medge_verts_get(const int index, const void *user_data, int r_v_index[2]) +static void cb_medge_verts_get(const int index, const Nearest2dUserData *data, int r_v_index[2]) { - const BVHTreeFromMesh *data = user_data; const MEdge *edge = &data->edge[index]; r_v_index[0] = edge->v1; r_v_index[1] = edge->v2; } -static void cb_bedge_verts_get(const int index, const void *user_data, int r_v_index[2]) +static void cb_bedge_verts_get(const int index, const Nearest2dUserData *data, int r_v_index[2]) { - const BMEditMesh *data = user_data; BMEdge *eed = BM_edge_at_index(data->bm, index); r_v_index[0] = BM_elem_index_get(eed->v1); r_v_index[1] = BM_elem_index_get(eed->v2); } -static void cb_mlooptri_edges_get(const int index, const void *user_data, int r_v_index[3]) +static void cb_mlooptri_edges_get(const int index, const Nearest2dUserData *data, int r_v_index[3]) { - const BVHTreeFromMesh *data = user_data; const MEdge *medge = data->edge; const MLoop *mloop = data->loop; const MLoopTri *lt = &data->looptri[index]; @@ -1261,9 +1307,8 @@ static void cb_mlooptri_edges_get(const int index, const void *user_data, int r_ } } -static void cb_mlooptri_verts_get(const int index, const void *user_data, int r_v_index[3]) +static void cb_mlooptri_verts_get(const int index, const Nearest2dUserData *data, int r_v_index[3]) { - const BVHTreeFromMesh *data = user_data; const MLoop *loop = data->loop; const MLoopTri *looptri = &data->looptri[index]; @@ -1332,66 +1377,6 @@ static bool test_projected_edge_dist(const struct DistProjectedAABBPrecalc *prec precalc, clip_plane, clip_plane_len, is_persp, near_co, dist_px_sq, r_co); } -/** \} */ - -/* -------------------------------------------------------------------- */ -/** \name Walk DFS - * \{ */ - -typedef void (*Nearest2DGetVertCoCallback)(const int index, - const void *user_data, - const float **r_co); -typedef void (*Nearest2DGetEdgeVertsCallback)(const int index, - const void *user_data, - int r_v_index[2]); -typedef void (*Nearest2DGetTriVertsCallback)(const int index, - const void *user_data, - int r_v_index[3]); -/* Equal the previous one */ -typedef void (*Nearest2DGetTriEdgesCallback)(const int index, - const void *user_data, - int r_e_index[3]); -typedef void (*Nearest2DCopyVertNoCallback)(const int index, const void *user_data, float r_no[3]); - -typedef struct Nearest2dUserData { - void *userdata; - Nearest2DGetVertCoCallback get_vert_co; - Nearest2DGetEdgeVertsCallback get_edge_verts_index; - Nearest2DGetTriVertsCallback get_tri_verts_index; - Nearest2DGetTriEdgesCallback get_tri_edges_index; - Nearest2DCopyVertNoCallback copy_vert_no; - - bool is_persp; - bool use_backface_culling; -} Nearest2dUserData; - -static void nearest2d_data_init(SnapObjectData *sod, - bool is_persp, - bool use_backface_culling, - Nearest2dUserData *r_nearest2d) -{ - if (sod->type == SNAP_MESH) { - r_nearest2d->userdata = &sod->treedata_mesh; - r_nearest2d->get_vert_co = cb_mvert_co_get; - r_nearest2d->get_edge_verts_index = cb_medge_verts_get; - r_nearest2d->copy_vert_no = cb_mvert_no_copy; - r_nearest2d->get_tri_verts_index = cb_mlooptri_verts_get; - r_nearest2d->get_tri_edges_index = cb_mlooptri_edges_get; - } - else { - BLI_assert(sod->type == SNAP_EDIT_MESH); - r_nearest2d->userdata = sod->treedata_editmesh.em; - r_nearest2d->get_vert_co = cb_bvert_co_get; - r_nearest2d->get_edge_verts_index = cb_bedge_verts_get; - r_nearest2d->copy_vert_no = cb_bvert_no_copy; - r_nearest2d->get_tri_verts_index = NULL; - r_nearest2d->get_tri_edges_index = NULL; - } - - r_nearest2d->is_persp = is_persp; - r_nearest2d->use_backface_culling = use_backface_culling; -} - static void cb_snap_vert(void *userdata, int index, const struct DistProjectedAABBPrecalc *precalc, @@ -1399,10 +1384,10 @@ static void cb_snap_vert(void *userdata, const int clip_plane_len, BVHTreeNearest *nearest) { - struct Nearest2dUserData *data = userdata; + Nearest2dUserData *data = userdata; const float *co; - data->get_vert_co(index, data->userdata, &co); + data->get_vert_co(index, data, &co); if (test_projected_vert_dist(precalc, clip_plane, @@ -1411,7 +1396,7 @@ static void cb_snap_vert(void *userdata, co, &nearest->dist_sq, nearest->co)) { - data->copy_vert_no(index, data->userdata, nearest->no); + data->copy_vert_no(index, data, nearest->no); nearest->index = index; } } @@ -1426,11 +1411,11 @@ static void cb_snap_edge(void *userdata, struct Nearest2dUserData *data = userdata; int vindex[2]; - data->get_edge_verts_index(index, data->userdata, vindex); + data->get_edge_verts_index(index, data, vindex); const float *v_pair[2]; - data->get_vert_co(vindex[0], data->userdata, &v_pair[0]); - data->get_vert_co(vindex[1], data->userdata, &v_pair[1]); + data->get_vert_co(vindex[0], data, &v_pair[0]); + data->get_vert_co(vindex[1], data, &v_pair[1]); if (test_projected_edge_dist(precalc, clip_plane, @@ -1455,7 +1440,7 @@ static void cb_snap_edge_verts(void *userdata, struct Nearest2dUserData *data = userdata; int vindex[2]; - data->get_edge_verts_index(index, data->userdata, vindex); + data->get_edge_verts_index(index, data, vindex); for (int i = 2; i--;) { if (vindex[i] == nearest->index) { @@ -1472,16 +1457,16 @@ static void cb_snap_tri_edges(void *userdata, const int clip_plane_len, BVHTreeNearest *nearest) { - struct Nearest2dUserData *data = userdata; + Nearest2dUserData *data = userdata; if (data->use_backface_culling) { int vindex[3]; - data->get_tri_verts_index(index, data->userdata, vindex); + data->get_tri_verts_index(index, data, vindex); const float *t0, *t1, *t2; - data->get_vert_co(vindex[0], data->userdata, &t0); - data->get_vert_co(vindex[1], data->userdata, &t1); - data->get_vert_co(vindex[2], data->userdata, &t2); + data->get_vert_co(vindex[0], data, &t0); + data->get_vert_co(vindex[1], data, &t1); + data->get_vert_co(vindex[2], data, &t2); float dummy[3]; if (raycast_tri_backface_culling_test(precalc->ray_direction, t0, t1, t2, dummy)) { return; @@ -1489,7 +1474,7 @@ static void cb_snap_tri_edges(void *userdata, } int eindex[3]; - data->get_tri_edges_index(index, data->userdata, eindex); + data->get_tri_edges_index(index, data, eindex); for (int i = 3; i--;) { if (eindex[i] != -1) { if (eindex[i] == nearest->index) { @@ -1510,13 +1495,13 @@ static void cb_snap_tri_verts(void *userdata, struct Nearest2dUserData *data = userdata; int vindex[3]; - data->get_tri_verts_index(index, data->userdata, vindex); + data->get_tri_verts_index(index, data, vindex); if (data->use_backface_culling) { const float *t0, *t1, *t2; - data->get_vert_co(vindex[0], data->userdata, &t0); - data->get_vert_co(vindex[1], data->userdata, &t1); - data->get_vert_co(vindex[2], data->userdata, &t2); + data->get_vert_co(vindex[0], data, &t0); + data->get_vert_co(vindex[1], data, &t1); + data->get_vert_co(vindex[2], data, &t2); float dummy[3]; if (raycast_tri_backface_culling_test(precalc->ray_direction, t0, t1, t2, dummy)) { return; @@ -1531,6 +1516,39 @@ static void cb_snap_tri_verts(void *userdata, } } +static void nearest2d_data_init(SnapObjectData *sod, + bool is_persp, + bool use_backface_culling, + Nearest2dUserData *r_nearest2d) +{ + if (sod->type == SNAP_MESH) { + r_nearest2d->get_vert_co = cb_mvert_co_get; + r_nearest2d->get_edge_verts_index = cb_medge_verts_get; + r_nearest2d->copy_vert_no = cb_mvert_no_copy; + r_nearest2d->get_tri_verts_index = cb_mlooptri_verts_get; + r_nearest2d->get_tri_edges_index = cb_mlooptri_edges_get; + + r_nearest2d->vert = sod->treedata_mesh.vert; + r_nearest2d->vert_normals = sod->treedata_mesh.vert_normals; + r_nearest2d->edge = sod->treedata_mesh.edge; + r_nearest2d->loop = sod->treedata_mesh.loop; + r_nearest2d->looptri = sod->treedata_mesh.looptri; + } + else { + BLI_assert(sod->type == SNAP_EDIT_MESH); + r_nearest2d->get_vert_co = cb_bvert_co_get; + r_nearest2d->get_edge_verts_index = cb_bedge_verts_get; + r_nearest2d->copy_vert_no = cb_bvert_no_copy; + r_nearest2d->get_tri_verts_index = NULL; + r_nearest2d->get_tri_edges_index = NULL; + + r_nearest2d->bm = sod->treedata_editmesh.em->bm; + } + + r_nearest2d->is_persp = is_persp; + r_nearest2d->use_backface_culling = use_backface_culling; +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -1689,11 +1707,11 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, sod, sctx->runtime.view_proj == VIEW_PROJ_PERSP, params->use_backface_culling, &nearest2d); int vindex[2]; - nearest2d.get_edge_verts_index(*r_index, nearest2d.userdata, vindex); + nearest2d.get_edge_verts_index(*r_index, &nearest2d, vindex); const float *v_pair[2]; - nearest2d.get_vert_co(vindex[0], nearest2d.userdata, &v_pair[0]); - nearest2d.get_vert_co(vindex[1], nearest2d.userdata, &v_pair[1]); + nearest2d.get_vert_co(vindex[0], &nearest2d, &v_pair[0]); + nearest2d.get_vert_co(vindex[1], &nearest2d, &v_pair[1]); struct DistProjectedAABBPrecalc neasrest_precalc; { @@ -1740,7 +1758,7 @@ static short snap_mesh_edge_verts_mixed(SnapObjectContext *sctx, if (r_no) { float imat[4][4]; invert_m4_m4(imat, obmat); - nearest2d.copy_vert_no(vindex[v_id], nearest2d.userdata, r_no); + nearest2d.copy_vert_no(vindex[v_id], &nearest2d, r_no); mul_transposed_mat3_m4_v3(imat, r_no); normalize_v3(r_no); } diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c index ca8b86d525d..c6fa5acfff5 100644 --- a/source/blender/editors/undo/ed_undo.c +++ b/source/blender/editors/undo/ed_undo.c @@ -64,6 +64,7 @@ #include "RNA_access.h" #include "RNA_define.h" +#include "RNA_enum_types.h" #include "UI_interface.h" #include "UI_resources.h" @@ -374,6 +375,9 @@ static int ed_undo_step_by_index(bContext *C, const int undo_index, ReportList * wmWindowManager *wm = CTX_wm_manager(C); const int active_step_index = BLI_findindex(&wm->undo_stack->steps, wm->undo_stack->step_active); + if (undo_index == active_step_index) { + return OPERATOR_CANCELLED; + } const enum eUndoStepDir undo_dir = (undo_index < active_step_index) ? STEP_UNDO : STEP_REDO; CLOG_INFO(&LOG, @@ -494,17 +498,28 @@ UndoStack *ED_undo_stack_get(void) /** \name Undo, Undo Push & Redo Operators * \{ */ +/** + * Refresh to run after user activated undo/redo actions. + */ +static void ed_undo_refresh_for_op(bContext *C) +{ + /* The "last operator" should disappear, later we can tie this with undo stack nicer. */ + WM_operator_stack_clear(CTX_wm_manager(C)); + + /* Keep button under the cursor active. */ + WM_event_add_mousemove(CTX_wm_window(C)); + + ED_outliner_select_sync_from_all_tag(C); +} + static int ed_undo_exec(bContext *C, wmOperator *op) { /* "last operator" should disappear, later we can tie this with undo stack nicer */ WM_operator_stack_clear(CTX_wm_manager(C)); int ret = ed_undo_step_direction(C, STEP_UNDO, op->reports); if (ret & OPERATOR_FINISHED) { - /* Keep button under the cursor active. */ - WM_event_add_mousemove(CTX_wm_window(C)); + ed_undo_refresh_for_op(C); } - - ED_outliner_select_sync_from_all_tag(C); return ret; } @@ -529,11 +544,8 @@ static int ed_redo_exec(bContext *C, wmOperator *op) { int ret = ed_undo_step_direction(C, STEP_REDO, op->reports); if (ret & OPERATOR_FINISHED) { - /* Keep button under the cursor active. */ - WM_event_add_mousemove(CTX_wm_window(C)); + ed_undo_refresh_for_op(C); } - - ED_outliner_select_sync_from_all_tag(C); return ret; } @@ -748,97 +760,36 @@ void ED_undo_operator_repeat_cb_evt(bContext *C, void *arg_op, int UNUSED(arg_un /* -------------------------------------------------------------------- */ /** \name Undo History Operator + * + * See `TOPBAR_MT_undo_history` which is used to access this operator. * \{ */ -/* create enum based on undo items */ -static const EnumPropertyItem *rna_undo_itemf(bContext *C, int *totitem) -{ - EnumPropertyItem item_tmp = {0}, *item = NULL; - int i = 0; - - wmWindowManager *wm = CTX_wm_manager(C); - if (wm->undo_stack == NULL) { - return NULL; - } - - for (UndoStep *us = wm->undo_stack->steps.first; us; us = us->next, i++) { - if (us->skip == false) { - item_tmp.identifier = us->name; - item_tmp.name = IFACE_(us->name); - if (us == wm->undo_stack->step_active) { - item_tmp.icon = ICON_LAYER_ACTIVE; - } - else { - item_tmp.icon = ICON_NONE; - } - item_tmp.value = i; - RNA_enum_item_add(&item, totitem, &item_tmp); - } - } - RNA_enum_item_end(&item, totitem); - - return item; -} - -static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +/* NOTE: also check #ed_undo_step() in top if you change notifiers. */ +static int undo_history_exec(bContext *C, wmOperator *op) { - int totitem = 0; - - { - const EnumPropertyItem *item = rna_undo_itemf(C, &totitem); - - if (totitem > 0) { - uiPopupMenu *pup = UI_popup_menu_begin( - C, WM_operatortype_name(op->type, op->ptr), ICON_NONE); - uiLayout *layout = UI_popup_menu_layout(pup); - uiLayout *split = uiLayoutSplit(layout, 0.0f, false); - uiLayout *column = NULL; - const int col_size = 20 + totitem / 12; - int i, c; - bool add_col = true; - - for (c = 0, i = totitem; i--;) { - if (add_col && !(c % col_size)) { - column = uiLayoutColumn(split, false); - add_col = false; - } - if (item[i].identifier) { - uiItemIntO(column, item[i].name, item[i].icon, op->type->idname, "item", item[i].value); - c++; - add_col = true; - } - } - - MEM_freeN((void *)item); + PropertyRNA *prop = RNA_struct_find_property(op->ptr, "item"); + if (RNA_property_is_set(op->ptr, prop)) { + const int item = RNA_property_int_get(op->ptr, prop); + const int ret = ed_undo_step_by_index(C, item, op->reports); + if (ret & OPERATOR_FINISHED) { + ed_undo_refresh_for_op(C); - UI_popup_menu_end(C, pup); + WM_event_add_notifier(C, NC_WINDOW, NULL); + return OPERATOR_FINISHED; } } return OPERATOR_CANCELLED; } -/* NOTE: also check #ed_undo_step() in top if you change notifiers. */ -static int undo_history_exec(bContext *C, wmOperator *op) +static int undo_history_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) { PropertyRNA *prop = RNA_struct_find_property(op->ptr, "item"); if (RNA_property_is_set(op->ptr, prop)) { - int item = RNA_property_int_get(op->ptr, prop); - WM_operator_stack_clear(CTX_wm_manager(C)); - ed_undo_step_by_index(C, item, op->reports); - WM_event_add_notifier(C, NC_WINDOW, NULL); - return OPERATOR_FINISHED; + return undo_history_exec(C, op); } - return OPERATOR_CANCELLED; -} -static bool undo_history_poll(bContext *C) -{ - if (!ed_undo_is_init_and_screenactive_poll(C)) { - return false; - } - UndoStack *undo_stack = CTX_wm_manager(C)->undo_stack; - /* More than just original state entry. */ - return BLI_listbase_count_at_most(&undo_stack->steps, 2) > 1; + WM_menu_name_call(C, "TOPBAR_MT_undo_history", WM_OP_INVOKE_DEFAULT); + return OPERATOR_FINISHED; } void ED_OT_undo_history(wmOperatorType *ot) @@ -851,7 +802,7 @@ void ED_OT_undo_history(wmOperatorType *ot) /* api callbacks */ ot->invoke = undo_history_invoke; ot->exec = undo_history_exec; - ot->poll = undo_history_poll; + ot->poll = ed_undo_is_init_and_screenactive_poll; RNA_def_int(ot->srna, "item", 0, 0, INT_MAX, "Item", "", 0, INT_MAX); } diff --git a/source/blender/editors/util/CMakeLists.txt b/source/blender/editors/util/CMakeLists.txt index b339bfbdc47..90a09c87cc6 100644 --- a/source/blender/editors/util/CMakeLists.txt +++ b/source/blender/editors/util/CMakeLists.txt @@ -55,6 +55,7 @@ set(SRC ../include/ED_clip.h ../include/ED_curve.h ../include/ED_datafiles.h + ../include/ED_file_indexer.h ../include/ED_fileselect.h ../include/ED_geometry.h ../include/ED_gizmo_library.h diff --git a/source/blender/editors/util/ed_draw.c b/source/blender/editors/util/ed_draw.c index ccbde07f5b1..3e85862a847 100644 --- a/source/blender/editors/util/ed_draw.c +++ b/source/blender/editors/util/ed_draw.c @@ -599,9 +599,9 @@ static void metadata_custom_draw_fields(const char *field, const char *value, vo } MetadataCustomDrawContext *ctx = (MetadataCustomDrawContext *)ctx_v; char temp_str[MAX_METADATA_STR]; - BLI_snprintf(temp_str, MAX_METADATA_STR, "%s: %s", field, value); + SNPRINTF(temp_str, "%s: %s", field, value); BLF_position(ctx->fontid, ctx->xmin, ctx->ymin + ctx->current_y, 0.0f); - BLF_draw(ctx->fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); + BLF_draw(ctx->fontid, temp_str, sizeof(temp_str)); ctx->current_y += ctx->vertical_offset; } @@ -625,18 +625,18 @@ static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const /* first line */ if (i == 0) { bool do_newline = false; - int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[0]); + int len = SNPRINTF_RLEN(temp_str, "%s: ", meta_data_list[0]); if (metadata_is_valid(ibuf, temp_str, 0, len)) { BLF_position(fontid, xmin, ymax - vertical_offset, 0.0f); - BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); + BLF_draw(fontid, temp_str, sizeof(temp_str)); do_newline = true; } - len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[1]); + len = SNPRINTF_RLEN(temp_str, "%s: ", meta_data_list[1]); if (metadata_is_valid(ibuf, temp_str, 1, len)) { - int line_width = BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); + int line_width = BLF_width(fontid, temp_str, sizeof(temp_str)); BLF_position(fontid, xmax - line_width, ymax - vertical_offset, 0.0f); - BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); + BLF_draw(fontid, temp_str, sizeof(temp_str)); do_newline = true; } @@ -645,32 +645,32 @@ static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const } } /* Strip */ else if (ELEM(i, 1, 2)) { - int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]); + int len = SNPRINTF_RLEN(temp_str, "%s: ", meta_data_list[i + 1]); if (metadata_is_valid(ibuf, temp_str, i + 1, len)) { BLF_position(fontid, xmin, ymax - vertical_offset - ofs_y, 0.0f); - BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); + BLF_draw(fontid, temp_str, sizeof(temp_str)); ofs_y += vertical_offset; } } /* Note (wrapped) */ else if (i == 3) { - int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]); + int len = SNPRINTF_RLEN(temp_str, "%s: ", meta_data_list[i + 1]); if (metadata_is_valid(ibuf, temp_str, i + 1, len)) { struct ResultBLF info; BLF_enable(fontid, BLF_WORD_WRAP); BLF_wordwrap(fontid, ibuf->x - (margin * 2)); BLF_position(fontid, xmin, ymax - vertical_offset - ofs_y, 0.0f); - BLF_draw_ex(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX, &info); + BLF_draw_ex(fontid, temp_str, sizeof(temp_str), &info); BLF_wordwrap(fontid, 0); BLF_disable(fontid, BLF_WORD_WRAP); ofs_y += vertical_offset * info.lines; } } else { - int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i + 1]); + int len = SNPRINTF_RLEN(temp_str, "%s: ", meta_data_list[i + 1]); if (metadata_is_valid(ibuf, temp_str, i + 1, len)) { - int line_width = BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); + int line_width = BLF_width(fontid, temp_str, sizeof(temp_str)); BLF_position(fontid, xmax - line_width, ymax - vertical_offset - ofs_y, 0.0f); - BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); + BLF_draw(fontid, temp_str, sizeof(temp_str)); ofs_y += vertical_offset; } } @@ -687,12 +687,12 @@ static void metadata_draw_imbuf(ImBuf *ibuf, const rctf *rect, int fontid, const int ofs_x = 0; ofs_y = ctx.current_y; for (int i = 5; i < 10; i++) { - int len = BLI_snprintf_rlen(temp_str, MAX_METADATA_STR, "%s: ", meta_data_list[i]); + int len = SNPRINTF_RLEN(temp_str, "%s: ", meta_data_list[i]); if (metadata_is_valid(ibuf, temp_str, i, len)) { BLF_position(fontid, xmin + ofs_x, ymin + ofs_y, 0.0f); - BLF_draw(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX); + BLF_draw(fontid, temp_str, sizeof(temp_str)); - ofs_x += BLF_width(fontid, temp_str, BLF_DRAW_STR_DUMMY_MAX) + UI_UNIT_X; + ofs_x += BLF_width(fontid, temp_str, sizeof(temp_str)) + UI_UNIT_X; } } } diff --git a/source/blender/editors/util/ed_transverts.c b/source/blender/editors/util/ed_transverts.c index b4a93eb996c..b8efbad1ad9 100644 --- a/source/blender/editors/util/ed_transverts.c +++ b/source/blender/editors/util/ed_transverts.c @@ -41,6 +41,7 @@ #include "BKE_editmesh.h" #include "BKE_lattice.h" #include "BKE_mesh_iterators.h" +#include "BKE_object.h" #include "DEG_depsgraph.h" @@ -168,11 +169,7 @@ void ED_transverts_update_obedit(TransVertStore *tvs, Object *obedit) } } -static void set_mapped_co(void *vuserdata, - int index, - const float co[3], - const float UNUSED(no[3]), - const short UNUSED(no_s[3])) +static void set_mapped_co(void *vuserdata, int index, const float co[3], const float UNUSED(no[3])) { void **userdata = vuserdata; BMEditMesh *em = userdata[0]; @@ -315,9 +312,10 @@ void ED_transverts_create_from_obedit(TransVertStore *tvs, Object *obedit, const userdata[1] = tvs->transverts; } - if (tvs->transverts && em->mesh_eval_cage) { + struct Mesh *editmesh_eval_cage = BKE_object_get_editmesh_eval_cage(obedit); + if (tvs->transverts && editmesh_eval_cage) { BM_mesh_elem_table_ensure(bm, BM_VERT); - BKE_mesh_foreach_mapped_vert(em->mesh_eval_cage, set_mapped_co, userdata, MESH_FOREACH_NOP); + BKE_mesh_foreach_mapped_vert(editmesh_eval_cage, set_mapped_co, userdata, MESH_FOREACH_NOP); } } else if (obedit->type == OB_ARMATURE) { diff --git a/source/blender/editors/util/ed_util.c b/source/blender/editors/util/ed_util.c index 8e94dc23085..0320a2a9a1a 100644 --- a/source/blender/editors/util/ed_util.c +++ b/source/blender/editors/util/ed_util.c @@ -35,6 +35,7 @@ #include "BKE_collection.h" #include "BKE_global.h" +#include "BKE_lib_remap.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_multires.h" @@ -352,6 +353,7 @@ void unpack_menu(bContext *C, uiLayout *layout; char line[FILE_MAX + 100]; wmOperatorType *ot = WM_operatortype_find(opname, 1); + const char *blendfile_path = BKE_main_blendfile_path(bmain); pup = UI_popup_menu_begin(C, IFACE_("Unpack File"), ICON_NONE); layout = UI_popup_menu_layout(pup); @@ -361,13 +363,13 @@ void unpack_menu(bContext *C, RNA_enum_set(&props_ptr, "method", PF_REMOVE); RNA_string_set(&props_ptr, "id", id_name); - if (G.relbase_valid) { + if (blendfile_path[0] != '\0') { char local_name[FILE_MAXDIR + FILE_MAX], fi[FILE_MAX]; BLI_split_file_part(abs_name, fi, sizeof(fi)); BLI_snprintf(local_name, sizeof(local_name), "//%s/%s", folder, fi); if (!STREQ(abs_name, local_name)) { - switch (BKE_packedfile_compare_to_file(BKE_main_blendfile_path(bmain), local_name, pf)) { + switch (BKE_packedfile_compare_to_file(blendfile_path, local_name, pf)) { case PF_CMP_NOFILE: BLI_snprintf(line, sizeof(line), TIP_("Create %s"), local_name); uiItemFullO_ptr(layout, ot, line, ICON_NONE, NULL, WM_OP_EXEC_DEFAULT, 0, &props_ptr); @@ -400,7 +402,7 @@ void unpack_menu(bContext *C, } } - switch (BKE_packedfile_compare_to_file(BKE_main_blendfile_path(bmain), abs_name, pf)) { + switch (BKE_packedfile_compare_to_file(blendfile_path, abs_name, pf)) { case PF_CMP_NOFILE: BLI_snprintf(line, sizeof(line), TIP_("Create %s"), abs_name); // uiItemEnumO_ptr(layout, ot, line, 0, "method", PF_WRITE_ORIGINAL); @@ -433,11 +435,27 @@ void unpack_menu(bContext *C, UI_popup_menu_end(C, pup); } -void ED_spacedata_id_remap(struct ScrArea *area, struct SpaceLink *sl, ID *old_id, ID *new_id) +void ED_spacedata_id_remap(struct ScrArea *area, + struct SpaceLink *sl, + const struct IDRemapper *mappings) +{ + SpaceType *st = BKE_spacetype_from_id(sl->spacetype); + if (st && st->id_remap) { + st->id_remap(area, sl, mappings); + } +} + +void ED_spacedata_id_remap_single(struct ScrArea *area, + struct SpaceLink *sl, + ID *old_id, + ID *new_id) { SpaceType *st = BKE_spacetype_from_id(sl->spacetype); if (st && st->id_remap) { - st->id_remap(area, sl, old_id, new_id); + struct IDRemapper *mappings = BKE_id_remapper_create(); + BKE_id_remapper_add(mappings, old_id, new_id); + st->id_remap(area, sl, mappings); + BKE_id_remapper_free(mappings); } } diff --git a/source/blender/editors/util/ed_util_imbuf.c b/source/blender/editors/util/ed_util_imbuf.c index 38ae98c678f..2e983eeff39 100644 --- a/source/blender/editors/util/ed_util_imbuf.c +++ b/source/blender/editors/util/ed_util_imbuf.c @@ -278,13 +278,13 @@ static void image_sample_apply(bContext *C, wmOperator *op, const wmEvent *event /* XXX node curve integration. */ #if 0 { - ScrArea *sa, *cur = curarea; + ScrArea *area, *cur = curarea; node_curvemap_sample(fp); /* sends global to node editor */ - for (sa = G.curscreen->areabase.first; sa; sa = sa->next) { - if (sa->spacetype == SPACE_NODE) { - areawinset(sa->win); - scrarea_do_windraw(sa); + for (area = G.curscreen->areabase.first; area; area = area->next) { + if (area->spacetype == SPACE_NODE) { + areawinset(area->win); + scrarea_do_windraw(area); } } node_curvemap_sample(NULL); /* clears global in node editor */ @@ -385,12 +385,12 @@ static void sequencer_sample_apply(bContext *C, wmOperator *op, const wmEvent *e static void ed_imbuf_sample_apply(bContext *C, wmOperator *op, const wmEvent *event) { - ScrArea *sa = CTX_wm_area(C); - if (sa == NULL) { + ScrArea *area = CTX_wm_area(C); + if (area == NULL) { return; } - switch (sa->spacetype) { + switch (area->spacetype) { case SPACE_IMAGE: { image_sample_apply(C, op, event); break; @@ -432,9 +432,9 @@ void ED_imbuf_sample_draw(const bContext *C, ARegion *region, void *arg_info) info->zfp); if (info->sample_size > 1) { - ScrArea *sa = CTX_wm_area(C); + ScrArea *area = CTX_wm_area(C); - if (sa && sa->spacetype == SPACE_IMAGE) { + if (area && area->spacetype == SPACE_IMAGE) { const wmWindow *win = CTX_wm_window(C); const wmEvent *event = win->eventstate; @@ -482,11 +482,11 @@ void ED_imbuf_sample_exit(bContext *C, wmOperator *op) int ED_imbuf_sample_invoke(bContext *C, wmOperator *op, const wmEvent *event) { ARegion *region = CTX_wm_region(C); - ScrArea *sa = CTX_wm_area(C); - if (sa) { - switch (sa->spacetype) { + ScrArea *area = CTX_wm_area(C); + if (area) { + switch (area->spacetype) { case SPACE_IMAGE: { - SpaceImage *sima = sa->spacedata.first; + SpaceImage *sima = area->spacedata.first; if (region->regiontype == RGN_TYPE_WINDOW) { if (ED_space_image_show_cache_and_mval_over(sima, region, event->mval)) { return OPERATOR_PASS_THROUGH; diff --git a/source/blender/editors/util/ed_util_ops.cc b/source/blender/editors/util/ed_util_ops.cc index a1b17d799bc..ae37dab7bb4 100644 --- a/source/blender/editors/util/ed_util_ops.cc +++ b/source/blender/editors/util/ed_util_ops.cc @@ -121,6 +121,22 @@ static void ED_OT_lib_id_load_custom_preview(wmOperatorType *ot) FILE_SORT_DEFAULT); } +static bool lib_id_generate_preview_poll(bContext *C) +{ + if (!lib_id_preview_editing_poll(C)) { + return false; + } + + const PointerRNA idptr = CTX_data_pointer_get(C, "id"); + const ID *id = (ID *)idptr.data; + if (GS(id->name) == ID_NT) { + CTX_wm_operator_poll_msg_set(C, TIP_("Can't generate automatic preview for node group")); + return false; + } + + return true; +} + static int lib_id_generate_preview_exec(bContext *C, wmOperator *UNUSED(op)) { PointerRNA idptr = CTX_data_pointer_get(C, "id"); @@ -148,13 +164,57 @@ static void ED_OT_lib_id_generate_preview(wmOperatorType *ot) ot->idname = "ED_OT_lib_id_generate_preview"; /* api callbacks */ - ot->poll = lib_id_preview_editing_poll; + ot->poll = lib_id_generate_preview_poll; ot->exec = lib_id_generate_preview_exec; /* flags */ ot->flag = OPTYPE_INTERNAL | OPTYPE_REGISTER | OPTYPE_UNDO; } +static bool lib_id_generate_preview_from_object_poll(bContext *C) +{ + if (!lib_id_preview_editing_poll(C)) { + return false; + } + if (CTX_data_active_object(C) == nullptr) { + return false; + } + return true; +} + +static int lib_id_generate_preview_from_object_exec(bContext *C, wmOperator *UNUSED(op)) +{ + PointerRNA idptr = CTX_data_pointer_get(C, "id"); + ID *id = (ID *)idptr.data; + + ED_preview_kill_jobs(CTX_wm_manager(C), CTX_data_main(C)); + + Object *object_to_render = CTX_data_active_object(C); + + BKE_previewimg_id_free(id); + PreviewImage *preview_image = BKE_previewimg_id_ensure(id); + UI_icon_render_id_ex(C, nullptr, &object_to_render->id, ICON_SIZE_PREVIEW, true, preview_image); + + WM_event_add_notifier(C, NC_ASSET | NA_EDITED, nullptr); + ED_assetlist_storage_tag_main_data_dirty(); + + return OPERATOR_FINISHED; +} + +static void ED_OT_lib_id_generate_preview_from_object(wmOperatorType *ot) +{ + ot->name = "Generate Preview from Object"; + ot->description = "Create a preview for this asset by rendering the active object"; + ot->idname = "ED_OT_lib_id_generate_preview_from_object"; + + /* api callbacks */ + ot->poll = lib_id_generate_preview_from_object_poll; + ot->exec = lib_id_generate_preview_from_object_exec; + + /* flags */ + ot->flag = OPTYPE_INTERNAL | OPTYPE_REGISTER | OPTYPE_UNDO; +} + /** \} */ /* -------------------------------------------------------------------- */ @@ -280,6 +340,7 @@ void ED_operatortypes_edutils() { WM_operatortype_append(ED_OT_lib_id_load_custom_preview); WM_operatortype_append(ED_OT_lib_id_generate_preview); + WM_operatortype_append(ED_OT_lib_id_generate_preview_from_object); WM_operatortype_append(ED_OT_lib_id_fake_user_toggle); WM_operatortype_append(ED_OT_lib_id_unlink); diff --git a/source/blender/editors/uvedit/uvedit_intern.h b/source/blender/editors/uvedit/uvedit_intern.h index 1fa96a932ed..9646444c103 100644 --- a/source/blender/editors/uvedit/uvedit_intern.h +++ b/source/blender/editors/uvedit/uvedit_intern.h @@ -74,13 +74,13 @@ typedef struct UvNearestHit { bool uv_find_nearest_vert(struct Scene *scene, struct Object *obedit, const float co[2], - const float penalty_dist, + float penalty_dist, struct UvNearestHit *hit); bool uv_find_nearest_vert_multi(struct Scene *scene, struct Object **objects, - const uint objects_len, + uint objects_len, const float co[2], - const float penalty_dist, + float penalty_dist, struct UvNearestHit *hit); bool uv_find_nearest_edge(struct Scene *scene, @@ -89,7 +89,7 @@ bool uv_find_nearest_edge(struct Scene *scene, struct UvNearestHit *hit); bool uv_find_nearest_edge_multi(struct Scene *scene, struct Object **objects, - const uint objects_len, + uint objects_len, const float co[2], struct UvNearestHit *hit); @@ -106,20 +106,20 @@ bool uv_find_nearest_face_ex(struct Scene *scene, struct Object *obedit, const float co[2], struct UvNearestHit *hit, - const bool only_in_face); + bool only_in_face); bool uv_find_nearest_face(struct Scene *scene, struct Object *obedit, const float co[2], struct UvNearestHit *hit); bool uv_find_nearest_face_multi_ex(struct Scene *scene, struct Object **objects, - const uint objects_len, + uint objects_len, const float co[2], struct UvNearestHit *hit, - const bool only_in_face); + bool only_in_face); bool uv_find_nearest_face_multi(struct Scene *scene, struct Object **objects, - const uint objects_len, + uint objects_len, const float co[2], struct UvNearestHit *hit); @@ -162,14 +162,14 @@ void UV_OT_shortest_path_select(struct wmOperatorType *ot); bool uvedit_select_is_any_selected(struct Scene *scene, struct Object *obedit); bool uvedit_select_is_any_selected_multi(struct Scene *scene, struct Object **objects, - const uint objects_len); + uint objects_len); /** * \warning This returns first selected UV, * not ideal in many cases since there could be multiple. */ const float *uvedit_first_selected_uv_from_vertex(struct Scene *scene, struct BMVert *eve, - const int cd_loop_uv_offset); + int cd_loop_uv_offset); void UV_OT_select_all(struct wmOperatorType *ot); void UV_OT_select(struct wmOperatorType *ot); diff --git a/source/blender/editors/uvedit/uvedit_ops.c b/source/blender/editors/uvedit/uvedit_ops.c index 342afa847b4..64e1fa2f768 100644 --- a/source/blender/editors/uvedit/uvedit_ops.c +++ b/source/blender/editors/uvedit/uvedit_ops.c @@ -180,7 +180,7 @@ void ED_object_assign_active_image(Main *bmain, Object *ob, int mat_nr, Image *i if (node && is_image_texture_node(node)) { node->id = &ima->id; - ED_node_tag_update_nodetree(bmain, ma->nodetree, node); + ED_node_tree_propagate_change(NULL, bmain, ma->nodetree); } } |