Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoseph Eagar <joeedh@gmail.com>2021-09-16 23:44:21 +0300
committerJoseph Eagar <joeedh@gmail.com>2021-09-16 23:44:21 +0300
commit627edd1efabb0baaed3127bd127215ffb0ddfbac (patch)
treed42cf9d0de78dbdeb21c11a95c0fde2d4caf5fee /source/blender/editors
parent445889676bfd900a237acbacbedeaadc30881cc7 (diff)
parentdb7fca3588aab72e49a74cbb2c236f86c0e0e6c1 (diff)
Merge branch 'master' into temp_bmesh_multires
Diffstat (limited to 'source/blender/editors')
-rw-r--r--source/blender/editors/animation/anim_deps.c7
-rw-r--r--source/blender/editors/animation/anim_draw.c1
-rw-r--r--source/blender/editors/animation/anim_filter.c47
-rw-r--r--source/blender/editors/animation/anim_ipo_utils.c30
-rw-r--r--source/blender/editors/animation/anim_motion_paths.c2
-rw-r--r--source/blender/editors/animation/keyframes_draw.c49
-rw-r--r--source/blender/editors/animation/keyframes_general.c9
-rw-r--r--source/blender/editors/animation/keyframes_keylist.cc482
-rw-r--r--source/blender/editors/animation/keyframing.c16
-rw-r--r--source/blender/editors/armature/pose_select.c8
-rw-r--r--source/blender/editors/armature/pose_slide.c4
-rw-r--r--source/blender/editors/curve/editcurve_add.c9
-rw-r--r--source/blender/editors/datafiles/CMakeLists.txt4
-rw-r--r--source/blender/editors/gizmo_library/CMakeLists.txt1
-rw-r--r--source/blender/editors/gizmo_library/gizmo_library_utils.c33
-rw-r--r--source/blender/editors/gpencil/gpencil_edit.c4
-rw-r--r--source/blender/editors/gpencil/gpencil_fill.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_interpolate.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_paint.c21
-rw-r--r--source/blender/editors/gpencil/gpencil_primitive.c16
-rw-r--r--source/blender/editors/gpencil/gpencil_sculpt_paint.c2
-rw-r--r--source/blender/editors/gpencil/gpencil_utils.c28
-rw-r--r--source/blender/editors/gpencil/gpencil_vertex_ops.c8
-rw-r--r--source/blender/editors/include/ED_gpencil.h7
-rw-r--r--source/blender/editors/include/ED_keyframes_keylist.h14
-rw-r--r--source/blender/editors/include/ED_object.h1
-rw-r--r--source/blender/editors/include/ED_view3d.h10
-rw-r--r--source/blender/editors/include/UI_icons.h6
-rw-r--r--source/blender/editors/include/UI_interface.h12
-rw-r--r--source/blender/editors/interface/interface_template_asset_view.cc26
-rw-r--r--source/blender/editors/interface/interface_template_list.cc9
-rw-r--r--source/blender/editors/interface/interface_templates.c6
-rw-r--r--source/blender/editors/interface/interface_widgets.c11
-rw-r--r--source/blender/editors/mesh/editmesh_add.c14
-rw-r--r--source/blender/editors/mesh/editmesh_bevel.c10
-rw-r--r--source/blender/editors/mesh/editmesh_bisect.c32
-rw-r--r--source/blender/editors/mesh/editmesh_inset.c10
-rw-r--r--source/blender/editors/object/CMakeLists.txt5
-rw-r--r--source/blender/editors/object/object_add.c49
-rw-r--r--source/blender/editors/object/object_constraint.c7
-rw-r--r--source/blender/editors/object/object_gpencil_modifier.c238
-rw-r--r--source/blender/editors/object/object_intern.h4
-rw-r--r--source/blender/editors/object/object_ops.c4
-rw-r--r--source/blender/editors/object/object_relations.c20
-rw-r--r--source/blender/editors/screen/area.c10
-rw-r--r--source/blender/editors/screen/screen_geometry.c4
-rw-r--r--source/blender/editors/screen/screen_ops.c53
-rw-r--r--source/blender/editors/sculpt_paint/paint_mask.c1
-rw-r--r--source/blender/editors/sculpt_paint/sculpt_brush_machine.c322
-rw-r--r--source/blender/editors/space_action/action_edit.c4
-rw-r--r--source/blender/editors/space_action/action_select.c1
-rw-r--r--source/blender/editors/space_file/filelist.c8
-rw-r--r--source/blender/editors/space_file/filesel.c3
-rw-r--r--source/blender/editors/space_graph/graph_slider_ops.c46
-rw-r--r--source/blender/editors/space_image/space_image.c8
-rw-r--r--source/blender/editors/space_node/drawnode.cc17
-rw-r--r--source/blender/editors/space_node/node_add.cc2
-rw-r--r--source/blender/editors/space_node/node_draw.cc83
-rw-r--r--source/blender/editors/space_outliner/outliner_draw.c14
-rw-r--r--source/blender/editors/space_outliner/outliner_tools.c9
-rw-r--r--source/blender/editors/space_sequencer/sequencer_select.c402
-rw-r--r--source/blender/editors/space_spreadsheet/space_spreadsheet.cc4
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh5
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc29
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_layout.cc17
-rw-r--r--source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc2
-rw-r--r--source/blender/editors/space_view3d/view3d_select.c62
-rw-r--r--source/blender/editors/space_view3d/view3d_view.c171
-rw-r--r--source/blender/editors/transform/transform.h3
-rw-r--r--source/blender/editors/transform/transform_convert_action.c20
-rw-r--r--source/blender/editors/transform/transform_convert_armature.c8
-rw-r--r--source/blender/editors/transform/transform_generics.c15
-rw-r--r--source/blender/editors/transform/transform_gizmo_3d.c12
-rw-r--r--source/blender/editors/transform/transform_snap_object.c4
-rw-r--r--source/blender/editors/transform/transform_snap_sequencer.c2
-rw-r--r--source/blender/editors/undo/ed_undo.c7
76 files changed, 1846 insertions, 782 deletions
diff --git a/source/blender/editors/animation/anim_deps.c b/source/blender/editors/animation/anim_deps.c
index 916d4232f03..97679723d84 100644
--- a/source/blender/editors/animation/anim_deps.c
+++ b/source/blender/editors/animation/anim_deps.c
@@ -206,16 +206,17 @@ static void animchan_sync_fcurve_scene(bAnimListElem *ale)
BLI_assert(GS(owner_id->name) == ID_SCE);
Scene *scene = (Scene *)owner_id;
FCurve *fcu = (FCurve *)ale->data;
+ Sequence *seq = NULL;
/* Only affect if F-Curve involves sequence_editor.sequences. */
- char *seq_name = BLI_str_quoted_substrN(fcu->rna_path, "sequences_all[");
- if (seq_name == NULL) {
+ char seq_name[sizeof(seq->name)];
+ if (!BLI_str_quoted_substr(fcu->rna_path, "sequences_all[", seq_name, sizeof(seq_name))) {
return;
}
/* Check if this strip is selected. */
Editing *ed = SEQ_editing_get(scene);
- Sequence *seq = SEQ_get_sequence_by_name(ed->seqbasep, seq_name, false);
+ seq = SEQ_get_sequence_by_name(ed->seqbasep, seq_name, false);
MEM_freeN(seq_name);
if (seq == NULL) {
diff --git a/source/blender/editors/animation/anim_draw.c b/source/blender/editors/animation/anim_draw.c
index 6d272bfc180..993d10cf303 100644
--- a/source/blender/editors/animation/anim_draw.c
+++ b/source/blender/editors/animation/anim_draw.c
@@ -521,6 +521,7 @@ static bool find_prev_next_keyframes(struct bContext *C, int *r_nextfra, int *r_
MaskLayer *masklay = BKE_mask_layer_active(mask);
mask_to_keylist(&ads, masklay, keylist);
}
+ ED_keylist_prepare_for_direct_access(keylist);
/* TODO(jbakker): Keylists are ordered, no need to do any searching at all. */
/* find matching keyframe in the right direction */
diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c
index 7e3e3f363c2..b12e0ae5cab 100644
--- a/source/blender/editors/animation/anim_filter.c
+++ b/source/blender/editors/animation/anim_filter.c
@@ -1061,13 +1061,14 @@ static bool skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_id
if (GS(owner_id->name) == ID_OB) {
Object *ob = (Object *)owner_id;
- char *bone_name;
+ bPoseChannel *pchan = NULL;
+ char bone_name[sizeof(pchan->name)];
/* Only consider if F-Curve involves `pose.bones`. */
- if (fcu->rna_path && (bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones["))) {
+ if (fcu->rna_path &&
+ BLI_str_quoted_substr(fcu->rna_path, "pose.bones[", bone_name, sizeof(bone_name))) {
/* Get bone-name, and check if this bone is selected. */
- bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
- MEM_freeN(bone_name);
+ pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
/* check whether to continue or skip */
if (pchan && pchan->bone) {
@@ -1097,21 +1098,41 @@ static bool skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_id
}
else if (GS(owner_id->name) == ID_SCE) {
Scene *scene = (Scene *)owner_id;
- char *seq_name;
+ Sequence *seq = NULL;
+ char seq_name[sizeof(seq->name)];
/* Only consider if F-Curve involves `sequence_editor.sequences`. */
- if (fcu->rna_path && (seq_name = BLI_str_quoted_substrN(fcu->rna_path, "sequences_all["))) {
+ if (fcu->rna_path &&
+ BLI_str_quoted_substr(fcu->rna_path, "sequences_all[", seq_name, sizeof(seq_name))) {
/* Get strip name, and check if this strip is selected. */
- Sequence *seq = NULL;
Editing *ed = SEQ_editing_get(scene);
if (ed) {
seq = SEQ_get_sequence_by_name(ed->seqbasep, seq_name, false);
}
- MEM_freeN(seq_name);
/* Can only add this F-Curve if it is selected. */
if (ads->filterflag & ADS_FILTER_ONLYSEL) {
- if ((seq == NULL) || (seq->flag & SELECT) == 0) {
+
+ /* NOTE(@campbellbarton): The `seq == NULL` check doesn't look right
+ * (compared to other checks in this function which skip data that can't be found).
+ *
+ * This is done since the search for sequence strips doesn't use a global lookup:
+ * - Nested meta-strips are excluded.
+ * - When inside a meta-strip - strips outside the meta-strip excluded.
+ *
+ * Instead, only the strips directly visible to the user are considered for selection.
+ * The NULL check here means everything else is considered unselected and is not shown.
+ *
+ * There is a subtle difference between nodes, pose-bones ... etc
+ * since data-paths that point to missing strips are not shown.
+ * If this is an important difference, the NULL case could perform a global lookup,
+ * only returning `true` if the sequence strip exists elsewhere
+ * (ignoring it's selection state). */
+ if (seq == NULL) {
+ return true;
+ }
+
+ if ((seq->flag & SELECT) == 0) {
return true;
}
}
@@ -1119,14 +1140,14 @@ static bool skip_fcurve_selected_data(bDopeSheet *ads, FCurve *fcu, ID *owner_id
}
else if (GS(owner_id->name) == ID_NT) {
bNodeTree *ntree = (bNodeTree *)owner_id;
- char *node_name;
+ bNode *node = NULL;
+ char node_name[sizeof(node->name)];
/* Check for selected nodes. */
- if (fcu->rna_path && (node_name = BLI_str_quoted_substrN(fcu->rna_path, "nodes["))) {
- bNode *node = NULL;
+ if (fcu->rna_path &&
+ (BLI_str_quoted_substr(fcu->rna_path, "nodes[", node_name, sizeof(node_name)))) {
/* Get strip name, and check if this strip is selected. */
node = nodeFindNodebyName(ntree, node_name);
- MEM_freeN(node_name);
/* Can only add this F-Curve if it is selected. */
if (node) {
diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c
index eda87cf1897..33b4882927a 100644
--- a/source/blender/editors/animation/anim_ipo_utils.c
+++ b/source/blender/editors/animation/anim_ipo_utils.c
@@ -106,23 +106,14 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu)
* - If a pointer just refers to the ID-block, then don't repeat this info
* since this just introduces clutter.
*/
- if (strstr(fcu->rna_path, "bones") && strstr(fcu->rna_path, "constraints")) {
- /* perform string 'chopping' to get "Bone Name : Constraint Name" */
- char *pchanName = BLI_str_quoted_substrN(fcu->rna_path, "bones[");
- char *constName = BLI_str_quoted_substrN(fcu->rna_path, "constraints[");
+
+ char pchanName[256], constName[256];
+ if (BLI_str_quoted_substr(fcu->rna_path, "bones[", pchanName, sizeof(pchanName)) &&
+ BLI_str_quoted_substr(fcu->rna_path, "constraints[", constName, sizeof(constName))) {
/* assemble the string to display in the UI... */
- structname = BLI_sprintfN(
- "%s : %s", pchanName ? pchanName : "", constName ? constName : "");
+ structname = BLI_sprintfN("%s : %s", pchanName, constName);
free_structname = 1;
-
- /* free the temp names */
- if (pchanName) {
- MEM_freeN(pchanName);
- }
- if (constName) {
- MEM_freeN(constName);
- }
}
else if (ptr.data != ptr.owner_id) {
PropertyRNA *nameprop = RNA_struct_name_property(ptr.type);
@@ -139,18 +130,15 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu)
* displaying the struct name alone is no meaningful information (and also cannot be
* filtered well), same for modifiers. So display strip name alongside as well. */
if (GS(ptr.owner_id->name) == ID_SCE) {
- if (BLI_str_startswith(fcu->rna_path, "sequence_editor.sequences_all[\"")) {
+ char stripname[256];
+ if (BLI_str_quoted_substr(
+ fcu->rna_path, "sequence_editor.sequences_all[", stripname, sizeof(stripname))) {
if (strstr(fcu->rna_path, ".transform.") || strstr(fcu->rna_path, ".crop.") ||
strstr(fcu->rna_path, ".modifiers[")) {
- char *stripname = BLI_str_quoted_substrN(fcu->rna_path, "sequences_all[");
- const char *structname_all = BLI_sprintfN(
- "%s : %s", stripname ? stripname : "", structname);
+ const char *structname_all = BLI_sprintfN("%s : %s", stripname, structname);
if (free_structname) {
MEM_freeN((void *)structname);
}
- if (stripname) {
- MEM_freeN(stripname);
- }
structname = structname_all;
free_structname = 1;
}
diff --git a/source/blender/editors/animation/anim_motion_paths.c b/source/blender/editors/animation/anim_motion_paths.c
index d976f5f72ad..d130941b9bc 100644
--- a/source/blender/editors/animation/anim_motion_paths.c
+++ b/source/blender/editors/animation/anim_motion_paths.c
@@ -329,6 +329,7 @@ static void motionpath_calculate_update_range(MPathTarget *mpt,
for (FCurve *fcu = fcurve_list->first; fcu != NULL; fcu = fcu->next) {
struct AnimKeylist *keylist = ED_keylist_create();
fcurve_to_keylist(adt, fcu, keylist, 0);
+ ED_keylist_prepare_for_direct_access(keylist);
int fcu_sfra = motionpath_get_prev_prev_keyframe(mpt, keylist, current_frame);
int fcu_efra = motionpath_get_next_next_keyframe(mpt, keylist, current_frame);
@@ -443,6 +444,7 @@ void animviz_calc_motionpaths(Depsgraph *depsgraph,
action_to_keylist(adt, adt->action, mpt->keylist, 0);
}
}
+ ED_keylist_prepare_for_direct_access(mpt->keylist);
if (range == ANIMVIZ_CALC_RANGE_CHANGED) {
int mpt_sfra, mpt_efra;
diff --git a/source/blender/editors/animation/keyframes_draw.c b/source/blender/editors/animation/keyframes_draw.c
index 61918871b90..ac7db9f4f46 100644
--- a/source/blender/editors/animation/keyframes_draw.c
+++ b/source/blender/editors/animation/keyframes_draw.c
@@ -30,6 +30,7 @@
#include "BLI_dlrbTree.h"
#include "BLI_listbase.h"
#include "BLI_rect.h"
+#include "BLI_task.h"
#include "DNA_anim_types.h"
#include "DNA_gpencil_types.h"
@@ -346,10 +347,12 @@ static void draw_keylist_block(const DrawKeylistUIData *ctx, const ActKeyColumn
}
static void draw_keylist_blocks(const DrawKeylistUIData *ctx,
- const ListBase * /*ActKeyColumn*/ columns,
+ const ActKeyColumn *keys,
+ const int key_len,
float ypos)
{
- LISTBASE_FOREACH (ActKeyColumn *, ab, columns) {
+ for (int i = 0; i < key_len; i++) {
+ const ActKeyColumn *ab = &keys[i];
draw_keylist_block(ctx, ab, ypos);
}
}
@@ -362,13 +365,15 @@ static bool draw_keylist_is_visible_key(const View2D *v2d, const ActKeyColumn *a
static void draw_keylist_keys(const DrawKeylistUIData *ctx,
View2D *v2d,
const KeyframeShaderBindings *sh_bindings,
- const ListBase * /*ActKeyColumn*/ keys,
+ const ActKeyColumn *keys,
+ const int key_len,
float ypos,
eSAction_Flag saction_flag)
{
short handle_type = KEYFRAME_HANDLE_NONE, extreme_type = KEYFRAME_EXTREME_NONE;
- LISTBASE_FOREACH (ActKeyColumn *, ak, keys) {
+ for (int i = 0; i < key_len; i++) {
+ const ActKeyColumn *ak = &keys[i];
if (draw_keylist_is_visible_key(v2d, ak)) {
if (ctx->show_ipo) {
handle_type = ak->handle_type;
@@ -469,8 +474,9 @@ static void ED_keylist_draw_list_elem_draw_blocks(AnimKeylistDrawListElem *elem,
DrawKeylistUIData ctx;
draw_keylist_ui_data_init(&ctx, v2d, elem->yscale_fac, elem->channel_locked, elem->saction_flag);
- const ListBase *keys = ED_keylist_listbase(elem->keylist);
- draw_keylist_blocks(&ctx, keys, elem->ypos);
+ const int key_len = ED_keylist_array_len(elem->keylist);
+ const ActKeyColumn *keys = ED_keylist_array(elem->keylist);
+ draw_keylist_blocks(&ctx, keys, key_len, elem->ypos);
}
static void ED_keylist_draw_list_elem_draw_keys(AnimKeylistDrawListElem *elem,
@@ -479,8 +485,15 @@ static void ED_keylist_draw_list_elem_draw_keys(AnimKeylistDrawListElem *elem,
{
DrawKeylistUIData ctx;
draw_keylist_ui_data_init(&ctx, v2d, elem->yscale_fac, elem->channel_locked, elem->saction_flag);
- const ListBase *keys = ED_keylist_listbase(elem->keylist);
- draw_keylist_keys(&ctx, v2d, sh_bindings, keys, elem->ypos, elem->saction_flag);
+
+ const int key_len = ED_keylist_array_len(elem->keylist);
+ const ActKeyColumn *keys = ED_keylist_array(elem->keylist);
+ draw_keylist_keys(&ctx, v2d, sh_bindings, keys, key_len, elem->ypos, elem->saction_flag);
+}
+
+static void ED_keylist_draw_list_elem_prepare_for_drawing(AnimKeylistDrawListElem *elem)
+{
+ ED_keylist_prepare_for_direct_access(elem->keylist);
}
typedef struct AnimKeylistDrawList {
@@ -492,11 +505,25 @@ AnimKeylistDrawList *ED_keylist_draw_list_create(void)
return MEM_callocN(sizeof(AnimKeylistDrawList), __func__);
}
+static void ED_keylist_draw_list_elem_build_task(void *__restrict UNUSED(userdata),
+ void *item,
+ int UNUSED(index),
+ const TaskParallelTLS *__restrict UNUSED(tls))
+{
+ AnimKeylistDrawListElem *elem = item;
+ ED_keylist_draw_list_elem_build_keylist(elem);
+ ED_keylist_draw_list_elem_prepare_for_drawing(elem);
+}
+
static void ED_keylist_draw_list_build_keylists(AnimKeylistDrawList *draw_list)
{
- LISTBASE_FOREACH (AnimKeylistDrawListElem *, elem, &draw_list->channels) {
- ED_keylist_draw_list_elem_build_keylist(elem);
- }
+ TaskParallelSettings settings;
+ BLI_parallel_range_settings_defaults(&settings);
+ /* Create a task per item, a single item is complex enough to deserve its own task. */
+ settings.min_iter_per_thread = 1;
+
+ BLI_task_parallel_listbase(
+ &draw_list->channels, NULL, ED_keylist_draw_list_elem_build_task, &settings);
}
static void ED_keylist_draw_list_draw_blocks(AnimKeylistDrawList *draw_list, View2D *v2d)
diff --git a/source/blender/editors/animation/keyframes_general.c b/source/blender/editors/animation/keyframes_general.c
index 9f3fe239113..ec33a42af3b 100644
--- a/source/blender/editors/animation/keyframes_general.c
+++ b/source/blender/editors/animation/keyframes_general.c
@@ -761,11 +761,10 @@ short copy_animedit_keys(bAnimContext *ac, ListBase *anim_data)
if ((aci->id_type == ID_OB) && (((Object *)aci->id)->type == OB_ARMATURE) && aci->rna_path) {
Object *ob = (Object *)aci->id;
- char *bone_name = BLI_str_quoted_substrN(aci->rna_path, "pose.bones[");
- if (bone_name) {
- bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
- MEM_freeN(bone_name);
-
+ bPoseChannel *pchan;
+ char bone_name[sizeof(pchan->name)];
+ if (BLI_str_quoted_substr(aci->rna_path, "pose.bones[", bone_name, sizeof(bone_name))) {
+ pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
if (pchan) {
aci->is_bone = true;
}
diff --git a/source/blender/editors/animation/keyframes_keylist.cc b/source/blender/editors/animation/keyframes_keylist.cc
index f6ade11a517..c1a18196a3a 100644
--- a/source/blender/editors/animation/keyframes_keylist.cc
+++ b/source/blender/editors/animation/keyframes_keylist.cc
@@ -23,15 +23,20 @@
/* System includes ----------------------------------------------------- */
+#include <algorithm>
#include <cfloat>
#include <cmath>
#include <cstdlib>
#include <cstring>
+#include <functional>
+#include <optional>
#include "MEM_guardedalloc.h"
+#include "BLI_array.hh"
#include "BLI_dlrbTree.h"
#include "BLI_listbase.h"
+#include "BLI_math.h"
#include "BLI_range.h"
#include "BLI_utildefines.h"
@@ -50,117 +55,294 @@
extern "C" {
/* *************************** Keyframe Processing *************************** */
-struct AnimKeylist {
- DLRBT_Tree keys;
-};
+/* ActKeyColumns (Keyframe Columns) ------------------------------------------ */
+
+BLI_INLINE bool is_cfra_eq(const float a, const float b)
+{
+ return IS_EQT(a, b, BEZT_BINARYSEARCH_THRESH);
+}
-static void ED_keylist_init(AnimKeylist *keylist)
+BLI_INLINE bool is_cfra_lt(const float a, const float b)
{
- BLI_dlrbTree_init(&keylist->keys);
+ return (b - a) > BEZT_BINARYSEARCH_THRESH;
}
+/* --------------- */
+
+struct AnimKeylist {
+ /* Number of ActKeyColumn's in the keylist. */
+ size_t column_len = 0;
+
+ bool is_runtime_initialized = false;
+
+ /* Before initializing the runtime, the key_columns list base is used to quickly add columns.
+ * Contains `ActKeyColumn`. Should not be used after runtime is initialized. */
+ 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.*/
+ std::optional<ActKeyColumn *> last_accessed_column = std::nullopt;
+
+ struct {
+ /* When initializing the runtime the columns from the list base `AnimKeyList.key_columns` are
+ * transferred to an array to support binary searching and index based access. */
+ blender::Array<ActKeyColumn> key_columns;
+ /* Wrapper around runtime.key_columns so it can still be accessed as a ListBase. Elements are
+ * owned by runtime.key_columns. */
+ ListBase /* ActKeyColumn */ list_wrapper;
+ } runtime;
+
+ AnimKeylist()
+ {
+ BLI_listbase_clear(&this->key_columns);
+ BLI_listbase_clear(&this->runtime.list_wrapper);
+ }
+
+ ~AnimKeylist()
+ {
+ BLI_freelistN(&this->key_columns);
+ BLI_listbase_clear(&this->runtime.list_wrapper);
+ }
+
+#ifdef WITH_CXX_GUARDEDALLOC
+ MEM_CXX_CLASS_ALLOC_FUNCS("editors:AnimKeylist")
+#endif
+};
+
AnimKeylist *ED_keylist_create(void)
{
- AnimKeylist *keylist = static_cast<AnimKeylist *>(MEM_callocN(sizeof(AnimKeylist), __func__));
- ED_keylist_init(keylist);
+ AnimKeylist *keylist = new AnimKeylist();
return keylist;
}
void ED_keylist_free(AnimKeylist *keylist)
{
BLI_assert(keylist);
- BLI_dlrbTree_free(&keylist->keys);
- MEM_freeN(keylist);
+ delete keylist;
}
-const ActKeyColumn *ED_keylist_find_exact(const AnimKeylist *keylist, float cfra)
+static void ED_keylist_convert_key_columns_to_array(AnimKeylist *keylist)
{
- return (const ActKeyColumn *)BLI_dlrbTree_search_exact(
- &keylist->keys, compare_ak_cfraPtr, &cfra);
+ size_t index;
+ LISTBASE_FOREACH_INDEX (ActKeyColumn *, key, &keylist->key_columns, index) {
+ keylist->runtime.key_columns[index] = *key;
+ }
}
-const ActKeyColumn *ED_keylist_find_next(const AnimKeylist *keylist, float cfra)
+static void ED_keylist_runtime_update_key_column_next_prev(AnimKeylist *keylist)
{
- return (const ActKeyColumn *)BLI_dlrbTree_search_next(&keylist->keys, compare_ak_cfraPtr, &cfra);
+ for (size_t index = 0; index < keylist->column_len; index++) {
+ const bool is_first = (index == 0);
+ keylist->runtime.key_columns[index].prev = is_first ? nullptr :
+ &keylist->runtime.key_columns[index - 1];
+ const bool is_last = (index == keylist->column_len - 1);
+ keylist->runtime.key_columns[index].next = is_last ? nullptr :
+ &keylist->runtime.key_columns[index + 1];
+ }
}
-const ActKeyColumn *ED_keylist_find_prev(const AnimKeylist *keylist, float cfra)
+static void ED_keylist_runtime_init_listbase(AnimKeylist *keylist)
{
- return (const ActKeyColumn *)BLI_dlrbTree_search_prev(&keylist->keys, compare_ak_cfraPtr, &cfra);
+ if (ED_keylist_is_empty(keylist)) {
+ BLI_listbase_clear(&keylist->runtime.list_wrapper);
+ return;
+ }
+
+ keylist->runtime.list_wrapper.first = &keylist->runtime.key_columns[0];
+ keylist->runtime.list_wrapper.last = &keylist->runtime.key_columns[keylist->column_len - 1];
}
-/* TODO(jbakker): Should we change this to use `ED_keylist_find_next(keys, min_fra)` and only check
- * boundary of `max_fra`. */
-const ActKeyColumn *ED_keylist_find_any_between(const AnimKeylist *keylist,
- const Range2f frame_range)
+static void ED_keylist_runtime_init(AnimKeylist *keylist)
{
- for (const ActKeyColumn *ak = static_cast<const ActKeyColumn *>(keylist->keys.root); ak;
- ak = static_cast<const ActKeyColumn *>((ak->cfra < frame_range.min) ? ak->right :
- ak->left)) {
- if (range2f_in_range(&frame_range, ak->cfra)) {
- return ak;
- }
+ BLI_assert(!keylist->is_runtime_initialized);
+
+ keylist->runtime.key_columns = blender::Array<ActKeyColumn>(keylist->column_len);
+
+ /* Convert linked list to array to support fast searching. */
+ ED_keylist_convert_key_columns_to_array(keylist);
+ /* Ensure that the array can also be used as a listbase for external usages. */
+ ED_keylist_runtime_update_key_column_next_prev(keylist);
+ ED_keylist_runtime_init_listbase(keylist);
+
+ keylist->is_runtime_initialized = true;
+}
+
+static void ED_keylist_reset_last_accessed(AnimKeylist *keylist)
+{
+ BLI_assert(!keylist->is_runtime_initialized);
+ keylist->last_accessed_column.reset();
+}
+
+void ED_keylist_prepare_for_direct_access(AnimKeylist *keylist)
+{
+ if (keylist->is_runtime_initialized) {
+ return;
+ }
+ ED_keylist_runtime_init(keylist);
+}
+
+static const ActKeyColumn *ED_keylist_find_lower_bound(const AnimKeylist *keylist,
+ const float cfra)
+{
+ BLI_assert(!ED_keylist_is_empty(keylist));
+ const ActKeyColumn *begin = std::begin(keylist->runtime.key_columns);
+ const ActKeyColumn *end = std::end(keylist->runtime.key_columns);
+ ActKeyColumn value;
+ value.cfra = cfra;
+
+ const ActKeyColumn *found_column = std::lower_bound(
+ begin, end, value, [](const ActKeyColumn &column, const ActKeyColumn &other) {
+ return is_cfra_lt(column.cfra, other.cfra);
+ });
+ return found_column;
+}
+
+static const ActKeyColumn *ED_keylist_find_upper_bound(const AnimKeylist *keylist,
+ const float cfra)
+{
+ BLI_assert(!ED_keylist_is_empty(keylist));
+ const ActKeyColumn *begin = std::begin(keylist->runtime.key_columns);
+ const ActKeyColumn *end = std::end(keylist->runtime.key_columns);
+ ActKeyColumn value;
+ value.cfra = cfra;
+
+ const ActKeyColumn *found_column = std::upper_bound(
+ begin, end, value, [](const ActKeyColumn &column, const ActKeyColumn &other) {
+ return is_cfra_lt(column.cfra, other.cfra);
+ });
+ return found_column;
+}
+
+const ActKeyColumn *ED_keylist_find_exact(const AnimKeylist *keylist, const float cfra)
+{
+ BLI_assert_msg(keylist->is_runtime_initialized,
+ "ED_keylist_prepare_for_direct_access needs to be called before searching.");
+
+ if (ED_keylist_is_empty(keylist)) {
+ return nullptr;
+ }
+
+ const ActKeyColumn *found_column = ED_keylist_find_lower_bound(keylist, cfra);
+
+ const ActKeyColumn *end = std::end(keylist->runtime.key_columns);
+ if (found_column == end) {
+ return nullptr;
+ }
+ if (is_cfra_eq(found_column->cfra, cfra)) {
+ return found_column;
}
return nullptr;
}
-bool ED_keylist_is_empty(const struct AnimKeylist *keylist)
+const ActKeyColumn *ED_keylist_find_next(const AnimKeylist *keylist, const float cfra)
{
- return keylist->keys.root == nullptr;
+ BLI_assert_msg(keylist->is_runtime_initialized,
+ "ED_keylist_prepare_for_direct_access needs to be called before searching.");
+
+ if (ED_keylist_is_empty(keylist)) {
+ return nullptr;
+ }
+
+ const ActKeyColumn *found_column = ED_keylist_find_upper_bound(keylist, cfra);
+
+ const ActKeyColumn *end = std::end(keylist->runtime.key_columns);
+ if (found_column == end) {
+ return nullptr;
+ }
+ return found_column;
}
-const struct ListBase *ED_keylist_listbase(const AnimKeylist *keylist)
+const ActKeyColumn *ED_keylist_find_prev(const AnimKeylist *keylist, const float cfra)
{
- return (ListBase *)&keylist->keys;
+ BLI_assert_msg(keylist->is_runtime_initialized,
+ "ED_keylist_prepare_for_direct_access needs to be called before searching.");
+
+ if (ED_keylist_is_empty(keylist)) {
+ return nullptr;
+ }
+
+ const ActKeyColumn *end = std::end(keylist->runtime.key_columns);
+ const ActKeyColumn *found_column = ED_keylist_find_lower_bound(keylist, cfra);
+
+ if (found_column == end) {
+ /* Nothing found, return the last item. */
+ return end - 1;
+ }
+
+ const ActKeyColumn *prev_column = found_column->prev;
+ return prev_column;
}
-bool ED_keylist_frame_range(const struct AnimKeylist *keylist, Range2f *r_frame_range)
+const ActKeyColumn *ED_keylist_find_any_between(const AnimKeylist *keylist,
+ const Range2f frame_range)
{
- BLI_assert(r_frame_range);
+ BLI_assert_msg(keylist->is_runtime_initialized,
+ "ED_keylist_prepare_for_direct_access needs to be called before searching.");
if (ED_keylist_is_empty(keylist)) {
- return false;
+ return nullptr;
}
- const ActKeyColumn *first_column = (const ActKeyColumn *)keylist->keys.first;
- r_frame_range->min = first_column->cfra;
+ const ActKeyColumn *column = ED_keylist_find_lower_bound(keylist, frame_range.min);
+ const ActKeyColumn *end = std::end(keylist->runtime.key_columns);
+ if (column == end) {
+ return nullptr;
+ }
+ if (column->cfra >= frame_range.max) {
+ return nullptr;
+ }
+ return column;
+}
- const ActKeyColumn *last_column = (const ActKeyColumn *)keylist->keys.last;
- r_frame_range->max = last_column->cfra;
+const ActKeyColumn *ED_keylist_array(const struct AnimKeylist *keylist)
+{
+ BLI_assert_msg(
+ keylist->is_runtime_initialized,
+ "ED_keylist_prepare_for_direct_access needs to be called before accessing array.");
+ return keylist->runtime.key_columns.data();
+}
- return true;
+int64_t ED_keylist_array_len(const struct AnimKeylist *keylist)
+{
+ return keylist->column_len;
}
-/* ActKeyColumns (Keyframe Columns) ------------------------------------------ */
-BLI_INLINE bool is_cfra_eq(const float a, const float b)
+bool ED_keylist_is_empty(const struct AnimKeylist *keylist)
{
- return IS_EQT(a, b, BEZT_BINARYSEARCH_THRESH);
+ return keylist->column_len == 0;
}
-BLI_INLINE bool is_cfra_lt(const float a, const float b)
+const struct ListBase *ED_keylist_listbase(const AnimKeylist *keylist)
{
- return (b - a) > BEZT_BINARYSEARCH_THRESH;
+ if (keylist->is_runtime_initialized) {
+ return &keylist->runtime.list_wrapper;
+ }
+ return &keylist->key_columns;
}
-/* Comparator callback used for ActKeyColumns and cframe float-value pointer */
-/* NOTE: this is exported to other modules that use the ActKeyColumns for finding keyframes */
-short compare_ak_cfraPtr(void *node, void *data)
+bool ED_keylist_frame_range(const struct AnimKeylist *keylist, Range2f *r_frame_range)
{
- ActKeyColumn *ak = (ActKeyColumn *)node;
- const float *cframe = static_cast<const float *>(data);
- const float val = *cframe;
+ BLI_assert(r_frame_range);
- if (is_cfra_eq(val, ak->cfra)) {
- return 0;
+ if (ED_keylist_is_empty(keylist)) {
+ return false;
}
- if (val < ak->cfra) {
- return -1;
+ const ActKeyColumn *first_column;
+ const ActKeyColumn *last_column;
+ if (keylist->is_runtime_initialized) {
+ first_column = &keylist->runtime.key_columns[0];
+ last_column = &keylist->runtime.key_columns[keylist->column_len - 1];
}
- return 1;
-}
+ else {
+ first_column = static_cast<const ActKeyColumn *>(keylist->key_columns.first);
+ last_column = static_cast<const ActKeyColumn *>(keylist->key_columns.last);
+ }
+ r_frame_range->min = first_column->cfra;
+ r_frame_range->max = last_column->cfra;
-/* --------------- */
+ return true;
+}
/* Set of references to three logically adjacent keys. */
struct BezTripleChain {
@@ -243,16 +425,8 @@ static eKeyframeExtremeDrawOpts bezt_extreme_type(const BezTripleChain *chain)
return KEYFRAME_EXTREME_NONE;
}
-/* Comparator callback used for ActKeyColumns and BezTripleChain */
-static short compare_ak_bezt(void *node, void *data)
-{
- BezTripleChain *chain = static_cast<BezTripleChain *>(data);
-
- return compare_ak_cfraPtr(node, &chain->cur->vec[1][0]);
-}
-
/* New node callback used for building ActKeyColumns from BezTripleChain */
-static DLRBT_Node *nalloc_ak_bezt(void *data)
+static ActKeyColumn *nalloc_ak_bezt(void *data)
{
ActKeyColumn *ak = static_cast<ActKeyColumn *>(
MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumn"));
@@ -269,13 +443,12 @@ static DLRBT_Node *nalloc_ak_bezt(void *data)
/* count keyframes in this column */
ak->totkey = 1;
- return (DLRBT_Node *)ak;
+ return ak;
}
/* Node updater callback used for building ActKeyColumns from BezTripleChain */
-static void nupdate_ak_bezt(void *node, void *data)
+static void nupdate_ak_bezt(ActKeyColumn *ak, void *data)
{
- ActKeyColumn *ak = static_cast<ActKeyColumn *>(node);
const BezTripleChain *chain = static_cast<const BezTripleChain *>(data);
const BezTriple *bezt = chain->cur;
@@ -312,17 +485,8 @@ static void nupdate_ak_bezt(void *node, void *data)
/* ......... */
-/* Comparator callback used for ActKeyColumns and GPencil frame */
-static short compare_ak_gpframe(void *node, void *data)
-{
- const bGPDframe *gpf = (bGPDframe *)data;
-
- float frame = gpf->framenum;
- return compare_ak_cfraPtr(node, &frame);
-}
-
/* New node callback used for building ActKeyColumns from GPencil frames */
-static DLRBT_Node *nalloc_ak_gpframe(void *data)
+static ActKeyColumn *nalloc_ak_gpframe(void *data)
{
ActKeyColumn *ak = static_cast<ActKeyColumn *>(
MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumnGPF"));
@@ -340,14 +504,13 @@ static DLRBT_Node *nalloc_ak_gpframe(void *data)
ak->block.sel = ak->sel;
ak->block.flag |= ACTKEYBLOCK_FLAG_GPENCIL;
- return (DLRBT_Node *)ak;
+ return ak;
}
/* Node updater callback used for building ActKeyColumns from GPencil frames */
-static void nupdate_ak_gpframe(void *node, void *data)
+static void nupdate_ak_gpframe(ActKeyColumn *ak, void *data)
{
- ActKeyColumn *ak = (ActKeyColumn *)node;
- const bGPDframe *gpf = (bGPDframe *)data;
+ bGPDframe *gpf = (bGPDframe *)data;
/* set selection status and 'touched' status */
if (gpf->flag & GP_FRAME_SELECT) {
@@ -366,17 +529,8 @@ static void nupdate_ak_gpframe(void *node, void *data)
/* ......... */
-/* Comparator callback used for ActKeyColumns and GPencil frame */
-static short compare_ak_masklayshape(void *node, void *data)
-{
- const MaskLayerShape *masklay_shape = (const MaskLayerShape *)data;
-
- float frame = masklay_shape->frame;
- return compare_ak_cfraPtr(node, &frame);
-}
-
/* New node callback used for building ActKeyColumns from GPencil frames */
-static DLRBT_Node *nalloc_ak_masklayshape(void *data)
+static ActKeyColumn *nalloc_ak_masklayshape(void *data)
{
ActKeyColumn *ak = static_cast<ActKeyColumn *>(
MEM_callocN(sizeof(ActKeyColumn), "ActKeyColumnGPF"));
@@ -389,14 +543,13 @@ static DLRBT_Node *nalloc_ak_masklayshape(void *data)
/* count keyframes in this column */
ak->totkey = 1;
- return (DLRBT_Node *)ak;
+ return ak;
}
/* Node updater callback used for building ActKeyColumns from GPencil frames */
-static void nupdate_ak_masklayshape(void *node, void *data)
+static void nupdate_ak_masklayshape(ActKeyColumn *ak, void *data)
{
- ActKeyColumn *ak = (ActKeyColumn *)node;
- const MaskLayerShape *masklay_shape = (const MaskLayerShape *)data;
+ MaskLayerShape *masklay_shape = (MaskLayerShape *)data;
/* set selection status and 'touched' status */
if (masklay_shape->flag & MASK_SHAPE_SELECT) {
@@ -408,6 +561,95 @@ static void nupdate_ak_masklayshape(void *node, void *data)
}
/* --------------- */
+using KeylistCreateColumnFunction = std::function<ActKeyColumn *(void *userdata)>;
+using KeylistUpdateColumnFunction = std::function<void(ActKeyColumn *, void *)>;
+
+/* `ED_keylist_find_neighbour_front_to_back` is called before the runtime can be initialized so we
+ * cannot use bin searching. */
+static ActKeyColumn *ED_keylist_find_neighbour_front_to_back(ActKeyColumn *cursor, float cfra)
+{
+ while (cursor->next && cursor->next->cfra <= cfra) {
+ cursor = cursor->next;
+ }
+ return cursor;
+}
+
+/* `ED_keylist_find_neighbour_back_to_front` is called before the runtime can be initialized so we
+ * cannot use bin searching. */
+static ActKeyColumn *ED_keylist_find_neighbour_back_to_front(ActKeyColumn *cursor, float cfra)
+{
+ while (cursor->prev && cursor->prev->cfra >= cfra) {
+ cursor = cursor->prev;
+ }
+ return cursor;
+}
+
+/*
+ * `ED_keylist_find_exact_or_neighbour_column` is called before the runtime can be initialized so
+ * we cannot use bin searching.
+ *
+ * This function is called to add or update columns in the keylist.
+ * Typically columns are sorted by frame number so keeping track of the last_accessed_column
+ * reduces searching.
+ */
+static ActKeyColumn *ED_keylist_find_exact_or_neighbour_column(AnimKeylist *keylist, float cfra)
+{
+ BLI_assert(!keylist->is_runtime_initialized);
+ if (ED_keylist_is_empty(keylist)) {
+ return nullptr;
+ }
+
+ ActKeyColumn *cursor = keylist->last_accessed_column.value_or(
+ static_cast<ActKeyColumn *>(keylist->key_columns.first));
+ if (!is_cfra_eq(cursor->cfra, cfra)) {
+ const bool walking_direction_front_to_back = cursor->cfra <= cfra;
+ if (walking_direction_front_to_back) {
+ cursor = ED_keylist_find_neighbour_front_to_back(cursor, cfra);
+ }
+ else {
+ cursor = ED_keylist_find_neighbour_back_to_front(cursor, cfra);
+ }
+ }
+
+ keylist->last_accessed_column = cursor;
+ return cursor;
+}
+
+static void ED_keylist_add_or_update_column(AnimKeylist *keylist,
+ float cfra,
+ KeylistCreateColumnFunction create_func,
+ KeylistUpdateColumnFunction update_func,
+ void *userdata)
+{
+ BLI_assert_msg(
+ !keylist->is_runtime_initialized,
+ "Modifying AnimKeylist isn't allowed after runtime is initialized "
+ "keylist->key_columns/columns_len will get out of sync with runtime.key_columns.");
+ if (ED_keylist_is_empty(keylist)) {
+ ActKeyColumn *key_column = create_func(userdata);
+ BLI_addhead(&keylist->key_columns, key_column);
+ keylist->column_len += 1;
+ keylist->last_accessed_column = key_column;
+ return;
+ }
+
+ ActKeyColumn *nearest = ED_keylist_find_exact_or_neighbour_column(keylist, cfra);
+ if (is_cfra_eq(nearest->cfra, cfra)) {
+ update_func(nearest, userdata);
+ }
+ else if (is_cfra_lt(nearest->cfra, cfra)) {
+ ActKeyColumn *key_column = create_func(userdata);
+ BLI_insertlinkafter(&keylist->key_columns, nearest, key_column);
+ keylist->column_len += 1;
+ keylist->last_accessed_column = key_column;
+ }
+ else {
+ ActKeyColumn *key_column = create_func(userdata);
+ BLI_insertlinkbefore(&keylist->key_columns, nearest, key_column);
+ keylist->column_len += 1;
+ keylist->last_accessed_column = key_column;
+ }
+}
/* Add the given BezTriple to the given 'list' of Keyframes */
static void add_bezt_to_keycolumns_list(AnimKeylist *keylist, BezTripleChain *bezt)
@@ -416,7 +658,8 @@ static void add_bezt_to_keycolumns_list(AnimKeylist *keylist, BezTripleChain *be
return;
}
- BLI_dlrbTree_add(&keylist->keys, compare_ak_bezt, nalloc_ak_bezt, nupdate_ak_bezt, bezt);
+ float cfra = bezt->cur->vec[1][0];
+ ED_keylist_add_or_update_column(keylist, cfra, nalloc_ak_bezt, nupdate_ak_bezt, bezt);
}
/* Add the given GPencil Frame to the given 'list' of Keyframes */
@@ -426,7 +669,8 @@ static void add_gpframe_to_keycolumns_list(AnimKeylist *keylist, bGPDframe *gpf)
return;
}
- BLI_dlrbTree_add(&keylist->keys, compare_ak_gpframe, nalloc_ak_gpframe, nupdate_ak_gpframe, gpf);
+ float cfra = gpf->framenum;
+ ED_keylist_add_or_update_column(keylist, cfra, nalloc_ak_gpframe, nupdate_ak_gpframe, gpf);
}
/* Add the given MaskLayerShape Frame to the given 'list' of Keyframes */
@@ -436,11 +680,9 @@ static void add_masklay_to_keycolumns_list(AnimKeylist *keylist, MaskLayerShape
return;
}
- BLI_dlrbTree_add(&keylist->keys,
- compare_ak_masklayshape,
- nalloc_ak_masklayshape,
- nupdate_ak_masklayshape,
- masklay_shape);
+ float cfra = masklay_shape->frame;
+ ED_keylist_add_or_update_column(
+ keylist, cfra, nalloc_ak_masklayshape, nupdate_ak_masklayshape, masklay_shape);
}
/* ActKeyBlocks (Long Keyframes) ------------------------------------------ */
@@ -476,7 +718,7 @@ static void compute_keyblock_data(ActKeyBlockInfo *info,
hold = IS_EQF(beztn->vec[1][1], beztn->vec[0][1]) &&
IS_EQF(prev->vec[1][1], prev->vec[2][1]);
}
- /* This interpolation type induces movement even between identical keys. */
+ /* This interpolation type induces movement even between identical columns. */
else {
hold = !ELEM(prev->ipo, BEZT_IPO_ELASTIC);
}
@@ -514,7 +756,7 @@ static void add_keyblock_info(ActKeyColumn *col, const ActKeyBlockInfo *block)
static void add_bezt_to_keyblocks_list(AnimKeylist *keylist, BezTriple *bezt, const int bezt_len)
{
- ActKeyColumn *col = static_cast<ActKeyColumn *>(keylist->keys.first);
+ ActKeyColumn *col = static_cast<ActKeyColumn *>(keylist->key_columns.first);
if (bezt && bezt_len >= 2) {
ActKeyBlockInfo block;
@@ -532,19 +774,15 @@ static void add_bezt_to_keyblocks_list(AnimKeylist *keylist, BezTriple *bezt, co
if (is_cfra_lt(bezt[1].vec[1][0], bezt[0].vec[1][0])) {
/* Backtrack to find the right location. */
if (is_cfra_lt(bezt[1].vec[1][0], col->cfra)) {
- ActKeyColumn *newcol = (ActKeyColumn *)BLI_dlrbTree_search_exact(
- &keylist->keys, compare_ak_cfraPtr, &bezt[1].vec[1][0]);
+ ActKeyColumn *newcol = ED_keylist_find_exact_or_neighbour_column(keylist, col->cfra);
- if (newcol != nullptr) {
- col = newcol;
+ BLI_assert(newcol);
+ BLI_assert(newcol->cfra == col->cfra);
- /* The previous keyblock is garbage too. */
- if (col->prev != nullptr) {
- add_keyblock_info(col->prev, &dummy_keyblock);
- }
- }
- else {
- BLI_assert(false);
+ col = newcol;
+ /* The previous keyblock is garbage too. */
+ if (col->prev != nullptr) {
+ add_keyblock_info(col->prev, &dummy_keyblock);
}
}
@@ -577,20 +815,17 @@ static void add_bezt_to_keyblocks_list(AnimKeylist *keylist, BezTriple *bezt, co
*/
static void update_keyblocks(AnimKeylist *keylist, BezTriple *bezt, const int bezt_len)
{
- /* Recompute the prev/next linked list. */
- BLI_dlrbTree_linkedlist_sync(&keylist->keys);
-
/* Find the curve count */
int max_curve = 0;
- LISTBASE_FOREACH (ActKeyColumn *, col, &keylist->keys) {
+ LISTBASE_FOREACH (ActKeyColumn *, col, &keylist->key_columns) {
max_curve = MAX2(max_curve, col->totcurve);
}
/* Propagate blocks to inserted keys */
ActKeyColumn *prev_ready = nullptr;
- LISTBASE_FOREACH (ActKeyColumn *, col, &keylist->keys) {
+ LISTBASE_FOREACH (ActKeyColumn *, col, &keylist->key_columns) {
/* Pre-existing column. */
if (col->totcurve > 0) {
prev_ready = col;
@@ -775,6 +1010,7 @@ void cachefile_to_keylist(bDopeSheet *ads,
void fcurve_to_keylist(AnimData *adt, FCurve *fcu, AnimKeylist *keylist, const int saction_flag)
{
if (fcu && fcu->totvert && fcu->bezt) {
+ ED_keylist_reset_last_accessed(keylist);
/* apply NLA-mapping (if applicable) */
if (adt) {
ANIM_nla_mapping_apply_fcurve(adt, fcu, false, false);
@@ -790,7 +1026,7 @@ void fcurve_to_keylist(AnimData *adt, FCurve *fcu, AnimKeylist *keylist, const i
for (int v = 0; v < fcu->totvert; v++) {
chain.cur = &fcu->bezt[v];
- /* Neighbor keys, accounting for being cyclic. */
+ /* Neighbor columns, accounting for being cyclic. */
if (do_extremes) {
chain.prev = (v > 0) ? &fcu->bezt[v - 1] :
is_cyclic ? &fcu->bezt[fcu->totvert - 2] :
@@ -856,6 +1092,7 @@ void gpencil_to_keylist(bDopeSheet *ads, bGPdata *gpd, AnimKeylist *keylist, con
void gpl_to_keylist(bDopeSheet *UNUSED(ads), bGPDlayer *gpl, AnimKeylist *keylist)
{
if (gpl && keylist) {
+ ED_keylist_reset_last_accessed(keylist);
/* Although the frames should already be in an ordered list,
* they are not suitable for displaying yet. */
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
@@ -869,6 +1106,7 @@ void gpl_to_keylist(bDopeSheet *UNUSED(ads), bGPDlayer *gpl, AnimKeylist *keylis
void mask_to_keylist(bDopeSheet *UNUSED(ads), MaskLayer *masklay, AnimKeylist *keylist)
{
if (masklay && keylist) {
+ ED_keylist_reset_last_accessed(keylist);
LISTBASE_FOREACH (MaskLayerShape *, masklay_shape, &masklay->splines_shapes) {
add_masklay_to_keycolumns_list(keylist, masklay_shape);
}
diff --git a/source/blender/editors/animation/keyframing.c b/source/blender/editors/animation/keyframing.c
index 292d665caca..8dc4aed9f0e 100644
--- a/source/blender/editors/animation/keyframing.c
+++ b/source/blender/editors/animation/keyframing.c
@@ -2218,11 +2218,11 @@ static int clear_anim_v3d_exec(bContext *C, wmOperator *UNUSED(op))
if (ob->mode & OB_MODE_POSE) {
if (fcu->rna_path) {
/* Get bone-name, and check if this bone is selected. */
- char *bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones[");
- if (bone_name) {
- bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
- MEM_freeN(bone_name);
-
+ bPoseChannel *pchan = NULL;
+ char bone_name[sizeof(pchan->name)];
+ if (BLI_str_quoted_substr(
+ fcu->rna_path, "pose.bones[", bone_name, sizeof(bone_name))) {
+ pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
/* Delete if bone is selected. */
if ((pchan) && (pchan->bone)) {
if (pchan->bone->flag & BONE_SELECTED) {
@@ -2323,13 +2323,11 @@ static int delete_key_v3d_without_keying_set(bContext *C, wmOperator *op)
bPoseChannel *pchan = NULL;
/* Get bone-name, and check if this bone is selected. */
- char *bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones[");
- if (bone_name == NULL) {
+ char bone_name[sizeof(pchan->name)];
+ if (!BLI_str_quoted_substr(fcu->rna_path, "pose.bones[", bone_name, sizeof(bone_name))) {
continue;
}
-
pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
- MEM_freeN(bone_name);
/* skip if bone is not selected */
if ((pchan) && (pchan->bone)) {
diff --git a/source/blender/editors/armature/pose_select.c b/source/blender/editors/armature/pose_select.c
index 4db8569a7d2..e5b8983af93 100644
--- a/source/blender/editors/armature/pose_select.c
+++ b/source/blender/editors/armature/pose_select.c
@@ -1106,12 +1106,12 @@ static bool pose_select_same_keyingset(bContext *C, ReportList *reports, bool ex
for (ksp = ks->paths.first; ksp; ksp = ksp->next) {
/* only items related to this object will be relevant */
if ((ksp->id == &ob->id) && (ksp->rna_path != NULL)) {
- char *boneName = BLI_str_quoted_substrN(ksp->rna_path, "bones[");
- if (boneName == NULL) {
+ bPoseChannel *pchan = NULL;
+ char boneName[sizeof(pchan->name)];
+ if (!BLI_str_quoted_substr(ksp->rna_path, "bones[", boneName, sizeof(boneName))) {
continue;
}
- bPoseChannel *pchan = BKE_pose_channel_find_name(pose, boneName);
- MEM_freeN(boneName);
+ pchan = BKE_pose_channel_find_name(pose, boneName);
if (pchan) {
/* select if bone is visible and can be affected */
diff --git a/source/blender/editors/armature/pose_slide.c b/source/blender/editors/armature/pose_slide.c
index bc5cbd92deb..f23376867af 100644
--- a/source/blender/editors/armature/pose_slide.c
+++ b/source/blender/editors/armature/pose_slide.c
@@ -976,6 +976,7 @@ static int pose_slide_invoke_common(bContext *C, wmOperator *op, const wmEvent *
}
/* Cancel if no keyframes found. */
+ ED_keylist_prepare_for_direct_access(pso->keylist);
if (ED_keylist_is_empty(pso->keylist)) {
BKE_report(op->reports, RPT_ERROR, "No keyframes to slide between");
pose_slide_exit(C, op);
@@ -1267,6 +1268,8 @@ static int pose_slide_modal(bContext *C, wmOperator *op, const wmEvent *event)
/* Perform pose updates - in response to some user action
* (e.g. pressing a key or moving the mouse). */
if (do_pose_update) {
+ RNA_float_set(op->ptr, "factor", ED_slider_factor_get(pso->slider));
+
/* Update percentage indicator in header. */
pose_slide_draw_status(C, pso);
@@ -1712,6 +1715,7 @@ static float pose_propagate_get_boneHoldEndFrame(tPChanFCurveLink *pfl, float st
FCurve *fcu = (FCurve *)ld->data;
fcurve_to_keylist(adt, fcu, keylist, 0);
}
+ ED_keylist_prepare_for_direct_access(keylist);
/* Find the long keyframe (i.e. hold), and hence obtain the endFrame value
* - the best case would be one that starts on the frame itself
diff --git a/source/blender/editors/curve/editcurve_add.c b/source/blender/editors/curve/editcurve_add.c
index d1fe162fc4a..75fb17e8cc1 100644
--- a/source/blender/editors/curve/editcurve_add.c
+++ b/source/blender/editors/curve/editcurve_add.c
@@ -515,7 +515,6 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
bool newob = false;
bool enter_editmode;
ushort local_view_bits;
- float dia;
float loc[3], rot[3];
float mat[4][4];
@@ -535,7 +534,6 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
newob = true;
cu = (Curve *)obedit->data;
- cu->flag |= CU_DEFORM_FILL;
if (type & CU_PRIM_PATH) {
cu->flag |= CU_PATH | CU_3D;
@@ -556,9 +554,10 @@ static int curvesurf_prim_add(bContext *C, wmOperator *op, int type, int isSurf)
}
}
- ED_object_new_primitive_matrix(C, obedit, loc, rot, mat);
- dia = RNA_float_get(op->ptr, "radius");
- mul_mat3_m4_fl(mat, dia);
+ float radius = RNA_float_get(op->ptr, "radius");
+ float scale[3];
+ copy_v3_fl(scale, radius);
+ ED_object_new_primitive_matrix(C, obedit, loc, rot, scale, mat);
nu = ED_curve_add_nurbs_primitive(C, obedit, mat, type, newob);
editnurb = object_editcurve_get(obedit);
diff --git a/source/blender/editors/datafiles/CMakeLists.txt b/source/blender/editors/datafiles/CMakeLists.txt
index 2542247f252..5f25114eaf3 100644
--- a/source/blender/editors/datafiles/CMakeLists.txt
+++ b/source/blender/editors/datafiles/CMakeLists.txt
@@ -336,6 +336,7 @@ set(ICON_NAMES
lightprobe_cubemap
lightprobe_planar
lightprobe_grid
+ mod_dash
color_red
color_green
color_blue
@@ -390,6 +391,9 @@ set(ICON_NAMES
small_caps
modifier
con_action
+ mod_length
+ mod_dash
+ mod_lineart
holdout_off
holdout_on
indirect_only_off
diff --git a/source/blender/editors/gizmo_library/CMakeLists.txt b/source/blender/editors/gizmo_library/CMakeLists.txt
index eeb1e60166b..bfe8334b390 100644
--- a/source/blender/editors/gizmo_library/CMakeLists.txt
+++ b/source/blender/editors/gizmo_library/CMakeLists.txt
@@ -27,6 +27,7 @@ set(INC
../../makesdna
../../makesrna
../../windowmanager
+ ../../../../intern/clog
../../../../intern/eigen
../../../../intern/glew-mx
../../../../intern/guardedalloc
diff --git a/source/blender/editors/gizmo_library/gizmo_library_utils.c b/source/blender/editors/gizmo_library/gizmo_library_utils.c
index 7d0ae5afb9b..a0db2a8e627 100644
--- a/source/blender/editors/gizmo_library/gizmo_library_utils.c
+++ b/source/blender/editors/gizmo_library/gizmo_library_utils.c
@@ -39,9 +39,13 @@
#include "ED_view3d.h"
+#include "CLG_log.h"
+
/* own includes */
#include "gizmo_library_intern.h"
+static CLG_LogRef LOG = {"ed.gizmo.library_utils"};
+
/* factor for precision tweaking */
#define GIZMO_PRECISION_FAC 0.05f
@@ -182,7 +186,7 @@ bool gizmo_window_project_2d(bContext *C,
bool use_offset,
float r_co[2])
{
- float mat[4][4];
+ float mat[4][4], imat[4][4];
{
float mat_identity[4][4];
struct WM_GizmoMatrixParams params = {NULL};
@@ -193,6 +197,14 @@ bool gizmo_window_project_2d(bContext *C,
WM_gizmo_calc_matrix_final_params(gz, &params, mat);
}
+ if (!invert_m4_m4(imat, mat)) {
+ CLOG_WARN(&LOG,
+ "Gizmo \"%s\" of group \"%s\" has matrix that could not be inverted "
+ "(projection will fail)",
+ gz->type->idname,
+ gz->parent_gzgroup->type->idname);
+ }
+
/* rotate mouse in relation to the center and relocate it */
if (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) {
/* For 3d views, transform 2D mouse pos onto plane. */
@@ -202,8 +214,6 @@ bool gizmo_window_project_2d(bContext *C,
plane_from_point_normal_v3(plane, mat[3], mat[2]);
bool clip_ray = ((RegionView3D *)region->regiondata)->is_persp;
if (ED_view3d_win_to_3d_on_plane(region, plane, mval, clip_ray, co)) {
- float imat[4][4];
- invert_m4_m4(imat, mat);
mul_m4_v3(imat, co);
r_co[0] = co[(axis + 1) % 3];
r_co[1] = co[(axis + 2) % 3];
@@ -213,8 +223,6 @@ bool gizmo_window_project_2d(bContext *C,
}
float co[3] = {mval[0], mval[1], 0.0f};
- float imat[4][4];
- invert_m4_m4(imat, mat);
mul_m4_v3(imat, co);
copy_v2_v2(r_co, co);
return true;
@@ -223,7 +231,7 @@ bool gizmo_window_project_2d(bContext *C,
bool gizmo_window_project_3d(
bContext *C, const struct wmGizmo *gz, const float mval[2], bool use_offset, float r_co[3])
{
- float mat[4][4];
+ float mat[4][4], imat[4][4];
{
float mat_identity[4][4];
struct WM_GizmoMatrixParams params = {NULL};
@@ -234,20 +242,25 @@ bool gizmo_window_project_3d(
WM_gizmo_calc_matrix_final_params(gz, &params, mat);
}
+ if (!invert_m4_m4(imat, mat)) {
+ CLOG_WARN(&LOG,
+ "Gizmo \"%s\" of group \"%s\" has matrix that could not be inverted "
+ "(projection will fail)",
+ gz->type->idname,
+ gz->parent_gzgroup->type->idname);
+ }
+
if (gz->parent_gzgroup->type->flag & WM_GIZMOGROUPTYPE_3D) {
View3D *v3d = CTX_wm_view3d(C);
ARegion *region = CTX_wm_region(C);
/* NOTE: we might want a custom reference point passed in,
* instead of the gizmo center. */
ED_view3d_win_to_3d(v3d, region, mat[3], mval, r_co);
- invert_m4(mat);
- mul_m4_v3(mat, r_co);
+ mul_m4_v3(imat, r_co);
return true;
}
float co[3] = {mval[0], mval[1], 0.0f};
- float imat[4][4];
- invert_m4_m4(imat, mat);
mul_m4_v3(imat, co);
copy_v2_v2(r_co, co);
return true;
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c
index 8d1f841da6c..aa3178ddc2c 100644
--- a/source/blender/editors/gpencil/gpencil_edit.c
+++ b/source/blender/editors/gpencil/gpencil_edit.c
@@ -3618,7 +3618,7 @@ static int gpencil_stroke_join_exec(bContext *C, wmOperator *op)
}
elem = &strokes_list[i];
/* Join new_stroke and stroke B. */
- BKE_gpencil_stroke_join(gps_new, elem->gps, leave_gaps, true);
+ BKE_gpencil_stroke_join(gps_new, elem->gps, leave_gaps, true, false);
elem->used = true;
}
@@ -3967,7 +3967,7 @@ static void gpencil_smooth_stroke(bContext *C, wmOperator *op)
/* perform smoothing */
if (smooth_position) {
- BKE_gpencil_stroke_smooth(gps, i, factor);
+ BKE_gpencil_stroke_smooth_point(gps, i, factor);
}
if (smooth_strength) {
BKE_gpencil_stroke_smooth_strength(gps, i, factor);
diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c
index 0c88d678ef4..f5474a7cdc3 100644
--- a/source/blender/editors/gpencil/gpencil_fill.c
+++ b/source/blender/editors/gpencil/gpencil_fill.c
@@ -1569,7 +1569,7 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf)
float smoothfac = 1.0f;
for (int r = 0; r < 1; r++) {
for (int i = 0; i < gps->totpoints; i++) {
- BKE_gpencil_stroke_smooth(gps, i, smoothfac - reduce);
+ BKE_gpencil_stroke_smooth_point(gps, i, smoothfac - reduce);
}
reduce += 0.25f; /* reduce the factor */
}
diff --git a/source/blender/editors/gpencil/gpencil_interpolate.c b/source/blender/editors/gpencil/gpencil_interpolate.c
index a8bd3b11bb1..fdd9f44605e 100644
--- a/source/blender/editors/gpencil/gpencil_interpolate.c
+++ b/source/blender/editors/gpencil/gpencil_interpolate.c
@@ -333,7 +333,7 @@ static void gpencil_interpolate_smooth_stroke(bGPDstroke *gps,
float reduce = 0.0f;
for (int r = 0; r < smooth_steps; r++) {
for (int i = 0; i < gps->totpoints - 1; i++) {
- BKE_gpencil_stroke_smooth(gps, i, smooth_factor - reduce);
+ BKE_gpencil_stroke_smooth_point(gps, i, smooth_factor - reduce);
BKE_gpencil_stroke_smooth_strength(gps, i, smooth_factor);
}
reduce += 0.25f; /* reduce the factor */
diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c
index 28a22633742..9b157224178 100644
--- a/source/blender/editors/gpencil/gpencil_paint.c
+++ b/source/blender/editors/gpencil/gpencil_paint.c
@@ -1209,7 +1209,8 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
float reduce = 0.0f;
for (int r = 0; r < brush->gpencil_settings->draw_smoothlvl; r++) {
for (i = 0; i < gps->totpoints - 1; i++) {
- BKE_gpencil_stroke_smooth(gps, i, brush->gpencil_settings->draw_smoothfac - reduce);
+ BKE_gpencil_stroke_smooth_point(
+ gps, i, brush->gpencil_settings->draw_smoothfac - reduce);
BKE_gpencil_stroke_smooth_strength(gps, i, brush->gpencil_settings->draw_smoothfac);
}
reduce += 0.25f; /* reduce the factor */
@@ -1221,7 +1222,7 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
float ifac = (float)brush->gpencil_settings->input_samples / 10.0f;
float sfac = interpf(1.0f, 0.2f, ifac);
for (i = 0; i < gps->totpoints - 1; i++) {
- BKE_gpencil_stroke_smooth(gps, i, sfac);
+ BKE_gpencil_stroke_smooth_point(gps, i, sfac);
BKE_gpencil_stroke_smooth_strength(gps, i, sfac);
}
}
@@ -1288,11 +1289,23 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p)
/* Join with existing strokes. */
if (ts->gpencil_flags & GP_TOOL_FLAG_AUTOMERGE_STROKE) {
if (gps->prev != 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);
+ ED_gpencil_stroke_extremes_to2d(&p->gsc, diff_mat, gps, ctrl1, ctrl2);
+
int pt_index = 0;
bool doit = true;
while (doit && gps) {
- bGPDstroke *gps_target = ED_gpencil_stroke_nearest_to_ends(
- p->C, &p->gsc, gpl, gpl->actframe, gps, GPENCIL_MINIMUM_JOIN_DIST, &pt_index);
+ bGPDstroke *gps_target = ED_gpencil_stroke_nearest_to_ends(p->C,
+ &p->gsc,
+ gpl,
+ gpl->actframe,
+ gps,
+ ctrl1,
+ ctrl2,
+ GPENCIL_MINIMUM_JOIN_DIST,
+ &pt_index);
if (gps_target != NULL) {
gps = ED_gpencil_stroke_join_and_trim(p->gpd, p->gpf, gps, gps_target, pt_index);
}
diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c
index 5ecb6d9a212..f8cfc130e35 100644
--- a/source/blender/editors/gpencil/gpencil_primitive.c
+++ b/source/blender/editors/gpencil/gpencil_primitive.c
@@ -1382,11 +1382,23 @@ static void gpencil_primitive_interaction_end(bContext *C,
if (ts->gpencil_flags & GP_TOOL_FLAG_AUTOMERGE_STROKE) {
if (ELEM(tgpi->type, GP_STROKE_ARC, GP_STROKE_LINE, GP_STROKE_CURVE, GP_STROKE_POLYLINE)) {
if (gps->prev != NULL) {
+ BKE_gpencil_stroke_boundingbox_calc(gps);
+ float diff_mat[4][4], ctrl1[2], ctrl2[2];
+ BKE_gpencil_layer_transform_matrix_get(tgpi->depsgraph, tgpi->ob, tgpi->gpl, diff_mat);
+ ED_gpencil_stroke_extremes_to2d(&tgpi->gsc, diff_mat, gps, ctrl1, ctrl2);
+
int pt_index = 0;
bool doit = true;
while (doit && gps) {
- bGPDstroke *gps_target = ED_gpencil_stroke_nearest_to_ends(
- C, &tgpi->gsc, tgpi->gpl, gpf, gps, GPENCIL_MINIMUM_JOIN_DIST, &pt_index);
+ bGPDstroke *gps_target = ED_gpencil_stroke_nearest_to_ends(C,
+ &tgpi->gsc,
+ tgpi->gpl,
+ gpf,
+ gps,
+ ctrl1,
+ ctrl2,
+ GPENCIL_MINIMUM_JOIN_DIST,
+ &pt_index);
if (gps_target != NULL) {
gps = ED_gpencil_stroke_join_and_trim(tgpi->gpd, gpf, gps, gps_target, pt_index);
}
diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
index 869254cef3b..e9a6beab798 100644
--- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c
+++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c
@@ -337,7 +337,7 @@ static bool gpencil_brush_smooth_apply(tGP_BrushEditData *gso,
/* perform smoothing */
if (gso->brush->gpencil_settings->sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_POSITION) {
- BKE_gpencil_stroke_smooth(gps, pt_index, inf);
+ BKE_gpencil_stroke_smooth_point(gps, pt_index, inf);
}
if (gso->brush->gpencil_settings->sculpt_mode_flag & GP_SCULPT_FLAGMODE_APPLY_STRENGTH) {
BKE_gpencil_stroke_smooth_strength(gps, pt_index, inf);
diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c
index 5cc52303cd6..bb05b93ad81 100644
--- a/source/blender/editors/gpencil/gpencil_utils.c
+++ b/source/blender/editors/gpencil/gpencil_utils.c
@@ -3213,11 +3213,28 @@ bool ED_gpencil_stroke_point_is_inside(const bGPDstroke *gps,
return hit;
}
+/* Get extremes of stroke in 2D using current view. */
+void ED_gpencil_stroke_extremes_to2d(const GP_SpaceConversion *gsc,
+ const float diff_mat[4][4],
+ bGPDstroke *gps,
+ float r_ctrl1[2],
+ float r_ctrl2[2])
+{
+ bGPDspoint pt_dummy_ps;
+
+ gpencil_point_to_parent_space(&gps->points[0], diff_mat, &pt_dummy_ps);
+ gpencil_point_to_xy_fl(gsc, gps, &pt_dummy_ps, &r_ctrl1[0], &r_ctrl1[1]);
+ gpencil_point_to_parent_space(&gps->points[gps->totpoints - 1], diff_mat, &pt_dummy_ps);
+ gpencil_point_to_xy_fl(gsc, gps, &pt_dummy_ps, &r_ctrl2[0], &r_ctrl2[1]);
+}
+
bGPDstroke *ED_gpencil_stroke_nearest_to_ends(bContext *C,
const GP_SpaceConversion *gsc,
bGPDlayer *gpl,
bGPDframe *gpf,
bGPDstroke *gps,
+ const float ctrl1[2],
+ const float ctrl2[2],
const float radius,
int *r_index)
{
@@ -3267,6 +3284,15 @@ bGPDstroke *ED_gpencil_stroke_nearest_to_ends(bContext *C,
gpencil_point_to_parent_space(pt, diff_mat, &pt_parent);
gpencil_point_to_xy_fl(gsc, gps, &pt_parent, &pt2d_target_end[0], &pt2d_target_end[1]);
+ /* If the distance to the original stroke extremes is too big, the stroke must not be joined.
+ */
+ if ((len_squared_v2v2(ctrl1, pt2d_target_start) > radius_sqr) &&
+ (len_squared_v2v2(ctrl1, pt2d_target_end) > radius_sqr) &&
+ (len_squared_v2v2(ctrl2, pt2d_target_start) > radius_sqr) &&
+ (len_squared_v2v2(ctrl2, pt2d_target_end) > radius_sqr)) {
+ continue;
+ }
+
if ((len_squared_v2v2(pt2d_start, pt2d_target_start) > radius_sqr) &&
(len_squared_v2v2(pt2d_start, pt2d_target_end) > radius_sqr) &&
(len_squared_v2v2(pt2d_end, pt2d_target_start) > radius_sqr) &&
@@ -3350,7 +3376,7 @@ bGPDstroke *ED_gpencil_stroke_join_and_trim(
/* Join both strokes. */
int totpoint = gps_final->totpoints;
- BKE_gpencil_stroke_join(gps_final, gps, false, true);
+ BKE_gpencil_stroke_join(gps_final, gps, false, true, true);
/* Select the join points and merge if the distance is very small. */
pt = &gps_final->points[totpoint - 1];
diff --git a/source/blender/editors/gpencil/gpencil_vertex_ops.c b/source/blender/editors/gpencil/gpencil_vertex_ops.c
index 402bccce2f7..5c3a7cf9e6f 100644
--- a/source/blender/editors/gpencil/gpencil_vertex_ops.c
+++ b/source/blender/editors/gpencil/gpencil_vertex_ops.c
@@ -588,6 +588,7 @@ static int gpencil_vertexpaint_set_exec(bContext *C, wmOperator *op)
changed = true;
copy_v3_v3(gps->vert_color_fill, brush->rgb);
gps->vert_color_fill[3] = factor;
+ srgb_to_linearrgb_v4(gps->vert_color_fill, gps->vert_color_fill);
}
/* Stroke points. */
@@ -596,10 +597,13 @@ static int gpencil_vertexpaint_set_exec(bContext *C, wmOperator *op)
int i;
bGPDspoint *pt;
+ float color[4];
+ copy_v3_v3(color, brush->rgb);
+ color[3] = factor;
+ srgb_to_linearrgb_v4(color, color);
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if ((!any_selected) || (pt->flag & GP_SPOINT_SELECT)) {
- copy_v3_v3(pt->vert_color, brush->rgb);
- pt->vert_color[3] = factor;
+ copy_v3_v3(pt->vert_color, color);
}
}
}
diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h
index 8a8d91a570c..c760b661373 100644
--- a/source/blender/editors/include/ED_gpencil.h
+++ b/source/blender/editors/include/ED_gpencil.h
@@ -391,8 +391,15 @@ struct bGPDstroke *ED_gpencil_stroke_nearest_to_ends(struct bContext *C,
struct bGPDlayer *gpl,
struct bGPDframe *gpf,
struct bGPDstroke *gps,
+ const float ctrl1[2],
+ const float ctrl2[2],
const float radius,
int *r_index);
+void ED_gpencil_stroke_extremes_to2d(const struct GP_SpaceConversion *gsc,
+ const float diff_mat[4][4],
+ struct bGPDstroke *gps,
+ float r_ctrl1[2],
+ float r_ctrl2[2]);
struct bGPDstroke *ED_gpencil_stroke_join_and_trim(struct bGPdata *gpd,
struct bGPDframe *gpf,
diff --git a/source/blender/editors/include/ED_keyframes_keylist.h b/source/blender/editors/include/ED_keyframes_keylist.h
index 3a9750c1206..4194444ca0f 100644
--- a/source/blender/editors/include/ED_keyframes_keylist.h
+++ b/source/blender/editors/include/ED_keyframes_keylist.h
@@ -139,14 +139,20 @@ typedef enum eKeyframeExtremeDrawOpts {
struct AnimKeylist *ED_keylist_create(void);
void ED_keylist_free(struct AnimKeylist *keylist);
-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);
+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_any_between(const struct AnimKeylist *keylist,
const Range2f frame_range);
bool ED_keylist_is_empty(const struct AnimKeylist *keylist);
const struct ListBase /* ActKeyColumn */ *ED_keylist_listbase(const struct AnimKeylist *keylist);
bool ED_keylist_frame_range(const struct AnimKeylist *keylist, Range2f *r_frame_range);
+const ActKeyColumn *ED_keylist_array(const struct AnimKeylist *keylist);
+int64_t ED_keylist_array_len(const struct AnimKeylist *keylist);
/* Key-data Generation --------------- */
@@ -197,8 +203,6 @@ void mask_to_keylist(struct bDopeSheet *ads,
struct AnimKeylist *keylist);
/* ActKeyColumn API ---------------- */
-/* Comparator callback used for ActKeyColumns and cframe float-value pointer */
-short compare_ak_cfraPtr(void *node, void *data);
/* Checks if ActKeyColumn has any block data */
bool actkeyblock_is_valid(const ActKeyColumn *ac);
diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h
index 3f02be64294..65e13b29015 100644
--- a/source/blender/editors/include/ED_object.h
+++ b/source/blender/editors/include/ED_object.h
@@ -287,6 +287,7 @@ float ED_object_new_primitive_matrix(struct bContext *C,
struct Object *obedit,
const float loc[3],
const float rot[3],
+ const float scale[3],
float primmat[4][4]);
/* Avoid allowing too much insane values even by typing
diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h
index 2c958d282f9..cf8dcbd7995 100644
--- a/source/blender/editors/include/ED_view3d.h
+++ b/source/blender/editors/include/ED_view3d.h
@@ -566,6 +566,13 @@ eV3DSelectObjectFilter ED_view3d_select_filter_from_mode(const struct Scene *sce
void view3d_opengl_select_cache_begin(void);
void view3d_opengl_select_cache_end(void);
+int view3d_opengl_select_ex(struct ViewContext *vc,
+ unsigned int *buffer,
+ unsigned int bufsize,
+ const struct rcti *input,
+ eV3DSelectMode select_mode,
+ eV3DSelectObjectFilter select_filter,
+ const bool do_material_slot_selection);
int view3d_opengl_select(struct ViewContext *vc,
unsigned int *buffer,
unsigned int bufsize,
@@ -638,6 +645,9 @@ void ED_view3d_draw_setup_view(const struct wmWindowManager *wm,
struct Base *ED_view3d_give_base_under_cursor(struct bContext *C, const int mval[2]);
struct Object *ED_view3d_give_object_under_cursor(struct bContext *C, const int mval[2]);
+struct Object *ED_view3d_give_material_slot_under_cursor(struct bContext *C,
+ const int mval[2],
+ int *r_material_slot);
bool ED_view3d_is_object_under_cursor(struct bContext *C, const int mval[2]);
void ED_view3d_quadview_update(struct ScrArea *area, struct ARegion *region, bool do_clip);
void ED_view3d_update_viewmat(struct Depsgraph *depsgraph,
diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h
index 15689619c14..0ae3e61293c 100644
--- a/source/blender/editors/include/UI_icons.h
+++ b/source/blender/editors/include/UI_icons.h
@@ -490,9 +490,9 @@ DEF_ICON_MODIFIER(CON_ACTION)
DEF_ICON_BLANK(745)
DEF_ICON_BLANK(746)
DEF_ICON_BLANK(747)
-DEF_ICON_BLANK(748)
-DEF_ICON_BLANK(749)
-DEF_ICON_BLANK(750)
+DEF_ICON_MODIFIER(MOD_LENGTH)
+DEF_ICON_MODIFIER(MOD_DASH)
+DEF_ICON_MODIFIER(MOD_LINEART)
DEF_ICON_BLANK(751)
DEF_ICON(HOLDOUT_OFF)
DEF_ICON(HOLDOUT_ON)
diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h
index 7211cf9f893..916105b0f8e 100644
--- a/source/blender/editors/include/UI_interface.h
+++ b/source/blender/editors/include/UI_interface.h
@@ -2209,6 +2209,11 @@ enum uiTemplateListFlags {
UI_TEMPLATE_LIST_SORT_LOCK = (1 << 1),
/* Don't allow resizing the list, i.e. don't add the grip button. */
UI_TEMPLATE_LIST_NO_GRIP = (1 << 2),
+ /** Do not show filtering options, not even the button to expand/collapse them. Also hides the
+ * grip button. */
+ UI_TEMPLATE_LIST_NO_FILTER_OPTIONS = (1 << 3),
+ /** For #UILST_LAYOUT_BIG_PREVIEW_GRID, don't reserve space for the name label. */
+ UI_TEMPLATE_LIST_NO_NAMES = (1 << 4),
UI_TEMPLATE_LIST_FLAGS_LAST
};
@@ -2289,6 +2294,12 @@ int uiTemplateRecentFiles(struct uiLayout *layout, int rows);
void uiTemplateFileSelectPath(uiLayout *layout,
struct bContext *C,
struct FileSelectParams *params);
+
+enum {
+ UI_TEMPLATE_ASSET_DRAW_NO_NAMES = (1 << 0),
+ UI_TEMPLATE_ASSET_DRAW_NO_FILTER = (1 << 1),
+ UI_TEMPLATE_ASSET_DRAW_NO_LIBRARY = (1 << 2),
+};
void uiTemplateAssetView(struct uiLayout *layout,
struct bContext *C,
const char *list_id,
@@ -2299,6 +2310,7 @@ void uiTemplateAssetView(struct uiLayout *layout,
struct PointerRNA *active_dataptr,
const char *active_propname,
const struct AssetFilterSettings *filter_settings,
+ const int display_flags,
const char *activate_opname,
struct PointerRNA *r_activate_op_properties,
const char *drag_opname,
diff --git a/source/blender/editors/interface/interface_template_asset_view.cc b/source/blender/editors/interface/interface_template_asset_view.cc
index 9b601727e29..f27b37a27de 100644
--- a/source/blender/editors/interface/interface_template_asset_view.cc
+++ b/source/blender/editors/interface/interface_template_asset_view.cc
@@ -46,6 +46,7 @@
struct AssetViewListData {
AssetLibraryReference asset_library_ref;
bScreen *screen;
+ bool show_names;
};
static void asset_view_item_but_drag_set(uiBut *but,
@@ -95,14 +96,15 @@ static void asset_view_draw_item(uiList *ui_list,
uiLayoutSetContextPointer(layout, "asset_handle", itemptr);
uiBlock *block = uiLayoutGetBlock(layout);
+ const bool show_names = list_data->show_names;
/* TODO ED_fileselect_init_layout(). Share somehow? */
const float size_x = (96.0f / 20.0f) * UI_UNIT_X;
- const float size_y = (96.0f / 20.0f) * UI_UNIT_Y;
+ const float size_y = (96.0f / 20.0f) * UI_UNIT_Y - (show_names ? 0 : UI_UNIT_Y);
uiBut *but = uiDefIconTextBut(block,
UI_BTYPE_PREVIEW_TILE,
0,
ED_asset_handle_get_preview_icon_id(asset_handle),
- ED_asset_handle_get_name(asset_handle),
+ show_names ? ED_asset_handle_get_name(asset_handle) : "",
0,
0,
size_x,
@@ -202,6 +204,7 @@ void uiTemplateAssetView(uiLayout *layout,
PointerRNA *active_dataptr,
const char *active_propname,
const AssetFilterSettings *filter_settings,
+ const int display_flags,
const char *activate_opname,
PointerRNA *r_activate_op_properties,
const char *drag_opname,
@@ -220,9 +223,11 @@ void uiTemplateAssetView(uiLayout *layout,
RNA_property_enum_get(asset_library_dataptr, asset_library_prop));
uiLayout *row = uiLayoutRow(col, true);
- uiItemFullR(row, asset_library_dataptr, asset_library_prop, RNA_NO_INDEX, 0, 0, "", 0);
- if (asset_library_ref.type != ASSET_LIBRARY_LOCAL) {
- uiItemO(row, "", ICON_FILE_REFRESH, "ASSET_OT_list_refresh");
+ if ((display_flags & UI_TEMPLATE_ASSET_DRAW_NO_LIBRARY) == 0) {
+ uiItemFullR(row, asset_library_dataptr, asset_library_prop, RNA_NO_INDEX, 0, 0, "", 0);
+ if (asset_library_ref.type != ASSET_LIBRARY_LOCAL) {
+ uiItemO(row, "", ICON_FILE_REFRESH, "ASSET_OT_list_refresh");
+ }
}
ED_assetlist_storage_fetch(&asset_library_ref, C);
@@ -236,6 +241,15 @@ void uiTemplateAssetView(uiLayout *layout,
"AssetViewListData");
list_data->asset_library_ref = asset_library_ref;
list_data->screen = CTX_wm_screen(C);
+ list_data->show_names = (display_flags & UI_TEMPLATE_ASSET_DRAW_NO_NAMES) == 0;
+
+ uiTemplateListFlags template_list_flags = UI_TEMPLATE_LIST_NO_GRIP;
+ if ((display_flags & UI_TEMPLATE_ASSET_DRAW_NO_NAMES) != 0) {
+ template_list_flags |= UI_TEMPLATE_LIST_NO_NAMES;
+ }
+ if ((display_flags & UI_TEMPLATE_ASSET_DRAW_NO_FILTER) != 0) {
+ template_list_flags |= UI_TEMPLATE_LIST_NO_FILTER_OPTIONS;
+ }
/* TODO can we have some kind of model-view API to handle referencing, filtering and lazy loading
* (of previews) of the items? */
@@ -252,7 +266,7 @@ void uiTemplateAssetView(uiLayout *layout,
0,
UILST_LAYOUT_BIG_PREVIEW_GRID,
0,
- UI_TEMPLATE_LIST_NO_GRIP,
+ template_list_flags,
list_data);
if (!list) {
/* List creation failed. */
diff --git a/source/blender/editors/interface/interface_template_list.cc b/source/blender/editors/interface/interface_template_list.cc
index 0ab45ea0f81..8246759ad36 100644
--- a/source/blender/editors/interface/interface_template_list.cc
+++ b/source/blender/editors/interface/interface_template_list.cc
@@ -944,10 +944,16 @@ static void ui_template_list_layout_draw(bContext *C,
/* For scrollbar. */
row = uiLayoutRow(glob, false);
+ const bool show_names = (flags & UI_TEMPLATE_LIST_NO_NAMES) == 0;
+
/* TODO ED_fileselect_init_layout(). Share somehow? */
float size_x = (96.0f / 20.0f) * UI_UNIT_X;
float size_y = (96.0f / 20.0f) * UI_UNIT_Y;
+ if (!show_names) {
+ size_y -= UI_UNIT_Y;
+ }
+
const int cols_per_row = MAX2((uiLayoutGetWidth(box) - V2D_SCROLL_WIDTH) / size_x, 1);
uiLayout *grid = uiLayoutGridFlow(row, true, cols_per_row, true, true, true);
@@ -1033,7 +1039,8 @@ static void ui_template_list_layout_draw(bContext *C,
break;
}
- if (glob) {
+ const bool add_filters_but = (flags & UI_TEMPLATE_LIST_NO_FILTER_OPTIONS) == 0;
+ if (glob && add_filters_but) {
const bool add_grip_but = (flags & UI_TEMPLATE_LIST_NO_GRIP) == 0;
/* About #UI_BTYPE_GRIP drag-resize:
diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c
index 08d78552710..0c9eb20af19 100644
--- a/source/blender/editors/interface/interface_templates.c
+++ b/source/blender/editors/interface/interface_templates.c
@@ -673,8 +673,8 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event)
}
}
else {
- if (BKE_lib_id_make_local(bmain, id, false, 0)) {
- BKE_main_id_newptr_and_tag_clear(bmain);
+ if (BKE_lib_id_make_local(bmain, id, 0)) {
+ BKE_id_newptr_and_tag_clear(id);
/* Reassign to get proper updates/notifiers. */
idptr = RNA_property_pointer_get(&template_ui->ptr, template_ui->prop);
@@ -1031,7 +1031,7 @@ static void template_ID(const bContext *C,
UI_but_flag_enable(but, UI_BUT_DISABLED);
}
else {
- const bool disabled = (!BKE_lib_id_make_local(CTX_data_main(C), id, true /* test */, 0) ||
+ const bool disabled = (!BKE_idtype_idcode_is_localizable(GS(id->name)) ||
(idfrom && idfrom->lib));
but = uiDefIconBut(block,
UI_BTYPE_BUT,
diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c
index a2b86ccd947..0dc7c2d3f9a 100644
--- a/source/blender/editors/interface/interface_widgets.c
+++ b/source/blender/editors/interface/interface_widgets.c
@@ -5443,13 +5443,20 @@ void ui_draw_preview_item_stateless(const uiFontStyle *fstyle,
rcti trect = *rect;
const float text_size = UI_UNIT_Y;
float font_dims[2] = {0.0f, 0.0f};
+ const bool has_text = name && name[0];
- /* draw icon in rect above the space reserved for the label */
- rect->ymin += text_size;
+ if (has_text) {
+ /* draw icon in rect above the space reserved for the label */
+ rect->ymin += text_size;
+ }
GPU_blend(GPU_BLEND_ALPHA);
widget_draw_preview(iconid, 1.0f, rect);
GPU_blend(GPU_BLEND_NONE);
+ if (!has_text) {
+ return;
+ }
+
BLF_width_and_height(
fstyle->uifont_id, name, BLF_DRAW_STR_DUMMY_MAX, &font_dims[0], &font_dims[1]);
diff --git a/source/blender/editors/mesh/editmesh_add.c b/source/blender/editors/mesh/editmesh_add.c
index a64b90e15a3..c826da74010 100644
--- a/source/blender/editors/mesh/editmesh_add.c
+++ b/source/blender/editors/mesh/editmesh_add.c
@@ -73,11 +73,7 @@ static Object *make_prim_init(bContext *C,
r_creation_data->was_editmode = true;
}
- ED_object_new_primitive_matrix(C, obedit, loc, rot, r_creation_data->mat);
-
- if (scale) {
- rescale_m4(r_creation_data->mat, scale);
- }
+ ED_object_new_primitive_matrix(C, obedit, loc, rot, scale, r_creation_data->mat);
return obedit;
}
@@ -351,7 +347,7 @@ static int add_primitive_cylinder_exec(bContext *C, wmOperator *op)
op,
"verts.out",
false,
- "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%b "
+ "create_cone segments=%i radius1=%f radius2=%f cap_ends=%b "
"cap_tris=%b depth=%f matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "vertices"),
RNA_float_get(op->ptr, "radius"),
@@ -427,7 +423,7 @@ static int add_primitive_cone_exec(bContext *C, wmOperator *op)
op,
"verts.out",
false,
- "create_cone segments=%i diameter1=%f diameter2=%f cap_ends=%b "
+ "create_cone segments=%i radius1=%f radius2=%f cap_ends=%b "
"cap_tris=%b depth=%f matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "vertices"),
RNA_float_get(op->ptr, "radius1"),
@@ -642,7 +638,7 @@ static int add_primitive_uvsphere_exec(bContext *C, wmOperator *op)
op,
"verts.out",
false,
- "create_uvsphere u_segments=%i v_segments=%i diameter=%f matrix=%m4 calc_uvs=%b",
+ "create_uvsphere u_segments=%i v_segments=%i radius=%f matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "segments"),
RNA_int_get(op->ptr, "ring_count"),
RNA_float_get(op->ptr, "radius"),
@@ -710,7 +706,7 @@ static int add_primitive_icosphere_exec(bContext *C, wmOperator *op)
op,
"verts.out",
false,
- "create_icosphere subdivisions=%i diameter=%f matrix=%m4 calc_uvs=%b",
+ "create_icosphere subdivisions=%i radius=%f matrix=%m4 calc_uvs=%b",
RNA_int_get(op->ptr, "subdivisions"),
RNA_float_get(op->ptr, "radius"),
creation_data.mat,
diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c
index 01736f2919a..0d74187b50e 100644
--- a/source/blender/editors/mesh/editmesh_bevel.c
+++ b/source/blender/editors/mesh/editmesh_bevel.c
@@ -97,7 +97,6 @@ typedef struct {
int launch_event;
float mcenter[2];
void *draw_handle_pixel;
- short gizmo_flag;
short value_mode; /* Which value does mouse movement and numeric input affect? */
float segments; /* Segments as float so smooth mouse pan works in small increments */
@@ -307,11 +306,6 @@ static bool edbm_bevel_init(bContext *C, wmOperator *op, const bool is_modal)
opdata->draw_handle_pixel = ED_region_draw_cb_activate(
region->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL);
G.moving = G_TRANSFORM_EDIT;
-
- if (v3d) {
- opdata->gizmo_flag = v3d->gizmo_flag;
- v3d->gizmo_flag = V3D_GIZMO_HIDE;
- }
}
return true;
@@ -433,15 +427,11 @@ static void edbm_bevel_exit(bContext *C, wmOperator *op)
}
if (opdata->is_modal) {
- View3D *v3d = CTX_wm_view3d(C);
ARegion *region = CTX_wm_region(C);
for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) {
EDBM_redo_state_free(&opdata->ob_store[ob_index].mesh_backup);
}
ED_region_draw_cb_exit(region->type, opdata->draw_handle_pixel);
- if (v3d) {
- v3d->gizmo_flag = opdata->gizmo_flag;
- }
G.moving = 0;
}
MEM_SAFE_FREE(opdata->ob_store);
diff --git a/source/blender/editors/mesh/editmesh_bisect.c b/source/blender/editors/mesh/editmesh_bisect.c
index 3c8afe8e7db..27a1bf9658f 100644
--- a/source/blender/editors/mesh/editmesh_bisect.c
+++ b/source/blender/editors/mesh/editmesh_bisect.c
@@ -72,7 +72,6 @@ typedef struct {
bool is_dirty;
} * backup;
int backup_len;
- short gizmo_flag;
} BisectData;
static void mesh_bisect_interactive_calc(bContext *C,
@@ -88,6 +87,7 @@ static void mesh_bisect_interactive_calc(bContext *C,
int y_start = RNA_int_get(op->ptr, "ystart");
int x_end = RNA_int_get(op->ptr, "xend");
int y_end = RNA_int_get(op->ptr, "yend");
+ const bool use_flip = RNA_boolean_get(op->ptr, "flip");
/* reference location (some point in front of the view) for finding a point on a plane */
const float *co_ref = rv3d->ofs;
@@ -105,6 +105,9 @@ static void mesh_bisect_interactive_calc(bContext *C,
/* cross both to get a normal */
cross_v3_v3v3(plane_no, co_a, co_b);
normalize_v3(plane_no); /* not needed but nicer for user */
+ if (use_flip) {
+ negate_v3(plane_no);
+ }
/* point on plane, can use either start or endpoint */
ED_view3d_win_to_3d(v3d, region, co_ref, co_a_ss, plane_co);
@@ -116,7 +119,7 @@ static int mesh_bisect_invoke(bContext *C, wmOperator *op, const wmEvent *event)
int valid_objects = 0;
/* If the properties are set or there is no rv3d,
- * skip model and exec immediately. */
+ * skip modal and exec immediately. */
if ((CTX_wm_region_view3d(C) == NULL) || (RNA_struct_property_is_set(op->ptr, "plane_co") &&
RNA_struct_property_is_set(op->ptr, "plane_no"))) {
return mesh_bisect_exec(C, op);
@@ -140,10 +143,19 @@ static int mesh_bisect_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return OPERATOR_CANCELLED;
}
- int ret = WM_gesture_straightline_invoke(C, op, event);
- if (ret & OPERATOR_RUNNING_MODAL) {
- View3D *v3d = CTX_wm_view3d(C);
+ /* Support flipping if side matters. */
+ int ret;
+ const bool clear_inner = RNA_boolean_get(op->ptr, "clear_inner");
+ const bool clear_outer = RNA_boolean_get(op->ptr, "clear_outer");
+ const bool use_fill = RNA_boolean_get(op->ptr, "use_fill");
+ if ((clear_inner != clear_outer) || use_fill) {
+ ret = WM_gesture_straightline_active_side_invoke(C, op, event);
+ }
+ else {
+ ret = WM_gesture_straightline_invoke(C, op, event);
+ }
+ if (ret & OPERATOR_RUNNING_MODAL) {
wmGesture *gesture = op->customdata;
BisectData *opdata;
@@ -166,8 +178,6 @@ static int mesh_bisect_invoke(bContext *C, wmOperator *op, const wmEvent *event)
/* Misc other vars. */
G.moving = G_TRANSFORM_EDIT;
- opdata->gizmo_flag = v3d->gizmo_flag;
- v3d->gizmo_flag = V3D_GIZMO_HIDE;
/* Initialize modal callout. */
ED_workspace_status_text(C, TIP_("LMB: Click and drag to draw cut line"));
@@ -176,10 +186,8 @@ static int mesh_bisect_invoke(bContext *C, wmOperator *op, const wmEvent *event)
return ret;
}
-static void edbm_bisect_exit(bContext *C, BisectData *opdata)
+static void edbm_bisect_exit(BisectData *opdata)
{
- View3D *v3d = CTX_wm_view3d(C);
- v3d->gizmo_flag = opdata->gizmo_flag;
G.moving = 0;
for (int ob_index = 0; ob_index < opdata->backup_len; ob_index++) {
@@ -210,7 +218,7 @@ static int mesh_bisect_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
if (ret & (OPERATOR_FINISHED | OPERATOR_CANCELLED)) {
- edbm_bisect_exit(C, &opdata_back);
+ edbm_bisect_exit(&opdata_back);
#ifdef USE_GIZMO
/* Setup gizmos */
@@ -769,7 +777,7 @@ static void MESH_GGT_bisect(struct wmGizmoGroupType *gzgt)
gzgt->name = "Mesh Bisect";
gzgt->idname = "MESH_GGT_bisect";
- gzgt->flag = WM_GIZMOGROUPTYPE_3D;
+ gzgt->flag = WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_DRAW_MODAL_EXCLUDE;
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c
index 18f51ae9df2..7be169f70f4 100644
--- a/source/blender/editors/mesh/editmesh_inset.c
+++ b/source/blender/editors/mesh/editmesh_inset.c
@@ -76,7 +76,6 @@ typedef struct {
int launch_event;
float mcenter[2];
void *draw_handle_pixel;
- short gizmo_flag;
} InsetData;
static void edbm_inset_update_header(wmOperator *op, bContext *C)
@@ -177,7 +176,6 @@ static bool edbm_inset_init(bContext *C, wmOperator *op, const bool is_modal)
opdata->num_input.unit_type[1] = B_UNIT_LENGTH;
if (is_modal) {
- View3D *v3d = CTX_wm_view3d(C);
ARegion *region = CTX_wm_region(C);
for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) {
@@ -189,10 +187,6 @@ static bool edbm_inset_init(bContext *C, wmOperator *op, const bool is_modal)
opdata->draw_handle_pixel = ED_region_draw_cb_activate(
region->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL);
G.moving = G_TRANSFORM_EDIT;
- if (v3d) {
- opdata->gizmo_flag = v3d->gizmo_flag;
- v3d->gizmo_flag = V3D_GIZMO_HIDE;
- }
}
return true;
@@ -206,15 +200,11 @@ static void edbm_inset_exit(bContext *C, wmOperator *op)
opdata = op->customdata;
if (opdata->is_modal) {
- View3D *v3d = CTX_wm_view3d(C);
ARegion *region = CTX_wm_region(C);
for (uint ob_index = 0; ob_index < opdata->ob_store_len; ob_index++) {
EDBM_redo_state_free(&opdata->ob_store[ob_index].mesh_backup);
}
ED_region_draw_cb_exit(region->type, opdata->draw_handle_pixel);
- if (v3d) {
- v3d->gizmo_flag = opdata->gizmo_flag;
- }
G.moving = 0;
}
diff --git a/source/blender/editors/object/CMakeLists.txt b/source/blender/editors/object/CMakeLists.txt
index 18f2b58eb65..040b5cd5066 100644
--- a/source/blender/editors/object/CMakeLists.txt
+++ b/source/blender/editors/object/CMakeLists.txt
@@ -37,6 +37,9 @@ set(INC
../../../../intern/clog
../../../../intern/glew-mx
../../../../intern/guardedalloc
+
+ # dna_type_offsets.h in BLO_read_write.h
+ ${CMAKE_BINARY_DIR}/source/blender/makesdna/intern
)
set(SRC
@@ -93,3 +96,5 @@ if(WITH_EXPERIMENTAL_FEATURES)
endif()
blender_add_lib(bf_editor_object "${SRC}" "${INC}" "${INC_SYS}" "${LIB}")
+
+add_dependencies(bf_editor_object bf_dna)
diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c
index 2e34284f46e..beadbf2689e 100644
--- a/source/blender/editors/object/object_add.c
+++ b/source/blender/editors/object/object_add.c
@@ -332,8 +332,12 @@ void ED_object_base_init_transform_on_add(Object *object, const float loc[3], co
/* Uses context to figure out transform for primitive.
* Returns standard diameter. */
-float ED_object_new_primitive_matrix(
- bContext *C, Object *obedit, const float loc[3], const float rot[3], float r_primmat[4][4])
+float ED_object_new_primitive_matrix(bContext *C,
+ Object *obedit,
+ const float loc[3],
+ const float rot[3],
+ const float scale[3],
+ float r_primmat[4][4])
{
Scene *scene = CTX_data_scene(C);
View3D *v3d = CTX_wm_view3d(C);
@@ -356,6 +360,10 @@ float ED_object_new_primitive_matrix(
invert_m3_m3(imat, mat);
mul_m3_v3(imat, r_primmat[3]);
+ if (scale != NULL) {
+ rescale_m4(r_primmat, scale);
+ }
+
{
const float dia = v3d ? ED_view3d_grid_scale(scene, v3d, NULL) :
ED_scene_grid_scale(scene, NULL);
@@ -863,7 +871,7 @@ static int effector_add_exec(bContext *C, wmOperator *op)
ED_object_editmode_enter_ex(bmain, scene, ob, 0);
float mat[4][4];
- ED_object_new_primitive_matrix(C, ob, loc, rot, mat);
+ ED_object_new_primitive_matrix(C, ob, loc, rot, NULL, mat);
mul_mat3_m4_fl(mat, dia);
BLI_addtail(&cu->editnurb->nurbs,
ED_curve_add_nurbs_primitive(C, ob, mat, CU_NURBS | CU_PRIM_PATH, 1));
@@ -999,7 +1007,7 @@ static int object_metaball_add_exec(bContext *C, wmOperator *op)
}
float mat[4][4];
- ED_object_new_primitive_matrix(C, obedit, loc, rot, mat);
+ ED_object_new_primitive_matrix(C, obedit, loc, rot, NULL, mat);
/* Halving here is done to account for constant values from #BKE_mball_element_add.
* While the default radius of the resulting meta element is 2,
* we want to pass in 1 so other values such as resolution are scaled by 1.0. */
@@ -1365,30 +1373,28 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op)
case GP_EMPTY: {
float mat[4][4];
- ED_object_new_primitive_matrix(C, ob, loc, rot, mat);
+ ED_object_new_primitive_matrix(C, ob, loc, rot, NULL, mat);
ED_gpencil_create_blank(C, ob, mat);
break;
}
case GP_STROKE: {
float radius = RNA_float_get(op->ptr, "radius");
+ float scale[3];
+ copy_v3_fl(scale, radius);
float mat[4][4];
- ED_object_new_primitive_matrix(C, ob, loc, rot, mat);
- mul_v3_fl(mat[0], radius);
- mul_v3_fl(mat[1], radius);
- mul_v3_fl(mat[2], radius);
+ ED_object_new_primitive_matrix(C, ob, loc, rot, scale, mat);
ED_gpencil_create_stroke(C, ob, mat);
break;
}
case GP_MONKEY: {
float radius = RNA_float_get(op->ptr, "radius");
+ float scale[3];
+ copy_v3_fl(scale, radius);
float mat[4][4];
- ED_object_new_primitive_matrix(C, ob, loc, rot, mat);
- mul_v3_fl(mat[0], radius);
- mul_v3_fl(mat[1], radius);
- mul_v3_fl(mat[2], radius);
+ ED_object_new_primitive_matrix(C, ob, loc, rot, scale, mat);
ED_gpencil_create_monkey(C, ob, mat);
break;
@@ -1397,12 +1403,11 @@ static int object_gpencil_add_exec(bContext *C, wmOperator *op)
case GP_LRT_COLLECTION:
case GP_LRT_OBJECT: {
float radius = RNA_float_get(op->ptr, "radius");
+ float scale[3];
+ copy_v3_fl(scale, radius);
float mat[4][4];
- ED_object_new_primitive_matrix(C, ob, loc, rot, mat);
- mul_v3_fl(mat[0], radius);
- mul_v3_fl(mat[1], radius);
- mul_v3_fl(mat[2], radius);
+ ED_object_new_primitive_matrix(C, ob, loc, rot, scale, mat);
ED_gpencil_create_lineart(C, ob);
@@ -2246,13 +2251,6 @@ static bool dupliobject_instancer_cmp(const void *a_, const void *b_)
return false;
}
-static bool object_has_geometry_set_instances(const Object *object_eval)
-{
- struct GeometrySet *geometry_set = object_eval->runtime.geometry_set_eval;
-
- return (geometry_set != NULL) && BKE_geometry_set_has_instances(geometry_set);
-}
-
static void make_object_duplilist_real(bContext *C,
Depsgraph *depsgraph,
Scene *scene,
@@ -2266,7 +2264,8 @@ static void make_object_duplilist_real(bContext *C,
Object *object_eval = DEG_get_evaluated_object(depsgraph, base->object);
- if (!(base->object->transflag & OB_DUPLI) && !object_has_geometry_set_instances(object_eval)) {
+ if (!(base->object->transflag & OB_DUPLI) &&
+ !BKE_object_has_geometry_set_instances(object_eval)) {
return;
}
diff --git a/source/blender/editors/object/object_constraint.c b/source/blender/editors/object/object_constraint.c
index e0419e0a4cc..8702b18a46f 100644
--- a/source/blender/editors/object/object_constraint.c
+++ b/source/blender/editors/object/object_constraint.c
@@ -1786,7 +1786,8 @@ static bool constraint_copy_to_selected_poll(bContext *C)
if (pchan) {
bool found = false;
- CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, chan, selected_pose_bones, Object *, UNUSED(ob)) {
+ CTX_DATA_BEGIN_WITH_ID (C, bPoseChannel *, chan, selected_pose_bones, Object *, ob) {
+ UNUSED_VARS(ob);
if (pchan != chan) {
/** NOTE: Can not return here, because CTX_DATA_BEGIN_WITH_ID allocated
* a list that needs to be freed by CTX_DATA_END. */
@@ -1862,6 +1863,7 @@ static int constraint_move_down_exec(bContext *C, wmOperator *op)
BLI_remlink(conlist, con);
BLI_insertlinkafter(conlist, nextCon, con);
+ ED_object_constraint_update(CTX_data_main(C), ob);
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
return OPERATOR_FINISHED;
@@ -1917,6 +1919,7 @@ static int constraint_move_up_exec(bContext *C, wmOperator *op)
BLI_remlink(conlist, con);
BLI_insertlinkbefore(conlist, prevCon, con);
+ ED_object_constraint_update(CTX_data_main(C), ob);
WM_event_add_notifier(C, NC_OBJECT | ND_CONSTRAINT, ob);
return OPERATOR_FINISHED;
@@ -1970,6 +1973,8 @@ static int constraint_move_to_index_exec(bContext *C, wmOperator *op)
if (con) {
ED_object_constraint_move_to_index(ob, con, new_index);
+ ED_object_constraint_update(CTX_data_main(C), ob);
+
return OPERATOR_FINISHED;
}
diff --git a/source/blender/editors/object/object_gpencil_modifier.c b/source/blender/editors/object/object_gpencil_modifier.c
index 3995728c428..e3c2932e17a 100644
--- a/source/blender/editors/object/object_gpencil_modifier.c
+++ b/source/blender/editors/object/object_gpencil_modifier.c
@@ -28,6 +28,7 @@
#include "MEM_guardedalloc.h"
+#include "DNA_defaults.h"
#include "DNA_gpencil_modifier_types.h"
#include "DNA_gpencil_types.h"
#include "DNA_object_types.h"
@@ -35,6 +36,7 @@
#include "BLI_listbase.h"
#include "BLI_string_utf8.h"
+#include "BLI_string_utils.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
@@ -55,6 +57,8 @@
#include "ED_object.h"
#include "ED_screen.h"
+#include "BLT_translation.h"
+
#include "UI_interface.h"
#include "WM_api.h"
@@ -939,3 +943,237 @@ void OBJECT_OT_gpencil_modifier_copy_to_selected(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
gpencil_edit_modifier_properties(ot);
}
+
+/************************* Dash Modifier *******************************/
+
+static bool dash_segment_poll(bContext *C)
+{
+ return gpencil_edit_modifier_poll_generic(C, &RNA_DashGpencilModifierData, 0, false);
+}
+
+static bool dash_segment_name_exists_fn(void *arg, const char *name)
+{
+ const DashGpencilModifierData *dmd = (const DashGpencilModifierData *)arg;
+ for (int i = 0; i < dmd->segments_len; i++) {
+ if (STREQ(dmd->segments[i].name, name)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static int dash_segment_add_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_active_context(C);
+ DashGpencilModifierData *dmd = (DashGpencilModifierData *)gpencil_edit_modifier_property_get(
+ op, ob, eGpencilModifierType_Dash);
+
+ const int new_active_index = dmd->segment_active_index + 1;
+ DashGpencilModifierSegment *new_segments = MEM_malloc_arrayN(
+ dmd->segments_len + 1, sizeof(DashGpencilModifierSegment), __func__);
+
+ if (dmd->segments_len != 0) {
+ /* Copy the segments before the new segment. */
+ memcpy(new_segments, dmd->segments, sizeof(DashGpencilModifierSegment) * new_active_index);
+ /* Copy the segments after the new segment. */
+ memcpy(new_segments + new_active_index + 1,
+ dmd->segments + new_active_index,
+ sizeof(DashGpencilModifierSegment) * (dmd->segments_len - new_active_index));
+ }
+
+ /* Create the new segment. */
+ DashGpencilModifierSegment *ds = &new_segments[new_active_index];
+ memcpy(
+ ds, DNA_struct_default_get(DashGpencilModifierSegment), sizeof(DashGpencilModifierSegment));
+ BLI_uniquename_cb(
+ dash_segment_name_exists_fn, dmd, DATA_("Segment"), '.', ds->name, sizeof(ds->name));
+ ds->dmd = dmd;
+
+ MEM_SAFE_FREE(dmd->segments);
+ dmd->segments = new_segments;
+ dmd->segments_len++;
+ dmd->segment_active_index++;
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int dash_segment_add_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (gpencil_edit_modifier_invoke_properties(C, op, NULL, NULL)) {
+ return dash_segment_add_exec(C, op);
+ }
+ return OPERATOR_CANCELLED;
+}
+
+void GPENCIL_OT_segment_add(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Add Segment";
+ ot->description = "Add a segment to the dash modifier";
+ ot->idname = "GPENCIL_OT_segment_add";
+
+ /* api callbacks */
+ ot->poll = dash_segment_poll;
+ ot->invoke = dash_segment_add_invoke;
+ ot->exec = dash_segment_add_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ edit_modifier_properties(ot);
+}
+
+static int dash_segment_remove_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_active_context(C);
+
+ DashGpencilModifierData *dmd = (DashGpencilModifierData *)gpencil_edit_modifier_property_get(
+ op, ob, eGpencilModifierType_Dash);
+
+ if (dmd->segment_active_index < 0 || dmd->segment_active_index >= dmd->segments_len) {
+ return OPERATOR_CANCELLED;
+ }
+
+ if (dmd->segments_len == 1) {
+ MEM_SAFE_FREE(dmd->segments);
+ dmd->segment_active_index = -1;
+ }
+ else {
+ DashGpencilModifierSegment *new_segments = MEM_malloc_arrayN(
+ dmd->segments_len, sizeof(DashGpencilModifierSegment), __func__);
+
+ /* Copy the segments before the deleted segment. */
+ memcpy(new_segments,
+ dmd->segments,
+ sizeof(DashGpencilModifierSegment) * dmd->segment_active_index);
+
+ /* Copy the segments after the deleted segment. */
+ memcpy(new_segments + dmd->segment_active_index,
+ dmd->segments + dmd->segment_active_index + 1,
+ sizeof(DashGpencilModifierSegment) *
+ (dmd->segments_len - dmd->segment_active_index - 1));
+
+ MEM_freeN(dmd->segments);
+ dmd->segments = new_segments;
+ dmd->segment_active_index = MAX2(dmd->segment_active_index - 1, 0);
+ }
+
+ dmd->segments_len--;
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int dash_segment_remove_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (gpencil_edit_modifier_invoke_properties(C, op, NULL, NULL)) {
+ return dash_segment_remove_exec(C, op);
+ }
+ return OPERATOR_CANCELLED;
+}
+
+void GPENCIL_OT_segment_remove(wmOperatorType *ot)
+{
+ /* identifiers */
+ ot->name = "Remove Dash Segment";
+ ot->description = "Remove the active segment from the dash modifier";
+ ot->idname = "GPENCIL_OT_segment_remove";
+
+ /* api callbacks */
+ ot->poll = dash_segment_poll;
+ ot->invoke = dash_segment_remove_invoke;
+ ot->exec = dash_segment_remove_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ edit_modifier_properties(ot);
+
+ RNA_def_int(
+ ot->srna, "index", 0, 0, INT_MAX, "Index", "Index of the segment to remove", 0, INT_MAX);
+}
+
+enum {
+ GP_SEGEMENT_MOVE_UP = -1,
+ GP_SEGEMENT_MOVE_DOWN = 1,
+};
+
+static int dash_segment_move_exec(bContext *C, wmOperator *op)
+{
+ Object *ob = ED_object_active_context(C);
+
+ DashGpencilModifierData *dmd = (DashGpencilModifierData *)gpencil_edit_modifier_property_get(
+ op, ob, eGpencilModifierType_Dash);
+
+ if (dmd->segments_len < 2) {
+ return OPERATOR_CANCELLED;
+ }
+
+ const int direction = RNA_enum_get(op->ptr, "type");
+ if (direction == GP_SEGEMENT_MOVE_UP) {
+ if (dmd->segment_active_index == 0) {
+ return OPERATOR_CANCELLED;
+ }
+
+ SWAP(DashGpencilModifierSegment,
+ dmd->segments[dmd->segment_active_index],
+ dmd->segments[dmd->segment_active_index - 1]);
+
+ dmd->segment_active_index--;
+ }
+ else if (direction == GP_SEGEMENT_MOVE_DOWN) {
+ if (dmd->segment_active_index == dmd->segments_len - 1) {
+ return OPERATOR_CANCELLED;
+ }
+
+ SWAP(DashGpencilModifierSegment,
+ dmd->segments[dmd->segment_active_index],
+ dmd->segments[dmd->segment_active_index + 1]);
+
+ dmd->segment_active_index++;
+ }
+ else {
+ return OPERATOR_CANCELLED;
+ }
+
+ DEG_id_tag_update(&ob->id, ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE);
+ WM_event_add_notifier(C, NC_OBJECT | ND_MODIFIER, ob);
+
+ return OPERATOR_FINISHED;
+}
+
+static int dash_segment_move_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event))
+{
+ if (gpencil_edit_modifier_invoke_properties(C, op, NULL, NULL)) {
+ return dash_segment_move_exec(C, op);
+ }
+ return OPERATOR_CANCELLED;
+}
+
+void GPENCIL_OT_segment_move(wmOperatorType *ot)
+{
+ static const EnumPropertyItem segment_move[] = {
+ {GP_SEGEMENT_MOVE_UP, "UP", 0, "Up", ""},
+ {GP_SEGEMENT_MOVE_DOWN, "DOWN", 0, "Down", ""},
+ {0, NULL, 0, NULL, NULL},
+ };
+
+ /* identifiers */
+ ot->name = "Move Dash Segment";
+ ot->description = "Move the active dash segment up or down";
+ ot->idname = "GPENCIL_OT_segment_move";
+
+ /* api callbacks */
+ ot->poll = dash_segment_poll;
+ ot->invoke = dash_segment_move_invoke;
+ ot->exec = dash_segment_move_exec;
+
+ /* flags */
+ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_INTERNAL;
+ edit_modifier_properties(ot);
+
+ ot->prop = RNA_def_enum(ot->srna, "type", segment_move, 0, "Type", "");
+}
diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h
index 10e016738d0..b2d3216b101 100644
--- a/source/blender/editors/object/object_intern.h
+++ b/source/blender/editors/object/object_intern.h
@@ -202,6 +202,10 @@ void OBJECT_OT_gpencil_modifier_apply(struct wmOperatorType *ot);
void OBJECT_OT_gpencil_modifier_copy(struct wmOperatorType *ot);
void OBJECT_OT_gpencil_modifier_copy_to_selected(struct wmOperatorType *ot);
+void GPENCIL_OT_segment_add(struct wmOperatorType *ot);
+void GPENCIL_OT_segment_remove(struct wmOperatorType *ot);
+void GPENCIL_OT_segment_move(struct wmOperatorType *ot);
+
/* object_shader_fx.c */
void OBJECT_OT_shaderfx_add(struct wmOperatorType *ot);
void OBJECT_OT_shaderfx_copy(struct wmOperatorType *ot);
diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c
index c1928cf7f8a..4b8431be530 100644
--- a/source/blender/editors/object/object_ops.c
+++ b/source/blender/editors/object/object_ops.c
@@ -156,6 +156,10 @@ void ED_operatortypes_object(void)
WM_operatortype_append(OBJECT_OT_gpencil_modifier_copy);
WM_operatortype_append(OBJECT_OT_gpencil_modifier_copy_to_selected);
+ WM_operatortype_append(GPENCIL_OT_segment_add);
+ WM_operatortype_append(GPENCIL_OT_segment_remove);
+ WM_operatortype_append(GPENCIL_OT_segment_move);
+
/* grease pencil line art */
WM_operatortypes_lineart();
diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c
index ec72ff11683..75269dffec8 100644
--- a/source/blender/editors/object/object_relations.c
+++ b/source/blender/editors/object/object_relations.c
@@ -2729,25 +2729,26 @@ char *ED_object_ot_drop_named_material_tooltip(bContext *C,
PointerRNA *properties,
const wmEvent *event)
{
- Object *ob = ED_view3d_give_object_under_cursor(C, event->mval);
+ int mat_slot = 0;
+ Object *ob = ED_view3d_give_material_slot_under_cursor(C, event->mval, &mat_slot);
if (ob == NULL) {
return BLI_strdup("");
}
+ mat_slot = max_ii(mat_slot, 1);
char name[MAX_ID_NAME - 2];
RNA_string_get(properties, "name", name);
- int active_mat_slot = max_ii(ob->actcol, 1);
- Material *prev_mat = BKE_object_material_get(ob, active_mat_slot);
+ Material *prev_mat = BKE_object_material_get(ob, mat_slot);
char *result;
if (prev_mat) {
const char *tooltip = TIP_("Drop %s on %s (slot %d, replacing %s)");
- result = BLI_sprintfN(tooltip, name, ob->id.name + 2, active_mat_slot, prev_mat->id.name + 2);
+ result = BLI_sprintfN(tooltip, name, ob->id.name + 2, mat_slot, prev_mat->id.name + 2);
}
else {
const char *tooltip = TIP_("Drop %s on %s (slot %d)");
- result = BLI_sprintfN(tooltip, name, ob->id.name + 2, active_mat_slot);
+ result = BLI_sprintfN(tooltip, name, ob->id.name + 2, mat_slot);
}
return result;
}
@@ -2755,7 +2756,10 @@ char *ED_object_ot_drop_named_material_tooltip(bContext *C,
static int drop_named_material_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
Main *bmain = CTX_data_main(C);
- Object *ob = ED_view3d_give_object_under_cursor(C, event->mval);
+ int mat_slot = 0;
+ Object *ob = ED_view3d_give_material_slot_under_cursor(C, event->mval, &mat_slot);
+ mat_slot = max_ii(mat_slot, 1);
+
Material *ma;
char name[MAX_ID_NAME - 2];
@@ -2765,9 +2769,7 @@ static int drop_named_material_invoke(bContext *C, wmOperator *op, const wmEvent
return OPERATOR_CANCELLED;
}
- const short active_mat_slot = ob->actcol;
-
- BKE_object_material_assign(CTX_data_main(C), ob, ma, active_mat_slot, BKE_MAT_ASSIGN_USERPREF);
+ BKE_object_material_assign(CTX_data_main(C), ob, ma, mat_slot, BKE_MAT_ASSIGN_USERPREF);
DEG_id_tag_update(&ob->id, ID_RECALC_TRANSFORM);
diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c
index e08a4e946f6..9546035375c 100644
--- a/source/blender/editors/screen/area.c
+++ b/source/blender/editors/screen/area.c
@@ -882,7 +882,7 @@ static void area_azone_init(wmWindow *win, const bScreen *screen, ScrArea *area)
return;
}
- if (U.app_flag & USER_APP_LOCK_UI_LAYOUT) {
+ if (U.app_flag & USER_APP_LOCK_CORNER_SPLIT) {
return;
}
@@ -1058,6 +1058,14 @@ static bool region_azone_edge_poll(const ARegion *region, const bool is_fullscre
return false;
}
+ if (is_hidden && (U.app_flag & USER_APP_HIDE_REGION_TOGGLE)) {
+ return false;
+ }
+
+ if (!is_hidden && (U.app_flag & USER_APP_LOCK_EDGE_RESIZE)) {
+ return false;
+ }
+
return true;
}
diff --git a/source/blender/editors/screen/screen_geometry.c b/source/blender/editors/screen/screen_geometry.c
index 51edad0332b..e67c933cb8e 100644
--- a/source/blender/editors/screen/screen_geometry.c
+++ b/source/blender/editors/screen/screen_geometry.c
@@ -130,6 +130,10 @@ ScrEdge *screen_geom_find_active_scredge(const wmWindow *win,
const int mx,
const int my)
{
+ if (U.app_flag & USER_APP_LOCK_EDGE_RESIZE) {
+ return NULL;
+ }
+
/* Use layout size (screen excluding global areas) for screen-layout area edges */
rcti screen_rect;
WM_window_screen_rect_calc(win, &screen_rect);
diff --git a/source/blender/editors/screen/screen_ops.c b/source/blender/editors/screen/screen_ops.c
index daac196a90c..3efe4ae85d5 100644
--- a/source/blender/editors/screen/screen_ops.c
+++ b/source/blender/editors/screen/screen_ops.c
@@ -1134,14 +1134,22 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
if ((ED_area_actionzone_find_xy(sad->sa1, &event->x) != sad->az) &&
(screen_geom_area_map_find_active_scredge(
AREAMAP_FROM_SCREEN(screen), &screen_rect, event->x, event->y) == NULL)) {
- /* Are we still in same area? */
- if (BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y) == sad->sa1) {
+
+ /* What area are we now in? */
+ ScrArea *area = BKE_screen_find_area_xy(screen, SPACE_TYPE_ANY, event->x, event->y);
+
+ if (area == sad->sa1) {
/* Same area, so possible split. */
WM_cursor_set(win,
SCREEN_DIR_IS_VERTICAL(sad->gesture_dir) ? WM_CURSOR_H_SPLIT :
WM_CURSOR_V_SPLIT);
is_gesture = (delta_max > split_threshold);
}
+ else if (!area || area->global) {
+ /* No area or Top bar or Status bar. */
+ WM_cursor_set(win, WM_CURSOR_STOP);
+ is_gesture = false;
+ }
else {
/* Different area, so possible join. */
if (sad->gesture_dir == SCREEN_DIR_N) {
@@ -1161,7 +1169,7 @@ static int actionzone_modal(bContext *C, wmOperator *op, const wmEvent *event)
}
}
else {
- WM_cursor_set(CTX_wm_window(C), WM_CURSOR_CROSS);
+ WM_cursor_set(win, WM_CURSOR_CROSS);
is_gesture = false;
}
}
@@ -1466,15 +1474,39 @@ static void SCREEN_OT_area_dupli(wmOperatorType *ot)
* Close selected area, replace by expanding a neighbor
* \{ */
-/* operator callback */
-static int area_close_invoke(bContext *C, wmOperator *UNUSED(op), const wmEvent *UNUSED(event))
+/**
+ * \note This can be used interactively or from Python.
+ *
+ * \note Most of the window management operators don't support execution from Python.
+ * An exception is made for closing areas since it allows application templates
+ * to customize the layout.
+ */
+static int area_close_exec(bContext *C, wmOperator *op)
{
+ bScreen *screen = CTX_wm_screen(C);
ScrArea *area = CTX_wm_area(C);
- if ((area != NULL) && screen_area_close(C, CTX_wm_screen(C), area)) {
- WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
- return OPERATOR_FINISHED;
+
+ /* This operator is scriptable, so the area passed could be invalid. */
+ if (BLI_findindex(&screen->areabase, area) == -1) {
+ BKE_report(op->reports, RPT_ERROR, "Area not found in the active screen");
+ return OPERATOR_CANCELLED;
}
- return OPERATOR_CANCELLED;
+
+ if (!screen_area_close(C, screen, area)) {
+ BKE_report(op->reports, RPT_ERROR, "Unable to close area");
+ return OPERATOR_CANCELLED;
+ }
+
+ /* Ensure the event loop doesn't attempt to continue handling events.
+ *
+ * This causes execution from the Python console fail to return to the prompt as it should.
+ * This glitch could be solved in the event loop handling as other operators may also
+ * destructively manipulate windowing data. */
+ CTX_wm_window_set(C, NULL);
+
+ WM_event_add_notifier(C, NC_SCREEN | NA_EDITED, NULL);
+
+ return OPERATOR_FINISHED;
}
static bool area_close_poll(bContext *C)
@@ -1506,7 +1538,7 @@ static void SCREEN_OT_area_close(wmOperatorType *ot)
ot->name = "Close Area";
ot->description = "Close selected area";
ot->idname = "SCREEN_OT_area_close";
- ot->invoke = area_close_invoke;
+ ot->exec = area_close_exec;
ot->poll = area_close_poll;
}
@@ -3075,6 +3107,7 @@ static int keyframe_jump_exec(bContext *C, wmOperator *op)
mask_to_keylist(&ads, masklay, keylist);
}
}
+ ED_keylist_prepare_for_direct_access(keylist);
/* find matching keyframe in the right direction */
const ActKeyColumn *ak;
diff --git a/source/blender/editors/sculpt_paint/paint_mask.c b/source/blender/editors/sculpt_paint/paint_mask.c
index 53d85b33a5b..9a5d4de3ebd 100644
--- a/source/blender/editors/sculpt_paint/paint_mask.c
+++ b/source/blender/editors/sculpt_paint/paint_mask.c
@@ -1327,6 +1327,7 @@ static void sculpt_gesture_apply_trim(SculptGestureContext *sgcontext)
sculpt_mesh);
BM_mesh_free(bm);
result->runtime.cd_dirty_vert |= CD_MASK_NORMAL;
+ BKE_mesh_normals_tag_dirty(result);
BKE_mesh_nomain_to_mesh(
result, sgcontext->vc.obact->data, sgcontext->vc.obact, &CD_MASK_MESH, true);
}
diff --git a/source/blender/editors/sculpt_paint/sculpt_brush_machine.c b/source/blender/editors/sculpt_paint/sculpt_brush_machine.c
index 0f3b542f0e0..b4771bd783d 100644
--- a/source/blender/editors/sculpt_paint/sculpt_brush_machine.c
+++ b/source/blender/editors/sculpt_paint/sculpt_brush_machine.c
@@ -1,4 +1,4 @@
-#if 0
+#if 1
# include "MEM_guardedalloc.h"
# include "BLI_alloca.h"
@@ -10,53 +10,307 @@
# include "BLI_math.h"
# include "BLI_memarena.h"
+# include "DNA_brush_enums.h"
+# include "DNA_brush_types.h"
+# include "DNA_color_types.h"
+# include "DNA_curveprofile_types.h"
# include "DNA_node_types.h"
+# include "BKE_brush.h"
+# include "BKE_colorband.h"
+# include "BKE_colortools.h"
# include "BKE_context.h"
# include "BKE_node.h"
+# include "BKE_paint.h"
+
+# include "BKE_curveprofile.h"
+
+# define MAX_BRUSH_COMMAND_PARAMS 16
+# define MAX_BRUSH_CHANNEL_CURVES 3
+
+enum {
+ BRUSH_CHANNEL_RADIUS = 1 << 0,
+ BRUSH_CHANNEL_STRENGTH = 1 << 1,
+ BRUSH_CHANNEL_CLOTH_TYPE = 1 << 2, // int
+ BRUSH_CHANNEL_RADIUS_SCALE = 1 << 3,
+ // BRUSH_CHANNEL_ITERATIONS = 1 << 3, // int
+ // BRUSH_CHANNEL_BOUNDARY_TYPE = 1 << 4,
+ // BRUSH_CHANNEL_AUTOMASKING_TYPE = 1 << 5,
+ CHANNEL_CUSTOM = 1 << 20
+};
+
+typedef struct BrushChannel {
+ int type;
+ char name[32]; // for custom types
+
+ float value;
+ CurveMapping curves[MAX_BRUSH_CHANNEL_CURVES];
+ int flag;
+} BrushChannel;
+
+# define MAX_BRUSH_ENUM_DEF 32
+
+typedef struct BrushEnumDef {
+ EnumPropertyItem items[MAX_BRUSH_ENUM_DEF];
+} BrushEnumDef;
+
+typedef struct BrushChannelType {
+ char name[32];
+ int channel;
+ float min, max, softmin, softmax;
+ int curve_presets[MAX_BRUSH_CHANNEL_CURVES];
+ int type, subtype;
+ BrushEnumDef enumdef; // if an enum type
+} BrushChannelType;
+
+// curves
+enum { BRUSH_CHANNEL_PRESSURE, BRUSH_CHANNEL_XTILT, BRUSH_CHANNEL_YTILT };
+
+enum {
+ BRUSH_CHANNEL_FLOAT = 1 << 0,
+ BRUSH_CHANNEL_INT = 1 << 1,
+ BRUSH_CHANNEL_ENUM = 1 << 0 // subtype
+};
+
+/* BrushChannel->flag */
+enum {
+ /*float only flags*/
+ BRUSH_CHANNEL_USE_PRESSURE = 1 << 0,
+ BRUSH_CHANNEL_INV_PRESSURE = 1 << 1,
+ BRUSH_CHANNEL_USE_TILT = 1 << 2,
+};
+
+/*
+Brush command lists.
+
+Command lists are built dynamically from
+brush flags, pen input settings, etc.
+
+Eventually they will be generated by node
+networks. BrushCommandPreset will be
+generated from the node group inputs.
+*/
+
+typedef struct BrushCommandPreset {
+ char name[64];
+ int tool;
+
+ struct {
+ char name[32];
+ int type;
+ float defval;
+ BrushChannelType *custom_type;
+ } channels[32];
+} BrushCommandPreset;
+
+/* clang-format off */
+BrushCommandPreset DrawBrush = {
+ .name = "Draw",
+ .tool = SCULPT_TOOL_DRAW,
+ .channels = {
+ {.name = "Radius", .type = BRUSH_CHANNEL_RADIUS, .defval = 50.0f},
+ {.name = "Strength", .type = BRUSH_CHANNEL_STRENGTH, .defval = 1.0f},
+ {.name = "Autosmooth", .type = BRUSH_CHANNEL_STRENGTH, .defval = 0.0f},
+ {.name = "Autosmooth Radius Scale", .type = BRUSH_CHANNEL_RADIUS_SCALE, .defval = 1.0f},
+ {.name = "Topology Rake", .type = BRUSH_CHANNEL_STRENGTH, .defval = 0.0f},
+ {.name = "Topology Rake Radius Scale", .type = BRUSH_CHANNEL_RADIUS_SCALE, .defval = 1.0f},
+ {.type = -1}
+ }
+};
+
+typedef struct BrushCommand {
+ int tool;
+ BrushChannel params[MAX_BRUSH_COMMAND_PARAMS];
+ int totparam;
+} BrushCommand;
+
+typedef struct BrushCommandList {
+ BrushCommand *commands;
+ int totcommand;
+} BrushCommandList;
+
+static BrushChannelType brush_builtin_channels[] = {
+ {.name = "Radius",
+ .channel = BRUSH_CHANNEL_RADIUS,
+ .type = BRUSH_CHANNEL_FLOAT,
+ .min = 0.001,
+ .max = 1024,
+ .softmin = 0.001,
+ .softmax = 700,
+ .curve_presets = {CURVE_PRESET_SMOOTH}},
+ {.name = "Strength",
+ .channel = BRUSH_CHANNEL_STRENGTH,
+ .type = BRUSH_CHANNEL_FLOAT,
+ .min = 0.001,
+ .max = 1024,
+ .softmin = 0.001,
+ .softmax = 700,
+ .curve_presets = {CURVE_PRESET_SMOOTH}},
+ {.name = "Cloth Deform Type",
+ .channel = BRUSH_CHANNEL_CLOTH_TYPE,
+ .type = BRUSH_CHANNEL_INT,
+ .subtype = BRUSH_CHANNEL_ENUM,
+ .enumdef =
+ {
+ {BRUSH_CLOTH_DEFORM_DRAG, "DRAG", 0, "Drag", ""},
+ {BRUSH_CLOTH_DEFORM_PUSH, "PUSH", 0, "Push", ""},
+ {BRUSH_CLOTH_DEFORM_PINCH_POINT, "PINCH_POINT", 0, "Pinch Point", ""},
+ {BRUSH_CLOTH_DEFORM_PINCH_PERPENDICULAR,
+ "PINCH_PERPENDICULAR",
+ 0,
+ "Pinch Perpendicular",
+ ""},
+ {BRUSH_CLOTH_DEFORM_INFLATE, "INFLATE", 0, "Inflate", ""},
+ {BRUSH_CLOTH_DEFORM_GRAB, "GRAB", 0, "Grab", ""},
+ {BRUSH_CLOTH_DEFORM_EXPAND, "EXPAND", 0, "Expand", ""},
+ {BRUSH_CLOTH_DEFORM_SNAKE_HOOK, "SNAKE_HOOK", 0, "Snake Hook", ""},
+ {0, NULL, 0, NULL, NULL},
+ }},
+ {.name = "Radius Scale",
+ .channel = BRUSH_CHANNEL_RADIUS,
+ .type = BRUSH_CHANNEL_FLOAT,
+ .min = 0.001,
+ .max = 15.0,
+ .softmin = 0.1,
+ .softmax = 4.0,
+ .curve_presets = {CURVE_PRESET_SMOOTH}}};
+
+enum {
+ BRUSH_COMMAND_TOPOLOGY_RAKE = 500,
+ BRUSH_COMMAND_DYNTOPO = 501,
+ BRUSH_COMMAND_SMOOTH_LAP = 502,
+ BRUSH_COMMAND_SMOOTH_SURFACE = 503,
+};
+
+/* clang-format on */
enum {
- OP_MATH,
- OP_COERCE,
- OP_TOOL,
- OP_CURVE_MAP,
- OP_DYNTOPO,
- OP_PEN_INPUT,
- OP_PUSH,
- OP_POP,
- OP_POP_REG,
- OP_PUSH_REG,
- OP_LOAD_REG,
- OP_STORE_REG
-};
-
-# define MAX_BRUSH_OP_ARGS 8
-# define MAX_BRUSH_REGISTERS 128
-
-typedef union BrushOpArg {
+ SCULPT_OP_INT = 1 << 0,
+ SCULPT_OP_FLOAT = 1 << 1,
+ SCULPT_OP_VEC2 = 1 << 2,
+ SCULPT_OP_VEC3 = 1 << 3,
+ SCULPT_OP_VEC4 = 1 << 4,
+ SCULPT_OP_VEC5 = 1 << 5,
+ SCULPT_OP_PTR = 1 << 6
+};
+
+typedef union SculptReg {
float f;
int i;
+ float v[5];
void *p;
- char *s;
- float v[4];
-} BrushOpArg;
+ char ch[32];
+ // BrushChannel *ch;
+} SculptReg;
-typedef struct BrushOpCode {
+typedef struct SculptOpCode {
int code;
+ SculptReg params[16];
+} SculptOpCode;
+
+# define SCULPT_MAXREG 32
+
+typedef struct SculptVM {
+ SculptOpCode *opcodes;
+ int totopcode;
+ SculptReg regs[SCULPT_MAXREG];
+};
+
+enum {
+ SOP_LOADF = 0, // reg, float
+ SOP_LOADI,
+ SOP_LOADF2, // reg, float, float
+ SOP_LOADF3, // reg, float, float, float
+ SOP_LOADF4, // reg, float, float, float, float
+ SOP_LOADPTR, // reg, ptr
+
+ SOP_PUSH, // reg
+ SOP_POP, // reg
+ SOP_POP_DISCARD, //
+ SOP_MUL, // dstreg reg reg
+ SOP_ADD, // dstreg reg reg
+ SOP_SUB, // dstreg reg reg
+ SOP_DIV, // dstreg reg reg
+
+ SOP_LOAD_CHANNEL_F, // reg channel
+ SOP_LOAD_CHANNEL_I, // reg channel
+ SOP_TOOL_EXEC, // tool, ...
+};
+
+# define BRUSH_VALUE_DEFAULT FLT_MAX;
+
+/* clang-format off */
+#define REG_RADIUS 10
+#define REG_STRENGTH 11
+#define REG_AUTOSMOOTH 12
+#define REG_TOPORAKE 13
+
+#define OP(op) {op},
+#define OP_I_CH(op, i1, ch1) {op, {{.i = i1}, {.ch = ch1}, {.i = -1}}},
+#define OP_I(op, i1, i2) {op, {{.i = i1}, {.i = -1}}},
+#define OP_I2(op, i1, i2) {op, {{.i = i1}, {.i = i2}, {.i = -1}}},
+#define OP_I3(op, i1, i2, i3) {op, {{.i = i1}, {.i = i2}, {.i = i3}, {.i = -1}}},
+#define OP_I4(op, i1, i2, i3, i4) {op, {{.i = i1}, {.i = i2}, {.i = i3}, {.i = i4}, {.i = -1}}},
+
+SculptOpCode preset[] = {
+ OP_I_CH(SOP_LOAD_CHANNEL_F, REG_RADIUS, "Radius")
+ OP_I_CH(SOP_LOAD_CHANNEL_F, REG_STRENGTH, "Strength")
+ OP_I3(SOP_TOOL_EXEC, SCULPT_TOOL_DRAW, REG_RADIUS, REG_STRENGTH)
+
+ OP_I_CH(SOP_LOAD_CHANNEL_F, REG_AUTOSMOOTH, "Radius")
+ OP_I_CH(SOP_LOAD_CHANNEL_F, REG_AUTOSMOOTH, "Autosmooth Radius Scale")
+ OP_I3(SOP_MUL, REG_AUTOSMOOTH, REG_AUTOSMOOTH, REG_RADIUS)
+};
+
+typedef struct GraphNode {
+ char name[32];
+ char id[32];
+
+ struct {
+ char src[32];
+ char node[32];
+ char dst[32];
+ } inputs[32];
+} GraphNode;
+
+/* node preset solution b:
+
+from brush_builder import Builder;
+
+def build(input, output):
+ input.add("Strength", "float", "strength").range(0.0, 3.0)
+ input.add("Radius", "float", "radius").range(0.01, 1024.0)
+ input.add("Autosmooth", "float", "autosmooth").range(0.0, 4.0)
+ input.add("Topology Rake", "float", "topology rake").range(0.0, 4.0)
+ input.add("Smooth Radius Scale", "float", "autosmooth_radius_scale").range(0.01, 5.0)
+ input.add("Rake Radius Scale", "float", "toporake_radius_scale").range(0.01, 5.0)
+
+ draw = input.make.tool("DRAW")
+ draw.radius = input.radius
+ draw.strength = input.strength
+
+ smooth = input.make.tool("SMOOTH")
+ smooth.radius = input.radius * input.autosmooth_radius_scale
+ smooth.strength = input.autosmooth;
+ smooth.flow = draw.outflow
+
+ rake = input.make.tool("TOPORAKE")
+ rake.radius = input.radius * input.toporake_radius_scale
+ rake.strength = input.topology;
+ rake.flow = smooth.outflow
+
+ output.out = rake.outflow
- BrushOpArg args[MAX_BRUSH_OP_ARGS];
-} BrushOpCode;
+preset = Builder(build)
-typedef struct SculptBrushVM {
- BrushOpCode *codes;
- int totcode;
+*/
- BrushOpArg registers[MAX_BRUSH_REGISTERS];
- BLI_
-} SculptBrushVM;
-void SculptVM_AppendOp(SculptBrushVM *vm, BrushOpArg arg)
-{
-}
+/*
+bNodeType sculpt_tool_node = {
+ .idname = "SculptTool",
+ .ui_name = "SculptTool",
+};*/
+/* cland-format on */
#endif
diff --git a/source/blender/editors/space_action/action_edit.c b/source/blender/editors/space_action/action_edit.c
index 6f4e295cbb2..3e38be243c9 100644
--- a/source/blender/editors/space_action/action_edit.c
+++ b/source/blender/editors/space_action/action_edit.c
@@ -192,7 +192,7 @@ static bool get_keyframe_extents(bAnimContext *ac, float *min, float *max, const
bGPDlayer *gpl = ale->data;
bGPDframe *gpf;
- /* find gp-frame which is less than or equal to cframe */
+ /* Find gp-frame which is less than or equal to current-frame. */
for (gpf = gpl->frames.first; gpf; gpf = gpf->next) {
const float framenum = (float)gpf->framenum;
*min = min_ff(*min, framenum);
@@ -204,7 +204,7 @@ static bool get_keyframe_extents(bAnimContext *ac, float *min, float *max, const
MaskLayer *masklay = ale->data;
MaskLayerShape *masklay_shape;
- /* find mask layer which is less than or equal to cframe */
+ /* Find mask layer which is less than or equal to current-frame. */
for (masklay_shape = masklay->splines_shapes.first; masklay_shape;
masklay_shape = masklay_shape->next) {
const float framenum = (float)masklay_shape->frame;
diff --git a/source/blender/editors/space_action/action_select.c b/source/blender/editors/space_action/action_select.c
index 9dcfc626a50..a5e75e31e38 100644
--- a/source/blender/editors/space_action/action_select.c
+++ b/source/blender/editors/space_action/action_select.c
@@ -162,6 +162,7 @@ static void actkeys_find_key_in_list_element(bAnimContext *ac,
struct AnimKeylist *keylist = ED_keylist_create();
actkeys_list_element_to_keylist(ac, keylist, ale);
+ ED_keylist_prepare_for_direct_access(keylist);
AnimData *adt = ANIM_nla_mapping_get(ac, ale);
diff --git a/source/blender/editors/space_file/filelist.c b/source/blender/editors/space_file/filelist.c
index c7d23943b6c..511b5b255e9 100644
--- a/source/blender/editors/space_file/filelist.c
+++ b/source/blender/editors/space_file/filelist.c
@@ -1442,7 +1442,9 @@ static void filelist_cache_preview_runf(TaskPool *__restrict pool, void *taskdat
if (preview->in_memory_preview) {
if (BKE_previewimg_is_finished(preview->in_memory_preview, ICON_SIZE_PREVIEW)) {
ImBuf *imbuf = BKE_previewimg_to_imbuf(preview->in_memory_preview, ICON_SIZE_PREVIEW);
- preview->icon_id = BKE_icon_imbuf_create(imbuf);
+ if (imbuf) {
+ preview->icon_id = BKE_icon_imbuf_create(imbuf);
+ }
done = true;
}
}
@@ -1953,7 +1955,9 @@ static FileDirEntry *filelist_file_create_entry(FileList *filelist, const int in
if (entry->local_data.preview_image &&
BKE_previewimg_is_finished(entry->local_data.preview_image, ICON_SIZE_PREVIEW)) {
ImBuf *ibuf = BKE_previewimg_to_imbuf(entry->local_data.preview_image, ICON_SIZE_PREVIEW);
- ret->preview_icon_id = BKE_icon_imbuf_create(ibuf);
+ if (ibuf) {
+ ret->preview_icon_id = BKE_icon_imbuf_create(ibuf);
+ }
}
BLI_addtail(&cache->cached_entries, ret);
return ret;
diff --git a/source/blender/editors/space_file/filesel.c b/source/blender/editors/space_file/filesel.c
index 4ab7014cf82..11b06d2b414 100644
--- a/source/blender/editors/space_file/filesel.c
+++ b/source/blender/editors/space_file/filesel.c
@@ -135,7 +135,8 @@ static void fileselect_ensure_updated_asset_params(SpaceFile *sfile)
base_params->filter_id = FILTER_ID_OB | FILTER_ID_GR;
base_params->display = FILE_IMGDISPLAY;
base_params->sort = FILE_SORT_ALPHA;
- base_params->recursion_level = 1;
+ /* Asset libraries include all sub-directories, so enable maximal recursion. */
+ base_params->recursion_level = FILE_SELECT_MAX_RECURSIONS;
/* 'SMALL' size by default. More reasonable since this is typically used as regular editor,
* space is more of an issue here. */
base_params->thumbnail_size = 96;
diff --git a/source/blender/editors/space_graph/graph_slider_ops.c b/source/blender/editors/space_graph/graph_slider_ops.c
index 10629caa8b0..f04336cab84 100644
--- a/source/blender/editors/space_graph/graph_slider_ops.c
+++ b/source/blender/editors/space_graph/graph_slider_ops.c
@@ -41,6 +41,7 @@
#include "ED_keyframes_edit.h"
#include "ED_numinput.h"
#include "ED_screen.h"
+#include "ED_util.h"
#include "WM_api.h"
#include "WM_types.h"
@@ -94,6 +95,8 @@ typedef struct tDecimateGraphOp {
/** The original bezt curve data (used for restoring fcurves). */
ListBase bezt_arr_list;
+ struct tSlider *slider;
+
NumInput num;
} tDecimateGraphOp;
@@ -161,6 +164,8 @@ static void decimate_exit(bContext *C, wmOperator *op)
ScrArea *area = dgo->area;
LinkData *link;
+ ED_slider_destroy(C, dgo->slider);
+
for (link = dgo->bezt_arr_list.first; link != NULL; link = link->next) {
tBeztCopyData *copy = link->data;
MEM_freeN(copy->bezt);
@@ -178,11 +183,14 @@ static void decimate_exit(bContext *C, wmOperator *op)
op->customdata = NULL;
}
-/* Draw a percentage indicator in header. */
-static void decimate_draw_status_header(wmOperator *op, tDecimateGraphOp *dgo)
+/* Draw a percentage indicator in workspace footer. */
+static void decimate_draw_status(bContext *C, tDecimateGraphOp *dgo)
{
char status_str[UI_MAX_DRAW_STR];
char mode_str[32];
+ char slider_string[UI_MAX_DRAW_STR];
+
+ ED_slider_status_string_get(dgo->slider, slider_string, UI_MAX_DRAW_STR);
strcpy(mode_str, TIP_("Decimate Keyframes"));
@@ -194,23 +202,10 @@ static void decimate_draw_status_header(wmOperator *op, tDecimateGraphOp *dgo)
BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, str_ofs);
}
else {
- float percentage = RNA_property_float_get(op->ptr, dgo->percentage_prop);
- BLI_snprintf(
- status_str, sizeof(status_str), "%s: %d %%", mode_str, (int)(percentage * 100.0f));
+ BLI_snprintf(status_str, sizeof(status_str), "%s: %s", mode_str, slider_string);
}
- ED_area_status_text(dgo->area, status_str);
-}
-
-/* Calculate percentage based on position of mouse (we only use x-axis for now.
- * Since this is more convenient for users to do), and store new percentage value.
- */
-static void decimate_mouse_update_percentage(tDecimateGraphOp *dgo,
- wmOperator *op,
- const wmEvent *event)
-{
- float percentage = (event->x - dgo->region->winrct.xmin) / ((float)dgo->region->winx);
- RNA_property_float_set(op->ptr, dgo->percentage_prop, percentage);
+ ED_workspace_status_text(C, status_str);
}
static int graphkeys_decimate_invoke(bContext *C, wmOperator *op, const wmEvent *event)
@@ -234,10 +229,11 @@ static int graphkeys_decimate_invoke(bContext *C, wmOperator *op, const wmEvent
dgo->area = CTX_wm_area(C);
dgo->region = CTX_wm_region(C);
- /* Initialize percentage so that it will have the correct value before the first mouse move. */
- decimate_mouse_update_percentage(dgo, op, event);
+ dgo->slider = ED_slider_create(C);
+ ED_slider_init(dgo->slider, event);
+ ED_slider_allow_overshoot_set(dgo->slider, false);
- decimate_draw_status_header(op, dgo);
+ decimate_draw_status(C, dgo);
/* Construct a list with the original bezt arrays so we can restore them during modal operation.
*/
@@ -300,13 +296,14 @@ static void graphkeys_decimate_modal_update(bContext *C, wmOperator *op)
* (e.g. pressing a key or moving the mouse). */
tDecimateGraphOp *dgo = op->customdata;
- decimate_draw_status_header(op, dgo);
+ decimate_draw_status(C, dgo);
/* Reset keyframe data (so we get back to the original state). */
decimate_reset_bezts(dgo);
/* Apply... */
- float remove_ratio = RNA_property_float_get(op->ptr, dgo->percentage_prop);
+ float remove_ratio = ED_slider_factor_get(dgo->slider);
+ RNA_property_float_set(op->ptr, dgo->percentage_prop, remove_ratio);
/* We don't want to limit the decimation to a certain error margin. */
const float error_sq_max = FLT_MAX;
decimate_graph_keys(&dgo->ac, remove_ratio, error_sq_max);
@@ -323,6 +320,8 @@ static int graphkeys_decimate_modal(bContext *C, wmOperator *op, const wmEvent *
const bool has_numinput = hasNumInput(&dgo->num);
+ ED_slider_modal(dgo->slider, event);
+
switch (event->type) {
case LEFTMOUSE: /* Confirm */
case EVT_RETKEY:
@@ -353,9 +352,6 @@ static int graphkeys_decimate_modal(bContext *C, wmOperator *op, const wmEvent *
case MOUSEMOVE: /* Calculate new position. */
{
if (has_numinput == false) {
- /* Update percentage based on position of mouse. */
- decimate_mouse_update_percentage(dgo, op, event);
-
/* Update pose to reflect the new values. */
graphkeys_decimate_modal_update(C, op);
}
diff --git a/source/blender/editors/space_image/space_image.c b/source/blender/editors/space_image/space_image.c
index 4107fd619aa..de8e4684d45 100644
--- a/source/blender/editors/space_image/space_image.c
+++ b/source/blender/editors/space_image/space_image.c
@@ -461,7 +461,7 @@ static void IMAGE_GGT_gizmo2d(wmGizmoGroupType *gzgt)
gzgt->name = "UV Transform Gizmo";
gzgt->idname = "IMAGE_GGT_gizmo2d";
- gzgt->flag |= (WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
+ gzgt->flag |= (WM_GIZMOGROUPTYPE_DRAW_MODAL_EXCLUDE | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK);
gzgt->gzmap_params.spaceid = SPACE_IMAGE;
@@ -475,7 +475,7 @@ static void IMAGE_GGT_gizmo2d_translate(wmGizmoGroupType *gzgt)
gzgt->name = "UV Translate Gizmo";
gzgt->idname = "IMAGE_GGT_gizmo2d_translate";
- gzgt->flag |= (WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
+ gzgt->flag |= (WM_GIZMOGROUPTYPE_DRAW_MODAL_EXCLUDE | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK);
gzgt->gzmap_params.spaceid = SPACE_IMAGE;
@@ -489,7 +489,7 @@ static void IMAGE_GGT_gizmo2d_resize(wmGizmoGroupType *gzgt)
gzgt->name = "UV Transform Gizmo Resize";
gzgt->idname = "IMAGE_GGT_gizmo2d_resize";
- gzgt->flag |= (WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
+ gzgt->flag |= (WM_GIZMOGROUPTYPE_DRAW_MODAL_EXCLUDE | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK);
gzgt->gzmap_params.spaceid = SPACE_IMAGE;
@@ -503,7 +503,7 @@ static void IMAGE_GGT_gizmo2d_rotate(wmGizmoGroupType *gzgt)
gzgt->name = "UV Transform Gizmo Resize";
gzgt->idname = "IMAGE_GGT_gizmo2d_rotate";
- gzgt->flag |= (WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
+ gzgt->flag |= (WM_GIZMOGROUPTYPE_DRAW_MODAL_EXCLUDE | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK);
gzgt->gzmap_params.spaceid = SPACE_IMAGE;
diff --git a/source/blender/editors/space_node/drawnode.cc b/source/blender/editors/space_node/drawnode.cc
index 0f7a911e3ce..4b859de0ac9 100644
--- a/source/blender/editors/space_node/drawnode.cc
+++ b/source/blender/editors/space_node/drawnode.cc
@@ -362,8 +362,12 @@ static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float asp
float x = BLI_rctf_cent_x(rct) - (0.5f * width);
float y = rct->ymax - label_height;
- BLF_position(fontid, x, y, 0);
- BLF_draw(fontid, label, BLF_DRAW_STR_DUMMY_MAX);
+ /* label */
+ 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);
+ }
/* draw text body */
if (node->id) {
@@ -374,7 +378,8 @@ static void node_draw_frame_label(bNodeTree *ntree, bNode *node, const float asp
/* 'x' doesn't need aspect correction */
x = rct->xmin + margin;
- y = rct->ymax - (label_height + line_spacing);
+ y = rct->ymax - label_height - (has_label ? line_spacing : 0);
+
/* early exit */
int y_min = y + ((margin * 2) - (y - rct->ymin));
@@ -455,10 +460,8 @@ static void node_draw_frame(const bContext *C,
UI_draw_roundbox_aa(rct, false, BASIS_RAD, color);
}
- /* label */
- if (node->label[0] != '\0') {
- node_draw_frame_label(ntree, node, snode->runtime->aspect);
- }
+ /* label and text */
+ node_draw_frame_label(ntree, node, snode->runtime->aspect);
UI_block_end(C, node->block);
UI_block_draw(C, node->block);
diff --git a/source/blender/editors/space_node/node_add.cc b/source/blender/editors/space_node/node_add.cc
index 9264c9d3572..4d2e00e97a1 100644
--- a/source/blender/editors/space_node/node_add.cc
+++ b/source/blender/editors/space_node/node_add.cc
@@ -575,7 +575,7 @@ static int node_add_texture_exec(bContext *C, wmOperator *op)
bNode *texture_node = node_add_node(C,
nullptr,
- GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE,
+ GEO_NODE_LEGACY_ATTRIBUTE_SAMPLE_TEXTURE,
snode->runtime->cursor[0],
snode->runtime->cursor[1]);
if (!texture_node) {
diff --git a/source/blender/editors/space_node/node_draw.cc b/source/blender/editors/space_node/node_draw.cc
index 5b4e3b3b6f5..aa241071425 100644
--- a/source/blender/editors/space_node/node_draw.cc
+++ b/source/blender/editors/space_node/node_draw.cc
@@ -41,10 +41,12 @@
#include "BLI_span.hh"
#include "BLI_string_ref.hh"
#include "BLI_vector.hh"
+#include "BLI_vector_set.hh"
#include "BLT_translation.h"
#include "BKE_context.h"
+#include "BKE_geometry_set.hh"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
#include "BKE_main.h"
@@ -78,6 +80,8 @@
#include "NOD_geometry_nodes_eval_log.hh"
+#include "FN_field_cpp_type.hh"
+
#include "node_intern.h" /* own include */
#ifdef WITH_COMPOSITOR
@@ -88,7 +92,11 @@ 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;
+using blender::fn::GField;
using blender::fn::GPointer;
namespace geo_log = blender::nodes::geometry_nodes_eval_log;
@@ -850,31 +858,70 @@ static void create_inspection_string_for_generic_value(const geo_log::GenericVal
};
const GPointer value = value_log.value();
- if (value.is_type<int>()) {
- ss << *value.get<int>() << TIP_(" (Integer)");
- }
- else if (value.is_type<float>()) {
- ss << *value.get<float>() << TIP_(" (Float)");
- }
- else if (value.is_type<blender::float3>()) {
- ss << *value.get<blender::float3>() << TIP_(" (Vector)");
- }
- else if (value.is_type<bool>()) {
- ss << (*value.get<bool>() ? TIP_("True") : TIP_("False")) << TIP_(" (Boolean)");
- }
- else if (value.is_type<std::string>()) {
- ss << *value.get<std::string>() << TIP_(" (String)");
+ const CPPType &type = *value.type();
+ if (const FieldCPPType *field_type = dynamic_cast<const FieldCPPType *>(&type)) {
+ const CPPType &base_type = field_type->field_type();
+ BUFFER_FOR_CPP_TYPE_VALUE(base_type, buffer);
+ const GField &field = field_type->get_gfield(value.get());
+ if (field.node().depends_on_input()) {
+ if (base_type.is<int>()) {
+ ss << TIP_("Integer Field");
+ }
+ else if (base_type.is<float>()) {
+ ss << TIP_("Float Field");
+ }
+ else if (base_type.is<blender::float3>()) {
+ ss << TIP_("Vector Field");
+ }
+ else if (base_type.is<bool>()) {
+ ss << TIP_("Boolean Field");
+ }
+ else if (base_type.is<std::string>()) {
+ ss << TIP_("String Field");
+ }
+ ss << TIP_(" based on:\n");
+
+ /* Use vector set to deduplicate inputs. */
+ VectorSet<std::reference_wrapper<const FieldInput>> field_inputs;
+ field.node().foreach_field_input(
+ [&](const FieldInput &field_input) { field_inputs.add(field_input); });
+ for (const FieldInput &field_input : field_inputs) {
+ ss << "\u2022 " << field_input.socket_inspection_name();
+ if (field_input != field_inputs.as_span().last().get()) {
+ ss << ".\n";
+ }
+ }
+ }
+ else {
+ blender::fn::evaluate_constant_field(field, buffer);
+ if (base_type.is<int>()) {
+ ss << *(int *)buffer << TIP_(" (Integer)");
+ }
+ else if (base_type.is<float>()) {
+ ss << *(float *)buffer << TIP_(" (Float)");
+ }
+ else if (base_type.is<blender::float3>()) {
+ ss << *(blender::float3 *)buffer << TIP_(" (Vector)");
+ }
+ else if (base_type.is<bool>()) {
+ ss << ((*(bool *)buffer) ? TIP_("True") : TIP_("False")) << TIP_(" (Boolean)");
+ }
+ else if (base_type.is<std::string>()) {
+ ss << *(std::string *)buffer << TIP_(" (String)");
+ }
+ base_type.destruct(buffer);
+ }
}
- else if (value.is_type<Object *>()) {
+ else if (type.is<Object *>()) {
id_to_inspection_string((ID *)*value.get<Object *>(), ID_OB);
}
- else if (value.is_type<Material *>()) {
+ else if (type.is<Material *>()) {
id_to_inspection_string((ID *)*value.get<Material *>(), ID_MA);
}
- else if (value.is_type<Tex *>()) {
+ else if (type.is<Tex *>()) {
id_to_inspection_string((ID *)*value.get<Tex *>(), ID_TE);
}
- else if (value.is_type<Collection *>()) {
+ else if (type.is<Collection *>()) {
id_to_inspection_string((ID *)*value.get<Collection *>(), ID_GR);
}
}
diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c
index db37c8c1c8c..c06a1010168 100644
--- a/source/blender/editors/space_outliner/outliner_draw.c
+++ b/source/blender/editors/space_outliner/outliner_draw.c
@@ -32,6 +32,7 @@
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "DNA_sequence_types.h"
+#include "DNA_text_types.h"
#include "BLI_blenlib.h"
#include "BLI_math.h"
@@ -59,6 +60,7 @@
#include "DEG_depsgraph_build.h"
#include "ED_armature.h"
+#include "ED_fileselect.h"
#include "ED_outliner.h"
#include "ED_screen.h"
@@ -2625,9 +2627,17 @@ TreeElementIcon tree_element_get_icon(TreeStoreElem *tselem, TreeElement *te)
case ID_NLA:
data.icon = ICON_NLA;
break;
- case ID_TXT:
- data.icon = ICON_SCRIPT;
+ case ID_TXT: {
+ Text *text = (Text *)tselem->id;
+ if (text->filepath == NULL || (text->flags & TXT_ISMEM)) {
+ data.icon = ICON_FILE_TEXT;
+ }
+ else {
+ /* Helps distinguish text-based formats like the file-browser does. */
+ data.icon = ED_file_extension_icon(text->filepath);
+ }
break;
+ }
case ID_GR:
data.icon = ICON_OUTLINER_COLLECTION;
break;
diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c
index 7709c6bb053..9e314701719 100644
--- a/source/blender/editors/space_outliner/outliner_tools.c
+++ b/source/blender/editors/space_outliner/outliner_tools.c
@@ -737,13 +737,8 @@ static void id_local_fn(bContext *C,
{
if (ID_IS_LINKED(tselem->id) && (tselem->id->tag & LIB_TAG_EXTERN)) {
Main *bmain = CTX_data_main(C);
- /* if the ID type has no special local function,
- * just clear the lib */
- if (BKE_lib_id_make_local(bmain, tselem->id, false, 0) == false) {
- BKE_lib_id_clear_library_data(bmain, tselem->id);
- }
- else {
- BKE_main_id_newptr_and_tag_clear(bmain);
+ if (BKE_lib_id_make_local(bmain, tselem->id, 0)) {
+ BKE_id_newptr_and_tag_clear(tselem->id);
}
}
else if (ID_IS_OVERRIDE_LIBRARY_REAL(tselem->id)) {
diff --git a/source/blender/editors/space_sequencer/sequencer_select.c b/source/blender/editors/space_sequencer/sequencer_select.c
index 4c938a412d2..80d3e2cbdaa 100644
--- a/source/blender/editors/space_sequencer/sequencer_select.c
+++ b/source/blender/editors/space_sequencer/sequencer_select.c
@@ -504,238 +504,245 @@ void SEQUENCER_OT_select_inverse(struct wmOperatorType *ot)
/** \name Select Operator
* \{ */
-static int sequencer_select_exec(bContext *C, wmOperator *op)
+static void sequencer_select_set_active(Scene *scene, Sequence *seq)
{
- View2D *v2d = UI_view2d_fromcontext(C);
- Scene *scene = CTX_data_scene(C);
Editing *ed = SEQ_editing_get(scene);
- const bool extend = RNA_boolean_get(op->ptr, "extend");
- const bool deselect_all = RNA_boolean_get(op->ptr, "deselect_all");
- const bool linked_handle = RNA_boolean_get(op->ptr, "linked_handle");
- const bool linked_time = RNA_boolean_get(op->ptr, "linked_time");
- bool side_of_frame = RNA_boolean_get(op->ptr, "side_of_frame");
- bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
- int mval[2];
- int ret_value = OPERATOR_CANCELLED;
- mval[0] = RNA_int_get(op->ptr, "mouse_x");
- mval[1] = RNA_int_get(op->ptr, "mouse_y");
-
- Sequence *seq, *neighbor, *act_orig;
- int hand, sel_side;
+ SEQ_select_active_set(scene, seq);
- if (ed == NULL) {
- return OPERATOR_CANCELLED;
+ if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE)) {
+ if (seq->strip) {
+ BLI_strncpy(ed->act_imagedir, seq->strip->dir, FILE_MAXDIR);
+ }
}
-
- if (extend) {
- wait_to_deselect_others = false;
+ else if (seq->type == SEQ_TYPE_SOUND_RAM) {
+ if (seq->strip) {
+ BLI_strncpy(ed->act_sounddir, seq->strip->dir, FILE_MAXDIR);
+ }
}
+ recurs_sel_seq(seq);
+}
- seq = find_nearest_seq(scene, v2d, &hand, mval);
+static void sequencer_select_do_updates(bContext *C, Scene *scene)
+{
+ ED_outliner_select_sync_from_sequence_tag(C);
+ WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
+}
- /* XXX: not nice, Ctrl+RMB needs to do side_of_frame only when not over a strip. */
- if (seq && linked_time) {
- side_of_frame = false;
- }
+static void sequencer_select_side_of_frame(const bContext *C,
+ const View2D *v2d,
+ const int mval[2],
+ Scene *scene)
+{
+ Editing *ed = SEQ_editing_get(scene);
- /* Select left, right or overlapping the current frame. */
- if (side_of_frame) {
- /* Use different logic for this. */
- if (extend == false) {
- ED_sequencer_deselect_all(scene);
+ const float x = UI_view2d_region_to_view_x(v2d, mval[0]);
+ LISTBASE_FOREACH (Sequence *, seq_iter, SEQ_active_seqbase_get(ed)) {
+ if (((x < CFRA) && (seq_iter->enddisp <= CFRA)) ||
+ ((x >= CFRA) && (seq_iter->startdisp >= CFRA))) {
+ /* Select left or right. */
+ seq_iter->flag |= SELECT;
+ recurs_sel_seq(seq_iter);
}
+ }
- const float x = UI_view2d_region_to_view_x(v2d, mval[0]);
+ {
+ SpaceSeq *sseq = CTX_wm_space_seq(C);
+ if (sseq && sseq->flag & SEQ_MARKER_TRANS) {
+ TimeMarker *tmarker;
- LISTBASE_FOREACH (Sequence *, seq_iter, SEQ_active_seqbase_get(ed)) {
- if (((x < CFRA) && (seq_iter->enddisp <= CFRA)) ||
- ((x >= CFRA) && (seq_iter->startdisp >= CFRA))) {
- /* Select left or right. */
- seq_iter->flag |= SELECT;
- recurs_sel_seq(seq_iter);
+ for (tmarker = scene->markers.first; tmarker; tmarker = tmarker->next) {
+ if (((x < CFRA) && (tmarker->frame <= CFRA)) ||
+ ((x >= CFRA) && (tmarker->frame >= CFRA))) {
+ tmarker->flag |= SELECT;
+ }
+ else {
+ tmarker->flag &= ~SELECT;
+ }
}
}
+ }
+}
- {
- SpaceSeq *sseq = CTX_wm_space_seq(C);
- if (sseq && sseq->flag & SEQ_MARKER_TRANS) {
- TimeMarker *tmarker;
+static void sequencer_select_linked_handle(const bContext *C,
+ Sequence *seq,
+ const int handle_clicked)
+{
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = SEQ_editing_get(scene);
+ if (!ELEM(handle_clicked, SEQ_SIDE_LEFT, SEQ_SIDE_RIGHT)) {
+ /* First click selects the strip and its adjacent handles (if valid).
+ * Second click selects the strip,
+ * both of its handles and its adjacent handles (if valid). */
+ const bool is_striponly_selected = ((seq->flag & SEQ_ALLSEL) == SELECT);
+ seq->flag &= ~SEQ_ALLSEL;
+ seq->flag |= is_striponly_selected ? SEQ_ALLSEL : SELECT;
+ select_surrounding_handles(scene, seq);
+ }
+ else {
+ /* Always select the strip under the cursor. */
+ seq->flag |= SELECT;
- for (tmarker = scene->markers.first; tmarker; tmarker = tmarker->next) {
- if (((x < CFRA) && (tmarker->frame <= CFRA)) ||
- ((x >= CFRA) && (tmarker->frame >= CFRA))) {
- tmarker->flag |= SELECT;
+ /* First click selects adjacent handles on that side.
+ * Second click selects all strips in that direction.
+ * If there are no adjacent strips, it just selects all in that direction.
+ */
+ int sel_side = handle_clicked;
+ Sequence *neighbor = find_neighboring_sequence(scene, seq, sel_side, -1);
+ if (neighbor) {
+ switch (sel_side) {
+ case SEQ_SIDE_LEFT:
+ if ((seq->flag & SEQ_LEFTSEL) && (neighbor->flag & SEQ_RIGHTSEL)) {
+ seq->flag |= SELECT;
+ select_active_side(ed->seqbasep, SEQ_SIDE_LEFT, seq->machine, seq->startdisp);
}
else {
- tmarker->flag &= ~SELECT;
+ seq->flag |= SELECT;
+ neighbor->flag |= SELECT;
+ recurs_sel_seq(neighbor);
+ neighbor->flag |= SEQ_RIGHTSEL;
+ seq->flag |= SEQ_LEFTSEL;
}
- }
+ break;
+ case SEQ_SIDE_RIGHT:
+ if ((seq->flag & SEQ_RIGHTSEL) && (neighbor->flag & SEQ_LEFTSEL)) {
+ seq->flag |= SELECT;
+ select_active_side(ed->seqbasep, SEQ_SIDE_RIGHT, seq->machine, seq->startdisp);
+ }
+ else {
+ seq->flag |= SELECT;
+ neighbor->flag |= SELECT;
+ recurs_sel_seq(neighbor);
+ neighbor->flag |= SEQ_LEFTSEL;
+ seq->flag |= SEQ_RIGHTSEL;
+ }
+ break;
}
}
+ else {
- ret_value = OPERATOR_FINISHED;
+ select_active_side(ed->seqbasep, sel_side, seq->machine, seq->startdisp);
+ }
}
- else {
- act_orig = ed->act_seq;
-
- if (seq) {
- /* Are we trying to select a handle that's already selected? */
- const bool handle_selected = ((hand == SEQ_SIDE_LEFT) && (seq->flag & SEQ_LEFTSEL)) ||
- ((hand == SEQ_SIDE_RIGHT) && (seq->flag & SEQ_RIGHTSEL));
-
- if (wait_to_deselect_others && (seq->flag & SELECT) &&
- (hand == SEQ_SIDE_NONE || handle_selected)) {
- ret_value = OPERATOR_RUNNING_MODAL;
- }
- else if (!extend && !linked_handle) {
- ED_sequencer_deselect_all(scene);
- ret_value = OPERATOR_FINISHED;
- }
- else {
- ret_value = OPERATOR_FINISHED;
- }
-
- SEQ_select_active_set(scene, seq);
+}
- if (ELEM(seq->type, SEQ_TYPE_IMAGE, SEQ_TYPE_MOVIE)) {
- if (seq->strip) {
- BLI_strncpy(ed->act_imagedir, seq->strip->dir, FILE_MAXDIR);
- }
- }
- else if (seq->type == SEQ_TYPE_SOUND_RAM) {
- if (seq->strip) {
- BLI_strncpy(ed->act_sounddir, seq->strip->dir, FILE_MAXDIR);
- }
- }
+static bool element_already_selected(const Sequence *seq, const int handle_clicked)
+{
+ const bool handle_already_selected = ((handle_clicked == SEQ_SIDE_LEFT) &&
+ (seq->flag & SEQ_LEFTSEL)) ||
+ ((handle_clicked == SEQ_SIDE_RIGHT) &&
+ (seq->flag & SEQ_RIGHTSEL));
+ return ((seq->flag & SELECT) && handle_clicked == SEQ_SIDE_NONE) || handle_already_selected;
+}
- /* On Alt selection, select the strip and bordering handles. */
- if (linked_handle) {
- if (!ELEM(hand, SEQ_SIDE_LEFT, SEQ_SIDE_RIGHT)) {
- /* First click selects the strip and its adjacent handles (if valid).
- * Second click selects the strip,
- * both of its handles and its adjacent handles (if valid). */
- const bool is_striponly_selected = ((seq->flag & SEQ_ALLSEL) == SELECT);
+static void sequencer_select_strip_impl(const Editing *ed,
+ Sequence *seq,
+ const int handle_clicked,
+ const bool extend)
+{
+ /* Deselect strip. */
+ if (extend && (seq->flag & SELECT) && ed->act_seq == seq) {
+ switch (handle_clicked) {
+ case SEQ_SIDE_NONE:
+ seq->flag &= ~SEQ_ALLSEL;
+ break;
+ case SEQ_SIDE_LEFT:
+ seq->flag ^= SEQ_LEFTSEL;
+ break;
+ case SEQ_SIDE_RIGHT:
+ seq->flag ^= SEQ_RIGHTSEL;
+ break;
+ }
+ }
+ else { /* Select strip. */
+ seq->flag |= SELECT;
+ if (handle_clicked == SEQ_SIDE_LEFT) {
+ seq->flag |= SEQ_LEFTSEL;
+ }
+ if (handle_clicked == SEQ_SIDE_RIGHT) {
+ seq->flag |= SEQ_RIGHTSEL;
+ }
+ }
+}
- if (!extend) {
- ED_sequencer_deselect_all(scene);
- }
- seq->flag &= ~SEQ_ALLSEL;
- seq->flag |= is_striponly_selected ? SEQ_ALLSEL : SELECT;
- select_surrounding_handles(scene, seq);
- }
- else {
- /* Always select the strip under the cursor. */
- seq->flag |= SELECT;
+static int sequencer_select_exec(bContext *C, wmOperator *op)
+{
+ View2D *v2d = UI_view2d_fromcontext(C);
+ Scene *scene = CTX_data_scene(C);
+ Editing *ed = SEQ_editing_get(scene);
+ const bool extend = RNA_boolean_get(op->ptr, "extend");
- /* First click selects adjacent handles on that side.
- * Second click selects all strips in that direction.
- * If there are no adjacent strips, it just selects all in that direction.
- */
- sel_side = hand;
- neighbor = find_neighboring_sequence(scene, seq, sel_side, -1);
- if (neighbor) {
- switch (sel_side) {
- case SEQ_SIDE_LEFT:
- if ((seq->flag & SEQ_LEFTSEL) && (neighbor->flag & SEQ_RIGHTSEL)) {
- if (extend == 0) {
- ED_sequencer_deselect_all(scene);
- }
- seq->flag |= SELECT;
-
- select_active_side(ed->seqbasep, SEQ_SIDE_LEFT, seq->machine, seq->startdisp);
- }
- else {
- if (extend == 0) {
- ED_sequencer_deselect_all(scene);
- }
- seq->flag |= SELECT;
-
- neighbor->flag |= SELECT;
- recurs_sel_seq(neighbor);
- neighbor->flag |= SEQ_RIGHTSEL;
- seq->flag |= SEQ_LEFTSEL;
- }
- break;
- case SEQ_SIDE_RIGHT:
- if ((seq->flag & SEQ_RIGHTSEL) && (neighbor->flag & SEQ_LEFTSEL)) {
- if (extend == 0) {
- ED_sequencer_deselect_all(scene);
- }
- seq->flag |= SELECT;
-
- select_active_side(ed->seqbasep, SEQ_SIDE_RIGHT, seq->machine, seq->startdisp);
- }
- else {
- if (extend == 0) {
- ED_sequencer_deselect_all(scene);
- }
- seq->flag |= SELECT;
-
- neighbor->flag |= SELECT;
- recurs_sel_seq(neighbor);
- neighbor->flag |= SEQ_LEFTSEL;
- seq->flag |= SEQ_RIGHTSEL;
- }
- break;
- }
- }
- else {
- if (extend == 0) {
- ED_sequencer_deselect_all(scene);
- }
- select_active_side(ed->seqbasep, sel_side, seq->machine, seq->startdisp);
- }
- }
+ if (ed == NULL) {
+ return OPERATOR_CANCELLED;
+ }
- ret_value = OPERATOR_FINISHED;
- }
- else {
- if (extend && (seq->flag & SELECT) && ed->act_seq == act_orig) {
- switch (hand) {
- case SEQ_SIDE_NONE:
- if (linked_handle == 0) {
- seq->flag &= ~SEQ_ALLSEL;
- }
- break;
- case SEQ_SIDE_LEFT:
- seq->flag ^= SEQ_LEFTSEL;
- break;
- case SEQ_SIDE_RIGHT:
- seq->flag ^= SEQ_RIGHTSEL;
- break;
- }
- ret_value = OPERATOR_FINISHED;
- }
- else {
- seq->flag |= SELECT;
- if (hand == SEQ_SIDE_LEFT) {
- seq->flag |= SEQ_LEFTSEL;
- }
- if (hand == SEQ_SIDE_RIGHT) {
- seq->flag |= SEQ_RIGHTSEL;
- }
- }
- }
+ int mval[2];
+ mval[0] = RNA_int_get(op->ptr, "mouse_x");
+ mval[1] = RNA_int_get(op->ptr, "mouse_y");
- recurs_sel_seq(seq);
+ int handle_clicked;
+ Sequence *seq = find_nearest_seq(scene, v2d, &handle_clicked, mval);
- if (linked_time) {
- select_linked_time(ed->seqbasep, seq);
- }
+ /* NOTE: `side_of_frame` and `linked_time` functionality is designed to be shared on one keymap,
+ * therefore both properties can be true at the same time. */
+ if (seq && RNA_boolean_get(op->ptr, "linked_time")) {
+ if (!extend) {
+ ED_sequencer_deselect_all(scene);
+ }
+ sequencer_select_strip_impl(ed, seq, handle_clicked, extend);
+ select_linked_time(ed->seqbasep, seq);
+ sequencer_select_do_updates(C, scene);
+ sequencer_select_set_active(scene, seq);
+ return OPERATOR_FINISHED;
+ }
- BLI_assert((ret_value & OPERATOR_CANCELLED) == 0);
+ /* Select left, right or overlapping the current frame. */
+ if (RNA_boolean_get(op->ptr, "side_of_frame")) {
+ if (!extend) {
+ ED_sequencer_deselect_all(scene);
}
- else if (deselect_all) {
+ sequencer_select_side_of_frame(C, v2d, mval, scene);
+ sequencer_select_do_updates(C, scene);
+ return OPERATOR_FINISHED;
+ }
+
+ /* On Alt selection, select the strip and bordering handles. */
+ if (seq && RNA_boolean_get(op->ptr, "linked_handle")) {
+ if (!extend) {
ED_sequencer_deselect_all(scene);
- ret_value = OPERATOR_FINISHED;
}
+ sequencer_select_linked_handle(C, seq, handle_clicked);
+ sequencer_select_do_updates(C, scene);
+ sequencer_select_set_active(scene, seq);
+ return OPERATOR_FINISHED;
}
- ED_outliner_select_sync_from_sequence_tag(C);
+ const bool wait_to_deselect_others = RNA_boolean_get(op->ptr, "wait_to_deselect_others");
- WM_event_add_notifier(C, NC_SCENE | ND_SEQUENCER | NA_SELECTED, scene);
+ /* Clicking on already selected element falls on modal operation.
+ * All strips are deselected on mouse button release unless extend mode is used. */
+ if (seq && element_already_selected(seq, handle_clicked) && wait_to_deselect_others && !extend) {
+ return OPERATOR_RUNNING_MODAL;
+ }
+
+ int ret_value = OPERATOR_CANCELLED;
+ if (!extend) {
+ ED_sequencer_deselect_all(scene);
+ ret_value = OPERATOR_FINISHED;
+ }
+
+ /* Nothing to select, but strips could be deselected. */
+ if (!seq) {
+ sequencer_select_do_updates(C, scene);
+ return ret_value;
+ }
+
+ /* Do actual selection. */
+ sequencer_select_strip_impl(ed, seq, handle_clicked, extend);
+ ret_value = OPERATOR_FINISHED;
+ sequencer_select_do_updates(C, scene);
+ sequencer_select_set_active(scene, seq);
return ret_value;
}
@@ -764,13 +771,6 @@ void SEQUENCER_OT_select(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
prop = RNA_def_boolean(ot->srna,
- "deselect_all",
- false,
- "Deselect On Nothing",
- "Deselect all when nothing under the cursor");
- RNA_def_property_flag(prop, PROP_SKIP_SAVE);
-
- prop = RNA_def_boolean(ot->srna,
"linked_handle",
false,
"Linked Handle",
diff --git a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
index fcc92345bea..a82648aeee0 100644
--- a/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
+++ b/source/blender/editors/space_spreadsheet/space_spreadsheet.cc
@@ -270,7 +270,7 @@ Object *spreadsheet_get_object_eval(const SpaceSpreadsheet *sspreadsheet,
return nullptr;
}
Object *object_orig = (Object *)used_id;
- if (!ELEM(object_orig->type, OB_MESH, OB_POINTCLOUD, OB_VOLUME)) {
+ if (!ELEM(object_orig->type, OB_MESH, OB_POINTCLOUD, OB_VOLUME, OB_CURVE, OB_FONT)) {
return nullptr;
}
@@ -370,7 +370,7 @@ static void spreadsheet_main_region_draw(const bContext *C, ARegion *region)
std::unique_ptr<ColumnValues> values_ptr = data_source->get_column_values(*column->id);
/* Should have been removed before if it does not exist anymore. */
BLI_assert(values_ptr);
- const ColumnValues *values = scope.add(std::move(values_ptr), __func__);
+ const ColumnValues *values = scope.add(std::move(values_ptr));
const int width = get_column_width_in_pixels(*values);
spreadsheet_layout.columns.append({values, width});
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh b/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh
index 680da9b6794..97170693cb3 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_cell_value.hh
@@ -35,6 +35,10 @@ 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.
@@ -53,6 +57,7 @@ class CellValue {
std::optional<ColorGeometry4f> value_color;
std::optional<ObjectCellValue> value_object;
std::optional<CollectionCellValue> value_collection;
+ std::optional<GeometrySetCellValue> value_geometry_set;
};
} // namespace blender::ed::spreadsheet
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 e38c70afd0f..78d9f61d8d5 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_data_source_geometry.cc
@@ -45,15 +45,19 @@ namespace blender::ed::spreadsheet {
void GeometryDataSource::foreach_default_column_ids(
FunctionRef<void(const SpreadsheetColumnID &)> fn) const
{
- component_->attribute_foreach([&](StringRefNull name, const AttributeMetaData &meta_data) {
- if (meta_data.domain != domain_) {
- return true;
- }
- SpreadsheetColumnID column_id;
- column_id.name = (char *)name.c_str();
- fn(column_id);
- return true;
- });
+ component_->attribute_foreach(
+ [&](const bke::AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
+ if (meta_data.domain != domain_) {
+ return true;
+ }
+ if (attribute_id.is_anonymous()) {
+ return true;
+ }
+ SpreadsheetColumnID column_id;
+ column_id.name = (char *)attribute_id.name().data();
+ fn(column_id);
+ return true;
+ });
}
std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
@@ -65,7 +69,7 @@ std::unique_ptr<ColumnValues> GeometryDataSource::get_column_values(
if (!attribute) {
return {};
}
- const fn::GVArray *varray = scope_.add(std::move(attribute.varray), __func__);
+ const fn::GVArray *varray = scope_.add(std::move(attribute.varray));
if (attribute.domain != domain_) {
return {};
}
@@ -332,6 +336,11 @@ std::unique_ptr<ColumnValues> InstancesDataSource::get_column_values(
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;
}
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
index 8079763a339..1a5eac53306 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_layout.cc
@@ -209,6 +209,23 @@ class SpreadsheetLayoutDrawer : public SpreadsheetDrawer {
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);
+ }
}
void draw_float_vector(const CellDrawParams &params, const Span<float> values) const
diff --git a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
index ae336edfead..1e46fef8d71 100644
--- a/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
+++ b/source/blender/editors/space_spreadsheet/spreadsheet_row_filter.cc
@@ -328,7 +328,7 @@ Span<int64_t> spreadsheet_filter_rows(const SpaceSpreadsheet &sspreadsheet,
geometry_data_source->apply_selection_filter(rows_included);
}
- Vector<int64_t> &indices = scope.construct<Vector<int64_t>>(__func__);
+ Vector<int64_t> &indices = scope.construct<Vector<int64_t>>();
index_vector_from_bools(rows_included, indices);
return indices;
diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c
index e3f97dd1c63..ff98762e373 100644
--- a/source/blender/editors/space_view3d/view3d_select.c
+++ b/source/blender/editors/space_view3d/view3d_select.c
@@ -1953,7 +1953,8 @@ static int mixed_bones_object_selectbuffer(ViewContext *vc,
const int mval[2],
eV3DSelectObjectFilter select_filter,
bool do_nearest,
- bool do_nearest_xray_if_supported)
+ bool do_nearest_xray_if_supported,
+ const bool do_material_slot_selection)
{
rcti rect;
int hits15, hits9 = 0, hits5 = 0;
@@ -1972,7 +1973,8 @@ static int mixed_bones_object_selectbuffer(ViewContext *vc,
view3d_opengl_select_cache_begin();
BLI_rcti_init_pt_radius(&rect, mval, 14);
- hits15 = view3d_opengl_select(vc, buffer, MAXPICKBUF, &rect, select_mode, select_filter);
+ hits15 = view3d_opengl_select_ex(
+ vc, buffer, MAXPICKBUF, &rect, select_mode, select_filter, do_material_slot_selection);
if (hits15 == 1) {
hits = selectbuffer_ret_hits_15(buffer, hits15);
goto finally;
@@ -2071,7 +2073,8 @@ static int mixed_bones_object_selectbuffer_extended(ViewContext *vc,
do_nearest = do_nearest && !enumerate;
- int hits = mixed_bones_object_selectbuffer(vc, buffer, mval, select_filter, do_nearest, true);
+ int hits = mixed_bones_object_selectbuffer(
+ vc, buffer, mval, select_filter, do_nearest, true, false);
return hits;
}
@@ -2088,12 +2091,14 @@ static Base *mouse_select_eval_buffer(ViewContext *vc,
int hits,
Base *startbase,
bool has_bones,
- bool do_nearest)
+ bool do_nearest,
+ int *r_sub_selection)
{
ViewLayer *view_layer = vc->view_layer;
View3D *v3d = vc->v3d;
Base *base, *basact = NULL;
int a;
+ int sub_selection_id = 0;
if (do_nearest) {
uint min = 0xFFFFFFFF;
@@ -2105,6 +2110,7 @@ static Base *mouse_select_eval_buffer(ViewContext *vc,
if (min > buffer[4 * a + 1] && (buffer[4 * a + 3] & 0xFFFF0000)) {
min = buffer[4 * a + 1];
selcol = buffer[4 * a + 3] & 0xFFFF;
+ sub_selection_id = (buffer[4 * a + 3] & 0xFFFF0000) >> 16;
}
}
}
@@ -2118,6 +2124,7 @@ static Base *mouse_select_eval_buffer(ViewContext *vc,
if (min > buffer[4 * a + 1] && notcol != (buffer[4 * a + 3] & 0xFFFF)) {
min = buffer[4 * a + 1];
selcol = buffer[4 * a + 3] & 0xFFFF;
+ sub_selection_id = (buffer[4 * a + 3] & 0xFFFF0000) >> 16;
}
}
}
@@ -2184,11 +2191,16 @@ static Base *mouse_select_eval_buffer(ViewContext *vc,
}
}
+ if (basact && r_sub_selection) {
+ *r_sub_selection = sub_selection_id;
+ }
+
return basact;
}
-/* mval comes from event->mval, only use within region handlers */
-Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
+static Base *ed_view3d_give_base_under_cursor_ex(bContext *C,
+ const int mval[2],
+ int *r_material_slot)
{
Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ViewContext vc;
@@ -2202,18 +2214,30 @@ Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
ED_view3d_viewcontext_init(C, &vc, depsgraph);
const bool do_nearest = !XRAY_ACTIVE(vc.v3d);
+ const bool do_material_slot_selection = r_material_slot != NULL;
const int hits = mixed_bones_object_selectbuffer(
- &vc, buffer, mval, VIEW3D_SELECT_FILTER_NOP, do_nearest, false);
+ &vc, buffer, mval, VIEW3D_SELECT_FILTER_NOP, do_nearest, false, do_material_slot_selection);
if (hits > 0) {
- const bool has_bones = selectbuffer_has_bones(buffer, hits);
- basact = mouse_select_eval_buffer(
- &vc, buffer, hits, vc.view_layer->object_bases.first, has_bones, do_nearest);
+ const bool has_bones = (r_material_slot == NULL) && selectbuffer_has_bones(buffer, hits);
+ basact = mouse_select_eval_buffer(&vc,
+ buffer,
+ hits,
+ vc.view_layer->object_bases.first,
+ has_bones,
+ do_nearest,
+ r_material_slot);
}
return basact;
}
+/* mval comes from event->mval, only use within region handlers */
+Base *ED_view3d_give_base_under_cursor(bContext *C, const int mval[2])
+{
+ return ed_view3d_give_base_under_cursor_ex(C, mval, NULL);
+}
+
Object *ED_view3d_give_object_under_cursor(bContext *C, const int mval[2])
{
Base *base = ED_view3d_give_base_under_cursor(C, mval);
@@ -2223,6 +2247,17 @@ Object *ED_view3d_give_object_under_cursor(bContext *C, const int mval[2])
return NULL;
}
+struct Object *ED_view3d_give_material_slot_under_cursor(struct bContext *C,
+ const int mval[2],
+ int *r_material_slot)
+{
+ Base *base = ed_view3d_give_base_under_cursor_ex(C, mval, r_material_slot);
+ if (base) {
+ return base->object;
+ }
+ return NULL;
+}
+
bool ED_view3d_is_object_under_cursor(bContext *C, const int mval[2])
{
return ED_view3d_give_object_under_cursor(C, mval) != NULL;
@@ -2374,7 +2409,8 @@ static bool ed_object_select_pick(bContext *C,
}
}
else {
- basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, has_bones, do_nearest);
+ basact = mouse_select_eval_buffer(
+ &vc, buffer, hits, startbase, has_bones, do_nearest, NULL);
}
if (has_bones && basact) {
@@ -2436,7 +2472,7 @@ static bool ed_object_select_pick(bContext *C,
if (!changed) {
/* fallback to regular object selection if no new bundles were selected,
* allows to select object parented to reconstruction object */
- basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, 0, do_nearest);
+ basact = mouse_select_eval_buffer(&vc, buffer, hits, startbase, 0, do_nearest, NULL);
}
}
}
@@ -2677,7 +2713,7 @@ static int view3d_select_exec(bContext *C, wmOperator *op)
uint buffer[MAXPICKBUF];
const int hits = mixed_bones_object_selectbuffer(
- &vc, buffer, location, VIEW3D_SELECT_FILTER_NOP, false, true);
+ &vc, buffer, location, VIEW3D_SELECT_FILTER_NOP, false, true, false);
retval = bone_mouse_select_menu(C, buffer, hits, true, extend, deselect, toggle);
}
if (!retval) {
diff --git a/source/blender/editors/space_view3d/view3d_view.c b/source/blender/editors/space_view3d/view3d_view.c
index 86a610f8dd9..f5da7c14a88 100644
--- a/source/blender/editors/space_view3d/view3d_view.c
+++ b/source/blender/editors/space_view3d/view3d_view.c
@@ -137,7 +137,6 @@ void ED_view3d_smooth_view_ex(
{
RegionView3D *rv3d = region->regiondata;
struct SmoothView3DStore sms = {{0}};
- bool ok = false;
/* initialize sms */
view3d_smooth_view_state_backup(&sms.dst, v3d, rv3d);
@@ -200,92 +199,75 @@ void ED_view3d_smooth_view_ex(
sms.to_camera = true; /* restore view3d values in end */
}
- /* skip smooth viewing for external render engine draw */
+ if ((sview->camera_old == sview->camera) && /* Camera. */
+ (sms.dst.dist == rv3d->dist) && /* Distance. */
+ (sms.dst.lens == v3d->lens) && /* Lens. */
+ equals_v3v3(sms.dst.ofs, rv3d->ofs) && /* Offset. */
+ equals_v4v4(sms.dst.quat, rv3d->viewquat) /* Rotation. */
+ ) {
+ /* Early return if nothing changed. */
+ return;
+ }
+
+ /* Skip smooth viewing for external render engine draw. */
if (smooth_viewtx && !(v3d->shading.type == OB_RENDER && rv3d->render_engine)) {
- bool changed = false; /* zero means no difference */
- if (sview->camera_old != sview->camera) {
- changed = true;
- }
- else if (sms.dst.dist != rv3d->dist) {
- changed = true;
- }
- else if (sms.dst.lens != v3d->lens) {
- changed = true;
- }
- else if (!equals_v3v3(sms.dst.ofs, rv3d->ofs)) {
- changed = true;
+ /* original values */
+ if (sview->camera_old) {
+ Object *ob_camera_old_eval = DEG_get_evaluated_object(depsgraph, sview->camera_old);
+ if (sview->ofs != NULL) {
+ sms.src.dist = ED_view3d_offset_distance(ob_camera_old_eval->obmat, sview->ofs, 0.0f);
+ }
+ ED_view3d_from_object(
+ ob_camera_old_eval, sms.src.ofs, sms.src.quat, &sms.src.dist, &sms.src.lens);
}
- else if (!equals_v4v4(sms.dst.quat, rv3d->viewquat)) {
- changed = true;
+ /* grid draw as floor */
+ if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0) {
+ /* use existing if exists, means multiple calls to smooth view
+ * won't lose the original 'view' setting */
+ rv3d->view = RV3D_VIEW_USER;
}
- /* The new view is different from the old one
- * so animate the view */
- if (changed) {
- /* original values */
- if (sview->camera_old) {
- Object *ob_camera_old_eval = DEG_get_evaluated_object(depsgraph, sview->camera_old);
- if (sview->ofs != NULL) {
- sms.src.dist = ED_view3d_offset_distance(ob_camera_old_eval->obmat, sview->ofs, 0.0f);
- }
- ED_view3d_from_object(
- ob_camera_old_eval, sms.src.ofs, sms.src.quat, &sms.src.dist, &sms.src.lens);
- }
- /* grid draw as floor */
- if ((RV3D_LOCK_FLAGS(rv3d) & RV3D_LOCK_ROTATION) == 0) {
- /* use existing if exists, means multiple calls to smooth view
- * won't lose the original 'view' setting */
- rv3d->view = RV3D_VIEW_USER;
- }
-
- sms.time_allowed = (double)smooth_viewtx / 1000.0;
-
- /* if this is view rotation only
- * we can decrease the time allowed by
- * the angle between quats
- * this means small rotations won't lag */
- if (sview->quat && !sview->ofs && !sview->dist) {
- /* scale the time allowed by the rotation */
- /* 180deg == 1.0 */
- sms.time_allowed *= (double)fabsf(
- angle_signed_normalized_qtqt(sms.dst.quat, sms.src.quat)) /
- M_PI;
- }
+ sms.time_allowed = (double)smooth_viewtx / 1000.0;
- /* ensure it shows correct */
- if (sms.to_camera) {
- /* use ortho if we move from an ortho view to an ortho camera */
- Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, sview->camera);
- rv3d->persp = (((rv3d->is_persp == false) && (ob_camera_eval->type == OB_CAMERA) &&
- (((Camera *)ob_camera_eval->data)->type == CAM_ORTHO)) ?
- RV3D_ORTHO :
- RV3D_PERSP);
- }
+ /* If this is view rotation only we can decrease the time allowed by the angle between quats
+ * this means small rotations won't lag. */
+ if (sview->quat && !sview->ofs && !sview->dist) {
+ /* scale the time allowed by the rotation */
+ /* 180deg == 1.0 */
+ sms.time_allowed *= (double)fabsf(angle_signed_normalized_qtqt(sms.dst.quat, sms.src.quat)) /
+ M_PI;
+ }
- rv3d->rflag |= RV3D_NAVIGATING;
+ /* ensure it shows correct */
+ if (sms.to_camera) {
+ /* use ortho if we move from an ortho view to an ortho camera */
+ Object *ob_camera_eval = DEG_get_evaluated_object(depsgraph, sview->camera);
+ rv3d->persp = (((rv3d->is_persp == false) && (ob_camera_eval->type == OB_CAMERA) &&
+ (((Camera *)ob_camera_eval->data)->type == CAM_ORTHO)) ?
+ RV3D_ORTHO :
+ RV3D_PERSP);
+ }
- /* not essential but in some cases the caller will tag the area for redraw, and in that
- * case we can get a flicker of the 'org' user view but we want to see 'src' */
- view3d_smooth_view_state_restore(&sms.src, v3d, rv3d);
+ rv3d->rflag |= RV3D_NAVIGATING;
- /* keep track of running timer! */
- if (rv3d->sms == NULL) {
- rv3d->sms = MEM_mallocN(sizeof(struct SmoothView3DStore), "smoothview v3d");
- }
- *rv3d->sms = sms;
- if (rv3d->smooth_timer) {
- WM_event_remove_timer(wm, win, rv3d->smooth_timer);
- }
- /* #TIMER1 is hard-coded in key-map. */
- rv3d->smooth_timer = WM_event_add_timer(wm, win, TIMER1, 1.0 / 100.0);
+ /* not essential but in some cases the caller will tag the area for redraw, and in that
+ * case we can get a flicker of the 'org' user view but we want to see 'src' */
+ view3d_smooth_view_state_restore(&sms.src, v3d, rv3d);
- ok = true;
+ /* keep track of running timer! */
+ if (rv3d->sms == NULL) {
+ rv3d->sms = MEM_mallocN(sizeof(struct SmoothView3DStore), "smoothview v3d");
+ }
+ *rv3d->sms = sms;
+ if (rv3d->smooth_timer) {
+ WM_event_remove_timer(wm, win, rv3d->smooth_timer);
}
+ /* #TIMER1 is hard-coded in key-map. */
+ rv3d->smooth_timer = WM_event_add_timer(wm, win, TIMER1, 1.0 / 100.0);
}
-
- /* if we get here nothing happens */
- if (ok == false) {
+ else {
+ /* Animation is disabled, apply immediately. */
if (sms.to_camera == false) {
copy_v3_v3(rv3d->ofs, sms.dst.ofs);
copy_qt_qt(rv3d->viewquat, sms.dst.quat);
@@ -300,6 +282,8 @@ void ED_view3d_smooth_view_ex(
}
ED_region_tag_redraw(region);
+
+ WM_event_add_mousemove(win);
}
}
@@ -320,6 +304,7 @@ void ED_view3d_smooth_view(bContext *C,
/* only meant for timer usage */
static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *region, bool sync_boxview)
{
+ wmWindowManager *wm = CTX_wm_manager(C);
RegionView3D *rv3d = region->regiondata;
struct SmoothView3DStore *sms = rv3d->sms;
float step, step_inv;
@@ -333,6 +318,7 @@ static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *region, b
/* end timer */
if (step >= 1.0f) {
+ wmWindow *win = CTX_wm_window(C);
/* if we went to camera, store the original */
if (sms->to_camera) {
@@ -355,9 +341,12 @@ static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *region, b
MEM_freeN(rv3d->sms);
rv3d->sms = NULL;
- WM_event_remove_timer(CTX_wm_manager(C), CTX_wm_window(C), rv3d->smooth_timer);
+ WM_event_remove_timer(wm, win, rv3d->smooth_timer);
rv3d->smooth_timer = NULL;
rv3d->rflag &= ~RV3D_NAVIGATING;
+
+ /* Event handling won't know if a UI item has been moved under the pointer. */
+ WM_event_add_mousemove(win);
}
else {
/* ease in/out */
@@ -380,12 +369,9 @@ static void view3d_smoothview_apply(bContext *C, View3D *v3d, ARegion *region, b
const Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
ED_view3d_camera_lock_sync(depsgraph, v3d, rv3d);
- if (ED_screen_animation_playing(CTX_wm_manager(C))) {
+ if (ED_screen_animation_playing(wm)) {
ED_view3d_camera_lock_autokey(v3d, rv3d, C, true, true);
}
-
- /* Event handling won't know if a UI item has been moved under the pointer. */
- WM_event_add_mousemove(CTX_wm_window(C));
}
if (sync_boxview && (RV3D_LOCK_FLAGS(rv3d) & RV3D_BOXVIEW)) {
@@ -964,12 +950,13 @@ static bool drw_select_filter_object_mode_lock_for_weight_paint(Object *ob, void
*
* \note (vc->obedit == NULL) can be set to explicitly skip edit-object selection.
*/
-int view3d_opengl_select(ViewContext *vc,
- uint *buffer,
- uint bufsize,
- const rcti *input,
- eV3DSelectMode select_mode,
- eV3DSelectObjectFilter select_filter)
+int view3d_opengl_select_ex(ViewContext *vc,
+ uint *buffer,
+ uint bufsize,
+ const rcti *input,
+ eV3DSelectMode select_mode,
+ eV3DSelectObjectFilter select_filter,
+ const bool do_material_slot_selection)
{
struct bThemeState theme_state;
const wmWindowManager *wm = CTX_wm_manager(vc->C);
@@ -1119,6 +1106,7 @@ int view3d_opengl_select(ViewContext *vc,
use_obedit_skip,
draw_surface,
use_nearest,
+ do_material_slot_selection,
&rect,
drw_select_loop_pass,
&drw_select_loop_user_data,
@@ -1149,6 +1137,7 @@ int view3d_opengl_select(ViewContext *vc,
use_obedit_skip,
draw_surface,
use_nearest,
+ do_material_slot_selection,
&rect,
drw_select_loop_pass,
&drw_select_loop_user_data,
@@ -1178,6 +1167,16 @@ finally:
return hits;
}
+int view3d_opengl_select(ViewContext *vc,
+ uint *buffer,
+ uint bufsize,
+ const rcti *input,
+ eV3DSelectMode select_mode,
+ eV3DSelectObjectFilter select_filter)
+{
+ return view3d_opengl_select_ex(vc, buffer, bufsize, input, select_mode, select_filter, false);
+}
+
int view3d_opengl_select_with_id_filter(ViewContext *vc,
uint *buffer,
uint bufsize,
diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h
index 013c5faa54a..d1a1937cef1 100644
--- a/source/blender/editors/transform/transform.h
+++ b/source/blender/editors/transform/transform.h
@@ -618,9 +618,6 @@ typedef struct TransInfo {
O_SET,
} orient_curr;
- /** backup from view3d, to restore on end. */
- short gizmo_flag;
-
short prop_mode;
/** Value taken as input, either through mouse coordinates or entered as a parameter. */
diff --git a/source/blender/editors/transform/transform_convert_action.c b/source/blender/editors/transform/transform_convert_action.c
index 075db30fa61..a6658ae00a3 100644
--- a/source/blender/editors/transform/transform_convert_action.c
+++ b/source/blender/editors/transform/transform_convert_action.c
@@ -51,7 +51,10 @@
/* helper struct for gp-frame transforms */
typedef struct tGPFtransdata {
- float val; /* where transdata writes transform */
+ union {
+ float val; /* where transdata writes transform */
+ float loc[3]; /* #td->val and #td->loc share the same pointer. */
+ };
int *sdata; /* pointer to gpf->framenum */
} tGPFtransdata;
@@ -245,8 +248,8 @@ static int GPLayerToTransData(TransData *td,
tfd->val = (float)gpf->framenum;
tfd->sdata = &gpf->framenum;
- td->val = td->loc = &tfd->val; /* XXX: It's not a 3d array. */
- td->ival = td->iloc[0] = (float)gpf->framenum;
+ td->val = td->loc = &tfd->val;
+ td->ival = td->iloc[0] = tfd->val;
td->center[0] = td->ival;
td->center[1] = ypos;
@@ -279,16 +282,15 @@ static int MaskLayerToTransData(TransData *td,
masklay_shape = masklay_shape->next) {
if (is_prop_edit || (masklay_shape->flag & MASK_SHAPE_SELECT)) {
if (FrameOnMouseSide(side, (float)masklay_shape->frame, cfra)) {
- /* memory is calloc'ed, so that should zero everything nicely for us */
- td->val = &tfd->val;
- td->ival = (float)masklay_shape->frame;
+ tfd->val = (float)masklay_shape->frame;
+ tfd->sdata = &masklay_shape->frame;
+
+ td->val = td->loc = &tfd->val;
+ td->ival = td->iloc[0] = tfd->val;
td->center[0] = td->ival;
td->center[1] = ypos;
- tfd->val = (float)masklay_shape->frame;
- tfd->sdata = &masklay_shape->frame;
-
/* advance td now */
td++;
tfd++;
diff --git a/source/blender/editors/transform/transform_convert_armature.c b/source/blender/editors/transform/transform_convert_armature.c
index 98e00c20170..8f896512410 100644
--- a/source/blender/editors/transform/transform_convert_armature.c
+++ b/source/blender/editors/transform/transform_convert_armature.c
@@ -145,15 +145,15 @@ static void autokeyframe_pose(
if (act) {
for (fcu = act->curves.first; fcu; fcu = fcu->next) {
/* only insert keyframes for this F-Curve if it affects the current bone */
- char *pchanName = BLI_str_quoted_substrN(fcu->rna_path, "bones[");
- if (pchanName == NULL) {
+ char pchan_name[sizeof(pchan->name)];
+ if (!BLI_str_quoted_substr(fcu->rna_path, "bones[", pchan_name, sizeof(pchan_name))) {
continue;
}
/* only if bone name matches too...
* NOTE: this will do constraints too, but those are ok to do here too?
*/
- if (STREQ(pchanName, pchan->name)) {
+ if (STREQ(pchan_name, pchan->name)) {
insert_keyframe(bmain,
reports,
id,
@@ -166,8 +166,6 @@ static void autokeyframe_pose(
&nla_cache,
flag);
}
-
- MEM_freeN(pchanName);
}
}
}
diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c
index 9f5e74db501..c493b9bd102 100644
--- a/source/blender/editors/transform/transform_generics.c
+++ b/source/blender/editors/transform/transform_generics.c
@@ -249,12 +249,6 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->view = v3d;
t->animtimer = (animscreen) ? animscreen->animtimer : NULL;
- /* turn gizmo off during transform */
- if (t->flag & T_MODAL) {
- t->gizmo_flag = v3d->gizmo_flag;
- v3d->gizmo_flag = V3D_GIZMO_HIDE;
- }
-
if (t->scene->toolsettings->transform_flag & SCE_XFORM_AXIS_ALIGN) {
t->flag |= T_V3D_ALIGN;
}
@@ -742,13 +736,6 @@ void postTrans(bContext *C, TransInfo *t)
}
}
}
- else if (t->spacetype == SPACE_VIEW3D) {
- View3D *v3d = t->area->spacedata.first;
- /* restore gizmo */
- if (t->flag & T_MODAL) {
- v3d->gizmo_flag = t->gizmo_flag;
- }
- }
if (t->mouse.data) {
MEM_freeN(t->mouse.data);
@@ -791,7 +778,7 @@ static void restoreElement(TransData *td)
{
transdata_restore_basic((TransDataBasic *)td);
- if (td->val) {
+ if (td->val && td->val != td->loc) {
*td->val = td->ival;
}
diff --git a/source/blender/editors/transform/transform_gizmo_3d.c b/source/blender/editors/transform/transform_gizmo_3d.c
index 8dc4f107837..0fa179c4f74 100644
--- a/source/blender/editors/transform/transform_gizmo_3d.c
+++ b/source/blender/editors/transform/transform_gizmo_3d.c
@@ -1974,8 +1974,8 @@ void VIEW3D_GGT_xform_gizmo(wmGizmoGroupType *gzgt)
gzgt->name = "3D View: Transform Gizmo";
gzgt->idname = "VIEW3D_GGT_xform_gizmo";
- gzgt->flag = WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
- WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
+ gzgt->flag = WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_DRAW_MODAL_EXCLUDE |
+ WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP | WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
@@ -2216,8 +2216,8 @@ void VIEW3D_GGT_xform_cage(wmGizmoGroupType *gzgt)
gzgt->name = "Transform Cage";
gzgt->idname = "VIEW3D_GGT_xform_cage";
- gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
- WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
+ gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_DRAW_MODAL_EXCLUDE |
+ WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP | WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
@@ -2459,8 +2459,8 @@ void VIEW3D_GGT_xform_shear(wmGizmoGroupType *gzgt)
gzgt->name = "Transform Shear";
gzgt->idname = "VIEW3D_GGT_xform_shear";
- gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP |
- WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
+ gzgt->flag |= WM_GIZMOGROUPTYPE_3D | WM_GIZMOGROUPTYPE_DRAW_MODAL_EXCLUDE |
+ WM_GIZMOGROUPTYPE_TOOL_FALLBACK_KEYMAP | WM_GIZMOGROUPTYPE_DELAY_REFRESH_FOR_TWEAK;
gzgt->gzmap_params.spaceid = SPACE_VIEW3D;
gzgt->gzmap_params.regionid = RGN_TYPE_WINDOW;
diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c
index bb04f557074..811f30c96e5 100644
--- a/source/blender/editors/transform/transform_snap_object.c
+++ b/source/blender/editors/transform/transform_snap_object.c
@@ -501,9 +501,7 @@ static void iter_snap_objects(SnapObjectContext *sctx,
}
Object *obj_eval = DEG_get_evaluated_object(depsgraph, base->object);
- if (obj_eval->transflag & OB_DUPLI ||
- (obj_eval->runtime.geometry_set_eval != NULL &&
- BKE_geometry_set_has_instances(obj_eval->runtime.geometry_set_eval))) {
+ if (obj_eval->transflag & OB_DUPLI || BKE_object_has_geometry_set_instances(obj_eval)) {
ListBase *lb = object_duplilist(depsgraph, sctx->scene, obj_eval);
for (DupliObject *dupli_ob = lb->first; dupli_ob; dupli_ob = dupli_ob->next) {
BLI_assert(DEG_is_evaluated_object(dupli_ob->ob));
diff --git a/source/blender/editors/transform/transform_snap_sequencer.c b/source/blender/editors/transform/transform_snap_sequencer.c
index a54149912a9..e82a00bcc77 100644
--- a/source/blender/editors/transform/transform_snap_sequencer.c
+++ b/source/blender/editors/transform/transform_snap_sequencer.c
@@ -260,7 +260,7 @@ TransSeqSnapData *transform_snap_sequencer_data_alloc(const TransInfo *t)
SeqCollection *snap_sources = SEQ_query_selected_strips(seqbase);
SeqCollection *snap_targets = query_snap_targets(t, snap_sources);
- if (SEQ_collection_len(snap_sources) == 0 || SEQ_collection_len(snap_targets) == 0) {
+ if (SEQ_collection_len(snap_sources) == 0) {
SEQ_collection_free(snap_targets);
SEQ_collection_free(snap_sources);
MEM_freeN(snap_data);
diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c
index 3e0029156c1..22064e04e86 100644
--- a/source/blender/editors/undo/ed_undo.c
+++ b/source/blender/editors/undo/ed_undo.c
@@ -574,7 +574,12 @@ static bool ed_undo_is_init_poll(bContext *C)
{
wmWindowManager *wm = CTX_wm_manager(C);
if (wm->undo_stack == NULL) {
- CTX_wm_operator_poll_msg_set(C, "Undo disabled at startup");
+ /* This message is intended for Python developers,
+ * it will be part of the exception when attempting to call undo in background mode. */
+ CTX_wm_operator_poll_msg_set(
+ C,
+ "Undo disabled at startup in background-mode "
+ "(call `ed.undo_push()` to explicitly initialize the undo-system)");
return false;
}
return true;