From c134d7437d38160036e4ad3fc7b00986a98b0a4d Mon Sep 17 00:00:00 2001 From: Greg Neumiller Date: Mon, 25 Jan 2021 21:08:37 +0100 Subject: [PATCH 01/55] Fix T84031 initialize connectivity info of the base mesh before using Displacement Smear brush. Reviewed By: pablodp606 Maniphest Tasks: T84031 Differential Revision: https://developer.blender.org/D9956 --- source/blender/editors/sculpt_paint/sculpt.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 5070dba14ea..4d6330e03f8 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -7237,7 +7237,8 @@ static bool sculpt_needs_connectivity_info(const Sculpt *sd, (brush->sculpt_tool == SCULPT_TOOL_BOUNDARY) || (brush->sculpt_tool == SCULPT_TOOL_SLIDE_RELAX) || (brush->sculpt_tool == SCULPT_TOOL_CLOTH) || (brush->sculpt_tool == SCULPT_TOOL_SMEAR) || - (brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS)); + (brush->sculpt_tool == SCULPT_TOOL_DRAW_FACE_SETS) || + (brush->sculpt_tool == SCULPT_TOOL_DISPLACEMENT_SMEAR)); } void SCULPT_stroke_modifiers_check(const bContext *C, Object *ob, const Brush *brush) From 4fc54ddae18c64c27f440c7bf333f57e26f61171 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 26 Jan 2021 07:50:40 +1100 Subject: [PATCH 02/55] Cleanup: spelling --- intern/cycles/render/alembic.h | 2 +- source/blender/blenkernel/intern/lib_override.c | 12 ++++++------ source/blender/blenkernel/intern/undo_system.c | 2 +- .../blender/editors/animation/anim_channels_edit.c | 2 +- source/blender/editors/space_clip/space_clip.c | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/intern/cycles/render/alembic.h b/intern/cycles/render/alembic.h index 307d8436668..855d774bfdb 100644 --- a/intern/cycles/render/alembic.h +++ b/intern/cycles/render/alembic.h @@ -45,7 +45,7 @@ template struct is_array : public std::false_type { template struct is_array> : public std::true_type { }; -/* Store the data set for an animation at every time points, or at the begining of the animation +/* Store the data set for an animation at every time points, or at the beginning of the animation * for constant data. * * The data is supposed to be stored in chronological order, and is looked up using the current diff --git a/source/blender/blenkernel/intern/lib_override.c b/source/blender/blenkernel/intern/lib_override.c index b0438500413..7df0e08d405 100644 --- a/source/blender/blenkernel/intern/lib_override.c +++ b/source/blender/blenkernel/intern/lib_override.c @@ -422,7 +422,7 @@ static int lib_override_linked_group_tag_cb(LibraryIDLinkCallbackData *cb_data) return IDWALK_RET_NOP; } -/* Tag all IDs in dependency relationships whithin an override hierarchy/group. +/* Tag all IDs in dependency relationships within an override hierarchy/group. * * Note: this is typically called to complete `lib_override_linked_group_tag()`. * Note: BMain's relations mapping won't be valid anymore after that call. @@ -464,8 +464,8 @@ static bool lib_override_hierarchy_dependencies_recursive_tag(Main *bmain, /* This will tag at least all 'boundary' linked IDs for a potential override group. * - * Note that you will then need to call `lib_override_hierarchy_dependencies_recursive_tag` to - * complete tagging of all dependencies whitin theoverride group. + * Note that you will then need to call #lib_override_hierarchy_dependencies_recursive_tag to + * complete tagging of all dependencies within the override group. * * We currently only consider Collections and Objects (that are not used as bone shapes) as valid * boundary IDs to define an override group. @@ -483,7 +483,7 @@ static void lib_override_linked_group_tag(Main *bmain, BKE_library_foreach_ID_link( bmain, id, lib_override_linked_group_tag_cb, &data, IDWALK_READONLY | IDWALK_RECURSE); - /* Then, we remove (untag) bone shape objects, you shall never want to directly/explicitely + /* Then, we remove (untag) bone shape objects, you shall never want to directly/explicitly * override those. */ LISTBASE_FOREACH (Object *, ob, &bmain->objects) { if (ob->type == OB_ARMATURE && ob->pose != NULL && (ob->id.tag & tag)) { @@ -559,8 +559,8 @@ static int lib_override_local_group_tag_cb(LibraryIDLinkCallbackData *cb_data) /* This will tag at least all 'boundary' linked IDs for a potential override group. * - * Note that you will then need to call `lib_override_hierarchy_dependencies_recursive_tag` to - * complete tagging of all dependencies whitin theoverride group. + * Note that you will then need to call #lib_override_hierarchy_dependencies_recursive_tag to + * complete tagging of all dependencies within the override group. * * We currently only consider Collections and Objects (that are not used as bone shapes) as valid * boundary IDs to define an override group. diff --git a/source/blender/blenkernel/intern/undo_system.c b/source/blender/blenkernel/intern/undo_system.c index e78576206de..5f99f629f42 100644 --- a/source/blender/blenkernel/intern/undo_system.c +++ b/source/blender/blenkernel/intern/undo_system.c @@ -586,7 +586,7 @@ UndoPushReturn BKE_undosys_step_push_with_type(UndoStack *ustack, BLI_strncpy(us->name, name, sizeof(us->name)); } us->type = ut; - /* True by default, code needs to explicitely set it to false if necessary. */ + /* True by default, code needs to explicitly set it to false if necessary. */ us->use_old_bmain_data = true; /* Initialized, not added yet. */ diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index a6e96a4d919..7e54bca4c93 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -1197,7 +1197,7 @@ static void rearrange_nla_channels(bAnimContext *ac, AnimData *adt, eRearrangeAn rearrange_animchannel_islands( &adt->nla_tracks, rearrange_func, mode, ANIMTYPE_NLATRACK, &anim_data_visible); - /* Add back non-local NLA tracks at the begining of the animation data's list. */ + /* Add back non-local NLA tracks at the beginning of the animation data's list. */ if (!BLI_listbase_is_empty(&extracted_nonlocal_nla_tracks)) { BLI_assert(is_liboverride); ((NlaTrack *)extracted_nonlocal_nla_tracks.last)->next = adt->nla_tracks.first; diff --git a/source/blender/editors/space_clip/space_clip.c b/source/blender/editors/space_clip/space_clip.c index a5935f06927..33783f19a79 100644 --- a/source/blender/editors/space_clip/space_clip.c +++ b/source/blender/editors/space_clip/space_clip.c @@ -994,7 +994,7 @@ static void clip_main_region_draw(const bContext *C, ARegion *region) /* callback */ /* TODO(sergey): For being consistent with space image the projection needs to be configured - * the way how the commented out code does it. This works corrent for tracking data, but it + * the way how the commented out code does it. This works correct for tracking data, but it * causes wrong aspect correction for mask editor (see T84990). */ // GPU_matrix_push_projection(); // wmOrtho2(region->v2d.cur.xmin, region->v2d.cur.xmax, region->v2d.cur.ymin, From 14f61c619b0bd28386673672881a234e7e1ded11 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 26 Jan 2021 08:04:25 +1100 Subject: [PATCH 03/55] Fix wm.context_* operators reusing values when it's not expected wm.context_* operators typically have their options set by menus or key bindings. Re-using options in this case can cause problems where two actions that change unrelated properties will re-use a setting from the previous execution. For example changing the lights Power impacted changing it's Radius afterwards. --- release/scripts/startup/bl_operators/wm.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/release/scripts/startup/bl_operators/wm.py b/release/scripts/startup/bl_operators/wm.py index bef3e5d4384..ee46742fbd0 100644 --- a/release/scripts/startup/bl_operators/wm.py +++ b/release/scripts/startup/bl_operators/wm.py @@ -48,18 +48,21 @@ rna_reverse_prop = BoolProperty( name="Reverse", description="Cycle backwards", default=False, + options={'SKIP_SAVE'}, ) rna_wrap_prop = BoolProperty( name="Wrap", description="Wrap back to the first/last values", default=False, + options={'SKIP_SAVE'}, ) rna_relative_prop = BoolProperty( name="Relative", description="Apply relative to the current value (delta)", default=False, + options={'SKIP_SAVE'}, ) rna_space_type_prop = EnumProperty( @@ -233,6 +236,7 @@ class WM_OT_context_scale_int(Operator): name="Always Step", description="Always adjust the value by a minimum of 1 when 'value' is not 1.0", default=True, + options={'SKIP_SAVE'}, ) def execute(self, context): @@ -741,10 +745,12 @@ class WM_OT_context_modal_mouse(Operator): input_scale: FloatProperty( description="Scale the mouse movement by this value before applying the delta", default=0.01, + options={'SKIP_SAVE'}, ) invert: BoolProperty( description="Invert the mouse input", default=False, + options={'SKIP_SAVE'}, ) initial_x: IntProperty(options={'HIDDEN'}) @@ -1744,6 +1750,7 @@ class WM_OT_tool_set_by_index(Operator): expand: BoolProperty( description="Include tool subgroups", default=True, + options={'SKIP_SAVE'}, ) as_fallback: BoolProperty( From 77f73a92843965906189dd56dcc4d18eae2371cc Mon Sep 17 00:00:00 2001 From: Julian Eisel Date: Mon, 25 Jan 2021 22:54:00 +0100 Subject: [PATCH 04/55] Fix library name clipping most of the data-block name in data-block menus Issue is visible here https://developer.blender.org/F8626313. If there is enough space for both the item name and the library hint, display both. Otherwise, clip either the item name, the library hint, or both so that not more than 60% and 40% of the available width are used repectively. There are further improvements we could do, as noted in T84188, this just fixes the regression for the release. Part of T84188. There were multiple reports about this, see merged in and mentioned reports in T84188 and T78012. --- .../editors/interface/interface_intern.h | 16 ++++++- .../interface/interface_region_search.c | 35 ++++++++++---- .../editors/interface/interface_widgets.c | 48 ++++++++++++++++--- 3 files changed, 84 insertions(+), 15 deletions(-) diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 991e8aaf89a..f4e68ca3909 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -991,12 +991,26 @@ extern void ui_draw_but(const struct bContext *C, uiBut *but, rcti *rect); +/** + * Info about what the separator character separates, used to decide between different drawing + * styles. E.g. we never want a shortcut string to be clipped, but other hint strings can be + * clipped. + */ +typedef enum { + UI_MENU_ITEM_SEPARATOR_NONE, + /** Separator is used to indicate shortcut string of this item. Shortcut string will not get + * clipped. */ + UI_MENU_ITEM_SEPARATOR_SHORTCUT, + /** Separator is used to indicate some additional hint to display for this item. Hint string will + * get clipped before the normal text. */ + UI_MENU_ITEM_SEPARATOR_HINT, +} uiMenuItemSeparatorType; void ui_draw_menu_item(const struct uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int state, - bool use_sep, + uiMenuItemSeparatorType separator_type, int *r_xmax); void ui_draw_preview_item( const struct uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int state); diff --git a/source/blender/editors/interface/interface_region_search.c b/source/blender/editors/interface/interface_region_search.c index 7a665909c76..816162e9aa2 100644 --- a/source/blender/editors/interface/interface_region_search.c +++ b/source/blender/editors/interface/interface_region_search.c @@ -610,7 +610,15 @@ static void ui_searchbox_region_draw_cb(const bContext *C, ARegion *region) char *name = data->items.names[a]; int icon = data->items.icons[a]; char *name_sep_test = NULL; - const bool use_sep_char = data->use_sep || (state & UI_BUT_HAS_SEP_CHAR); + + uiMenuItemSeparatorType separator_type = UI_MENU_ITEM_SEPARATOR_NONE; + if (data->use_sep) { + separator_type = UI_MENU_ITEM_SEPARATOR_SHORTCUT; + } + /* Only set for displaying additional hint (e.g. library name of a linked data-block). */ + else if (state & UI_BUT_HAS_SEP_CHAR) { + separator_type = UI_MENU_ITEM_SEPARATOR_HINT; + } ui_searchbox_butrect(&rect, data, a); @@ -623,7 +631,7 @@ static void ui_searchbox_region_draw_cb(const bContext *C, ARegion *region) } /* Simple menu item. */ - ui_draw_menu_item(&data->fstyle, &rect, name, icon, state, use_sep_char, NULL); + ui_draw_menu_item(&data->fstyle, &rect, name, icon, state, separator_type, NULL); } else { /* Split menu item, faded text before the separator. */ @@ -637,8 +645,13 @@ static void ui_searchbox_region_draw_cb(const bContext *C, ARegion *region) const char name_sep_prev = *name_sep; *name_sep = '\0'; int name_width = 0; - ui_draw_menu_item( - &data->fstyle, &rect, name, 0, state | UI_BUT_INACTIVE, false, &name_width); + ui_draw_menu_item(&data->fstyle, + &rect, + name, + 0, + state | UI_BUT_INACTIVE, + UI_MENU_ITEM_SEPARATOR_NONE, + &name_width); *name_sep = name_sep_prev; rect.xmin += name_width; rect.xmin += UI_UNIT_X / 4; @@ -650,7 +663,7 @@ static void ui_searchbox_region_draw_cb(const bContext *C, ARegion *region) /* The previous menu item draws the active selection. */ ui_draw_menu_item( - &data->fstyle, &rect, name_sep, icon, state & ~UI_ACTIVE, use_sep_char, NULL); + &data->fstyle, &rect, name_sep, icon, state & ~UI_ACTIVE, separator_type, NULL); } } /* indicate more */ @@ -943,10 +956,16 @@ static void ui_searchbox_region_draw_cb__operator(const bContext *UNUSED(C), ARe CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, text_pre), data->items.icons[a], state, - false, + UI_MENU_ITEM_SEPARATOR_NONE, + NULL); + ui_draw_menu_item(&data->fstyle, + &rect_post, + data->items.names[a], + 0, + state, + data->use_sep ? UI_MENU_ITEM_SEPARATOR_SHORTCUT : + UI_MENU_ITEM_SEPARATOR_NONE, NULL); - ui_draw_menu_item( - &data->fstyle, &rect_post, data->items.names[a], 0, state, data->use_sep, NULL); } } /* indicate more */ diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index a99f05730bb..c0c34b0a93d 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -5221,11 +5221,13 @@ void ui_draw_menu_item(const uiFontStyle *fstyle, const char *name, int iconid, int state, - bool use_sep, + uiMenuItemSeparatorType separator_type, int *r_xmax) { uiWidgetType *wt = widget_type(UI_WTYPE_MENU_ITEM); const rcti _rect = *rect; + int max_hint_width = INT_MAX; + int padding = 0.25f * UI_UNIT_X; char *cpoin = NULL; wt->state(wt, state, 0, UI_EMBOSS_UNDEFINED); @@ -5234,13 +5236,13 @@ void ui_draw_menu_item(const uiFontStyle *fstyle, UI_fontstyle_set(fstyle); /* text location offset */ - rect->xmin += 0.25f * UI_UNIT_X; + rect->xmin += padding; if (iconid) { rect->xmin += UI_DPI_ICON_SIZE; } /* cut string in 2 parts? */ - if (use_sep) { + if (separator_type != UI_MENU_ITEM_SEPARATOR_NONE) { cpoin = strrchr(name, UI_SEP_CHAR); if (cpoin) { *cpoin = 0; @@ -5253,7 +5255,30 @@ void ui_draw_menu_item(const uiFontStyle *fstyle, BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT); } - rect->xmax -= BLF_width(fstyle->uifont_id, cpoin + 1, INT_MAX) + UI_DPI_ICON_SIZE; + if (separator_type == UI_MENU_ITEM_SEPARATOR_SHORTCUT) { + /* Shrink rect to exclude the shortcut string. */ + rect->xmax -= BLF_width(fstyle->uifont_id, cpoin + 1, INT_MAX) + UI_DPI_ICON_SIZE; + } + else if (separator_type == UI_MENU_ITEM_SEPARATOR_HINT) { + /* Deterimine max-width for the hint string to leave the name string un-clipped (if there's + * enough space to display it). */ + + const int available_width = BLI_rcti_size_x(rect) - padding; + const int name_width = BLF_width(fstyle->uifont_id, name, INT_MAX); + const int hint_width = BLF_width(fstyle->uifont_id, cpoin + 1, INT_MAX) + padding; + + if ((name_width + hint_width) > available_width) { + /* Clipping width for hint string. */ + max_hint_width = available_width * 0.40f; + /* Clipping xmax for clipping of item name. */ + rect->xmax = (hint_width < max_hint_width) ? + (rect->xmax - hint_width) : + (rect->xmin + (available_width - max_hint_width)); + } + } + else { + BLI_assert(!"Unknwon menu item separator type"); + } if (fstyle->kerning == 1) { BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT); @@ -5308,15 +5333,26 @@ void ui_draw_menu_item(const uiFontStyle *fstyle, } /* part text right aligned */ - if (use_sep) { + if (separator_type != UI_MENU_ITEM_SEPARATOR_NONE) { if (cpoin) { /* Set inactive state for grayed out text. */ wt->state(wt, state | UI_BUT_INACTIVE, 0, UI_EMBOSS_UNDEFINED); + char hint_drawstr[UI_MAX_DRAW_STR]; + { + const size_t max_len = sizeof(hint_drawstr); + const float minwidth = (float)(UI_DPI_ICON_SIZE); + + BLI_strncpy(hint_drawstr, cpoin + 1, sizeof(hint_drawstr)); + if (hint_drawstr[0] && (max_hint_width < INT_MAX)) { + UI_text_clip_middle_ex(fstyle, hint_drawstr, max_hint_width, minwidth, max_len, '\0'); + } + } + rect->xmax = _rect.xmax - 5; UI_fontstyle_draw(fstyle, rect, - cpoin + 1, + hint_drawstr, wt->wcol.text, &(struct uiFontStyleDraw_Params){ .align = UI_STYLE_TEXT_RIGHT, From 6249995c5ebb65127daae6fa235b7db9d26c9950 Mon Sep 17 00:00:00 2001 From: Falk David Date: Tue, 26 Jan 2021 09:15:09 +1100 Subject: [PATCH 05/55] Fix T85054: undo/redo app handlers broken Regression in recent commit c13383da416c9c99d03058caaf66c736af0272cb which swapped undo/redo when calling the handlers. Ref D10200 --- source/blender/editors/undo/ed_undo.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c index 860eaa37816..723e92b9d09 100644 --- a/source/blender/editors/undo/ed_undo.c +++ b/source/blender/editors/undo/ed_undo.c @@ -252,7 +252,7 @@ static int ed_undo_step_impl(bContext *C, Main *bmain = CTX_data_main(C); wm->op_undo_depth++; BKE_callback_exec_id( - bmain, &scene->id, (step_for_callback > 0) ? BKE_CB_EVT_UNDO_PRE : BKE_CB_EVT_REDO_PRE); + bmain, &scene->id, (step_for_callback == STEP_UNDO) ? BKE_CB_EVT_UNDO_PRE : BKE_CB_EVT_REDO_PRE); wm->op_undo_depth--; } @@ -301,7 +301,7 @@ static int ed_undo_step_impl(bContext *C, scene = CTX_data_scene(C); wm->op_undo_depth++; BKE_callback_exec_id( - bmain, &scene->id, step_for_callback > 0 ? BKE_CB_EVT_UNDO_POST : BKE_CB_EVT_REDO_POST); + bmain, &scene->id, (step_for_callback == STEP_UNDO) ? BKE_CB_EVT_UNDO_POST : BKE_CB_EVT_REDO_POST); wm->op_undo_depth--; } From c4f3475612bb21fe5da35b1a1c0fd24045a8316e Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 26 Jan 2021 09:23:44 +1100 Subject: [PATCH 06/55] Cleanup: update comment from 77f73a92843965906189dd56dcc4d18eae2371cc --- source/blender/editors/interface/interface_widgets.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index c0c34b0a93d..3c720a39003 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -5211,8 +5211,7 @@ void ui_draw_tooltip_background(const uiStyle *UNUSED(style), uiBlock *UNUSED(bl * * \param state: The state of the button, * typically #UI_ACTIVE, #UI_BUT_DISABLED, #UI_BUT_INACTIVE. - * \param use_sep: When true, characters after the last #UI_SEP_CHAR are right aligned, - * use for displaying key shortcuts. + * \param separator_type: The kind of separator which controls if and how the string is clipped. * \param r_xmax: The right hand position of the text, this takes into the icon, * padding and text clipping when there is not enough room to display the full text. */ @@ -5260,7 +5259,7 @@ void ui_draw_menu_item(const uiFontStyle *fstyle, rect->xmax -= BLF_width(fstyle->uifont_id, cpoin + 1, INT_MAX) + UI_DPI_ICON_SIZE; } else if (separator_type == UI_MENU_ITEM_SEPARATOR_HINT) { - /* Deterimine max-width for the hint string to leave the name string un-clipped (if there's + /* Determine max-width for the hint string to leave the name string un-clipped (if there's * enough space to display it). */ const int available_width = BLI_rcti_size_x(rect) - padding; From 70e064f1118d18e1671f16cd2789f8cb7b8fd1e1 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Mon, 25 Jan 2021 16:28:00 -0600 Subject: [PATCH 07/55] Cleanup: Correct comments in ID type enum --- source/blender/makesdna/DNA_ID.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 2c7e82e6587..26824216337 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -453,7 +453,7 @@ typedef enum ID_Type { ID_TXT = MAKE_ID2('T', 'X'), /* Text */ ID_SPK = MAKE_ID2('S', 'K'), /* Speaker */ ID_SO = MAKE_ID2('S', 'O'), /* Sound */ - ID_GR = MAKE_ID2('G', 'R'), /* Group */ + ID_GR = MAKE_ID2('G', 'R'), /* Collection */ ID_AR = MAKE_ID2('A', 'R'), /* bArmature */ ID_AC = MAKE_ID2('A', 'C'), /* bAction */ ID_NT = MAKE_ID2('N', 'T'), /* bNodeTree */ @@ -472,7 +472,7 @@ typedef enum ID_Type { ID_HA = MAKE_ID2('H', 'A'), /* Hair */ ID_PT = MAKE_ID2('P', 'T'), /* PointCloud */ ID_VO = MAKE_ID2('V', 'O'), /* Volume */ - ID_SIM = MAKE_ID2('S', 'I'), /* Simulation (currently unused) */ + ID_SIM = MAKE_ID2('S', 'I'), /* Simulation (geometry node groups) */ } ID_Type; /* Only used as 'placeholder' in .blend files for directly linked data-blocks. */ From ae1e68f5146deff825c390fd180d1d45f33cb162 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Mon, 25 Jan 2021 17:22:52 -0600 Subject: [PATCH 08/55] Cleanup: Declare variables where initialized --- source/blender/blenkernel/intern/collection.c | 8 ++-- .../editors/space_view3d/view3d_utils.c | 42 +++++++------------ 2 files changed, 17 insertions(+), 33 deletions(-) diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 4e29ca80d30..601ee57fc89 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -1943,9 +1943,6 @@ static void scene_collections_build_array(Collection *collection, void *data) static void scene_collections_array(Scene *scene, Collection ***collections_array, int *tot) { - Collection *collection; - Collection **array; - *collections_array = NULL; *tot = 0; @@ -1953,7 +1950,7 @@ static void scene_collections_array(Scene *scene, Collection ***collections_arra return; } - collection = scene->master_collection; + Collection *collection = scene->master_collection; BLI_assert(collection != NULL); scene_collection_callback(collection, scene_collections_count, tot); @@ -1961,7 +1958,8 @@ static void scene_collections_array(Scene *scene, Collection ***collections_arra return; } - *collections_array = array = MEM_mallocN(sizeof(Collection *) * (*tot), "CollectionArray"); + Collection **array = MEM_mallocN(sizeof(Collection *) * (*tot), "CollectionArray"); + *collections_array = array; scene_collection_callback(collection, scene_collections_build_array, &array); } diff --git a/source/blender/editors/space_view3d/view3d_utils.c b/source/blender/editors/space_view3d/view3d_utils.c index 2b7b8255068..a6a77ecd5f7 100644 --- a/source/blender/editors/space_view3d/view3d_utils.c +++ b/source/blender/editors/space_view3d/view3d_utils.c @@ -224,13 +224,11 @@ void view3d_region_operator_needs_opengl(wmWindow *UNUSED(win), ARegion *region) */ void ED_view3d_polygon_offset(const RegionView3D *rv3d, const float dist) { - float viewdist; - if (rv3d->rflag & RV3D_ZOFFSET_DISABLED) { return; } - viewdist = rv3d->dist; + float viewdist = rv3d->dist; /* special exception for ortho camera (viewdist isnt used for perspective cameras) */ if (dist != 0.0f) { @@ -248,7 +246,6 @@ bool ED_view3d_context_activate(bContext *C) { bScreen *screen = CTX_wm_screen(C); ScrArea *area = CTX_wm_area(C); - ARegion *region; /* area can be NULL when called from python */ if (area == NULL || area->spacetype != SPACE_VIEW3D) { @@ -259,7 +256,7 @@ bool ED_view3d_context_activate(bContext *C) return false; } - region = BKE_area_find_region_active_win(area); + ARegion *region = BKE_area_find_region_active_win(area); if (region == NULL) { return false; } @@ -282,9 +279,7 @@ void ED_view3d_clipping_calc_from_boundbox(float clip[4][4], const BoundBox *bb, const bool is_flip) { - int val; - - for (val = 0; val < 4; val++) { + for (int val = 0; val < 4; val++) { normal_tri_v3(clip[val], bb->vec[val], bb->vec[val == 3 ? 0 : val + 1], bb->vec[val + 4]); if (UNLIKELY(is_flip)) { negate_v3(clip[val]); @@ -752,14 +747,12 @@ bool ED_view3d_camera_lock_autokey(View3D *v3d, static void view3d_boxview_clip(ScrArea *area) { - ARegion *region; BoundBox *bb = MEM_callocN(sizeof(BoundBox), "clipbb"); float clip[6][4]; float x1 = 0.0f, y1 = 0.0f, z1 = 0.0f, ofs[3] = {0.0f, 0.0f, 0.0f}; - int val; /* create bounding box */ - for (region = area->regionbase.first; region; region = region->next) { + LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { if (region->regiontype == RGN_TYPE_WINDOW) { RegionView3D *rv3d = region->regiondata; @@ -794,7 +787,7 @@ static void view3d_boxview_clip(ScrArea *area) } } - for (val = 0; val < 8; val++) { + for (int val = 0; val < 8; val++) { if (ELEM(val, 0, 3, 4, 7)) { bb->vec[val][0] = -x1 - ofs[0]; } @@ -826,12 +819,12 @@ static void view3d_boxview_clip(ScrArea *area) normal_tri_v3(clip[5], bb->vec[0], bb->vec[2], bb->vec[1]); /* then plane equations */ - for (val = 0; val < 6; val++) { + for (int val = 0; val < 6; val++) { clip[val][3] = -dot_v3v3(clip[val], bb->vec[val % 5]); } /* create bounding box */ - for (region = area->regionbase.first; region; region = region->next) { + LISTBASE_FOREACH (ARegion *, region, &area->regionbase) { if (region->regiontype == RGN_TYPE_WINDOW) { RegionView3D *rv3d = region->regiondata; @@ -950,11 +943,10 @@ void ED_view3d_quadview_update(ScrArea *area, ARegion *region, bool do_clip) { ARegion *region_sync = NULL; RegionView3D *rv3d = region->regiondata; - short viewlock; /* this function copies flags from the first of the 3 other quadview * regions to the 2 other, so it assumes this is the region whose * properties are always being edited, weak */ - viewlock = rv3d->viewlock; + short viewlock = rv3d->viewlock; if ((viewlock & RV3D_LOCK_ROTATION) == 0) { do_clip = (viewlock & RV3D_BOXCLIP) != 0; @@ -1015,10 +1007,7 @@ void ED_view3d_quadview_update(ScrArea *area, ARegion *region, bool do_clip) static float view_autodist_depth_margin(ARegion *region, const int mval[2], int margin) { - ViewDepths depth_temp = {0}; rcti rect; - float depth_close; - if (margin == 0) { /* Get Z Depths, needed for perspective, nice for ortho */ rect.xmin = mval[0]; @@ -1030,8 +1019,9 @@ static float view_autodist_depth_margin(ARegion *region, const int mval[2], int BLI_rcti_init_pt_radius(&rect, mval, margin); } + ViewDepths depth_temp = {0}; view3d_update_depths_rect(region, &depth_temp, &rect); - depth_close = view3d_depth_near(&depth_temp); + float depth_close = view3d_depth_near(&depth_temp); MEM_SAFE_FREE(depth_temp.depths); return depth_close; } @@ -1053,14 +1043,13 @@ bool ED_view3d_autodist(Depsgraph *depsgraph, { float depth_close; int margin_arr[] = {0, 2, 4}; - int i; bool depth_ok = false; /* Get Z Depths, needed for perspective, nice for ortho */ ED_view3d_draw_depth(depsgraph, region, v3d, alphaoverride); /* Attempt with low margin's first */ - i = 0; + int i = 0; do { depth_close = view_autodist_depth_margin(region, mval, margin_arr[i++] * U.pixelsize); depth_ok = (depth_close != FLT_MAX); @@ -1104,9 +1093,8 @@ bool ED_view3d_autodist_simple(ARegion *region, int margin, const float *force_depth) { - float depth; - /* Get Z Depths, needed for perspective, nice for ortho */ + float depth; if (force_depth) { depth = *force_depth; } @@ -1237,7 +1225,6 @@ float ED_view3d_radius_to_dist(const View3D *v3d, } else { float lens, sensor_size, zoom; - float angle; if (persp == RV3D_CAMOB) { CameraParams params; @@ -1259,7 +1246,7 @@ float ED_view3d_radius_to_dist(const View3D *v3d, zoom = CAMERA_PARAM_ZOOM_INIT_PERSP; } - angle = focallength_to_fov(lens, sensor_size); + float angle = focallength_to_fov(lens, sensor_size); /* zoom influences lens, correct this by scaling the angle as a distance * (by the zoom-level) */ @@ -1319,14 +1306,13 @@ float ED_view3d_offset_distance(const float mat[4][4], { float pos[4] = {0.0f, 0.0f, 0.0f, 1.0f}; float dir[4] = {0.0f, 0.0f, 1.0f, 0.0f}; - float dist; mul_m4_v4(mat, pos); add_v3_v3(pos, ofs); mul_m4_v4(mat, dir); normalize_v3(dir); - dist = dot_v3v3(pos, dir); + float dist = dot_v3v3(pos, dir); if ((dist < FLT_EPSILON) && (fallback_dist != 0.0f)) { dist = fallback_dist; From 0734b235d20f4b764265fce089df73de0f052739 Mon Sep 17 00:00:00 2001 From: Zev Eisenberg Date: Mon, 25 Jan 2021 21:58:37 -0500 Subject: [PATCH 09/55] Fix typos in driver_functions.py I'm learning how driver functions work, and I found a couple of typos in the driver_functions.py template file. Here's a quick patch to fix them up. Reviewed By: Blendify Differential Revision: https://developer.blender.org/D10149 --- release/scripts/templates_py/driver_functions.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/release/scripts/templates_py/driver_functions.py b/release/scripts/templates_py/driver_functions.py index 1c6af0e574f..d3aab75e7ba 100644 --- a/release/scripts/templates_py/driver_functions.py +++ b/release/scripts/templates_py/driver_functions.py @@ -1,8 +1,8 @@ -# This script defines functions to be used directly in drivers expressions to -# extend the builtin set of python functions. +# This script defines functions to be used directly in driver expressions to +# extend the built-in set of python functions. # # This can be executed on manually or set to 'Register' to -# initialize thefunctions on file load. +# initialize the functions on file load. # two sample functions @@ -30,6 +30,6 @@ def slow_value(value, fac, uuid): import bpy -# Add variable defined in this script into the drivers namespace. +# Add functions defined in this script into the drivers namespace. bpy.app.driver_namespace["invert"] = invert bpy.app.driver_namespace["slow_value"] = slow_value From be262cf561293541b889a97026311adf3965a545 Mon Sep 17 00:00:00 2001 From: Juanfran Matheu Date: Mon, 25 Jan 2021 22:00:49 -0500 Subject: [PATCH 10/55] TEXTURE PAINT: Tools with wrong cursor Texture paint tools were using DEFAULT cursor instead of PAINT_CROSS cursor as vertex paint, weight paint and sculpt modes. Before {F9591366} After {F9591370} Reviewed By: Blendify Differential Revision: https://developer.blender.org/D10172 --- release/scripts/startup/bl_ui/space_toolsystem_toolbar.py | 1 + 1 file changed, 1 insertion(+) diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py index ba165d1e86c..fdc3732f92a 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -1561,6 +1561,7 @@ class _defs_texture_paint: icon_prefix="brush.paint_texture.", type=bpy.types.Brush, attr="image_tool", + cursor='PAINT_CROSS', ) From d7a2e0b83cf3d32ad883a3ae26d09e3897cadfe6 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Mon, 25 Jan 2021 21:11:57 -0600 Subject: [PATCH 11/55] Cleanup: Use const arguments --- source/blender/blenkernel/BKE_node.h | 6 +++--- source/blender/blenkernel/intern/node.c | 10 +++++----- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 12266cd48d9..fb517b7c1d0 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -685,7 +685,7 @@ void nodeSetSocketAvailability(struct bNodeSocket *sock, bool is_available); int nodeSocketLinkLimit(const struct bNodeSocket *sock); /* Node Clipboard */ -void BKE_node_clipboard_init(struct bNodeTree *ntree); +void BKE_node_clipboard_init(const struct bNodeTree *ntree); void BKE_node_clipboard_clear(void); void BKE_node_clipboard_free(void); bool BKE_node_clipboard_validate(void); @@ -706,8 +706,8 @@ extern const bNodeInstanceKey NODE_INSTANCE_KEY_BASE; extern const bNodeInstanceKey NODE_INSTANCE_KEY_NONE; bNodeInstanceKey BKE_node_instance_key(bNodeInstanceKey parent_key, - struct bNodeTree *ntree, - struct bNode *node); + const struct bNodeTree *ntree, + const struct bNode *node); bNodeInstanceHash *BKE_node_instance_hash_new(const char *info); void BKE_node_instance_hash_free(bNodeInstanceHash *hash, bNodeInstanceValueFP valfreefp); diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index f121f34d772..f4f0d991f06 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -3574,7 +3574,7 @@ typedef struct bNodeClipboard { static bNodeClipboard node_clipboard = {{NULL}}; -void BKE_node_clipboard_init(struct bNodeTree *ntree) +void BKE_node_clipboard_init(const struct bNodeTree *ntree) { node_clipboard.type = ntree->type; } @@ -3718,11 +3718,11 @@ static bNodeInstanceKey node_hash_int_str(bNodeInstanceKey hash, const char *str return hash; } -bNodeInstanceKey BKE_node_instance_key(bNodeInstanceKey parent_key, bNodeTree *ntree, bNode *node) +bNodeInstanceKey BKE_node_instance_key(bNodeInstanceKey parent_key, + const bNodeTree *ntree, + const bNode *node) { - bNodeInstanceKey key; - - key = node_hash_int_str(parent_key, ntree->id.name + 2); + bNodeInstanceKey key = node_hash_int_str(parent_key, ntree->id.name + 2); if (node) { key = node_hash_int_str(key, node->name); From 6499a2ec5c7f4efc927ea3975099060b37d22274 Mon Sep 17 00:00:00 2001 From: Zev Eisenberg Date: Mon, 25 Jan 2021 21:58:37 -0500 Subject: [PATCH 12/55] Fix typos in driver_functions.py I'm learning how driver functions work, and I found a couple of typos in the driver_functions.py template file. Here's a quick patch to fix them up. Reviewed By: Blendify Differential Revision: https://developer.blender.org/D10149 --- release/scripts/templates_py/driver_functions.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/release/scripts/templates_py/driver_functions.py b/release/scripts/templates_py/driver_functions.py index 1c6af0e574f..d3aab75e7ba 100644 --- a/release/scripts/templates_py/driver_functions.py +++ b/release/scripts/templates_py/driver_functions.py @@ -1,8 +1,8 @@ -# This script defines functions to be used directly in drivers expressions to -# extend the builtin set of python functions. +# This script defines functions to be used directly in driver expressions to +# extend the built-in set of python functions. # # This can be executed on manually or set to 'Register' to -# initialize thefunctions on file load. +# initialize the functions on file load. # two sample functions @@ -30,6 +30,6 @@ def slow_value(value, fac, uuid): import bpy -# Add variable defined in this script into the drivers namespace. +# Add functions defined in this script into the drivers namespace. bpy.app.driver_namespace["invert"] = invert bpy.app.driver_namespace["slow_value"] = slow_value From 7d2f746369e6f79bc6282990d9b1e10764462077 Mon Sep 17 00:00:00 2001 From: Juanfran Matheu Date: Mon, 25 Jan 2021 22:00:49 -0500 Subject: [PATCH 13/55] TEXTURE PAINT: Tools with wrong cursor Texture paint tools were using DEFAULT cursor instead of PAINT_CROSS cursor as vertex paint, weight paint and sculpt modes. Before {F9591366} After {F9591370} Reviewed By: Blendify Differential Revision: https://developer.blender.org/D10172 --- release/scripts/startup/bl_ui/space_toolsystem_toolbar.py | 1 + 1 file changed, 1 insertion(+) diff --git a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py index ba165d1e86c..fdc3732f92a 100644 --- a/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py +++ b/release/scripts/startup/bl_ui/space_toolsystem_toolbar.py @@ -1561,6 +1561,7 @@ class _defs_texture_paint: icon_prefix="brush.paint_texture.", type=bpy.types.Brush, attr="image_tool", + cursor='PAINT_CROSS', ) From d55d95b04da42f120406678fc47deb00081f7285 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 26 Jan 2021 15:08:28 +1100 Subject: [PATCH 14/55] WM: return success from WM_recover_last_session, minor cleanup - Return success from WM_recover_last_session - Avoid setting global variables is already called in WM_file_read. While it didn't cause any problems, these assignments ran even when recovering the session failed to load the file. - Return OPERATOR_CANCELLED when the operator fails. Returning success is needed to fix T85011. --- source/blender/windowmanager/WM_api.h | 2 +- .../blender/windowmanager/intern/wm_files.c | 31 ++++++------------- 2 files changed, 10 insertions(+), 23 deletions(-) diff --git a/source/blender/windowmanager/WM_api.h b/source/blender/windowmanager/WM_api.h index 1f205a71338..540896664da 100644 --- a/source/blender/windowmanager/WM_api.h +++ b/source/blender/windowmanager/WM_api.h @@ -188,7 +188,7 @@ bool WM_stereo3d_enabled(struct wmWindow *win, bool only_fullscreen_test); void WM_file_autoexec_init(const char *filepath); bool WM_file_read(struct bContext *C, const char *filepath, struct ReportList *reports); void WM_autosave_init(struct wmWindowManager *wm); -void WM_recover_last_session(struct bContext *C, struct ReportList *reports); +bool WM_recover_last_session(struct bContext *C, struct ReportList *reports); void WM_file_tag_modified(void); struct ID *WM_file_append_datablock(struct Main *bmain, diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index d179cc456f4..bfc3d7e1a5f 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -2549,35 +2549,22 @@ void WM_OT_revert_mainfile(wmOperatorType *ot) /** \name Recover Last Session Operator * \{ */ -void WM_recover_last_session(bContext *C, ReportList *reports) +bool WM_recover_last_session(bContext *C, ReportList *reports) { char filepath[FILE_MAX]; - BLI_join_dirfile(filepath, sizeof(filepath), BKE_tempdir_base(), BLENDER_QUIT_FILE); - /* if reports==NULL, it's called directly without operator, we add a quick check here */ - if (reports || BLI_exists(filepath)) { - G.fileflags |= G_FILE_RECOVER; - - wm_file_read_opwrap(C, filepath, reports, true); - - G.fileflags &= ~G_FILE_RECOVER; - - /* XXX bad global... fixme */ - Main *bmain = CTX_data_main(C); - if (BKE_main_blendfile_path(bmain)[0] != '\0') { - G.file_loaded = 1; /* prevents splash to show */ - } - else { - G.relbase_valid = 0; - G.save_over = 0; /* start with save preference untitled.blend */ - } - } + G.fileflags |= G_FILE_RECOVER; + const bool success = wm_file_read_opwrap(C, filepath, reports, true); + G.fileflags &= ~G_FILE_RECOVER; + return success; } static int wm_recover_last_session_exec(bContext *C, wmOperator *op) { - WM_recover_last_session(C, op->reports); - return OPERATOR_FINISHED; + if (WM_recover_last_session(C, op->reports)) { + return OPERATOR_FINISHED; + } + return OPERATOR_CANCELLED; } void WM_OT_recover_last_session(wmOperatorType *ot) From e9e054b987e5107308e3636f3a5aad18d961c2fe Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Mon, 25 Jan 2021 22:20:41 -0600 Subject: [PATCH 15/55] Geometry Nodes: Add float2 to attribute complexity map --- source/blender/nodes/geometry/node_geometry_util.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/source/blender/nodes/geometry/node_geometry_util.cc b/source/blender/nodes/geometry/node_geometry_util.cc index 53af6073793..daaccf4450b 100644 --- a/source/blender/nodes/geometry/node_geometry_util.cc +++ b/source/blender/nodes/geometry/node_geometry_util.cc @@ -54,6 +54,8 @@ static int attribute_data_type_complexity(const CustomDataType data_type) return 1; case CD_PROP_FLOAT: return 2; + case CD_PROP_FLOAT2: + return 3; case CD_PROP_FLOAT3: return 4; case CD_PROP_COLOR: From 7909f70f64e550633fd381b0875fc5ba21616187 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 26 Jan 2021 13:21:13 +1100 Subject: [PATCH 16/55] WM: add "use_scripts" to recover auto-save/session operators Support recovering blend files with scripts enabled, needed to fix T85011, can be useful in general too. Adding this also resolves an assert in BKE_autoexec_match, since it ran even when scripts were enabled. --- .../blender/windowmanager/intern/wm_files.c | 82 +++++++++---------- 1 file changed, 40 insertions(+), 42 deletions(-) diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index bfc3d7e1a5f..21364f00acf 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -2167,10 +2167,7 @@ void WM_OT_read_factory_settings(wmOperatorType *ot) /** * Wrap #WM_file_read, shared by file reading operators. */ -static bool wm_file_read_opwrap(bContext *C, - const char *filepath, - ReportList *reports, - const bool autoexec_init) +static bool wm_file_read_opwrap(bContext *C, const char *filepath, ReportList *reports) { bool success; @@ -2178,7 +2175,8 @@ static bool wm_file_read_opwrap(bContext *C, /* do it before for now, but is this correct with multiple windows? */ WM_event_add_notifier(C, NC_WINDOW, NULL); - if (autoexec_init) { + /* Set by the "use_scripts" property on file load. */ + if ((G.f & G_FLAG_SCRIPT_AUTOEXEC) == 0) { WM_file_autoexec_init(filepath); } @@ -2308,21 +2306,9 @@ static int wm_open_mainfile__open(bContext *C, wmOperator *op) wm_open_init_load_ui(op, false); wm_open_init_use_scripts(op, false); - if (RNA_boolean_get(op->ptr, "load_ui")) { - G.fileflags &= ~G_FILE_NO_UI; - } - else { - G.fileflags |= G_FILE_NO_UI; - } - - if (RNA_boolean_get(op->ptr, "use_scripts")) { - G.f |= G_FLAG_SCRIPT_AUTOEXEC; - } - else { - G.f &= ~G_FLAG_SCRIPT_AUTOEXEC; - } - - success = wm_file_read_opwrap(C, filepath, op->reports, !(G.f & G_FLAG_SCRIPT_AUTOEXEC)); + SET_FLAG_FROM_TEST(G.fileflags, !RNA_boolean_get(op->ptr, "load_ui"), G_FILE_NO_UI); + SET_FLAG_FROM_TEST(G.f, RNA_boolean_get(op->ptr, "use_scripts"), G_FLAG_SCRIPT_AUTOEXEC); + success = wm_file_read_opwrap(C, filepath, op->reports); /* for file open also popup for warnings, not only errors */ BKE_report_print_level_set(op->reports, RPT_WARNING); @@ -2453,6 +2439,16 @@ static void wm_open_mainfile_ui(bContext *UNUSED(C), wmOperator *op) uiItemR(col, op->ptr, "use_scripts", 0, autoexec_text, ICON_NONE); } +static void wm_open_mainfile_def_property_use_scripts(wmOperatorType *ot) +{ + RNA_def_boolean(ot->srna, + "use_scripts", + true, + "Trusted Source", + "Allow .blend file to execute scripts automatically, default available from " + "system preferences"); +} + void WM_OT_open_mainfile(wmOperatorType *ot) { ot->name = "Open"; @@ -2476,12 +2472,8 @@ void WM_OT_open_mainfile(wmOperatorType *ot) RNA_def_boolean( ot->srna, "load_ui", true, "Load UI", "Load user interface setup in the .blend file"); - RNA_def_boolean(ot->srna, - "use_scripts", - true, - "Trusted Source", - "Allow .blend file to execute scripts automatically, default available from " - "system preferences"); + + wm_open_mainfile_def_property_use_scripts(ot); PropertyRNA *prop = RNA_def_boolean( ot->srna, "display_file_selector", true, "Display File Selector", ""); @@ -2504,15 +2496,10 @@ static int wm_revert_mainfile_exec(bContext *C, wmOperator *op) wm_open_init_use_scripts(op, false); - if (RNA_boolean_get(op->ptr, "use_scripts")) { - G.f |= G_FLAG_SCRIPT_AUTOEXEC; - } - else { - G.f &= ~G_FLAG_SCRIPT_AUTOEXEC; - } + SET_FLAG_FROM_TEST(G.f, RNA_boolean_get(op->ptr, "use_scripts"), G_FLAG_SCRIPT_AUTOEXEC); BLI_strncpy(filepath, BKE_main_blendfile_path(bmain), sizeof(filepath)); - success = wm_file_read_opwrap(C, filepath, op->reports, !(G.f & G_FLAG_SCRIPT_AUTOEXEC)); + success = wm_file_read_opwrap(C, filepath, op->reports); if (success) { return OPERATOR_FINISHED; @@ -2535,12 +2522,7 @@ void WM_OT_revert_mainfile(wmOperatorType *ot) ot->exec = wm_revert_mainfile_exec; ot->poll = wm_revert_mainfile_poll; - RNA_def_boolean(ot->srna, - "use_scripts", - true, - "Trusted Source", - "Allow .blend file to execute scripts automatically, default available from " - "system preferences"); + wm_open_mainfile_def_property_use_scripts(ot); } /** \} */ @@ -2554,7 +2536,7 @@ bool WM_recover_last_session(bContext *C, ReportList *reports) char filepath[FILE_MAX]; BLI_join_dirfile(filepath, sizeof(filepath), BKE_tempdir_base(), BLENDER_QUIT_FILE); G.fileflags |= G_FILE_RECOVER; - const bool success = wm_file_read_opwrap(C, filepath, reports, true); + const bool success = wm_file_read_opwrap(C, filepath, reports); G.fileflags &= ~G_FILE_RECOVER; return success; } @@ -2567,14 +2549,24 @@ static int wm_recover_last_session_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } +static int wm_recover_last_session_invoke(bContext *C, wmOperator *op, const wmEvent *event) +{ + /* Keep the current setting instead of using the preferences since a file selector + * doesn't give us the option to change the setting. */ + wm_open_init_use_scripts(op, false); + return WM_operator_confirm(C, op, event); +} + void WM_OT_recover_last_session(wmOperatorType *ot) { ot->name = "Recover Last Session"; ot->idname = "WM_OT_recover_last_session"; ot->description = "Open the last closed file (\"" BLENDER_QUIT_FILE "\")"; - ot->invoke = WM_operator_confirm; + ot->invoke = wm_recover_last_session_invoke; ot->exec = wm_recover_last_session_exec; + + wm_open_mainfile_def_property_use_scripts(ot); } /** \} */ @@ -2590,9 +2582,12 @@ static int wm_recover_auto_save_exec(bContext *C, wmOperator *op) RNA_string_get(op->ptr, "filepath", filepath); + wm_open_init_use_scripts(op, true); + SET_FLAG_FROM_TEST(G.f, RNA_boolean_get(op->ptr, "use_scripts"), G_FLAG_SCRIPT_AUTOEXEC); + G.fileflags |= G_FILE_RECOVER; - success = wm_file_read_opwrap(C, filepath, op->reports, true); + success = wm_file_read_opwrap(C, filepath, op->reports); G.fileflags &= ~G_FILE_RECOVER; @@ -2608,6 +2603,7 @@ static int wm_recover_auto_save_invoke(bContext *C, wmOperator *op, const wmEven wm_autosave_location(filename); RNA_string_set(op->ptr, "filepath", filename); + wm_open_init_use_scripts(op, true); WM_event_add_fileselect(C, op); return OPERATOR_RUNNING_MODAL; @@ -2629,6 +2625,8 @@ void WM_OT_recover_auto_save(wmOperatorType *ot) WM_FILESEL_FILEPATH, FILE_VERTICALDISPLAY, FILE_SORT_TIME); + + wm_open_mainfile_def_property_use_scripts(ot); } /** \} */ From 0d9f79b163ee4f58a733138863ad6a934b82f794 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Mon, 25 Jan 2021 23:47:56 -0600 Subject: [PATCH 17/55] Cleanup: Reduce variable scope, use LISTBASE_FOREACH macro --- source/blender/blenkernel/intern/idprop.c | 104 +++++++--------------- 1 file changed, 32 insertions(+), 72 deletions(-) diff --git a/source/blender/blenkernel/intern/idprop.c b/source/blender/blenkernel/intern/idprop.c index b0991f1d343..6b164e6bc50 100644 --- a/source/blender/blenkernel/intern/idprop.c +++ b/source/blender/blenkernel/intern/idprop.c @@ -92,11 +92,9 @@ IDProperty *IDP_NewIDPArray(const char *name) IDProperty *IDP_CopyIDPArray(const IDProperty *array, const int flag) { /* don't use MEM_dupallocN because this may be part of an array */ - IDProperty *narray, *tmp; - BLI_assert(array->type == IDP_IDPARRAY); - narray = MEM_mallocN(sizeof(IDProperty), __func__); + IDProperty *narray = MEM_mallocN(sizeof(IDProperty), __func__); *narray = *array; narray->data.pointer = MEM_dupallocN(array->data.pointer); @@ -107,7 +105,7 @@ IDProperty *IDP_CopyIDPArray(const IDProperty *array, const int flag) * then free it. this makes for more maintainable * code than simply re-implementing the copy functions * in this loop.*/ - tmp = IDP_CopyProperty_ex(GETPROP(narray, i), flag); + IDProperty *tmp = IDP_CopyProperty_ex(GETPROP(narray, i), flag); memcpy(GETPROP(narray, i), tmp, sizeof(IDProperty)); MEM_freeN(tmp); } @@ -131,15 +129,13 @@ static void IDP_FreeIDPArray(IDProperty *prop, const bool do_id_user) /* shallow copies item */ void IDP_SetIndexArray(IDProperty *prop, int index, IDProperty *item) { - IDProperty *old; - BLI_assert(prop->type == IDP_IDPARRAY); if (index >= prop->len || index < 0) { return; } - old = GETPROP(prop, index); + IDProperty *old = GETPROP(prop, index); if (item != old) { IDP_FreePropertyContent(old); @@ -164,8 +160,6 @@ void IDP_AppendArray(IDProperty *prop, IDProperty *item) void IDP_ResizeIDPArray(IDProperty *prop, int newlen) { - int newsize; - BLI_assert(prop->type == IDP_IDPARRAY); /* first check if the array buffer size has room */ @@ -200,7 +194,7 @@ void IDP_ResizeIDPArray(IDProperty *prop, int newlen) * system realloc(). * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ... */ - newsize = newlen; + int newsize = newlen; newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize; prop->data.pointer = MEM_recallocN(prop->data.pointer, sizeof(IDProperty) * (size_t)newsize); prop->len = newlen; @@ -218,9 +212,8 @@ static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr) /* bigger */ IDProperty **array = newarr; IDPropertyTemplate val; - int a; - for (a = prop->len; a < newlen; a++) { + for (int a = prop->len; a < newlen; a++) { val.i = 0; /* silence MSVC warning about uninitialized var when debugging */ array[a] = IDP_New(IDP_GROUP, &val, "IDP_ResizeArray group"); } @@ -228,9 +221,8 @@ static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr) else { /* smaller */ IDProperty **array = prop->data.pointer; - int a; - for (a = newlen; a < prop->len; a++) { + for (int a = newlen; a < prop->len; a++) { IDP_FreeProperty(array[a]); } } @@ -239,7 +231,6 @@ static void idp_resize_group_array(IDProperty *prop, int newlen, void *newarr) /*this function works for strings too!*/ void IDP_ResizeArray(IDProperty *prop, int newlen) { - int newsize; const bool is_grow = newlen >= prop->len; /* first check if the array buffer size has room */ @@ -257,7 +248,7 @@ void IDP_ResizeArray(IDProperty *prop, int newlen) * system realloc(). * The growth pattern is: 0, 4, 8, 16, 25, 35, 46, 58, 72, 88, ... */ - newsize = newlen; + int newsize = newlen; newsize = (newsize >> 3) + (newsize < 9 ? 3 : 6) + newsize; if (is_grow == false) { @@ -362,10 +353,8 @@ IDProperty *IDP_NewString(const char *st, const char *name, int maxlen) static IDProperty *IDP_CopyString(const IDProperty *prop, const int flag) { - IDProperty *newp; - BLI_assert(prop->type == IDP_STRING); - newp = idp_generic_copy(prop, flag); + IDProperty *newp = idp_generic_copy(prop, flag); if (prop->data.pointer) { newp->data.pointer = MEM_dupallocN(prop->data.pointer); @@ -379,10 +368,8 @@ static IDProperty *IDP_CopyString(const IDProperty *prop, const int flag) void IDP_AssignString(IDProperty *prop, const char *st, int maxlen) { - int stlen; - BLI_assert(prop->type == IDP_STRING); - stlen = (int)strlen(st); + int stlen = (int)strlen(st); if (maxlen > 0 && maxlen < stlen) { stlen = maxlen; } @@ -400,11 +387,9 @@ void IDP_AssignString(IDProperty *prop, const char *st, int maxlen) void IDP_ConcatStringC(IDProperty *prop, const char *st) { - int newlen; - BLI_assert(prop->type == IDP_STRING); - newlen = prop->len + (int)strlen(st); + int newlen = prop->len + (int)strlen(st); /* we have to remember that prop->len includes the null byte for strings. * so there's no need to add +1 to the resize function.*/ IDP_ResizeArray(prop, newlen); @@ -413,13 +398,11 @@ void IDP_ConcatStringC(IDProperty *prop, const char *st) void IDP_ConcatString(IDProperty *str1, IDProperty *append) { - int newlen; - BLI_assert(append->type == IDP_STRING); /* since ->len for strings includes the NULL byte, we have to subtract one or * we'll get an extra null byte after each concatenation operation.*/ - newlen = str1->len + append->len - 1; + int newlen = str1->len + append->len - 1; IDP_ResizeArray(str1, newlen); strcat(str1->data.pointer, append->data.pointer); } @@ -440,10 +423,8 @@ void IDP_FreeString(IDProperty *prop) static IDProperty *IDP_CopyID(const IDProperty *prop, const int flag) { - IDProperty *newp; - BLI_assert(prop->type == IDP_ID); - newp = idp_generic_copy(prop, flag); + IDProperty *newp = idp_generic_copy(prop, flag); newp->data.pointer = prop->data.pointer; if ((flag & LIB_ID_CREATE_NO_USER_REFCOUNT) == 0) { @@ -479,14 +460,12 @@ void IDP_AssignID(IDProperty *prop, ID *id, const int flag) */ static IDProperty *IDP_CopyGroup(const IDProperty *prop, const int flag) { - IDProperty *newp, *link; - BLI_assert(prop->type == IDP_GROUP); - newp = idp_generic_copy(prop, flag); + IDProperty *newp = idp_generic_copy(prop, flag); newp->len = prop->len; newp->subtype = prop->subtype; - for (link = prop->data.group.first; link; link = link->next) { + LISTBASE_FOREACH (IDProperty *, link, &prop->data.group) { BLI_addtail(&newp->data.group, IDP_CopyProperty_ex(link, flag)); } @@ -497,13 +476,11 @@ static IDProperty *IDP_CopyGroup(const IDProperty *prop, const int flag) * When values name and types match, copy the values, else ignore */ void IDP_SyncGroupValues(IDProperty *dest, const IDProperty *src) { - IDProperty *other, *prop; - BLI_assert(dest->type == IDP_GROUP); BLI_assert(src->type == IDP_GROUP); - for (prop = src->data.group.first; prop; prop = prop->next) { - other = BLI_findstring(&dest->data.group, prop->name, offsetof(IDProperty, name)); + LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) { + IDProperty *other = BLI_findstring(&dest->data.group, prop->name, offsetof(IDProperty, name)); if (other && prop->type == other->type) { switch (prop->type) { case IDP_INT: @@ -526,12 +503,9 @@ void IDP_SyncGroupValues(IDProperty *dest, const IDProperty *src) void IDP_SyncGroupTypes(IDProperty *dest, const IDProperty *src, const bool do_arraylen) { - IDProperty *prop_dst, *prop_dst_next; - const IDProperty *prop_src; - - for (prop_dst = dest->data.group.first; prop_dst; prop_dst = prop_dst_next) { - prop_dst_next = prop_dst->next; - if ((prop_src = IDP_GetPropertyFromGroup((IDProperty *)src, prop_dst->name))) { + LISTBASE_FOREACH_MUTABLE (IDProperty *, prop_dst, &src->data.group) { + const IDProperty *prop_src = IDP_GetPropertyFromGroup((IDProperty *)src, prop_dst->name); + if (prop_src != NULL) { /* check of we should replace? */ if ((prop_dst->type != prop_src->type || prop_dst->subtype != prop_src->subtype) || (do_arraylen && ELEM(prop_dst->type, IDP_ARRAY, IDP_IDPARRAY) && @@ -554,12 +528,11 @@ void IDP_SyncGroupTypes(IDProperty *dest, const IDProperty *src, const bool do_a */ void IDP_ReplaceGroupInGroup(IDProperty *dest, const IDProperty *src) { - IDProperty *loop, *prop; - BLI_assert(dest->type == IDP_GROUP); BLI_assert(src->type == IDP_GROUP); - for (prop = src->data.group.first; prop; prop = prop->next) { + LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) { + IDProperty *loop; for (loop = dest->data.group.first; loop; loop = loop->next) { if (STREQ(loop->name, prop->name)) { BLI_insertlinkreplace(&dest->data.group, loop, IDP_CopyProperty(prop)); @@ -612,13 +585,11 @@ void IDP_MergeGroup_ex(IDProperty *dest, const bool do_overwrite, const int flag) { - IDProperty *prop; - BLI_assert(dest->type == IDP_GROUP); BLI_assert(src->type == IDP_GROUP); if (do_overwrite) { - for (prop = src->data.group.first; prop; prop = prop->next) { + LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) { if (prop->type == IDP_GROUP) { IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name); @@ -633,7 +604,7 @@ void IDP_MergeGroup_ex(IDProperty *dest, } } else { - for (prop = src->data.group.first; prop; prop = prop->next) { + LISTBASE_FOREACH (IDProperty *, prop, &src->data.group) { IDProperty *prop_exist = IDP_GetPropertyFromGroup(dest, prop->name); if (prop_exist != NULL) { if (prop->type == IDP_GROUP) { @@ -741,10 +712,9 @@ IDProperty *IDP_GetPropertyTypeFromGroup(const IDProperty *prop, const char *nam * direct data. */ static void IDP_FreeGroup(IDProperty *prop, const bool do_id_user) { - IDProperty *loop; - BLI_assert(prop->type == IDP_GROUP); - for (loop = prop->data.group.first; loop; loop = loop->next) { + + LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) { IDP_FreePropertyContent_ex(loop, do_id_user); } BLI_freelistN(&prop->data.group); @@ -863,14 +833,12 @@ bool IDP_EqualsProperties_ex(IDProperty *prop1, IDProperty *prop2, const bool is } return false; case IDP_GROUP: { - IDProperty *link1, *link2; - if (is_strict && prop1->len != prop2->len) { return false; } - for (link1 = prop1->data.group.first; link1; link1 = link1->next) { - link2 = IDP_GetPropertyFromGroup(prop2, link1->name); + LISTBASE_FOREACH (IDProperty *, link1, &prop1->data.group) { + IDProperty *link2 = IDP_GetPropertyFromGroup(prop2, link1->name); if (!IDP_EqualsProperties_ex(link1, link2, is_strict)) { return false; @@ -1158,11 +1126,10 @@ static void IDP_WriteIDPArray(const IDProperty *prop, BlendWriter *writer) /*REMEMBER to set totalen to len in the linking code!!*/ if (prop->data.pointer) { const IDProperty *array = prop->data.pointer; - int a; BLO_write_struct_array(writer, IDProperty, prop->len, array); - for (a = 0; a < prop->len; a++) { + for (int a = 0; a < prop->len; a++) { IDP_WriteProperty_OnlyData(&array[a], writer); } } @@ -1176,9 +1143,7 @@ static void IDP_WriteString(const IDProperty *prop, BlendWriter *writer) static void IDP_WriteGroup(const IDProperty *prop, BlendWriter *writer) { - IDProperty *loop; - - for (loop = prop->data.group.first; loop; loop = loop->next) { + LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) { IDP_BlendWrite(writer, loop); } } @@ -1212,13 +1177,11 @@ static void IDP_DirectLinkProperty(IDProperty *prop, BlendDataReader *reader); static void IDP_DirectLinkIDPArray(IDProperty *prop, BlendDataReader *reader) { - IDProperty *array; - /* since we didn't save the extra buffer, set totallen to len */ prop->totallen = prop->len; BLO_read_data_address(reader, &prop->data.pointer); - array = (IDProperty *)prop->data.pointer; + IDProperty *array = (IDProperty *)prop->data.pointer; /* note!, idp-arrays didn't exist in 2.4x, so the pointer will be cleared * there's not really anything we can do to correct this, at least don't crash */ @@ -1234,14 +1197,12 @@ static void IDP_DirectLinkIDPArray(IDProperty *prop, BlendDataReader *reader) static void IDP_DirectLinkArray(IDProperty *prop, BlendDataReader *reader) { - IDProperty **array; - /* since we didn't save the extra buffer, set totallen to len */ prop->totallen = prop->len; if (prop->subtype == IDP_GROUP) { BLO_read_pointer_array(reader, &prop->data.pointer); - array = prop->data.pointer; + IDProperty **array = prop->data.pointer; for (int i = 0; i < prop->len; i++) { IDP_DirectLinkProperty(array[i], reader); @@ -1266,12 +1227,11 @@ static void IDP_DirectLinkString(IDProperty *prop, BlendDataReader *reader) static void IDP_DirectLinkGroup(IDProperty *prop, BlendDataReader *reader) { ListBase *lb = &prop->data.group; - IDProperty *loop; BLO_read_list(reader, lb); /*Link child id properties now*/ - for (loop = prop->data.group.first; loop; loop = loop->next) { + LISTBASE_FOREACH (IDProperty *, loop, &prop->data.group) { IDP_DirectLinkProperty(loop, reader); } } From 2a8122fb65c50999b9e89484724c27c9d15ae628 Mon Sep 17 00:00:00 2001 From: Bastien Montagne Date: Thu, 14 Jan 2021 16:15:30 +0100 Subject: [PATCH 18/55] ed_undo refactor: split/remove `ed_undo_step_impl`. This function was doing too many things, with behaviors fairly different depending on its input parameters. This was making the code fragile and hard to follow. Split it in three: * `ed_undo_step_pre` does the common actions before we actually undo data. * `ed_undo_step_post` does the common actions after we have undone/redone data. Then, `ed_undo_step_direction`, `ed_undo_step_by_name` and `ed_undo_step_by_index` do their actual specific actions, with their own logic. Note: Since the actual behavior of those three funtions is fairly different (the first only undo/redo one effective step, the second is only supposed to **undo** //before// given named step, and the third actually undo/redo until given indexed step become active), we could also find better names for those. right now, it sounds like they are doing the same thing, with just different ways to specify the target step. Note: This is part of on-going refactor work on undo system, see T83806. Differential Revision: https://developer.blender.org/D10112 --- source/blender/editors/undo/ed_undo.c | 223 +++++++++++++++----------- 1 file changed, 127 insertions(+), 96 deletions(-) diff --git a/source/blender/editors/undo/ed_undo.c b/source/blender/editors/undo/ed_undo.c index 723e92b9d09..883c13f20db 100644 --- a/source/blender/editors/undo/ed_undo.c +++ b/source/blender/editors/undo/ed_undo.c @@ -77,8 +77,6 @@ static CLG_LogRef LOG = {"ed.undo"}; enum eUndoStepDir { STEP_REDO = 1, STEP_UNDO = -1, - /** Only used when the undo step name or index is passed to #ed_undo_step_impl. */ - STEP_NONE = 0, }; /* -------------------------------------------------------------------- */ @@ -180,19 +178,16 @@ void ED_undo_push(bContext *C, const char *str) } /** - * \note Also check #undo_history_exec in bottom if you change notifiers. + * Common pre management of undo/redo (killing all running jobs, calling pre handlers, etc.). */ -static int ed_undo_step_impl(bContext *C, - enum eUndoStepDir step, - const char *undo_name, - const int undo_index, +static void ed_undo_step_pre(bContext *C, + wmWindowManager *wm, + const enum eUndoStepDir undo_dir, ReportList *reports) { - /* Mutually exclusives, ensure correct input. */ - BLI_assert(((undo_name || undo_index != -1) && (step == STEP_NONE)) || - (!(undo_name || undo_index != -1) && (step != STEP_NONE))); - CLOG_INFO(&LOG, 1, "name='%s', index=%d, step=%d", undo_name, undo_index, step); - wmWindowManager *wm = CTX_wm_manager(C); + BLI_assert(ELEM(undo_dir, STEP_UNDO, STEP_REDO)); + + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); ScrArea *area = CTX_wm_area(C); @@ -201,22 +196,12 @@ static int ed_undo_step_impl(bContext *C, WM_jobs_kill_all(wm); if (G.debug & G_DEBUG_IO) { - Main *bmain = CTX_data_main(C); if (bmain->lock != NULL) { BKE_report(reports, RPT_INFO, "Checking sanity of current .blend file *BEFORE* undo step"); BLO_main_validate_libraries(bmain, reports); } } - /* TODO(campbell): undo_system: use undo system */ - /* grease pencil can be can be used in plenty of spaces, so check it first */ - /* FIXME: This gpencil undo effectively only supports the one step undo/redo, undo based on name - * or index is fully not implemented. - * FIXME: However, it seems to never be used in current code (`ED_gpencil_session_active` seems - * to always return false). */ - if (ED_gpencil_session_active()) { - return ED_undo_gpencil_step(C, (int)step); - } if (area && (area->spacetype == SPACE_VIEW3D)) { Object *obact = CTX_data_active_object(C); if (obact && (obact->type == OB_GPENCIL)) { @@ -224,89 +209,40 @@ static int ed_undo_step_impl(bContext *C, } } - UndoStep *step_data_from_name = NULL; - enum eUndoStepDir step_for_callback = step; - if (undo_name != NULL) { - step_data_from_name = BKE_undosys_step_find_by_name(wm->undo_stack, undo_name); - if (step_data_from_name == NULL) { - return OPERATOR_CANCELLED; - } - - /* TODO(campbell), could use simple optimization. */ - /* Pointers match on redo. */ - step_for_callback = (BLI_findindex(&wm->undo_stack->steps, step_data_from_name) < - BLI_findindex(&wm->undo_stack->steps, wm->undo_stack->step_active)) ? - STEP_UNDO : - STEP_REDO; - } - else if (undo_index != -1) { - step_for_callback = (undo_index < - BLI_findindex(&wm->undo_stack->steps, wm->undo_stack->step_active)) ? - STEP_UNDO : - STEP_REDO; - } - /* App-Handlers (pre). */ { /* Note: ignore grease pencil for now. */ - Main *bmain = CTX_data_main(C); wm->op_undo_depth++; BKE_callback_exec_id( - bmain, &scene->id, (step_for_callback == STEP_UNDO) ? BKE_CB_EVT_UNDO_PRE : BKE_CB_EVT_REDO_PRE); + bmain, &scene->id, (undo_dir == STEP_UNDO) ? BKE_CB_EVT_UNDO_PRE : BKE_CB_EVT_REDO_PRE); wm->op_undo_depth--; } +} - /* Undo System */ - { - if (undo_name) { - BKE_undosys_step_undo_with_data(wm->undo_stack, C, step_data_from_name); - } - else if (undo_index != -1) { - BKE_undosys_step_undo_from_index(wm->undo_stack, C, undo_index); - } - else { - if (step == STEP_UNDO) { - BKE_undosys_step_undo(wm->undo_stack, C); - } - else { - BKE_undosys_step_redo(wm->undo_stack, C); - } - } +/** + * Common post management of undo/redo (calling post handlers, adding notifiers etc.). + * + * \note Also check #undo_history_exec in bottom if you change notifiers. + */ +static void ed_undo_step_post(bContext *C, + wmWindowManager *wm, + const enum eUndoStepDir undo_dir, + ReportList *reports) +{ + BLI_assert(ELEM(undo_dir, STEP_UNDO, STEP_REDO)); - /* Set special modes for grease pencil */ - if (area && (area->spacetype == SPACE_VIEW3D)) { - Object *obact = CTX_data_active_object(C); - if (obact && (obact->type == OB_GPENCIL)) { - /* set cursor */ - if (ELEM(obact->mode, - OB_MODE_PAINT_GPENCIL, - OB_MODE_SCULPT_GPENCIL, - OB_MODE_WEIGHT_GPENCIL, - OB_MODE_VERTEX_GPENCIL)) { - ED_gpencil_toggle_brush_cursor(C, true, NULL); - } - else { - ED_gpencil_toggle_brush_cursor(C, false, NULL); - } - /* set workspace mode */ - Base *basact = CTX_data_active_base(C); - ED_object_base_activate(C, basact); - } - } - } + Main *bmain = CTX_data_main(C); + Scene *scene = CTX_data_scene(C); /* App-Handlers (post). */ { - Main *bmain = CTX_data_main(C); - scene = CTX_data_scene(C); wm->op_undo_depth++; BKE_callback_exec_id( - bmain, &scene->id, (step_for_callback == STEP_UNDO) ? BKE_CB_EVT_UNDO_POST : BKE_CB_EVT_REDO_POST); + bmain, &scene->id, (undo_dir == STEP_UNDO) ? BKE_CB_EVT_UNDO_POST : BKE_CB_EVT_REDO_POST); wm->op_undo_depth--; } if (G.debug & G_DEBUG_IO) { - Main *bmain = CTX_data_main(C); if (bmain->lock != NULL) { BKE_report(reports, RPT_INFO, "Checking sanity of current .blend file *AFTER* undo step"); BLO_main_validate_libraries(bmain, reports); @@ -317,30 +253,125 @@ static int ed_undo_step_impl(bContext *C, WM_event_add_notifier(C, NC_WM | ND_UNDO, NULL); WM_toolsystem_refresh_active(C); - - Main *bmain = CTX_data_main(C); WM_toolsystem_refresh_screen_all(bmain); if (CLOG_CHECK(&LOG, 1)) { BKE_undosys_print(wm->undo_stack); } +} + +/** Undo or redo one step from current active one. + * May undo or redo several steps at once only if the target step is a 'skipped' one. + * The target step will be the one immediately before or after the active one. */ +static int ed_undo_step_direction(bContext *C, enum eUndoStepDir step, ReportList *reports) +{ + BLI_assert(ELEM(step, STEP_UNDO, STEP_REDO)); + + CLOG_INFO(&LOG, 1, "direction=%s", (step == STEP_UNDO) ? "STEP_UNDO" : "STEP_REDO"); + + /* TODO(campbell): undo_system: use undo system */ + /* grease pencil can be can be used in plenty of spaces, so check it first */ + /* FIXME: This gpencil undo effectively only supports the one step undo/redo, undo based on name + * or index is fully not implemented. + * FIXME: However, it seems to never be used in current code (`ED_gpencil_session_active` seems + * to always return false). */ + if (ED_gpencil_session_active()) { + return ED_undo_gpencil_step(C, (int)step); + } + + wmWindowManager *wm = CTX_wm_manager(C); + + ed_undo_step_pre(C, wm, step, reports); + + if (step == STEP_UNDO) { + BKE_undosys_step_undo(wm->undo_stack, C); + } + else { + BKE_undosys_step_redo(wm->undo_stack, C); + } + + ed_undo_step_post(C, wm, step, reports); return OPERATOR_FINISHED; } -static int ed_undo_step_direction(bContext *C, enum eUndoStepDir step, ReportList *reports) -{ - return ed_undo_step_impl(C, step, NULL, -1, reports); -} - +/** Undo the step matching given name. + * May undo several steps at once. + * The target step will be the one immediately before given named one. + * Only supposed to undo (will assert in case given named step is after current active one). */ static int ed_undo_step_by_name(bContext *C, const char *undo_name, ReportList *reports) { - return ed_undo_step_impl(C, STEP_NONE, undo_name, -1, reports); + BLI_assert(undo_name != NULL); + + /* FIXME: See comments in `ed_undo_step_direction`. */ + if (ED_gpencil_session_active()) { + BLI_assert(!"Not implemented currently."); + } + + wmWindowManager *wm = CTX_wm_manager(C); + UndoStep *undo_step_from_name = BKE_undosys_step_find_by_name(wm->undo_stack, undo_name); + if (undo_step_from_name == NULL) { + CLOG_ERROR(&LOG, "Step name='%s' not found in current undo stack", undo_name); + + return OPERATOR_CANCELLED; + } + + /* TODO(campbell), could use simple optimization. */ + /* Pointers match on redo. */ + const int target_step_index = BLI_findindex(&wm->undo_stack->steps, undo_step_from_name); + const int active_step_index = BLI_findindex(&wm->undo_stack->steps, wm->undo_stack->step_active); + const enum eUndoStepDir undo_dir = (target_step_index < active_step_index) ? STEP_UNDO : + STEP_REDO; + + CLOG_INFO(&LOG, + 1, + "name='%s', found direction=%s, index=%d", + undo_name, + (undo_dir == STEP_UNDO) ? "STEP_UNDO" : "STEP_REDO", + target_step_index); + + /* This function is currently not supposed to redo ever. + * TODO: Will be fixed in future in continuing undo code refactor effort. */ + BLI_assert(undo_dir == STEP_UNDO); + + ed_undo_step_pre(C, wm, undo_dir, reports); + + BKE_undosys_step_undo_with_data(wm->undo_stack, C, undo_step_from_name); + + ed_undo_step_post(C, wm, undo_dir, reports); + + return OPERATOR_FINISHED; } +/** Load the step matching given index in the stack. + * May undo or redo several steps at once. + * The target step will be the one indicated by the given index. */ static int ed_undo_step_by_index(bContext *C, const int undo_index, ReportList *reports) { - return ed_undo_step_impl(C, STEP_NONE, NULL, undo_index, reports); + BLI_assert(undo_index >= 0); + + /* FIXME: See comments in `ed_undo_step_direction`. */ + if (ED_gpencil_session_active()) { + BLI_assert(!"Not implemented currently."); + } + + wmWindowManager *wm = CTX_wm_manager(C); + const int active_step_index = BLI_findindex(&wm->undo_stack->steps, wm->undo_stack->step_active); + const enum eUndoStepDir undo_dir = (undo_index < active_step_index) ? STEP_UNDO : STEP_REDO; + + CLOG_INFO(&LOG, + 1, + "index='%d', found direction=%s", + undo_index, + (undo_dir == STEP_UNDO) ? "STEP_UNDO" : "STEP_REDO"); + + ed_undo_step_pre(C, wm, undo_dir, reports); + + BKE_undosys_step_undo_from_index(wm->undo_stack, C, undo_index); + + ed_undo_step_post(C, wm, undo_dir, reports); + + return OPERATOR_FINISHED; } void ED_undo_grouped_push(bContext *C, const char *str) From 548d8a397c39f43459af404170614db6a18ebde1 Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Tue, 26 Jan 2021 21:56:49 +1100 Subject: [PATCH 19/55] Fix T85011: "Allow Execution" reloads the wrong file when recovering Support custom revert actions, necessary for recover operations to be able to reload the file with scripts enabled. --- .../blender/windowmanager/intern/wm_files.c | 80 +++++++++++++++++-- .../windowmanager/intern/wm_init_exit.c | 3 + source/blender/windowmanager/wm_window.h | 1 + 3 files changed, 77 insertions(+), 7 deletions(-) diff --git a/source/blender/windowmanager/intern/wm_files.c b/source/blender/windowmanager/intern/wm_files.c index 21364f00acf..7680a786634 100644 --- a/source/blender/windowmanager/intern/wm_files.c +++ b/source/blender/windowmanager/intern/wm_files.c @@ -143,6 +143,8 @@ static void wm_history_file_free(RecentFile *recent); static void wm_history_file_update(void); static void wm_history_file_write(void); +static void wm_test_autorun_revert_action_exec(bContext *C); + /* -------------------------------------------------------------------- */ /** \name Misc Utility Functions * \{ */ @@ -669,6 +671,9 @@ static void wm_file_read_post(bContext *C, * won't be set to a valid value again */ CTX_wm_window_set(C, NULL); /* exits queues */ + /* Ensure auto-run action is not used from a previous blend file load. */ + wm_test_autorun_revert_action_set(NULL, NULL); + /* Ensure tools are registered. */ WM_toolsystem_init(C); } @@ -2543,7 +2548,16 @@ bool WM_recover_last_session(bContext *C, ReportList *reports) static int wm_recover_last_session_exec(bContext *C, wmOperator *op) { + wm_open_init_use_scripts(op, true); + SET_FLAG_FROM_TEST(G.f, RNA_boolean_get(op->ptr, "use_scripts"), G_FLAG_SCRIPT_AUTOEXEC); if (WM_recover_last_session(C, op->reports)) { + if (!G.background) { + wmOperatorType *ot = op->type; + PointerRNA *props_ptr = MEM_callocN(sizeof(PointerRNA), __func__); + WM_operator_properties_create_ptr(props_ptr, ot); + RNA_boolean_set(props_ptr, "use_scripts", true); + wm_test_autorun_revert_action_set(ot, props_ptr); + } return OPERATOR_FINISHED; } return OPERATOR_CANCELLED; @@ -2592,6 +2606,13 @@ static int wm_recover_auto_save_exec(bContext *C, wmOperator *op) G.fileflags &= ~G_FILE_RECOVER; if (success) { + if (!G.background) { + wmOperatorType *ot = op->type; + PointerRNA *props_ptr = MEM_callocN(sizeof(PointerRNA), __func__); + WM_operator_properties_create_ptr(props_ptr, ot); + RNA_boolean_set(props_ptr, "use_scripts", true); + wm_test_autorun_revert_action_set(ot, props_ptr); + } return OPERATOR_FINISHED; } return OPERATOR_CANCELLED; @@ -2892,6 +2913,9 @@ static void wm_block_autorun_warning_ignore(bContext *C, void *arg_block, void * { wmWindow *win = CTX_wm_window(C); UI_popup_block_close(C, win, arg_block); + + /* Free the data as it's no longer needed. */ + wm_test_autorun_revert_action_set(NULL, NULL); } static void wm_block_autorun_warning_reload_with_scripts(bContext *C, @@ -2909,13 +2933,7 @@ static void wm_block_autorun_warning_reload_with_scripts(bContext *C, /* Load file again with scripts enabled. * The reload is necessary to allow scripts to run when the files loads. */ - wmOperatorType *ot = WM_operatortype_find("WM_OT_revert_mainfile", false); - - PointerRNA props_ptr; - WM_operator_properties_create_ptr(&props_ptr, ot); - RNA_boolean_set(&props_ptr, "use_scripts", true); - WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, &props_ptr); - WM_operator_properties_free(&props_ptr); + wm_test_autorun_revert_action_exec(C); } static void wm_block_autorun_warning_enable_scripts(bContext *C, @@ -3053,6 +3071,54 @@ static uiBlock *block_create_autorun_warning(struct bContext *C, return block; } +/** + * Store the action needed if the user needs to reload the file with Python scripts enabled. + * + * When left to NULL, this is simply revert. + * When loading files through the recover auto-save or session, + * we need to revert using other operators. + */ +static struct { + wmOperatorType *ot; + PointerRNA *ptr; +} wm_test_autorun_revert_action_data = { + .ot = NULL, + .ptr = NULL, +}; + +void wm_test_autorun_revert_action_set(wmOperatorType *ot, PointerRNA *ptr) +{ + BLI_assert(!G.background); + wm_test_autorun_revert_action_data.ot = NULL; + if (wm_test_autorun_revert_action_data.ptr != NULL) { + WM_operator_properties_free(wm_test_autorun_revert_action_data.ptr); + MEM_freeN(wm_test_autorun_revert_action_data.ptr); + wm_test_autorun_revert_action_data.ptr = NULL; + } + wm_test_autorun_revert_action_data.ot = ot; + wm_test_autorun_revert_action_data.ptr = ptr; +} + +void wm_test_autorun_revert_action_exec(bContext *C) +{ + wmOperatorType *ot = wm_test_autorun_revert_action_data.ot; + PointerRNA *ptr = wm_test_autorun_revert_action_data.ptr; + + /* Use regular revert. */ + if (ot == NULL) { + ot = WM_operatortype_find("WM_OT_revert_mainfile", false); + ptr = MEM_callocN(sizeof(PointerRNA), __func__); + WM_operator_properties_create_ptr(ptr, ot); + RNA_boolean_set(ptr, "use_scripts", true); + + /* Set state, so it's freed correctly */ + wm_test_autorun_revert_action_set(ot, ptr); + } + + WM_operator_name_call_ptr(C, ot, WM_OP_EXEC_DEFAULT, ptr); + wm_test_autorun_revert_action_set(NULL, NULL); +} + void wm_test_autorun_warning(bContext *C) { /* Test if any auto-execution of scripts failed. */ diff --git a/source/blender/windowmanager/intern/wm_init_exit.c b/source/blender/windowmanager/intern/wm_init_exit.c index d513598cf19..608aa116239 100644 --- a/source/blender/windowmanager/intern/wm_init_exit.c +++ b/source/blender/windowmanager/intern/wm_init_exit.c @@ -517,6 +517,9 @@ void WM_exit_ex(bContext *C, const bool do_python) BKE_blendfile_userdef_write_all(NULL); } } + /* Free the callback data used on file-open + * (will be set when a recover operation has run). */ + wm_test_autorun_revert_action_set(NULL, NULL); } } diff --git a/source/blender/windowmanager/wm_window.h b/source/blender/windowmanager/wm_window.h index 336db7edb50..0ac67b987d7 100644 --- a/source/blender/windowmanager/wm_window.h +++ b/source/blender/windowmanager/wm_window.h @@ -86,6 +86,7 @@ void wm_quit_with_optional_confirmation_prompt(bContext *C, wmWindow *win) ATTR_ int wm_window_new_exec(bContext *C, struct wmOperator *op); int wm_window_new_main_exec(bContext *C, struct wmOperator *op); +void wm_test_autorun_revert_action_set(struct wmOperatorType *ot, struct PointerRNA *ptr); void wm_test_autorun_warning(bContext *C); #ifdef __cplusplus From dc8b31af578bfcf9f77dbce6d7b7da1006a3c8c1 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 26 Jan 2021 12:02:02 +0100 Subject: [PATCH 20/55] Fix T84935: boolean custom data layers not saved correctly The issue was that boolean custom data layers were not written to files, because the dna struct name `bool` does not exist. Adding a struct that just contains a `bool/uint8_t` does not seem to be possible, it looks like the minimum dna struct size is 4 bytes. The proposed solution has two parts: 1. Write the custom data layer using `BLO_write_raw` instead of `BLO_write_struct_array_by_name`. 2. When loading a file, reinitialize any custom data layer that was not saved correctly (this is just a fix for existing files). Differential Revision: https://developer.blender.org/D10194 --- source/blender/blenkernel/intern/customdata.c | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 5d61b1165ed..446ef12574d 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -5104,6 +5104,10 @@ void CustomData_blend_write(BlendWriter *writer, const int *layer_data = layer->data; BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data); } + else if (layer->type == CD_PROP_BOOL) { + const bool *layer_data = layer->data; + BLO_write_raw(writer, sizeof(*layer_data) * count, layer_data); + } else { const char *structname; int structnum; @@ -5193,6 +5197,16 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, int count) if (CustomData_verify_versions(data, i)) { BLO_read_data_address(reader, &layer->data); + if (layer->data == NULL) { + /* Usually this should never happen, except when a custom data layer has not been written + * to a file correctly. */ + CLOG_WARN(&LOG, "Reallocating custom data layer that was not saved correctly."); + const LayerTypeInfo *info = layerType_getInfo(layer->type); + layer->data = MEM_calloc_arrayN((size_t)count, info->size, layerType_getName(layer->type)); + if (info->set_default) { + info->set_default(layer->data, count); + } + } if (layer->type == CD_MDISPS) { blend_read_mdisps(reader, count, layer->data, layer->flag & CD_FLAG_EXTERNAL); } From 4935ed6ce6b3e3d8829d6096bd19412d8bbb0de2 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 26 Jan 2021 12:09:44 +0100 Subject: [PATCH 21/55] Fix T84907: incorrect dirty mask after geometry join node Hans noticed that these dirty flags are only used for normals currently and that the edge flag is not used at all. This patch still applies the "entire" fix with all four flags. Differential Revision: https://developer.blender.org/D10193 --- .../nodes/geometry/nodes/node_geo_join_geometry.cc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc index 75736ae714a..e00ee9b01d8 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc @@ -43,18 +43,32 @@ static Mesh *join_mesh_topology_and_builtin_attributes(Spanget_for_read(); totverts += mesh->totvert; totloops += mesh->totloop; totedges += mesh->totedge; totpolys += mesh->totpoly; + cd_dirty_vert |= mesh->runtime.cd_dirty_vert; + cd_dirty_poly |= mesh->runtime.cd_dirty_poly; + cd_dirty_edge |= mesh->runtime.cd_dirty_edge; + cd_dirty_loop |= mesh->runtime.cd_dirty_loop; } const Mesh *first_input_mesh = src_components[0]->get_for_read(); Mesh *new_mesh = BKE_mesh_new_nomain(totverts, totedges, 0, totloops, totpolys); BKE_mesh_copy_settings(new_mesh, first_input_mesh); + new_mesh->runtime.cd_dirty_vert = cd_dirty_vert; + new_mesh->runtime.cd_dirty_poly = cd_dirty_poly; + new_mesh->runtime.cd_dirty_edge = cd_dirty_edge; + new_mesh->runtime.cd_dirty_loop = cd_dirty_loop; + int vert_offset = 0; int loop_offset = 0; int edge_offset = 0; From c3a4c6c2099b9ee5630957584d6503da06c77cdc Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 26 Jan 2021 12:30:54 +0100 Subject: [PATCH 22/55] GPU: Enable HQ normals workaround for AMD 21.1.1 driver. AMD 21.1.1 still has the same issues as reported in T82856. --- source/blender/gpu/opengl/gl_backend.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc index 29ff1b3e81a..84bd9abf156 100644 --- a/source/blender/gpu/opengl/gl_backend.cc +++ b/source/blender/gpu/opengl/gl_backend.cc @@ -43,7 +43,7 @@ namespace blender::gpu { static bool is_faulty_T82856_platform(const char *version, const char *renderer) { /* On Linux the driver does not report its version. Test the OpenGL version in stead. */ - if (strstr(version, "4.5.14756") || strstr(version, "4.5.14757")) { + if (strstr(version, "4.5.1475")) { if (strstr(renderer, " RX 460 ") || strstr(renderer, " RX 470 ") || strstr(renderer, " RX 480 ") || strstr(renderer, " RX 490 ") || strstr(renderer, " RX 560 ") || strstr(renderer, " RX 560X ") || From c399651637a3a9c8e416b8baffc571fa8cfa571f Mon Sep 17 00:00:00 2001 From: Robert Guetzkow Date: Tue, 26 Jan 2021 12:37:46 +0100 Subject: [PATCH 23/55] Fix T84708: Versioning for Set Alpha node The versioning code introduced in rB38df935c0985 skips the composite node tree that is used by the scene thus not correctly versioning Set Alpha nodes outside of node groups. This fix iterates through all node trees to version all Set Alpha nodes. Reviewed By: JacquesLucke Differential Revision: https://developer.blender.org/D10110 --- source/blender/blenloader/intern/versioning_290.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index ec537e6f3d8..bb477745849 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -1504,7 +1504,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) if (!MAIN_VERSION_ATLEAST(bmain, 292, 10)) { if (!DNA_struct_find(fd->filesdna, "NodeSetAlpha")) { - LISTBASE_FOREACH (bNodeTree *, ntree, &bmain->nodetrees) { + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { if (ntree->type != NTREE_COMPOSIT) { continue; } @@ -1517,6 +1517,7 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) node->storage = storage; } } + FOREACH_NODETREE_END; } LISTBASE_FOREACH (Scene *, scene, &bmain->scenes) { From e6aece32a0499fb50648ad6249c38af9fffc8d24 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 26 Jan 2021 12:48:02 +0100 Subject: [PATCH 24/55] GPU: Enable HQ normals workaround for any AMD Drivers on Polaris. --- source/blender/gpu/opengl/gl_backend.cc | 34 ++++++++----------------- 1 file changed, 10 insertions(+), 24 deletions(-) diff --git a/source/blender/gpu/opengl/gl_backend.cc b/source/blender/gpu/opengl/gl_backend.cc index 84bd9abf156..1d76b07c966 100644 --- a/source/blender/gpu/opengl/gl_backend.cc +++ b/source/blender/gpu/opengl/gl_backend.cc @@ -34,28 +34,6 @@ namespace blender::gpu { -/* See T82856: AMD drivers since 20.11 running on a polaris architecture doesn't support the - * `GL_INT_2_10_10_10_REV` data type correctly. This data type is used to pack normals and flags. - * The work around uses `GPU_RGBA16I` but that is only possible for loop normals. - * - * Vertex and Face normals would still render resulting in undefined behavior during selection and - * rendering. */ -static bool is_faulty_T82856_platform(const char *version, const char *renderer) -{ - /* On Linux the driver does not report its version. Test the OpenGL version in stead. */ - if (strstr(version, "4.5.1475")) { - if (strstr(renderer, " RX 460 ") || strstr(renderer, " RX 470 ") || - strstr(renderer, " RX 480 ") || strstr(renderer, " RX 490 ") || - strstr(renderer, " RX 560 ") || strstr(renderer, " RX 560X ") || - strstr(renderer, " RX 570 ") || strstr(renderer, " RX 580 ") || - strstr(renderer, " RX 590 ") || strstr(renderer, " RX550/550 ") || - strstr(renderer, " (TM) 520 ") || strstr(renderer, " (TM) 530 ") || - strstr(renderer, " R5 ") || strstr(renderer, " R7 ") || strstr(renderer, " R9 ")) { - return true; - } - } - return false; -} /* -------------------------------------------------------------------- */ /** \name Platform * \{ */ @@ -294,9 +272,17 @@ static void detect_workarounds() GCaps.broken_amd_driver = true; } /* See T82856: AMD drivers since 20.11 running on a polaris architecture doesn't support the - * `GL_INT_2_10_10_10_REV` data type. */ + * `GL_INT_2_10_10_10_REV` data type correctly. This data type is used to pack normals and flags. + * The work around uses `GPU_RGBA16I`. + */ if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_OFFICIAL)) { - if (is_faulty_T82856_platform(version, renderer)) { + if (strstr(renderer, " RX 460 ") || strstr(renderer, " RX 470 ") || + strstr(renderer, " RX 480 ") || strstr(renderer, " RX 490 ") || + strstr(renderer, " RX 560 ") || strstr(renderer, " RX 560X ") || + strstr(renderer, " RX 570 ") || strstr(renderer, " RX 580 ") || + strstr(renderer, " RX 590 ") || strstr(renderer, " RX550/550 ") || + strstr(renderer, " (TM) 520 ") || strstr(renderer, " (TM) 530 ") || + strstr(renderer, " R5 ") || strstr(renderer, " R7 ") || strstr(renderer, " R9 ")) { GCaps.use_hq_normals_workaround = true; } } From ed809866b17262b1eaa24765aaf711e44f62d862 Mon Sep 17 00:00:00 2001 From: Jeroen Bakker Date: Tue, 26 Jan 2021 14:05:50 +0100 Subject: [PATCH 25/55] Viewport Rendering: Don't clamp when overlays are disabled. During viewport rendering the color values were clamped in order to apply the overlay on top of it. This clamping would show the scene colors washed out. This patch adds a work around to skip the clamping when the overlays are turned off. Parial fix for {T77909} --- source/blender/draw/intern/draw_manager.c | 4 ++-- source/blender/gpu/GPU_viewport.h | 6 ++++-- source/blender/gpu/intern/gpu_viewport.c | 20 ++++++++++++------- .../gpu_shader_image_overlays_merge_frag.glsl | 10 ++++++---- .../windowmanager/xr/intern/wm_xr_draw.c | 3 ++- 5 files changed, 27 insertions(+), 16 deletions(-) diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 1115d819659..f474ae542d9 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -1715,8 +1715,8 @@ void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph, GPU_matrix_identity_set(); GPU_matrix_identity_projection_set(); - - GPU_viewport_unbind_from_offscreen(render_viewport, ofs, do_color_management); + const bool do_overlays = (v3d->flag2 & V3D_HIDE_OVERLAYS) == 0; + GPU_viewport_unbind_from_offscreen(render_viewport, ofs, do_color_management, do_overlays); if (draw_background) { /* Reset default. */ diff --git a/source/blender/gpu/GPU_viewport.h b/source/blender/gpu/GPU_viewport.h index d8e4c5377b0..095e17f344e 100644 --- a/source/blender/gpu/GPU_viewport.h +++ b/source/blender/gpu/GPU_viewport.h @@ -114,7 +114,8 @@ void GPU_viewport_draw_to_screen(GPUViewport *viewport, int view, const rcti *re void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport, int view, const rcti *rect, - bool display_colorspace); + bool display_colorspace, + bool do_overlay_merge); void GPU_viewport_free(GPUViewport *viewport); void GPU_viewport_colorspace_set(GPUViewport *viewport, @@ -125,7 +126,8 @@ void GPU_viewport_colorspace_set(GPUViewport *viewport, void GPU_viewport_bind_from_offscreen(GPUViewport *viewport, struct GPUOffScreen *ofs); void GPU_viewport_unbind_from_offscreen(GPUViewport *viewport, struct GPUOffScreen *ofs, - bool display_colorspace); + bool display_colorspace, + bool do_overlay_merge); ViewportMemoryPool *GPU_viewport_mempool_get(GPUViewport *viewport); struct DRWInstanceDataList *GPU_viewport_instance_data_list_get(GPUViewport *viewport); diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c index a83654d31e7..205ba1d06d6 100644 --- a/source/blender/gpu/intern/gpu_viewport.c +++ b/source/blender/gpu/intern/gpu_viewport.c @@ -749,7 +749,8 @@ static void gpu_viewport_batch_free(GPUViewport *viewport) static void gpu_viewport_draw_colormanaged(GPUViewport *viewport, const rctf *rect_pos, const rctf *rect_uv, - bool display_colorspace) + bool display_colorspace, + bool do_overlay_merge) { DefaultTextureList *dtxl = viewport->txl; GPUTexture *color = dtxl->color; @@ -771,7 +772,7 @@ static void gpu_viewport_draw_colormanaged(GPUViewport *viewport, NULL, viewport->dither, false, - true); + do_overlay_merge); } GPUBatch *batch = gpu_viewport_batch_get(viewport, rect_pos, rect_uv); @@ -780,6 +781,7 @@ static void gpu_viewport_draw_colormanaged(GPUViewport *viewport, } else { GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_IMAGE_OVERLAYS_MERGE); + GPU_batch_uniform_1i(batch, "overlay", do_overlay_merge); GPU_batch_uniform_1i(batch, "display_transform", display_colorspace); GPU_batch_uniform_1i(batch, "image_texture", 0); GPU_batch_uniform_1i(batch, "overlays_texture", 1); @@ -803,7 +805,8 @@ static void gpu_viewport_draw_colormanaged(GPUViewport *viewport, void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport, int view, const rcti *rect, - bool display_colorspace) + bool display_colorspace, + bool do_overlay_merge) { gpu_viewport_framebuffer_view_set(viewport, view); DefaultFramebufferList *dfbl = viewport->fbl; @@ -850,7 +853,8 @@ void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport, SWAP(float, uv_rect.ymin, uv_rect.ymax); } - gpu_viewport_draw_colormanaged(viewport, &pos_rect, &uv_rect, display_colorspace); + gpu_viewport_draw_colormanaged( + viewport, &pos_rect, &uv_rect, display_colorspace, do_overlay_merge); } /** @@ -862,7 +866,7 @@ void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport, */ void GPU_viewport_draw_to_screen(GPUViewport *viewport, int view, const rcti *rect) { - GPU_viewport_draw_to_screen_ex(viewport, view, rect, true); + GPU_viewport_draw_to_screen_ex(viewport, view, rect, true, true); } /** @@ -870,7 +874,8 @@ void GPU_viewport_draw_to_screen(GPUViewport *viewport, int view, const rcti *re */ void GPU_viewport_unbind_from_offscreen(GPUViewport *viewport, struct GPUOffScreen *ofs, - bool display_colorspace) + bool display_colorspace, + bool do_overlay_merge) { DefaultFramebufferList *dfbl = viewport->fbl; DefaultTextureList *dtxl = viewport->txl; @@ -896,7 +901,8 @@ void GPU_viewport_unbind_from_offscreen(GPUViewport *viewport, .ymax = 1.0f, }; - gpu_viewport_draw_colormanaged(viewport, &pos_rect, &uv_rect, display_colorspace); + gpu_viewport_draw_colormanaged( + viewport, &pos_rect, &uv_rect, display_colorspace, do_overlay_merge); /* This one is from the offscreen. Don't free it with the viewport. */ dtxl->depth = NULL; diff --git a/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl b/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl index 73f40c693ae..7f3fe2f5252 100644 --- a/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl +++ b/source/blender/gpu/shaders/gpu_shader_image_overlays_merge_frag.glsl @@ -4,6 +4,7 @@ uniform sampler2D image_texture; uniform sampler2D overlays_texture; uniform bool display_transform; +uniform bool overlay; in vec2 texCoord_interp; @@ -30,12 +31,13 @@ void linearrgb_to_srgb(vec4 col_from, out vec4 col_to) void main() { fragColor = texture(image_texture, texCoord_interp.st); - vec4 overlay_col = texture(overlays_texture, texCoord_interp.st); - fragColor = clamp(fragColor, 0.0, 1.0); - fragColor *= 1.0 - overlay_col.a; - fragColor += overlay_col; + if (overlay) { + fragColor = clamp(fragColor, 0.0, 1.0); + fragColor *= 1.0 - overlay_col.a; + fragColor += overlay_col; + } if (display_transform) { linearrgb_to_srgb(fragColor, fragColor); diff --git a/source/blender/windowmanager/xr/intern/wm_xr_draw.c b/source/blender/windowmanager/xr/intern/wm_xr_draw.c index 1b1ea6c1e61..499ec136e03 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_draw.c +++ b/source/blender/windowmanager/xr/intern/wm_xr_draw.c @@ -92,7 +92,8 @@ static void wm_xr_draw_viewport_buffers_to_active_framebuffer( if (is_upside_down) { SWAP(int, rect.ymin, rect.ymax); } - GPU_viewport_draw_to_screen_ex(surface_data->viewport, 0, &rect, draw_view->expects_srgb_buffer); + GPU_viewport_draw_to_screen_ex( + surface_data->viewport, 0, &rect, draw_view->expects_srgb_buffer, true); } /** From b665781808167011a7a7c3c51b6862a15380129e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Mon, 25 Jan 2021 14:19:14 +0100 Subject: [PATCH 26/55] Asset Browser: fix context properties reported to Python Change `"active_id"` to `"id"` so that tab completion in the asset browser context returns the correct properties. 055ef5df615632f81e30e39ae47b42a87af350ca renamed the `active_id` property to `id`, but `dir(thecontext)` still returned `"active_id"`. --- source/blender/editors/space_file/space_file.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index aedc6228355..7f33b0212d6 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -785,7 +785,7 @@ static void file_space_subtype_item_extend(bContext *UNUSED(C), } } -static const char *file_context_dir[] = {"active_file", "active_id", NULL}; +static const char *file_context_dir[] = {"active_file", "id", NULL}; static int /*eContextResult*/ file_context(const bContext *C, const char *member, From 532d3a103a874574856d732fffc3a04fee30b337 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Charles=20Fl=C3=A8che?= Date: Mon, 18 Jan 2021 07:43:42 +0100 Subject: [PATCH 27/55] Cycles standalone: fix missing dependencies in CMake files Also set default CYCLES_INSTALL_PATH to CMAKE_INSTALL_PREFIX. By default with a `make cycles` this will build to ${CMAKE_BINARY_DIR}/bin Differential Revision: https://developer.blender.org/D9961 --- CMakeLists.txt | 12 ++++++++++++ intern/cycles/CMakeLists.txt | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d00b89ef3ed..199fe9d3eeb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1763,8 +1763,20 @@ if(WITH_BLENDER) # internal and external library information first, for test linking add_subdirectory(source) elseif(WITH_CYCLES_STANDALONE) + add_subdirectory(intern/glew-mx) + add_subdirectory(intern/guardedalloc) + add_subdirectory(intern/libc_compat) + add_subdirectory(intern/numaapi) + add_subdirectory(intern/sky) + add_subdirectory(intern/cycles) add_subdirectory(extern/clew) + if(WITH_CYCLES_LOGGING) + if(NOT WITH_SYSTEM_GFLAGS) + add_subdirectory(extern/gflags) + endif() + add_subdirectory(extern/glog) + endif() if(WITH_CUDA_DYNLOAD) add_subdirectory(extern/cuew) endif() diff --git a/intern/cycles/CMakeLists.txt b/intern/cycles/CMakeLists.txt index 8167576a177..2a28d905144 100644 --- a/intern/cycles/CMakeLists.txt +++ b/intern/cycles/CMakeLists.txt @@ -14,7 +14,7 @@ # Standalone or with Blender if(NOT WITH_BLENDER AND WITH_CYCLES_STANDALONE) - set(CYCLES_INSTALL_PATH "") + set(CYCLES_INSTALL_PATH ${CMAKE_INSTALL_PREFIX}) else() set(WITH_CYCLES_BLENDER ON) # WINDOWS_PYTHON_DEBUG needs to write into the user addons folder since it will From 76ab0381d1e5f8df6b23803b75b2013933484bcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Charles=20Fl=C3=A8che?= Date: Mon, 18 Jan 2021 07:43:42 +0100 Subject: [PATCH 28/55] Fix Cycles standalone compilation following API changes The changes to the socket API were not applied to the standalone app. Also modify Camera.compute_auto_viewplane() to use Camera.full_width and Camera.full_height as it is not possible to publicly access Camera.width and Camera.height anymore, so the aspect ratio could be computed with stale data. Differential Revision: https://developer.blender.org/D9961 --- intern/cycles/app/cycles_standalone.cpp | 31 ++++++------- intern/cycles/app/cycles_xml.cpp | 62 ++++++++++++++----------- intern/cycles/render/camera.cpp | 4 +- 3 files changed, 50 insertions(+), 47 deletions(-) diff --git a/intern/cycles/app/cycles_standalone.cpp b/intern/cycles/app/cycles_standalone.cpp index f057ce7a2f0..6b3513b065a 100644 --- a/intern/cycles/app/cycles_standalone.cpp +++ b/intern/cycles/app/cycles_standalone.cpp @@ -133,12 +133,12 @@ static void scene_init() /* Camera width/height override? */ if (!(options.width == 0 || options.height == 0)) { - options.scene->camera->width = options.width; - options.scene->camera->height = options.height; + options.scene->camera->set_full_width(options.width); + options.scene->camera->set_full_height(options.height); } else { - options.width = options.scene->camera->width; - options.height = options.scene->camera->height; + options.width = options.scene->camera->get_full_width(); + options.height = options.scene->camera->get_full_height(); } /* Calculate Viewplane */ @@ -233,7 +233,7 @@ static void display() static void motion(int x, int y, int button) { if (options.interactive) { - Transform matrix = options.session->scene->camera->matrix; + Transform matrix = options.session->scene->camera->get_matrix(); /* Translate */ if (button == 0) { @@ -251,8 +251,8 @@ static void motion(int x, int y, int button) } /* Update and Reset */ - options.session->scene->camera->matrix = matrix; - options.session->scene->camera->need_update = true; + options.session->scene->camera->set_matrix(matrix); + options.session->scene->camera->need_flags_update = true; options.session->scene->camera->need_device_update = true; options.session->reset(session_buffer_params(), options.session_params.samples); @@ -266,10 +266,10 @@ static void resize(int width, int height) if (options.session) { /* Update camera */ - options.session->scene->camera->width = width; - options.session->scene->camera->height = height; + options.session->scene->camera->set_full_width(options.width); + options.session->scene->camera->set_full_height(options.height); options.session->scene->camera->compute_auto_viewplane(); - options.session->scene->camera->need_update = true; + options.session->scene->camera->need_flags_update = true; options.session->scene->camera->need_device_update = true; options.session->reset(session_buffer_params(), options.session_params.samples); @@ -302,7 +302,7 @@ static void keyboard(unsigned char key) /* Navigation */ else if (options.interactive && (key == 'w' || key == 'a' || key == 's' || key == 'd')) { - Transform matrix = options.session->scene->camera->matrix; + Transform matrix = options.session->scene->camera->get_matrix(); float3 translate; if (key == 'w') @@ -317,8 +317,8 @@ static void keyboard(unsigned char key) matrix = matrix * transform_translate(translate); /* Update and Reset */ - options.session->scene->camera->matrix = matrix; - options.session->scene->camera->need_update = true; + options.session->scene->camera->set_matrix(matrix); + options.session->scene->camera->need_flags_update = true; options.session->scene->camera->need_device_update = true; options.session->reset(session_buffer_params(), options.session_params.samples); @@ -345,10 +345,7 @@ static void keyboard(unsigned char key) break; } - options.session->scene->integrator->max_bounce = bounce; - - /* Update and Reset */ - options.session->scene->integrator->need_update = true; + options.session->scene->integrator->set_max_bounce(bounce); options.session->reset(session_buffer_params(), options.session_params.samples); } diff --git a/intern/cycles/app/cycles_xml.cpp b/intern/cycles/app/cycles_xml.cpp index a86e06f92d1..272d509585e 100644 --- a/intern/cycles/app/cycles_xml.cpp +++ b/intern/cycles/app/cycles_xml.cpp @@ -190,17 +190,18 @@ static void xml_read_camera(XMLReadState &state, xml_node node) { Camera *cam = state.scene->camera; - xml_read_int(&cam->width, node, "width"); - xml_read_int(&cam->height, node, "height"); + int width = -1, height = -1; + xml_read_int(&width, node, "width"); + xml_read_int(&height, node, "height"); - cam->full_width = cam->width; - cam->full_height = cam->height; + cam->set_full_width(width); + cam->set_full_height(height); xml_read_node(state, cam, node); - cam->matrix = state.tfm; + cam->set_matrix(state.tfm); - cam->need_update = true; + cam->need_flags_update = true; cam->update(state.scene); } @@ -338,11 +339,13 @@ static void xml_read_shader_graph(XMLReadState &state, Shader *shader, xml_node if (node_name == "image_texture") { ImageTextureNode *img = (ImageTextureNode *)snode; - img->filename = path_join(state.base, img->filename.string()); + ustring filename(path_join(state.base, img->get_filename().string())); + img->set_filename(filename); } else if (node_name == "environment_texture") { EnvironmentTextureNode *env = (EnvironmentTextureNode *)snode; - env->filename = path_join(state.base, env->filename.string()); + ustring filename(path_join(state.base, env->get_filename().string())); + env->set_filename(filename); } if (snode) { @@ -384,8 +387,8 @@ static Mesh *xml_add_mesh(Scene *scene, const Transform &tfm) /* create object*/ Object *object = new Object(); - object->geometry = mesh; - object->tfm = tfm; + object->set_geometry(mesh); + object->set_tfm(tfm); scene->objects.push_back(object); return mesh; @@ -395,7 +398,9 @@ static void xml_read_mesh(const XMLReadState &state, xml_node node) { /* add mesh */ Mesh *mesh = xml_add_mesh(state.scene, state.tfm); - mesh->used_shaders.push_back(state.shader); + array used_shaders = mesh->get_used_shaders(); + used_shaders.push_back_slow(state.shader); + mesh->set_used_shaders(used_shaders); /* read state */ int shader = 0; @@ -411,20 +416,24 @@ static void xml_read_mesh(const XMLReadState &state, xml_node node) xml_read_int_array(nverts, node, "nverts"); if (xml_equal_string(node, "subdivision", "catmull-clark")) { - mesh->subdivision_type = Mesh::SUBDIVISION_CATMULL_CLARK; + mesh->set_subdivision_type(Mesh::SUBDIVISION_CATMULL_CLARK); } else if (xml_equal_string(node, "subdivision", "linear")) { - mesh->subdivision_type = Mesh::SUBDIVISION_LINEAR; + mesh->set_subdivision_type(Mesh::SUBDIVISION_LINEAR); } - if (mesh->subdivision_type == Mesh::SUBDIVISION_NONE) { + array P_array; + P_array = P; + + if (mesh->get_subdivision_type() == Mesh::SUBDIVISION_NONE) { /* create vertices */ - mesh->verts = P; + + mesh->set_verts(P_array); size_t num_triangles = 0; for (size_t i = 0; i < nverts.size(); i++) num_triangles += nverts[i] - 2; - mesh->reserve_mesh(mesh->verts.size(), num_triangles); + mesh->reserve_mesh(mesh->get_verts().size(), num_triangles); /* create triangles */ int index_offset = 0; @@ -474,7 +483,7 @@ static void xml_read_mesh(const XMLReadState &state, xml_node node) } else { /* create vertices */ - mesh->verts = P; + mesh->set_verts(P_array); size_t num_ngons = 0; size_t num_corners = 0; @@ -513,23 +522,20 @@ static void xml_read_mesh(const XMLReadState &state, xml_node node) } /* setup subd params */ - if (!mesh->subd_params) { - mesh->subd_params = new SubdParams(mesh); - } - SubdParams &sdparams = *mesh->subd_params; + float dicing_rate = state.dicing_rate; + xml_read_float(&dicing_rate, node, "dicing_rate"); + dicing_rate = std::max(0.1f, dicing_rate); - sdparams.dicing_rate = state.dicing_rate; - xml_read_float(&sdparams.dicing_rate, node, "dicing_rate"); - sdparams.dicing_rate = std::max(0.1f, sdparams.dicing_rate); - - sdparams.objecttoworld = state.tfm; + mesh->set_subd_dicing_rate(dicing_rate); + mesh->set_subd_objecttoworld(state.tfm); } /* we don't yet support arbitrary attributes, for now add vertex * coordinates as generated coordinates if requested */ if (mesh->need_attribute(state.scene, ATTR_STD_GENERATED)) { Attribute *attr = mesh->attributes.add(ATTR_STD_GENERATED); - memcpy(attr->data_float3(), mesh->verts.data(), sizeof(float3) * mesh->verts.size()); + memcpy( + attr->data_float3(), mesh->get_verts().data(), sizeof(float3) * mesh->get_verts().size()); } } @@ -539,7 +545,7 @@ static void xml_read_light(XMLReadState &state, xml_node node) { Light *light = new Light(); - light->shader = state.shader; + light->set_shader(state.shader); xml_read_node(state, light, node); state.scene->lights.push_back(light); diff --git a/intern/cycles/render/camera.cpp b/intern/cycles/render/camera.cpp index 92cf712d32a..3beb3d1d4d3 100644 --- a/intern/cycles/render/camera.cpp +++ b/intern/cycles/render/camera.cpp @@ -212,8 +212,8 @@ void Camera::compute_auto_viewplane() viewplane.top = 1.0f; } else { - float aspect = (float)width / (float)height; - if (width >= height) { + float aspect = (float)full_width / (float)full_height; + if (full_width >= full_height) { viewplane.left = -aspect; viewplane.right = aspect; viewplane.bottom = -1.0f; From 26b5760d6d75cb2bc9a1d8f8158e4982972d467f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sybren=20A=2E=20St=C3=BCvel?= Date: Tue, 26 Jan 2021 15:13:42 +0100 Subject: [PATCH 29/55] Fix T85038: No curve is "active" after selecting all curves Check for selection status beforec learing the "active" flag from an FCurve. This allows the "Select All Curves" operator to retain what is seen as the active curve. --- source/blender/editors/animation/anim_channels_edit.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/source/blender/editors/animation/anim_channels_edit.c b/source/blender/editors/animation/anim_channels_edit.c index 7e54bca4c93..7afb03b833d 100644 --- a/source/blender/editors/animation/anim_channels_edit.c +++ b/source/blender/editors/animation/anim_channels_edit.c @@ -393,7 +393,11 @@ static void anim_channels_select_set(bAnimContext *ac, FCurve *fcu = (FCurve *)ale->data; ACHANNEL_SET_FLAG(fcu, sel, FCURVE_SELECTED); - fcu->flag &= ~FCURVE_ACTIVE; + if ((fcu->flag & FCURVE_SELECTED) == 0) { + /* Only erase the ACTIVE flag when deselecting. This ensures that "select all curves" + * retains the currently active curve. */ + fcu->flag &= ~FCURVE_ACTIVE; + } break; } case ANIMTYPE_SHAPEKEY: { From c51a5b204cc15d079dd319bd95296f5ebe4922c9 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 26 Jan 2021 15:14:29 +0100 Subject: [PATCH 30/55] Fix T85048: Cycles sculpt vertex color issues after recent changes Attribute fields were not fully copied. Ref D10208 --- intern/cycles/render/attribute.cpp | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/intern/cycles/render/attribute.cpp b/intern/cycles/render/attribute.cpp index 6a3fbb7772f..ce4ae6e4295 100644 --- a/intern/cycles/render/attribute.cpp +++ b/intern/cycles/render/attribute.cpp @@ -661,15 +661,8 @@ void AttributeSet::update(AttributeSet &&new_attributes) { /* add or update old_attributes based on the new_attributes */ foreach (Attribute &attr, new_attributes.attributes) { - Attribute *nattr = nullptr; - - if (attr.std != ATTR_STD_NONE) { - nattr = add(attr.std, attr.name); - } - else { - nattr = add(attr.name, attr.type, attr.element); - } - + Attribute *nattr = add(attr.name, attr.type, attr.element); + nattr->std = attr.std; nattr->set_data_from(std::move(attr)); } From dde3ecc1a88f1838a77917d92341a0078b55c47e Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 26 Jan 2021 15:23:17 +0100 Subject: [PATCH 31/55] Cleanup: compiler warnings If one method is marked as override, clang warns if others are not. --- .../blender/compositor/operations/COM_RenderLayersProg.h | 9 +++++---- .../compositor/operations/COM_SocketProxyOperation.h | 4 ++-- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/source/blender/compositor/operations/COM_RenderLayersProg.h b/source/blender/compositor/operations/COM_RenderLayersProg.h index ec98969b223..a0d5bc2953b 100644 --- a/source/blender/compositor/operations/COM_RenderLayersProg.h +++ b/source/blender/compositor/operations/COM_RenderLayersProg.h @@ -68,7 +68,8 @@ class RenderLayersProg : public NodeOperation { /** * Determine the output resolution. The resolution is retrieved from the Renderer */ - void determineResolution(unsigned int resolution[2], unsigned int preferredResolution[2]); + void determineResolution(unsigned int resolution[2], + unsigned int preferredResolution[2]) override; /** * retrieve the reference to the float buffer of the renderer. @@ -118,9 +119,9 @@ class RenderLayersProg : public NodeOperation { { return this->m_viewName; } - void initExecution(); - void deinitExecution(); - void executePixelSampled(float output[4], float x, float y, PixelSampler sampler); + void initExecution() override; + void deinitExecution() override; + void executePixelSampled(float output[4], float x, float y, PixelSampler sampler) override; std::unique_ptr getMetaData() const override; }; diff --git a/source/blender/compositor/operations/COM_SocketProxyOperation.h b/source/blender/compositor/operations/COM_SocketProxyOperation.h index 435083f5008..712347a8ea2 100644 --- a/source/blender/compositor/operations/COM_SocketProxyOperation.h +++ b/source/blender/compositor/operations/COM_SocketProxyOperation.h @@ -24,11 +24,11 @@ class SocketProxyOperation : public NodeOperation { public: SocketProxyOperation(DataType type, bool use_conversion); - bool isProxyOperation() const + bool isProxyOperation() const override { return true; } - bool useDatatypeConversion() const + bool useDatatypeConversion() const override { return m_use_conversion; } From 31f568c33692e543fc84179c783870c20844c3d0 Mon Sep 17 00:00:00 2001 From: Brecht Van Lommel Date: Tue, 26 Jan 2021 15:27:57 +0100 Subject: [PATCH 32/55] Fix: incomplete integration of PugiXML and Potrace build options Add them to the standard build configurations, disable properly when library not found and print as part of configuration overview. --- CMakeLists.txt | 2 ++ build_files/cmake/config/blender_full.cmake | 2 ++ build_files/cmake/config/blender_lite.cmake | 2 ++ build_files/cmake/config/blender_release.cmake | 2 ++ build_files/cmake/platform/platform_unix.cmake | 5 +++++ 5 files changed, 13 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 199fe9d3eeb..035cf81e1b3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1857,6 +1857,8 @@ if(FIRST_RUN) info_cfg_option(WITH_OPENCOLORIO) info_cfg_option(WITH_OPENIMAGEDENOISE) info_cfg_option(WITH_OPENVDB) + info_cfg_option(WITH_POTRACE) + info_cfg_option(WITH_PUGIXML) info_cfg_option(WITH_QUADRIFLOW) info_cfg_option(WITH_TBB) info_cfg_option(WITH_USD) diff --git a/build_files/cmake/config/blender_full.cmake b/build_files/cmake/config/blender_full.cmake index 08065ec0276..aab997ab453 100644 --- a/build_files/cmake/config/blender_full.cmake +++ b/build_files/cmake/config/blender_full.cmake @@ -44,6 +44,8 @@ set(WITH_OPENMP ON CACHE BOOL "" FORCE) set(WITH_OPENSUBDIV ON CACHE BOOL "" FORCE) set(WITH_OPENVDB ON CACHE BOOL "" FORCE) set(WITH_OPENVDB_BLOSC ON CACHE BOOL "" FORCE) +set(WITH_POTRACE ON CACHE BOOL "" FORCE) +set(WITH_PUGIXML ON CACHE BOOL "" FORCE) set(WITH_NANOVDB ON CACHE BOOL "" FORCE) set(WITH_POTRACE ON CACHE BOOL "" FORCE) set(WITH_PYTHON_INSTALL ON CACHE BOOL "" FORCE) diff --git a/build_files/cmake/config/blender_lite.cmake b/build_files/cmake/config/blender_lite.cmake index 4150094e9f5..480548abca7 100644 --- a/build_files/cmake/config/blender_lite.cmake +++ b/build_files/cmake/config/blender_lite.cmake @@ -51,6 +51,8 @@ set(WITH_OPENIMAGEIO OFF CACHE BOOL "" FORCE) set(WITH_OPENMP OFF CACHE BOOL "" FORCE) set(WITH_OPENSUBDIV OFF CACHE BOOL "" FORCE) set(WITH_OPENVDB OFF CACHE BOOL "" FORCE) +set(WITH_POTRACE OFF CACHE BOOL "" FORCE) +set(WITH_PUGIXML OFF CACHE BOOL "" FORCE) set(WITH_NANOVDB OFF CACHE BOOL "" FORCE) set(WITH_QUADRIFLOW OFF CACHE BOOL "" FORCE) set(WITH_SDL OFF CACHE BOOL "" FORCE) diff --git a/build_files/cmake/config/blender_release.cmake b/build_files/cmake/config/blender_release.cmake index fd3225b0287..96101ee7bcc 100644 --- a/build_files/cmake/config/blender_release.cmake +++ b/build_files/cmake/config/blender_release.cmake @@ -45,6 +45,8 @@ set(WITH_OPENMP ON CACHE BOOL "" FORCE) set(WITH_OPENSUBDIV ON CACHE BOOL "" FORCE) set(WITH_OPENVDB ON CACHE BOOL "" FORCE) set(WITH_OPENVDB_BLOSC ON CACHE BOOL "" FORCE) +set(WITH_POTRACE ON CACHE BOOL "" FORCE) +set(WITH_PUGIXML ON CACHE BOOL "" FORCE) set(WITH_NANOVDB ON CACHE BOOL "" FORCE) set(WITH_POTRACE ON CACHE BOOL "" FORCE) set(WITH_PYTHON_INSTALL ON CACHE BOOL "" FORCE) diff --git a/build_files/cmake/platform/platform_unix.cmake b/build_files/cmake/platform/platform_unix.cmake index abacd0500e5..a2448829206 100644 --- a/build_files/cmake/platform/platform_unix.cmake +++ b/build_files/cmake/platform/platform_unix.cmake @@ -352,6 +352,11 @@ endif() if(WITH_PUGIXML) find_package_wrapper(PugiXML) + + if (NOT PUGIXML_FOUND) + set(WITH_PUGIXML OFF) + message(STATUS "PugiXML not found, disabling WITH_PUGIXML") + endif() endif() if(WITH_OPENIMAGEIO) From 20d0bb43afc84c1161e693ae75ab19ba3f322077 Mon Sep 17 00:00:00 2001 From: Antonio Vazquez Date: Tue, 26 Jan 2021 15:28:17 +0100 Subject: [PATCH 33/55] GPencil: Swap positions of Pie menu options for Vertex Paint and Weight Paint This keep the same logic used with meshes because now the Weight Paint and Vertex Paint are not in the same position for grease pencil. --- source/blender/makesrna/intern/rna_object.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/blender/makesrna/intern/rna_object.c b/source/blender/makesrna/intern/rna_object.c index faa20e642cf..c418c8eb4dc 100644 --- a/source/blender/makesrna/intern/rna_object.c +++ b/source/blender/makesrna/intern/rna_object.c @@ -85,16 +85,16 @@ const EnumPropertyItem rna_enum_object_mode_items[] = { ICON_GREASEPENCIL, "Draw", "Paint Grease Pencil Strokes"}, - {OB_MODE_VERTEX_GPENCIL, - "VERTEX_GPENCIL", - ICON_VPAINT_HLT, - "Vertex Paint", - "Grease Pencil Vertex Paint Strokes"}, {OB_MODE_WEIGHT_GPENCIL, "WEIGHT_GPENCIL", ICON_WPAINT_HLT, "Weight Paint", "Grease Pencil Weight Paint Strokes"}, + {OB_MODE_VERTEX_GPENCIL, + "VERTEX_GPENCIL", + ICON_VPAINT_HLT, + "Vertex Paint", + "Grease Pencil Vertex Paint Strokes"}, {0, NULL, 0, NULL, NULL}, }; From 8d51c06611c703bdb92d029837812db61a84db52 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 26 Jan 2021 09:21:42 -0600 Subject: [PATCH 34/55] Cleanup: Reduce variable scope --- source/blender/blenkernel/intern/customdata.c | 140 +++++++----------- 1 file changed, 55 insertions(+), 85 deletions(-) diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 446ef12574d..42f59a710c1 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -212,9 +212,9 @@ static void layerFree_mdeformvert(void *data, int count, int size) /* copy just zeros in this case */ static void layerCopy_bmesh_elem_py_ptr(const void *UNUSED(source), void *dest, int count) { - int i, size = sizeof(void *); + const int size = sizeof(void *); - for (i = 0; i < count; i++) { + for (int i = 0; i < count; i++) { void **ptr = POINTER_OFFSET(dest, i * size); *ptr = NULL; } @@ -253,15 +253,14 @@ static void layerInterp_mdeformvert(const void **sources, MDeformVert *dvert = dest; struct MDeformWeight_Link *dest_dwlink = NULL; struct MDeformWeight_Link *node; - int i, j, totweight; /* build a list of unique def_nrs for dest */ - totweight = 0; - for (i = 0; i < count; i++) { + int totweight = 0; + for (int i = 0; i < count; i++) { const MDeformVert *source = sources[i]; float interp_weight = weights[i]; - for (j = 0; j < source->totweight; j++) { + for (int j = 0; j < source->totweight; j++) { MDeformWeight *dw = &source->dw[j]; float weight = dw->weight * interp_weight; @@ -311,7 +310,8 @@ static void layerInterp_mdeformvert(const void **sources, if (totweight) { dvert->totweight = totweight; - for (i = 0, node = dest_dwlink; node; node = node->next, i++) { + int i = 0; + for (node = dest_dwlink; node; node = node->next, i++) { if (node->dw.weight > 1.0f) { node->dw.weight = 1.0f; } @@ -416,18 +416,16 @@ static void layerInterp_tface( const void **sources, const float *weights, const float *sub_weights, int count, void *dest) { MTFace *tf = dest; - int i, j, k; float uv[4][2] = {{0.0f}}; - const float *sub_weight; - sub_weight = sub_weights; - for (i = 0; i < count; i++) { + const float *sub_weight = sub_weights; + for (int i = 0; i < count; i++) { const float interp_weight = weights[i]; const MTFace *src = sources[i]; - for (j = 0; j < 4; j++) { + for (int j = 0; j < 4; j++) { if (sub_weights) { - for (k = 0; k < 4; k++, sub_weight++) { + for (int k = 0; k < 4; k++, sub_weight++) { madd_v2_v2fl(uv[j], src->uv[k], (*sub_weight) * interp_weight); } } @@ -446,9 +444,8 @@ static void layerSwap_tface(void *data, const int *corner_indices) { MTFace *tf = data; float uv[4][2]; - int j; - for (j = 0; j < 4; j++) { + for (int j = 0; j < 4; j++) { const int source_index = corner_indices[j]; copy_v2_v2(uv[j], tf->uv[source_index]); } @@ -517,18 +514,16 @@ static void layerInterp_origspace_face( const void **sources, const float *weights, const float *sub_weights, int count, void *dest) { OrigSpaceFace *osf = dest; - int i, j, k; float uv[4][2] = {{0.0f}}; - const float *sub_weight; - sub_weight = sub_weights; - for (i = 0; i < count; i++) { + const float *sub_weight = sub_weights; + for (int i = 0; i < count; i++) { const float interp_weight = weights[i]; const OrigSpaceFace *src = sources[i]; - for (j = 0; j < 4; j++) { + for (int j = 0; j < 4; j++) { if (sub_weights) { - for (k = 0; k < 4; k++, sub_weight++) { + for (int k = 0; k < 4; k++, sub_weight++) { madd_v2_v2fl(uv[j], src->uv[k], (*sub_weight) * interp_weight); } } @@ -546,9 +541,8 @@ static void layerSwap_origspace_face(void *data, const int *corner_indices) { OrigSpaceFace *osf = data; float uv[4][2]; - int j; - for (j = 0; j < 4; j++) { + for (int j = 0; j < 4; j++) { copy_v2_v2(uv[j], osf->uv[corner_indices[j]]); } memcpy(osf->uv, uv, sizeof(osf->uv)); @@ -567,13 +561,11 @@ static void layerDefault_origspace_face(void *data, int count) static void layerSwap_mdisps(void *data, const int *ci) { MDisps *s = data; - float(*d)[3] = NULL; - int corners, cornersize, S; if (s->disps) { int nverts = (ci[1] == 3) ? 4 : 3; /* silly way to know vertex count of face */ - corners = multires_mdisp_corners(s); - cornersize = s->totdisp / corners; + int corners = multires_mdisp_corners(s); + int cornersize = s->totdisp / corners; if (corners != nverts) { /* happens when face changed vertex count in edit mode @@ -585,9 +577,9 @@ static void layerSwap_mdisps(void *data, const int *ci) return; } - d = MEM_calloc_arrayN(s->totdisp, sizeof(float[3]), "mdisps swap"); + float(*d)[3] = MEM_calloc_arrayN(s->totdisp, sizeof(float[3]), "mdisps swap"); - for (S = 0; S < corners; S++) { + for (int S = 0; S < corners; S++) { memcpy(d + cornersize * S, s->disps + cornersize * ci[S], sizeof(float[3]) * cornersize); } @@ -1128,9 +1120,8 @@ static void layerSwap_mcol(void *data, const int *corner_indices) { MCol *mcol = data; MCol col[4]; - int j; - for (j = 0; j < 4; j++) { + for (int j = 0; j < 4; j++) { col[j] = mcol[corner_indices[j]]; } @@ -2064,13 +2055,13 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, void CustomData_update_typemap(CustomData *data) { - int i, lasttype = -1; + int lasttype = -1; - for (i = 0; i < CD_NUMTYPES; i++) { + for (int i = 0; i < CD_NUMTYPES; i++) { data->typemap[i] = -1; } - for (i = 0; i < data->totlayer; i++) { + for (int i = 0; i < data->totlayer; i++) { const int type = data->layers[i].type; if (type != lasttype) { data->typemap[type] = i; @@ -2097,18 +2088,16 @@ bool CustomData_merge(const struct CustomData *source, { /*const LayerTypeInfo *typeInfo;*/ CustomDataLayer *layer, *newlayer; - void *data; - int i, type, lasttype = -1, lastactive = 0, lastrender = 0, lastclone = 0, lastmask = 0, - flag = 0; + int lasttype = -1, lastactive = 0, lastrender = 0, lastclone = 0, lastmask = 0; int number = 0, maxnumber = -1; bool changed = false; - for (i = 0; i < source->totlayer; i++) { + for (int i = 0; i < source->totlayer; i++) { layer = &source->layers[i]; /*typeInfo = layerType_getInfo(layer->type);*/ /*UNUSED*/ - type = layer->type; - flag = layer->flag; + int type = layer->type; + int flag = layer->flag; if (type != lasttype) { number = 0; @@ -2136,6 +2125,7 @@ bool CustomData_merge(const struct CustomData *source, continue; } + void *data; switch (alloctype) { case CD_ASSIGN: case CD_REFERENCE: @@ -2518,8 +2508,7 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, /* Passing a layer-data to copy from with an alloctype that won't copy is * most likely a bug */ - BLI_assert(!layerdata || (alloctype == CD_ASSIGN) || (alloctype == CD_DUPLICATE) || - (alloctype == CD_REFERENCE)); + BLI_assert(!layerdata || ELEM(alloctype, CD_ASSIGN, CD_DUPLICATE, CD_REFERENCE)); if (!typeInfo->defaultname && CustomData_has_layer(data, type)) { return &data->layers[CustomData_get_layer_index(data, type)]; @@ -2616,10 +2605,9 @@ static CustomDataLayer *customData_add_layer__internal(CustomData *data, void *CustomData_add_layer( CustomData *data, int type, eCDAllocType alloctype, void *layerdata, int totelem) { - CustomDataLayer *layer; const LayerTypeInfo *typeInfo = layerType_getInfo(type); - layer = customData_add_layer__internal( + CustomDataLayer *layer = customData_add_layer__internal( data, type, alloctype, layerdata, totelem, typeInfo->defaultname); CustomData_update_typemap(data); @@ -2638,9 +2626,8 @@ void *CustomData_add_layer_named(CustomData *data, int totelem, const char *name) { - CustomDataLayer *layer; - - layer = customData_add_layer__internal(data, type, alloctype, layerdata, totelem, name); + CustomDataLayer *layer = customData_add_layer__internal( + data, type, alloctype, layerdata, totelem, name); CustomData_update_typemap(data); if (layer) { @@ -2828,12 +2815,10 @@ bool CustomData_is_referenced_layer(struct CustomData *data, int type) void CustomData_free_temporary(CustomData *data, int totelem) { - CustomDataLayer *layer; int i, j; bool changed = false; - for (i = 0, j = 0; i < data->totlayer; i++) { - layer = &data->layers[i]; + CustomDataLayer *layer = &data->layers[i]; if (i != j) { data->layers[j] = data->layers[i]; @@ -3681,10 +3666,8 @@ void CustomData_bmesh_free_block_data_exclude_by_type(CustomData *data, static void CustomData_bmesh_set_default_n(CustomData *data, void **block, int n) { - const LayerTypeInfo *typeInfo; int offset = data->layers[n].offset; - - typeInfo = layerType_getInfo(data->layers[n].type); + const LayerTypeInfo *typeInfo = layerType_getInfo(data->layers[n].type); if (typeInfo->set_default) { typeInfo->set_default(POINTER_OFFSET(*block, offset), 1); @@ -4050,7 +4033,6 @@ void CustomData_bmesh_interp(CustomData *data, return; } - int i, j; void *source_buf[SOURCE_BUF_SIZE]; const void **sources = (const void **)source_buf; @@ -4071,11 +4053,11 @@ void CustomData_bmesh_interp(CustomData *data, } /* interpolates a layer at a time */ - for (i = 0; i < data->totlayer; i++) { + for (int i = 0; i < data->totlayer; i++) { CustomDataLayer *layer = &data->layers[i]; const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); if (typeInfo->interp) { - for (j = 0; j < count; j++) { + for (int j = 0; j < count; j++) { sources[j] = POINTER_OFFSET(src_blocks[j], layer->offset); } CustomData_bmesh_interp_n( @@ -4453,7 +4435,6 @@ bool CustomData_layer_validate(CustomDataLayer *layer, const uint totitems, cons void CustomData_layers__print(CustomData *data) { - printf("{\n"); int i; @@ -4508,10 +4489,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int { CustomDataExternal *external = data->external; CustomDataLayer *layer; - CDataFile *cdf; - CDataFileLayer *blay; char filename[FILE_MAX]; - const LayerTypeInfo *typeInfo; int update = 0; if (!external) { @@ -4520,7 +4498,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int for (int i = 0; i < data->totlayer; i++) { layer = &data->layers[i]; - typeInfo = layerType_getInfo(layer->type); + const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); if (!(mask & CD_TYPE_AS_MASK(layer->type))) { /* pass */ @@ -4539,7 +4517,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int customdata_external_filename(filename, id, external); - cdf = cdf_create(CDF_TYPE_MESH); + CDataFile *cdf = cdf_create(CDF_TYPE_MESH); if (!cdf_read_open(cdf, filename)) { cdf_free(cdf); CLOG_ERROR(&LOG, "Failed to read %s layer from %s.", layerType_getName(layer->type), filename); @@ -4548,7 +4526,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int for (int i = 0; i < data->totlayer; i++) { layer = &data->layers[i]; - typeInfo = layerType_getInfo(layer->type); + const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); if (!(mask & CD_TYPE_AS_MASK(layer->type))) { /* pass */ @@ -4557,7 +4535,7 @@ void CustomData_external_read(CustomData *data, ID *id, CustomDataMask mask, int /* pass */ } else if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->read) { - blay = cdf_layer_find(cdf, layer->type, layer->name); + CDataFileLayer *blay = cdf_layer_find(cdf, layer->type, layer->name); if (blay) { if (cdf_read_layer(cdf, blay)) { @@ -4584,10 +4562,6 @@ void CustomData_external_write( CustomData *data, ID *id, CustomDataMask mask, int totelem, int free) { CustomDataExternal *external = data->external; - CustomDataLayer *layer; - CDataFile *cdf; - CDataFileLayer *blay; - const LayerTypeInfo *typeInfo; int update = 0; char filename[FILE_MAX]; @@ -4597,8 +4571,8 @@ void CustomData_external_write( /* test if there is anything to write */ for (int i = 0; i < data->totlayer; i++) { - layer = &data->layers[i]; - typeInfo = layerType_getInfo(layer->type); + CustomDataLayer *layer = &data->layers[i]; + const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); if (!(mask & CD_TYPE_AS_MASK(layer->type))) { /* pass */ @@ -4616,11 +4590,11 @@ void CustomData_external_write( CustomData_external_read(data, id, mask, totelem); customdata_external_filename(filename, id, external); - cdf = cdf_create(CDF_TYPE_MESH); + CDataFile *cdf = cdf_create(CDF_TYPE_MESH); for (int i = 0; i < data->totlayer; i++) { - layer = &data->layers[i]; - typeInfo = layerType_getInfo(layer->type); + CustomDataLayer *layer = &data->layers[i]; + const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->filesize) { if (layer->flag & CD_FLAG_IN_MEMORY) { @@ -4642,11 +4616,11 @@ void CustomData_external_write( int i; for (i = 0; i < data->totlayer; i++) { - layer = &data->layers[i]; - typeInfo = layerType_getInfo(layer->type); + CustomDataLayer *layer = &data->layers[i]; + const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->write) { - blay = cdf_layer_find(cdf, layer->type, layer->name); + CDataFileLayer *blay = cdf_layer_find(cdf, layer->type, layer->name); if (cdf_write_layer(cdf, blay)) { if (typeInfo->write(cdf, layer->data, totelem)) { @@ -4670,8 +4644,8 @@ void CustomData_external_write( } for (i = 0; i < data->totlayer; i++) { - layer = &data->layers[i]; - typeInfo = layerType_getInfo(layer->type); + CustomDataLayer *layer = &data->layers[i]; + const LayerTypeInfo *typeInfo = layerType_getInfo(layer->type); if ((layer->flag & CD_FLAG_EXTERNAL) && typeInfo->write) { if (free) { @@ -4691,15 +4665,13 @@ void CustomData_external_add( CustomData *data, ID *UNUSED(id), int type, int UNUSED(totelem), const char *filename) { CustomDataExternal *external = data->external; - CustomDataLayer *layer; - int layer_index; - layer_index = CustomData_get_active_layer_index(data, type); + int layer_index = CustomData_get_active_layer_index(data, type); if (layer_index == -1) { return; } - layer = &data->layers[layer_index]; + CustomDataLayer *layer = &data->layers[layer_index]; if (layer->flag & CD_FLAG_EXTERNAL) { return; @@ -4823,8 +4795,6 @@ static void customdata_data_transfer_interp_generic(const CustomDataTransferLaye cd_interp interp_cd = NULL; cd_copy copy_cd = NULL; - void *tmp_dst; - if (!sources) { /* Not supported here, abort. */ return; @@ -4841,7 +4811,7 @@ static void customdata_data_transfer_interp_generic(const CustomDataTransferLaye copy_cd = type_info->copy; } - tmp_dst = MEM_mallocN(data_size, __func__); + void *tmp_dst = MEM_mallocN(data_size, __func__); if (count > 1 && !interp_cd) { if (data_flag) { From c1d0b234fbff45c11ecf74b1e5b346c3bbbaa513 Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 13 Jan 2021 16:29:51 +0100 Subject: [PATCH 35/55] Subdiv: Fix typo in RNA enum value name Was duplicated from SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES value. --- source/blender/makesrna/intern/rna_modifier.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index e02e47745b0..78cef590123 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1657,7 +1657,7 @@ static void rna_def_property_subdivision_common(StructRNA *srna) "Smooth, keep corners", "UVs are smoothed, boundaries are kept sharp"}, # endif - {SUBSURF_UV_SMOOTH_ALL, "PRESERVE_BOUNDARIES", 0, "All", "UVs and boundaries are smoothed"}, + {SUBSURF_UV_SMOOTH_ALL, "SMOOTH_ALL", 0, "All", "UVs and boundaries are smoothed"}, {0, NULL, 0, NULL, NULL}, }; From 66151b5de3ff7c49e2cb1be5708c3e030c22b64e Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 13 Jan 2021 16:49:50 +0100 Subject: [PATCH 36/55] Subsurf: Expose all UV interpolation options Useful for interoperability, and allows to change default mode without breaking compatibility. --- source/blender/makesrna/intern/rna_modifier.c | 56 ++++++++++--------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 78cef590123..c13f592f7fb 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -1632,33 +1632,35 @@ static IDProperty *rna_NodesModifier_properties(PointerRNA *ptr, bool create) static void rna_def_property_subdivision_common(StructRNA *srna) { static const EnumPropertyItem prop_uv_smooth_items[] = { - {SUBSURF_UV_SMOOTH_NONE, "NONE", 0, "None", "UVs are not smoothed, boundaries are kept sharp"}, - {SUBSURF_UV_SMOOTH_PRESERVE_CORNERS, - "PRESERVE_CORNERS", - 0, - "Keep Corners", - "UVs are smoothed, corners on discontinuous boundary are kept sharp"}, -# if 0 - {SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_AND_JUNCTIONS, - "PRESERVE_CORNERS_AND_JUNCTIONS", - 0, - "Smooth, keep corners+junctions", - "UVs are smoothed, corners on discontinuous boundary and " - "junctions of 3 or more regions are kept sharp"}, - {SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE, - "PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE", - 0, - "Smooth, keep corners+junctions+concave", - "UVs are smoothed, corners on discontinuous boundary, " - "junctions of 3 or more regions and darts and concave corners are kept sharp"}, - {SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES, - "PRESERVE_BOUNDARIES", - 0, - "Smooth, keep corners", - "UVs are smoothed, boundaries are kept sharp"}, -# endif - {SUBSURF_UV_SMOOTH_ALL, "SMOOTH_ALL", 0, "All", "UVs and boundaries are smoothed"}, - {0, NULL, 0, NULL, NULL}, + {SUBSURF_UV_SMOOTH_NONE, + "NONE", + 0, + "None", + "UVs are not smoothed, boundaries are kept sharp"}, + {SUBSURF_UV_SMOOTH_PRESERVE_CORNERS, + "PRESERVE_CORNERS", + 0, + "Keep Corners", + "UVs are smoothed, corners on discontinuous boundary are kept sharp"}, + {SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_AND_JUNCTIONS, + "PRESERVE_CORNERS_AND_JUNCTIONS", + 0, + "Keep Corners, Junctions", + "UVs are smoothed, corners on discontinuous boundary and " + "junctions of 3 or more regions are kept sharp"}, + {SUBSURF_UV_SMOOTH_PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE, + "PRESERVE_CORNERS_JUNCTIONS_AND_CONCAVE", + 0, + "Keep Corners, Junctions, Concave", + "UVs are smoothed, corners on discontinuous boundary, " + "junctions of 3 or more regions and darts and concave corners are kept sharp"}, + {SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES, + "PRESERVE_BOUNDARIES", + 0, + "Keep boundaries", + "UVs are smoothed, boundaries are kept sharp"}, + {SUBSURF_UV_SMOOTH_ALL, "SMOOTH_ALL", 0, "All", "UVs and boundaries are smoothed"}, + {0, NULL, 0, NULL, NULL}, }; static const EnumPropertyItem prop_boundary_smooth_items[] = { From 3d3b6d94e6e646828bd03c5656673a5d00a806aa Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Wed, 13 Jan 2021 16:58:36 +0100 Subject: [PATCH 37/55] Subdiv: Use better default UV interpolation The default one is now UVs are smoothed, boundaries are kept sharp. After some time of experimentation seems this is better default from interoperability point of view. This fixes distortion reported in T83470. Differential Revision: https://developer.blender.org/D10111 --- source/blender/blenkernel/intern/multires.c | 2 +- source/blender/makesdna/DNA_modifier_defaults.h | 4 ++-- source/blender/render/intern/multires_bake.c | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/source/blender/blenkernel/intern/multires.c b/source/blender/blenkernel/intern/multires.c index 441da8b134a..45ac20ef154 100644 --- a/source/blender/blenkernel/intern/multires.c +++ b/source/blender/blenkernel/intern/multires.c @@ -781,7 +781,7 @@ static DerivedMesh *subsurf_dm_create_local(Scene *scene, smd.levels = smd.renderLevels = lvl; smd.quality = 3; if (!is_plain_uv) { - smd.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS; + smd.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES; } else { smd.uv_smooth = SUBSURF_UV_SMOOTH_NONE; diff --git a/source/blender/makesdna/DNA_modifier_defaults.h b/source/blender/makesdna/DNA_modifier_defaults.h index 8601dcf76ac..860a9affb3e 100644 --- a/source/blender/makesdna/DNA_modifier_defaults.h +++ b/source/blender/makesdna/DNA_modifier_defaults.h @@ -440,7 +440,7 @@ .renderlvl = 0, \ .totlvl = 0, \ .flags = eMultiresModifierFlag_UseCrease | eMultiresModifierFlag_ControlEdges, \ - .uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS, \ + .uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES, \ .quality = 4, \ .boundary_smooth = SUBSURF_BOUNDARY_SMOOTH_ALL, \ } @@ -622,7 +622,7 @@ .levels = 1, \ .renderLevels = 2, \ .flags = eSubsurfModifierFlag_UseCrease | eSubsurfModifierFlag_ControlEdges, \ - .uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS, \ + .uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES, \ .quality = 3, \ .boundary_smooth = SUBSURF_BOUNDARY_SMOOTH_ALL, \ .emCache = NULL, \ diff --git a/source/blender/render/intern/multires_bake.c b/source/blender/render/intern/multires_bake.c index a4f68419c67..1859886f563 100644 --- a/source/blender/render/intern/multires_bake.c +++ b/source/blender/render/intern/multires_bake.c @@ -768,7 +768,7 @@ static void *init_heights_data(MultiresBakeRender *bkr, Image *ima) if (ss_lvl > 0) { smd.levels = smd.renderLevels = ss_lvl; - smd.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_CORNERS; + smd.uv_smooth = SUBSURF_UV_SMOOTH_PRESERVE_BOUNDARIES; smd.quality = 3; height_data->ssdm = subsurf_make_derived_from_derived( From 66f8835f9c03e7736297b5995a68e1455ed14e2a Mon Sep 17 00:00:00 2001 From: Sergey Sharybin Date: Tue, 19 Jan 2021 14:28:44 +0100 Subject: [PATCH 38/55] Fix T84850: "Lock to Selection" causes unwanted jumps Adding new tracks, mask points, mask primitives, changing selection was causing an unwanted jumps in the view. This change makes it so those operations are preserving view offset. Differential Revision: https://developer.blender.org/D10146 --- source/blender/editors/include/ED_clip.h | 24 +++ source/blender/editors/include/ED_mask.h | 5 +- source/blender/editors/mask/mask_add.c | 10 ++ source/blender/editors/mask/mask_edit.c | 36 ++++ source/blender/editors/mask/mask_intern.h | 15 ++ source/blender/editors/mask/mask_ops.c | 39 ++++- source/blender/editors/mask/mask_query.c | 13 +- source/blender/editors/mask/mask_select.c | 13 ++ .../blender/editors/space_clip/clip_editor.c | 160 ++++++------------ .../blender/editors/space_clip/clip_intern.h | 5 + source/blender/editors/space_clip/clip_ops.c | 8 + .../blender/editors/space_clip/clip_utils.c | 149 +++++++++++++++- .../blender/editors/space_clip/tracking_ops.c | 9 +- .../editors/space_clip/tracking_select.c | 17 +- .../blender/editors/space_image/image_ops.c | 2 +- 15 files changed, 375 insertions(+), 130 deletions(-) diff --git a/source/blender/editors/include/ED_clip.h b/source/blender/editors/include/ED_clip.h index 0a66c439f79..56494f87bfe 100644 --- a/source/blender/editors/include/ED_clip.h +++ b/source/blender/editors/include/ED_clip.h @@ -99,6 +99,30 @@ void ED_space_clip_set_clip(struct bContext *C, struct Mask *ED_space_clip_get_mask(struct SpaceClip *sc); void ED_space_clip_set_mask(struct bContext *C, struct SpaceClip *sc, struct Mask *mask); +/* Locked state is used to preserve current clip editor viewport upon changes. Example usage: + * + * ... + * + * ClipViewLockState lock_state; + * ED_clip_view_lock_state_store(C, &lock_state); + * + * + * + * ED_clip_view_lock_state_restore_no_jump(C, &lock_state); + * + * These function are to be used from space clip editor context only. Otherwise debug builds will + * assert, release builds will crash. */ + +typedef struct ClipViewLockState { + float offset_x, offset_y; + float lock_offset_x, lock_offset_y; + float zoom; +} ClipViewLockState; + +void ED_clip_view_lock_state_store(const struct bContext *C, ClipViewLockState *state); +void ED_clip_view_lock_state_restore_no_jump(const struct bContext *C, + const ClipViewLockState *state); + /* ** clip_ops.c ** */ void ED_operatormacros_clip(void); diff --git a/source/blender/editors/include/ED_mask.h b/source/blender/editors/include/ED_mask.h index bcf52da3f69..b20dae694fc 100644 --- a/source/blender/editors/include/ED_mask.h +++ b/source/blender/editors/include/ED_mask.h @@ -63,7 +63,10 @@ void ED_mask_point_pos__reverse( struct ScrArea *area, struct ARegion *region, float x, float y, float *xr, float *yr); void ED_mask_cursor_location_get(struct ScrArea *area, float cursor[2]); -bool ED_mask_selected_minmax(const struct bContext *C, float min[2], float max[2]); +bool ED_mask_selected_minmax(const struct bContext *C, + float min[2], + float max[2], + bool include_handles); /* mask_draw.c */ void ED_mask_draw(const struct bContext *C, const char draw_flag, const char draw_type); diff --git a/source/blender/editors/mask/mask_add.c b/source/blender/editors/mask/mask_add.c index d7b3d74bc7e..1226cc57359 100644 --- a/source/blender/editors/mask/mask_add.c +++ b/source/blender/editors/mask/mask_add.c @@ -507,6 +507,9 @@ static int add_vertex_handle_cyclic( static int add_vertex_exec(bContext *C, wmOperator *op) { + MaskViewLockState lock_state; + ED_mask_view_lock_state_store(C, &lock_state); + Mask *mask = CTX_data_edit_mask(C); if (mask == NULL) { /* if there's no active mask, create one */ @@ -548,6 +551,8 @@ static int add_vertex_exec(bContext *C, wmOperator *op) DEG_id_tag_update(&mask->id, ID_RECALC_GEOMETRY); + ED_mask_view_lock_state_restore_no_jump(C, &lock_state); + return OPERATOR_FINISHED; } @@ -690,6 +695,9 @@ void MASK_OT_add_feather_vertex(wmOperatorType *ot) static int create_primitive_from_points( bContext *C, wmOperator *op, const float (*points)[2], int num_points, char handle_type) { + MaskViewLockState lock_state; + ED_mask_view_lock_state_store(C, &lock_state); + ScrArea *area = CTX_wm_area(C); int size = RNA_float_get(op->ptr, "size"); @@ -752,6 +760,8 @@ static int create_primitive_from_points( DEG_id_tag_update(&mask->id, ID_RECALC_GEOMETRY); + ED_mask_view_lock_state_restore_no_jump(C, &lock_state); + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/mask/mask_edit.c b/source/blender/editors/mask/mask_edit.c index 663ae0097ad..e6c6424e5f0 100644 --- a/source/blender/editors/mask/mask_edit.c +++ b/source/blender/editors/mask/mask_edit.c @@ -184,3 +184,39 @@ void ED_operatormacros_mask(void) } /** \} */ + +/* -------------------------------------------------------------------- */ +/** \name Lock-to-selection viewport preservation + * \{ */ + +void ED_mask_view_lock_state_store(const bContext *C, MaskViewLockState *state) +{ + SpaceClip *space_clip = CTX_wm_space_clip(C); + if (space_clip != NULL) { + ED_clip_view_lock_state_store(C, &state->space_clip_state); + } +} + +void ED_mask_view_lock_state_restore_no_jump(const bContext *C, const MaskViewLockState *state) +{ + SpaceClip *space_clip = CTX_wm_space_clip(C); + if (space_clip != NULL) { + if ((space_clip->flag & SC_LOCK_SELECTION) == 0) { + /* Early output if the editor is not locked to selection. + * Avoids forced dependency graph evaluation here. */ + return; + } + + /* Mask's lock-to-selection requres deformed splines to be evaluated to calculate bounds of + * points after animation has been evaluated. The restore-no-jump type of function does + * calculation of new offset for the view for an updated state of mask to cancel the offset out + * by modifying locked offset. In order to do such calculation mask needs to be evaluated after + * modification by an operator. */ + struct Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C); + (void)depsgraph; + + ED_clip_view_lock_state_restore_no_jump(C, &state->space_clip_state); + } +} + +/** \} */ diff --git a/source/blender/editors/mask/mask_intern.h b/source/blender/editors/mask/mask_intern.h index f6990583383..ee1784011ea 100644 --- a/source/blender/editors/mask/mask_intern.h +++ b/source/blender/editors/mask/mask_intern.h @@ -23,6 +23,8 @@ #pragma once +#include "ED_clip.h" + struct Mask; struct bContext; struct wmOperatorType; @@ -92,6 +94,19 @@ void ED_mask_select_flush_all(struct Mask *mask); bool ED_maskedit_poll(struct bContext *C); bool ED_maskedit_mask_poll(struct bContext *C); +/* Generalized solution for preserving editor viewport when making changes while lock-to-selection + * is enabled. + * Any mask operator can use this API, without worrying that some editors do not have an idea of + * lock-to-selection. */ + +typedef struct MaskViewLockState { + ClipViewLockState space_clip_state; +} MaskViewLockState; + +void ED_mask_view_lock_state_store(const struct bContext *C, MaskViewLockState *state); +void ED_mask_view_lock_state_restore_no_jump(const struct bContext *C, + const MaskViewLockState *state); + /* mask_query.c */ bool ED_mask_find_nearest_diff_point(const struct bContext *C, struct Mask *mask, diff --git a/source/blender/editors/mask/mask_ops.c b/source/blender/editors/mask/mask_ops.c index 25cc39bf9a0..00a1dfb7d87 100644 --- a/source/blender/editors/mask/mask_ops.c +++ b/source/blender/editors/mask/mask_ops.c @@ -226,6 +226,12 @@ typedef struct SlidePointData { int width, height; float prev_mouse_coord[2]; + + /* Previous clip coordinate which was resolved from mouse position (0, 0). + * Is used to compansate for view offste moving in-between of mouse events when + * lock-to-selection is enabled. */ + float prev_zero_coord[2]; + float no[2]; bool is_curvature_only, is_accurate, is_initial_feather, is_overall_feather; @@ -431,6 +437,9 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent * const float threshold = 19; eMaskWhichHandle which_handle; + MaskViewLockState lock_state; + ED_mask_view_lock_state_store(C, &lock_state); + ED_mask_mouse_pos(area, region, event->mval, co); ED_mask_get_size(area, &width, &height); @@ -530,7 +539,15 @@ static void *slide_point_customdata(bContext *C, wmOperator *op, const wmEvent * } customdata->which_handle = which_handle; + { + WM_event_add_notifier(C, NC_MASK | NA_EDITED, mask); + DEG_id_tag_update(&mask->id, 0); + + ED_mask_view_lock_state_restore_no_jump(C, &lock_state); + } + ED_mask_mouse_pos(area, region, event->mval, customdata->prev_mouse_coord); + ED_mask_mouse_pos(area, region, (int[2]){0, 0}, customdata->prev_zero_coord); } return customdata; @@ -655,10 +672,24 @@ static int slide_point_modal(bContext *C, wmOperator *op, const wmEvent *event) ED_mask_mouse_pos(area, region, event->mval, co); sub_v2_v2v2(delta, co, data->prev_mouse_coord); + copy_v2_v2(data->prev_mouse_coord, co); + + /* Compensate for possibly moved view offset since the last event. + * The idea is to see how mapping of a fixed and known position did change. */ + { + float zero_coord[2]; + ED_mask_mouse_pos(area, region, (int[2]){0, 0}, zero_coord); + + float zero_delta[2]; + sub_v2_v2v2(zero_delta, zero_coord, data->prev_zero_coord); + sub_v2_v2(delta, zero_delta); + + copy_v2_v2(data->prev_zero_coord, zero_coord); + } + if (data->is_accurate) { mul_v2_fl(delta, 0.2f); } - copy_v2_v2(data->prev_mouse_coord, co); if (data->action == SLIDE_ACTION_HANDLE) { float new_handle[2]; @@ -966,6 +997,9 @@ static SlideSplineCurvatureData *slide_spline_curvature_customdata(bContext *C, float u, co[2]; BezTriple *next_bezt; + MaskViewLockState lock_state; + ED_mask_view_lock_state_store(C, &lock_state); + ED_mask_mouse_pos(CTX_wm_area(C), CTX_wm_region(C), event->mval, co); if (!ED_mask_find_nearest_diff_point(C, @@ -1047,6 +1081,9 @@ static SlideSplineCurvatureData *slide_spline_curvature_customdata(bContext *C, mask_layer->act_point = point; ED_mask_select_flush_all(mask); + DEG_id_tag_update(&mask->id, 0); + ED_mask_view_lock_state_restore_no_jump(C, &lock_state); + return slide_data; } diff --git a/source/blender/editors/mask/mask_query.c b/source/blender/editors/mask/mask_query.c index cfd57ca3477..8f4f14a1ba8 100644 --- a/source/blender/editors/mask/mask_query.c +++ b/source/blender/editors/mask/mask_query.c @@ -604,7 +604,7 @@ void ED_mask_point_pos__reverse( *yr = co[1]; } -bool ED_mask_selected_minmax(const bContext *C, float min[2], float max[2]) +bool ED_mask_selected_minmax(const bContext *C, float min[2], float max[2], bool include_handles) { Depsgraph *depsgraph = CTX_data_depsgraph_pointer(C); Mask *mask = CTX_data_edit_mask(C); @@ -638,22 +638,29 @@ bool ED_mask_selected_minmax(const bContext *C, float min[2], float max[2]) } if (bezt->f2 & SELECT) { minmax_v2v2_v2(min, max, deform_point->bezt.vec[1]); + ok = true; } - if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) { + + if (!include_handles) { + /* Ignore handles. */ + } + else if (BKE_mask_point_handles_mode_get(point) == MASK_HANDLE_MODE_STICK) { BKE_mask_point_handle(deform_point, MASK_WHICH_HANDLE_STICK, handle); minmax_v2v2_v2(min, max, handle); + ok = true; } else { if ((bezt->f1 & SELECT) && (bezt->h1 != HD_VECT)) { BKE_mask_point_handle(deform_point, MASK_WHICH_HANDLE_LEFT, handle); minmax_v2v2_v2(min, max, handle); + ok = true; } if ((bezt->f3 & SELECT) && (bezt->h2 != HD_VECT)) { BKE_mask_point_handle(deform_point, MASK_WHICH_HANDLE_RIGHT, handle); minmax_v2v2_v2(min, max, handle); + ok = true; } } - ok = true; } } } diff --git a/source/blender/editors/mask/mask_select.c b/source/blender/editors/mask/mask_select.c index cdc6ece1e84..5c369afc4cd 100644 --- a/source/blender/editors/mask/mask_select.c +++ b/source/blender/editors/mask/mask_select.c @@ -214,12 +214,17 @@ static int select_all_exec(bContext *C, wmOperator *op) Mask *mask = CTX_data_edit_mask(C); int action = RNA_enum_get(op->ptr, "action"); + MaskViewLockState lock_state; + ED_mask_view_lock_state_store(C, &lock_state); + ED_mask_select_toggle_all(mask, action); ED_mask_select_flush_all(mask); DEG_id_tag_update(&mask->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask); + ED_mask_view_lock_state_restore_no_jump(C, &lock_state); + return OPERATOR_FINISHED; } @@ -261,6 +266,9 @@ static int select_exec(bContext *C, wmOperator *op) eMaskWhichHandle which_handle; const float threshold = 19; + MaskViewLockState lock_state; + ED_mask_view_lock_state_store(C, &lock_state); + RNA_float_get_array(op->ptr, "location", co); point = ED_mask_point_find_nearest( @@ -324,6 +332,8 @@ static int select_exec(bContext *C, wmOperator *op) DEG_id_tag_update(&mask->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask); + ED_mask_view_lock_state_restore_no_jump(C, &lock_state); + return OPERATOR_FINISHED; } @@ -364,12 +374,15 @@ static int select_exec(bContext *C, wmOperator *op) DEG_id_tag_update(&mask->id, ID_RECALC_SELECT); WM_event_add_notifier(C, NC_MASK | ND_SELECT, mask); + ED_mask_view_lock_state_restore_no_jump(C, &lock_state); + return OPERATOR_FINISHED; } if (deselect_all) { /* For clip editor tracks, leave deselect all to clip editor. */ if (!ED_clip_can_select(C)) { ED_mask_deselect_all(C); + ED_mask_view_lock_state_restore_no_jump(C, &lock_state); return OPERATOR_FINISHED; } } diff --git a/source/blender/editors/space_clip/clip_editor.c b/source/blender/editors/space_clip/clip_editor.c index bd11a746e11..af1d082d317 100644 --- a/source/blender/editors/space_clip/clip_editor.c +++ b/source/blender/editors/space_clip/clip_editor.c @@ -327,118 +327,18 @@ void ED_clip_update_frame(const Main *mainp, int cfra) } } -static bool selected_tracking_boundbox(SpaceClip *sc, float min[2], float max[2]) +bool ED_clip_view_selection(const bContext *C, ARegion *UNUSED(region), bool fit) { - MovieClip *clip = ED_space_clip_get_clip(sc); - MovieTrackingTrack *track; - int width, height; - bool ok = false; - ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking); - int framenr = ED_space_clip_get_clip_frame_number(sc); - - INIT_MINMAX2(min, max); - - ED_space_clip_get_size(sc, &width, &height); - - track = tracksbase->first; - while (track) { - if (TRACK_VIEW_SELECTED(sc, track)) { - MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr); - - if (marker) { - float pos[3]; - - pos[0] = marker->pos[0] + track->offset[0]; - pos[1] = marker->pos[1] + track->offset[1]; - pos[2] = 0.0f; - - /* undistortion happens for normalized coords */ - if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) { - /* undistortion happens for normalized coords */ - ED_clip_point_undistorted_pos(sc, pos, pos); - } - - pos[0] *= width; - pos[1] *= height; - - mul_v3_m4v3(pos, sc->stabmat, pos); - - minmax_v2v2_v2(min, max, pos); - - ok = true; - } - } - - track = track->next; - } - - return ok; -} - -static bool selected_boundbox(const bContext *C, float min[2], float max[2]) -{ - SpaceClip *sc = CTX_wm_space_clip(C); - if (sc->mode == SC_MODE_TRACKING) { - return selected_tracking_boundbox(sc, min, max); - } - - if (ED_mask_selected_minmax(C, min, max)) { - MovieClip *clip = ED_space_clip_get_clip(sc); - int width, height; - ED_space_clip_get_size(sc, &width, &height); - BKE_mask_coord_to_movieclip(clip, &sc->user, min, min); - BKE_mask_coord_to_movieclip(clip, &sc->user, max, max); - min[0] *= width; - min[1] *= height; - max[0] *= width; - max[1] *= height; - return true; - } - return false; -} - -bool ED_clip_view_selection(const bContext *C, ARegion *region, bool fit) -{ - SpaceClip *sc = CTX_wm_space_clip(C); - int w, h, frame_width, frame_height; - float min[2], max[2]; - - ED_space_clip_get_size(sc, &frame_width, &frame_height); - - if ((frame_width == 0) || (frame_height == 0) || (sc->clip == NULL)) { + float offset_x, offset_y; + float zoom; + if (!clip_view_calculate_view_selection(C, fit, &offset_x, &offset_y, &zoom)) { return false; } - if (!selected_boundbox(C, min, max)) { - return false; - } - - /* center view */ - clip_view_center_to_point( - sc, (max[0] + min[0]) / (2 * frame_width), (max[1] + min[1]) / (2 * frame_height)); - - w = max[0] - min[0]; - h = max[1] - min[1]; - - /* set zoom to see all selection */ - if (w > 0 && h > 0) { - int width, height; - float zoomx, zoomy, newzoom, aspx, aspy; - - ED_space_clip_get_aspect(sc, &aspx, &aspy); - - width = BLI_rcti_size_x(®ion->winrct) + 1; - height = BLI_rcti_size_y(®ion->winrct) + 1; - - zoomx = (float)width / w / aspx; - zoomy = (float)height / h / aspy; - - newzoom = 1.0f / power_of_2(1.0f / min_ff(zoomx, zoomy)); - - if (fit || sc->zoom > newzoom) { - sc->zoom = newzoom; - } - } + SpaceClip *sc = CTX_wm_space_clip(C); + sc->xof = offset_x; + sc->yof = offset_y; + sc->zoom = zoom; return true; } @@ -1177,3 +1077,47 @@ void clip_start_prefetch_job(const bContext *C) /* and finally start the job */ WM_jobs_start(CTX_wm_manager(C), wm_job); } + +void ED_clip_view_lock_state_store(const bContext *C, ClipViewLockState *state) +{ + SpaceClip *space_clip = CTX_wm_space_clip(C); + BLI_assert(space_clip != NULL); + + state->offset_x = space_clip->xof; + state->offset_y = space_clip->yof; + state->zoom = space_clip->zoom; + + state->lock_offset_x = 0.0f; + state->lock_offset_y = 0.0f; + + if ((space_clip->flag & SC_LOCK_SELECTION) == 0) { + return; + } + + if (!clip_view_calculate_view_selection( + C, false, &state->offset_x, &state->offset_y, &state->zoom)) { + return; + } + + state->lock_offset_x = space_clip->xlockof; + state->lock_offset_y = space_clip->ylockof; +} + +void ED_clip_view_lock_state_restore_no_jump(const bContext *C, const ClipViewLockState *state) +{ + SpaceClip *space_clip = CTX_wm_space_clip(C); + BLI_assert(space_clip != NULL); + + if ((space_clip->flag & SC_LOCK_SELECTION) == 0) { + return; + } + + float offset_x, offset_y; + float zoom; + if (!clip_view_calculate_view_selection(C, false, &offset_x, &offset_y, &zoom)) { + return; + } + + space_clip->xlockof = state->offset_x + state->lock_offset_x - offset_x; + space_clip->ylockof = state->offset_y + state->lock_offset_y - offset_y; +} diff --git a/source/blender/editors/space_clip/clip_intern.h b/source/blender/editors/space_clip/clip_intern.h index 81df8cc8ecd..b9a69204281 100644 --- a/source/blender/editors/space_clip/clip_intern.h +++ b/source/blender/editors/space_clip/clip_intern.h @@ -171,8 +171,13 @@ void clip_delete_plane_track(struct bContext *C, struct MovieClip *clip, struct MovieTrackingPlaneTrack *plane_track); +void clip_view_offset_for_center_to_point( + SpaceClip *sc, const float x, const float y, float *r_offset_x, float *r_offset_y); void clip_view_center_to_point(SpaceClip *sc, float x, float y); +bool clip_view_calculate_view_selection( + const struct bContext *C, bool fit, float *r_offset_x, float *r_offset_y, float *r_zoom); + void clip_draw_sfra_efra(struct View2D *v2d, struct Scene *scene); /* tracking_ops.c */ diff --git a/source/blender/editors/space_clip/clip_ops.c b/source/blender/editors/space_clip/clip_ops.c index cd4a1ffb526..cb84ea6571c 100644 --- a/source/blender/editors/space_clip/clip_ops.c +++ b/source/blender/editors/space_clip/clip_ops.c @@ -1840,8 +1840,16 @@ void CLIP_OT_cursor_set(wmOperatorType *ot) static int lock_selection_togglee_exec(bContext *C, wmOperator *UNUSED(op)) { SpaceClip *space_clip = CTX_wm_space_clip(C); + + ClipViewLockState lock_state; + ED_clip_view_lock_state_store(C, &lock_state); + space_clip->flag ^= SC_LOCK_SELECTION; + + ED_clip_view_lock_state_restore_no_jump(C, &lock_state); + WM_event_add_notifier(C, NC_SPACE | ND_SPACE_CLIP, NULL); + return OPERATOR_FINISHED; } diff --git a/source/blender/editors/space_clip/clip_utils.c b/source/blender/editors/space_clip/clip_utils.c index c7f2a027ba8..faa3f18e8c1 100644 --- a/source/blender/editors/space_clip/clip_utils.c +++ b/source/blender/editors/space_clip/clip_utils.c @@ -27,10 +27,12 @@ #include "BLI_listbase.h" #include "BLI_math.h" +#include "BLI_rect.h" #include "BLI_utildefines.h" #include "BKE_animsys.h" #include "BKE_context.h" +#include "BKE_mask.h" #include "BKE_movieclip.h" #include "BKE_tracking.h" @@ -44,6 +46,7 @@ #include "WM_types.h" #include "ED_clip.h" +#include "ED_mask.h" #include "ED_screen.h" #include "UI_interface.h" @@ -395,16 +398,152 @@ void clip_delete_plane_track(bContext *C, MovieClip *clip, MovieTrackingPlaneTra DEG_id_tag_update(&clip->id, 0); } -void clip_view_center_to_point(SpaceClip *sc, float x, float y) +/* Calculate space clip offset to be centered at the given point. */ +void clip_view_offset_for_center_to_point( + SpaceClip *sc, const float x, const float y, float *r_offset_x, float *r_offset_y) { int width, height; - float aspx, aspy; - ED_space_clip_get_size(sc, &width, &height); + + float aspx, aspy; ED_space_clip_get_aspect(sc, &aspx, &aspy); - sc->xof = (x - 0.5f) * width * aspx; - sc->yof = (y - 0.5f) * height * aspy; + *r_offset_x = (x - 0.5f) * width * aspx; + *r_offset_y = (y - 0.5f) * height * aspy; +} + +void clip_view_center_to_point(SpaceClip *sc, float x, float y) +{ + clip_view_offset_for_center_to_point(sc, x, y, &sc->xof, &sc->yof); +} + +static bool selected_tracking_boundbox(SpaceClip *sc, float min[2], float max[2]) +{ + MovieClip *clip = ED_space_clip_get_clip(sc); + MovieTrackingTrack *track; + int width, height; + bool ok = false; + ListBase *tracksbase = BKE_tracking_get_active_tracks(&clip->tracking); + int framenr = ED_space_clip_get_clip_frame_number(sc); + + INIT_MINMAX2(min, max); + + ED_space_clip_get_size(sc, &width, &height); + + track = tracksbase->first; + while (track) { + if (TRACK_VIEW_SELECTED(sc, track)) { + MovieTrackingMarker *marker = BKE_tracking_marker_get(track, framenr); + + if (marker) { + float pos[3]; + + pos[0] = marker->pos[0] + track->offset[0]; + pos[1] = marker->pos[1] + track->offset[1]; + pos[2] = 0.0f; + + /* undistortion happens for normalized coords */ + if (sc->user.render_flag & MCLIP_PROXY_RENDER_UNDISTORT) { + /* undistortion happens for normalized coords */ + ED_clip_point_undistorted_pos(sc, pos, pos); + } + + pos[0] *= width; + pos[1] *= height; + + mul_v3_m4v3(pos, sc->stabmat, pos); + + minmax_v2v2_v2(min, max, pos); + + ok = true; + } + } + + track = track->next; + } + + return ok; +} + +static bool selected_boundbox(const bContext *C, float min[2], float max[2], bool include_handles) +{ + SpaceClip *sc = CTX_wm_space_clip(C); + if (sc->mode == SC_MODE_TRACKING) { + return selected_tracking_boundbox(sc, min, max); + } + + if (ED_mask_selected_minmax(C, min, max, include_handles)) { + MovieClip *clip = ED_space_clip_get_clip(sc); + int width, height; + ED_space_clip_get_size(sc, &width, &height); + BKE_mask_coord_to_movieclip(clip, &sc->user, min, min); + BKE_mask_coord_to_movieclip(clip, &sc->user, max, max); + min[0] *= width; + min[1] *= height; + max[0] *= width; + max[1] *= height; + return true; + } + return false; +} + +bool clip_view_calculate_view_selection( + const bContext *C, bool fit, float *r_offset_x, float *r_offset_y, float *r_zoom) +{ + SpaceClip *sc = CTX_wm_space_clip(C); + + int frame_width, frame_height; + ED_space_clip_get_size(sc, &frame_width, &frame_height); + + if ((frame_width == 0) || (frame_height == 0) || (sc->clip == NULL)) { + return false; + } + + /* NOTE: The `fit` argment is set to truth when doing "View to Selected" operator, and it set to + * false when this function is used for Lock-to-Selection functionality. When locking to + * selection the handles are to be ignored. So we can deriver the `include_handles` from `fit`. + * + * TODO(sergey): Make such decision more explicit. Maybe pass usecase for the calculation to tell + * operator from lock-to-selection apart. */ + float min[2], max[2]; + if (!selected_boundbox(C, min, max, fit)) { + return false; + } + + /* center view */ + clip_view_offset_for_center_to_point(sc, + (max[0] + min[0]) / (2 * frame_width), + (max[1] + min[1]) / (2 * frame_height), + r_offset_x, + r_offset_y); + + const int w = max[0] - min[0]; + const int h = max[1] - min[1]; + + /* set zoom to see all selection */ + *r_zoom = sc->zoom; + if (w > 0 && h > 0) { + ARegion *region = CTX_wm_region(C); + + int width, height; + float zoomx, zoomy, newzoom, aspx, aspy; + + ED_space_clip_get_aspect(sc, &aspx, &aspy); + + width = BLI_rcti_size_x(®ion->winrct) + 1; + height = BLI_rcti_size_y(®ion->winrct) + 1; + + zoomx = (float)width / w / aspx; + zoomy = (float)height / h / aspy; + + newzoom = 1.0f / power_of_2(1.0f / min_ff(zoomx, zoomy)); + + if (fit) { + *r_zoom = newzoom; + } + } + + return true; } void clip_draw_sfra_efra(View2D *v2d, Scene *scene) diff --git a/source/blender/editors/space_clip/tracking_ops.c b/source/blender/editors/space_clip/tracking_ops.c index 10574063ebd..0f4fc2a2160 100644 --- a/source/blender/editors/space_clip/tracking_ops.c +++ b/source/blender/editors/space_clip/tracking_ops.c @@ -88,17 +88,16 @@ static int add_marker_exec(bContext *C, wmOperator *op) MovieClip *clip = ED_space_clip_get_clip(sc); float pos[2]; + ClipViewLockState lock_state; + ED_clip_view_lock_state_store(C, &lock_state); + RNA_float_get_array(op->ptr, "location", pos); if (!add_marker(C, pos[0], pos[1])) { return OPERATOR_CANCELLED; } - /* Reset offset from locked position, so frame jumping wouldn't be so - * confusing. - */ - sc->xlockof = 0; - sc->ylockof = 0; + ED_clip_view_lock_state_restore_no_jump(C, &lock_state); WM_event_add_notifier(C, NC_MOVIECLIP | NA_EDITED, clip); diff --git a/source/blender/editors/space_clip/tracking_select.c b/source/blender/editors/space_clip/tracking_select.c index 063ea9592aa..ecd73f82e22 100644 --- a/source/blender/editors/space_clip/tracking_select.c +++ b/source/blender/editors/space_clip/tracking_select.c @@ -304,6 +304,9 @@ static int mouse_select(bContext *C, const float co[2], const bool extend, const track = find_nearest_track(sc, tracksbase, co, &distance_to_track); plane_track = find_nearest_plane_track(sc, plane_tracks_base, co, &distance_to_plane_track); + ClipViewLockState lock_state; + ED_clip_view_lock_state_store(C, &lock_state); + /* Do not select beyond some reasonable distance, that is useless and * prevents the 'deselect on nothing' behavior. */ if (distance_to_track > 0.05f) { @@ -377,10 +380,7 @@ static int mouse_select(bContext *C, const float co[2], const bool extend, const ED_mask_deselect_all(C); } - if (!extend) { - sc->xlockof = 0.0f; - sc->ylockof = 0.0f; - } + ED_clip_view_lock_state_restore_no_jump(C, &lock_state); BKE_tracking_dopesheet_tag_update(tracking); @@ -867,15 +867,20 @@ static int select_all_exec(bContext *C, wmOperator *op) MovieClip *clip = ED_space_clip_get_clip(sc); MovieTracking *tracking = &clip->tracking; - int action = RNA_enum_get(op->ptr, "action"); + const int action = RNA_enum_get(op->ptr, "action"); + + ClipViewLockState lock_state; + ED_clip_view_lock_state_store(C, &lock_state); bool has_selection = false; - ED_clip_select_all(sc, action, &has_selection); if (!has_selection) { sc->flag &= ~SC_LOCK_SELECTION; } + else { + ED_clip_view_lock_state_restore_no_jump(C, &lock_state); + } BKE_tracking_dopesheet_tag_update(tracking); diff --git a/source/blender/editors/space_image/image_ops.c b/source/blender/editors/space_image/image_ops.c index 86e52814d6f..097e304c893 100644 --- a/source/blender/editors/space_image/image_ops.c +++ b/source/blender/editors/space_image/image_ops.c @@ -900,7 +900,7 @@ static int image_view_selected_exec(bContext *C, wmOperator *UNUSED(op)) } } else if (ED_space_image_check_show_maskedit(sima, obedit)) { - if (!ED_mask_selected_minmax(C, min, max)) { + if (!ED_mask_selected_minmax(C, min, max, true)) { return OPERATOR_CANCELLED; } } From 89484e97548a026d0fdebe4822cb8e94c7209cf3 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 26 Jan 2021 10:10:07 -0600 Subject: [PATCH 39/55] Geometry Nodes: Use highest complexity attribute in join node This just implements a todo with a utility function that didn't exist at the time. For example, if one geometry has a "scale" attribute with a float type and another has a "scale" attribute with a vector type, the vector type will be used for the resulting geometry. Differential Revision: https://developer.blender.org/D10206 --- .../nodes/geometry/nodes/node_geo_join_geometry.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc index 02f0aca9c23..5c768531868 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc @@ -138,17 +138,17 @@ static void determine_final_data_type_and_domain(Span CustomDataType *r_type, AttributeDomain *r_domain) { + Vector data_types; for (const GeometryComponent *component : components) { ReadAttributePtr attribute = component->attribute_try_get_for_read(attribute_name); if (attribute) { - /* TODO: Use data type with most information. */ - *r_type = bke::cpp_type_to_custom_data_type(attribute->cpp_type()); + data_types.append(attribute->custom_data_type()); /* TODO: Use highest priority domain. */ *r_domain = attribute->domain(); - return; } } - BLI_assert(false); + + *r_type = attribute_data_type_highest_complexity(data_types); } static void fill_new_attribute(Span src_components, From ff7a557c67096fc8de870e5fb43caa17b649c538 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 26 Jan 2021 17:37:58 +0100 Subject: [PATCH 40/55] Geometry Nodes: new Points to Volume node This implements a new geometry node based on T84606. It is the first node that generates a `VolumeComponent`. Differential Revision: https://developer.blender.org/D10169 --- release/scripts/startup/nodeitems_builtins.py | 3 + source/blender/blenkernel/BKE_node.h | 1 + source/blender/blenkernel/intern/node.c | 1 + source/blender/editors/space_node/drawnode.c | 13 + source/blender/makesdna/DNA_node_types.h | 14 + source/blender/makesrna/intern/rna_nodetree.c | 31 +++ source/blender/nodes/CMakeLists.txt | 1 + source/blender/nodes/NOD_geometry.h | 1 + source/blender/nodes/NOD_static_types.h | 1 + .../nodes/node_geo_points_to_volume.cc | 259 ++++++++++++++++++ 10 files changed, 325 insertions(+) create mode 100644 source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc diff --git a/release/scripts/startup/nodeitems_builtins.py b/release/scripts/startup/nodeitems_builtins.py index 9da261d13f5..56f0b5c0ba4 100644 --- a/release/scripts/startup/nodeitems_builtins.py +++ b/release/scripts/startup/nodeitems_builtins.py @@ -521,6 +521,9 @@ geometry_node_categories = [ NodeItem("GeometryNodeRotatePoints"), NodeItem("GeometryNodeAlignRotationToVector"), ]), + GeometryNodeCategory("GEO_VOLUME", "Volume", items=[ + NodeItem("GeometryNodePointsToVolume"), + ]), GeometryNodeCategory("GEO_UTILITIES", "Utilities", items=[ NodeItem("ShaderNodeMapRange"), NodeItem("ShaderNodeClamp"), diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index fb517b7c1d0..4912d634471 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -1362,6 +1362,7 @@ int ntreeTexExecTree(struct bNodeTree *ntree, #define GEO_NODE_POINT_TRANSLATE 1019 #define GEO_NODE_POINT_SCALE 1020 #define GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE 1021 +#define GEO_NODE_POINTS_TO_VOLUME 1022 /** \} */ diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index f4f0d991f06..247bfafc099 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -4750,6 +4750,7 @@ static void registerGeometryNodes(void) register_node_type_geo_point_rotate(); register_node_type_geo_align_rotation_to_vector(); register_node_type_geo_sample_texture(); + register_node_type_geo_points_to_volume(); } static void registerFunctionNodes(void) diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index afd19df9f14..8f3602c8d50 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -3297,6 +3297,16 @@ static void node_geometry_buts_attribute_sample_texture(uiLayout *layout, uiTemplateID(layout, C, ptr, "texture", "texture.new", NULL, NULL, 0, ICON_NONE, NULL); } +static void node_geometry_buts_points_to_volume(uiLayout *layout, + bContext *UNUSED(C), + PointerRNA *ptr) +{ + uiLayoutSetPropSep(layout, true); + uiLayoutSetPropDecorate(layout, false); + uiItemR(layout, ptr, "resolution_mode", DEFAULT_FLAGS, IFACE_("Resolution"), ICON_NONE); + uiItemR(layout, ptr, "input_type_radius", DEFAULT_FLAGS, IFACE_("Radius"), ICON_NONE); +} + static void node_geometry_set_butfunc(bNodeType *ntype) { switch (ntype->type) { @@ -3354,6 +3364,9 @@ static void node_geometry_set_butfunc(bNodeType *ntype) case GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE: ntype->draw_buttons = node_geometry_buts_attribute_sample_texture; break; + case GEO_NODE_POINTS_TO_VOLUME: + ntype->draw_buttons = node_geometry_buts_points_to_volume; + break; } } diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 4dba856b87b..e26a2861f04 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1183,6 +1183,15 @@ typedef struct NodeGeometryPointInstance { char _pad[6]; } NodeGeometryPointInstance; +typedef struct NodeGeometryPointsToVolume { + /* GeometryNodePointsToVolumeResolutionMode */ + uint8_t resolution_mode; + /* GeometryNodeAttributeInputMode */ + uint8_t input_type_radius; + + char _pad[6]; +} NodeGeometryPointsToVolume; + /* script node mode */ #define NODE_SCRIPT_INTERNAL 0 #define NODE_SCRIPT_EXTERNAL 1 @@ -1633,6 +1642,11 @@ typedef enum GeometryNodeTransformSpace { GEO_NODE_TRANSFORM_SPACE_RELATIVE = 1, } GeometryNodeTransformSpace; +typedef enum GeometryNodePointsToVolumeResolutionMode { + GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT = 0, + GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE = 1, +} GeometryNodePointsToVolumeResolutionMode; + #ifdef __cplusplus } #endif diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index 355b1360ab0..db9c774bf9b 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -8889,6 +8889,37 @@ static void def_geo_object_info(StructRNA *srna) RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); } +static void def_geo_points_to_volume(StructRNA *srna) +{ + PropertyRNA *prop; + + static EnumPropertyItem resolution_mode_items[] = { + {GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT, + "VOXEL_AMOUNT", + 0, + "Amount", + "Specify the approximate number of voxels along the diagonal"}, + {GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE, + "VOXEL_SIZE", + 0, + "Size", + "Specify the voxel side length"}, + {0, NULL, 0, NULL, NULL}, + }; + + RNA_def_struct_sdna_from(srna, "NodeGeometryPointsToVolume", "storage"); + + prop = RNA_def_property(srna, "resolution_mode", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, resolution_mode_items); + RNA_def_property_ui_text(prop, "Resolution Mode", "How the voxel size is specified"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); + + prop = RNA_def_property(srna, "input_type_radius", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float); + RNA_def_property_ui_text(prop, "Radius Input Type", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); +} + /* -------------------------------------------------------------------------- */ static void rna_def_shader_node(BlenderRNA *brna) diff --git a/source/blender/nodes/CMakeLists.txt b/source/blender/nodes/CMakeLists.txt index d796c7c309c..405a8dcbf46 100644 --- a/source/blender/nodes/CMakeLists.txt +++ b/source/blender/nodes/CMakeLists.txt @@ -160,6 +160,7 @@ set(SRC geometry/nodes/node_geo_point_scale.cc geometry/nodes/node_geo_point_separate.cc geometry/nodes/node_geo_point_translate.cc + geometry/nodes/node_geo_points_to_volume.cc geometry/nodes/node_geo_subdivision_surface.cc geometry/nodes/node_geo_transform.cc geometry/nodes/node_geo_triangulate.cc diff --git a/source/blender/nodes/NOD_geometry.h b/source/blender/nodes/NOD_geometry.h index 1b3a8200beb..d78f76e0b52 100644 --- a/source/blender/nodes/NOD_geometry.h +++ b/source/blender/nodes/NOD_geometry.h @@ -48,6 +48,7 @@ void register_node_type_geo_attribute_color_ramp(void); void register_node_type_geo_point_rotate(void); void register_node_type_geo_align_rotation_to_vector(void); void register_node_type_geo_sample_texture(void); +void register_node_type_geo_points_to_volume(void); #ifdef __cplusplus } diff --git a/source/blender/nodes/NOD_static_types.h b/source/blender/nodes/NOD_static_types.h index 4c300916357..cc2f6a294f2 100644 --- a/source/blender/nodes/NOD_static_types.h +++ b/source/blender/nodes/NOD_static_types.h @@ -290,6 +290,7 @@ DefNode(GeometryNode, GEO_NODE_ALIGN_ROTATION_TO_VECTOR, def_geo_align_rotation_ DefNode(GeometryNode, GEO_NODE_POINT_SCALE, def_geo_point_scale, "POINT_SCALE", PointScale, "Point Scale", "") DefNode(GeometryNode, GEO_NODE_POINT_TRANSLATE, def_geo_point_translate, "POINT_TRANSLATE", PointTranslate, "Point Translate", "") DefNode(GeometryNode, GEO_NODE_ATTRIBUTE_SAMPLE_TEXTURE, def_geo_attribute_sample_texture, "ATTRIBUTE_SAMPLE_TEXTURE", AttributeSampleTexture, "Attribute Sample Texture", "") +DefNode(GeometryNode, GEO_NODE_POINTS_TO_VOLUME, def_geo_points_to_volume, "POINTS_TO_VOLUME", PointsToVolume, "Points to Volume", "") /* undefine macros */ #undef DefNode diff --git a/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc new file mode 100644 index 00000000000..b90ef2034a8 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_points_to_volume.cc @@ -0,0 +1,259 @@ +/* + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef WITH_OPENVDB +# include +# include +# include +#endif + +#include "node_geometry_util.hh" + +#include "BKE_lib_id.h" +#include "BKE_volume.h" + +static bNodeSocketTemplate geo_node_points_to_volume_in[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {SOCK_FLOAT, N_("Density"), 1.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX}, + {SOCK_FLOAT, N_("Voxel Size"), 0.3f, 0.0f, 0.0f, 0.0f, 0.01f, FLT_MAX}, + {SOCK_FLOAT, N_("Voxel Amount"), 64.0f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX}, + {SOCK_STRING, N_("Radius")}, + {SOCK_FLOAT, N_("Radius"), 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, FLT_MAX}, + {-1, ""}, +}; + +static bNodeSocketTemplate geo_node_point_translate_out[] = { + {SOCK_GEOMETRY, N_("Geometry")}, + {-1, ""}, +}; + +namespace blender::nodes { + +#ifdef WITH_OPENVDB +namespace { +/* Implements the interface required by #openvdb::tools::ParticlesToLevelSet. */ +struct ParticleList { + using PosType = openvdb::Vec3R; + + Span positions; + Span radii; + + size_t size() const + { + return (size_t)positions.size(); + } + + void getPos(size_t n, openvdb::Vec3R &xyz) const + { + xyz = &positions[n].x; + } + + void getPosRad(size_t n, openvdb::Vec3R &xyz, openvdb::Real &radius) const + { + xyz = &positions[n].x; + radius = radii[n]; + } +}; +} // namespace + +static openvdb::FloatGrid::Ptr generate_volume_from_points(const Span positions, + const Span radii, + const float density) +{ + /* Create a new grid that will be filled. #ParticlesToLevelSet requires the background value to + * be positive. It will be set to zero later on. */ + openvdb::FloatGrid::Ptr new_grid = openvdb::FloatGrid::create(1.0f); + + /* Create a narrow-band level set grid based on the positions and radii. */ + openvdb::tools::ParticlesToLevelSet op{*new_grid}; + /* Don't ignore particles based on their radius. */ + op.setRmin(0.0f); + op.setRmax(FLT_MAX); + ParticleList particles{positions, radii}; + op.rasterizeSpheres(particles); + op.finalize(); + + /* Convert the level set to a fog volume. This also sets the background value to zero. Inside the + * fog there will be a density of 1. */ + openvdb::tools::sdfToFogVolume(*new_grid); + + /* Take the desired density into account. */ + openvdb::tools::foreach (new_grid->beginValueOn(), + [&](const openvdb::FloatGrid::ValueOnIter &iter) { + iter.modifyValue([&](float &value) { value *= density; }); + }); + return new_grid; +} + +static float compute_voxel_size(const GeoNodeExecParams ¶ms, + Span positions, + const float radius) +{ + const NodeGeometryPointsToVolume &storage = + *(const NodeGeometryPointsToVolume *)params.node().storage; + + if (storage.resolution_mode == GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE) { + return params.get_input("Voxel Size"); + } + + if (positions.is_empty()) { + return 0.0f; + } + + float3 min, max; + INIT_MINMAX(min, max); + minmax_v3v3_v3_array(min, max, (float(*)[3])positions.data(), positions.size()); + + const float voxel_amount = params.get_input("Voxel Amount"); + if (voxel_amount <= 1) { + return 0.0f; + } + + /* The voxel size adapts to the final size of the volume. */ + const float diagonal = float3::distance(min, max); + const float extended_diagonal = diagonal + 2.0f * radius; + const float voxel_size = extended_diagonal / voxel_amount; + return voxel_size; +} + +static void gather_point_data_from_component(const GeoNodeExecParams ¶ms, + const GeometryComponent &component, + Vector &r_positions, + Vector &r_radii) +{ + Float3ReadAttribute positions = component.attribute_get_for_read( + "position", ATTR_DOMAIN_POINT, {0, 0, 0}); + FloatReadAttribute radii = params.get_input_attribute( + "Radius", component, ATTR_DOMAIN_POINT, 0.0f); + + r_positions.extend(positions.get_span()); + r_radii.extend(radii.get_span()); +} + +static void convert_to_grid_index_space(const float voxel_size, + MutableSpan positions, + MutableSpan radii) +{ + const float voxel_size_inv = 1.0f / voxel_size; + for (const int i : positions.index_range()) { + positions[i] *= voxel_size_inv; + /* Better align generated grid with source points. */ + positions[i] -= float3(0.5f); + radii[i] *= voxel_size_inv; + } +} + +static void initialize_volume_component_from_points(const GeometrySet &geometry_set_in, + GeometrySet &geometry_set_out, + const GeoNodeExecParams ¶ms) +{ + Vector positions; + Vector radii; + + if (geometry_set_in.has()) { + gather_point_data_from_component( + params, *geometry_set_in.get_component_for_read(), positions, radii); + } + if (geometry_set_in.has()) { + gather_point_data_from_component( + params, *geometry_set_in.get_component_for_read(), positions, radii); + } + + const float max_radius = *std::max_element(radii.begin(), radii.end()); + const float voxel_size = compute_voxel_size(params, positions, max_radius); + if (voxel_size == 0.0f || positions.is_empty()) { + return; + } + + Volume *volume = (Volume *)BKE_id_new_nomain(ID_VO, nullptr); + BKE_volume_init_grids(volume); + + VolumeGrid *c_density_grid = BKE_volume_grid_add(volume, "density", VOLUME_GRID_FLOAT); + openvdb::FloatGrid::Ptr density_grid = openvdb::gridPtrCast( + BKE_volume_grid_openvdb_for_write(volume, c_density_grid, false)); + + const float density = params.get_input("Density"); + convert_to_grid_index_space(voxel_size, positions, radii); + openvdb::FloatGrid::Ptr new_grid = generate_volume_from_points(positions, radii, density); + /* This merge is cheap, because the #density_grid is empty. */ + density_grid->merge(*new_grid); + density_grid->transform().postScale(voxel_size); + + VolumeComponent &volume_component = geometry_set_out.get_component_for_write(); + volume_component.replace(volume); +} +#endif + +static void geo_node_points_to_volume_exec(GeoNodeExecParams params) +{ + GeometrySet geometry_set_in = params.extract_input("Geometry"); + GeometrySet geometry_set_out; + +#ifdef WITH_OPENVDB + initialize_volume_component_from_points(geometry_set_in, geometry_set_out, params); +#endif + + params.set_output("Geometry", std::move(geometry_set_out)); +} + +static void geo_node_points_to_volume_init(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)MEM_callocN( + sizeof(NodeGeometryPointsToVolume), __func__); + data->resolution_mode = GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT; + data->input_type_radius = GEO_NODE_ATTRIBUTE_INPUT_FLOAT; + node->storage = data; + + bNodeSocket *radius_attribute_socket = nodeFindSocket(node, SOCK_IN, "Radius"); + bNodeSocketValueString *radius_attribute_socket_value = + (bNodeSocketValueString *)radius_attribute_socket->default_value; + STRNCPY(radius_attribute_socket_value->value, "radius"); +} + +static void geo_node_points_to_volume_update(bNodeTree *UNUSED(ntree), bNode *node) +{ + NodeGeometryPointsToVolume *data = (NodeGeometryPointsToVolume *)node->storage; + bNodeSocket *voxel_size_socket = nodeFindSocket(node, SOCK_IN, "Voxel Size"); + bNodeSocket *voxel_amount_socket = nodeFindSocket(node, SOCK_IN, "Voxel Amount"); + nodeSetSocketAvailability(voxel_amount_socket, + data->resolution_mode == + GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_AMOUNT); + nodeSetSocketAvailability( + voxel_size_socket, data->resolution_mode == GEO_NODE_POINTS_TO_VOLUME_RESOLUTION_MODE_SIZE); + + update_attribute_input_socket_availabilities( + *node, "Radius", (GeometryNodeAttributeInputMode)data->input_type_radius); +} + +} // namespace blender::nodes + +void register_node_type_geo_points_to_volume() +{ + static bNodeType ntype; + + geo_node_type_base( + &ntype, GEO_NODE_POINTS_TO_VOLUME, "Points to Volume", NODE_CLASS_GEOMETRY, 0); + node_type_socket_templates(&ntype, geo_node_points_to_volume_in, geo_node_point_translate_out); + node_type_storage(&ntype, + "NodeGeometryPointsToVolume", + node_free_standard_storage, + node_copy_standard_storage); + node_type_size(&ntype, 170, 120, 700); + node_type_init(&ntype, blender::nodes::geo_node_points_to_volume_init); + node_type_update(&ntype, blender::nodes::geo_node_points_to_volume_update); + ntype.geometry_node_execute = blender::nodes::geo_node_points_to_volume_exec; + nodeRegisterType(&ntype); +} From f22e85d72163a9649161dc550cb860f427a98111 Mon Sep 17 00:00:00 2001 From: Jacques Lucke Date: Tue, 26 Jan 2021 17:49:58 +0100 Subject: [PATCH 41/55] Fix T84935: improve previous fix for boolean custom data layers This improves the fix introduced in rBdc8b31af578bfcf9f77dbce6d7b7da1006a3c8c1. While it did not result in other bugs afaik, I thought it would be good to make the fix more specific, in case some other code did expect `layer->data` to be null. This updated fix checks for the very specific case the fix was intended for. --- source/blender/blenkernel/intern/customdata.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/blender/blenkernel/intern/customdata.c b/source/blender/blenkernel/intern/customdata.c index 446ef12574d..b0994fb683a 100644 --- a/source/blender/blenkernel/intern/customdata.c +++ b/source/blender/blenkernel/intern/customdata.c @@ -5197,7 +5197,7 @@ void CustomData_blend_read(BlendDataReader *reader, CustomData *data, int count) if (CustomData_verify_versions(data, i)) { BLO_read_data_address(reader, &layer->data); - if (layer->data == NULL) { + if (layer->data == NULL && count > 0 && layer->type == CD_PROP_BOOL) { /* Usually this should never happen, except when a custom data layer has not been written * to a file correctly. */ CLOG_WARN(&LOG, "Reallocating custom data layer that was not saved correctly."); From 20504e555e452e034016582dcf0868a51227f394 Mon Sep 17 00:00:00 2001 From: Richard Antalik Date: Tue, 26 Jan 2021 17:27:40 +0100 Subject: [PATCH 42/55] Fix T84979: No sound after changing strip datablock Tag relations to update to load new sound. Reviewed By: sergey Differential Revision: https://developer.blender.org/D10182 --- source/blender/makesrna/intern/rna_sequencer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source/blender/makesrna/intern/rna_sequencer.c b/source/blender/makesrna/intern/rna_sequencer.c index 217321b4991..01b083dc3c8 100644 --- a/source/blender/makesrna/intern/rna_sequencer.c +++ b/source/blender/makesrna/intern/rna_sequencer.c @@ -927,9 +927,10 @@ static void rna_Sequence_filepath_update(Main *bmain, Scene *UNUSED(scene), Poin rna_Sequence_invalidate_raw_update(bmain, scene, ptr); } -static void rna_Sequence_sound_update(Main *UNUSED(bmain), Scene *scene, PointerRNA *UNUSED(ptr)) +static void rna_Sequence_sound_update(Main *bmain, Scene *scene, PointerRNA *UNUSED(ptr)) { DEG_id_tag_update(&scene->id, ID_RECALC_SEQUENCER_STRIPS | ID_RECALC_AUDIO); + DEG_relations_tag_update(bmain); } static int seqproxy_seq_cmp_fn(Sequence *seq, void *arg_pt) From 981380cf6d086517cc1b5dfc60e9bde6253e5bd7 Mon Sep 17 00:00:00 2001 From: Richard Antalik Date: Tue, 26 Jan 2021 17:33:03 +0100 Subject: [PATCH 43/55] VSE: Fix memory leak when building proxies With no valid strips selected, file_list is not freed. Reviewed By: sergey Differential Revision: https://developer.blender.org/D10191 --- source/blender/editors/space_sequencer/sequencer_proxy.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source/blender/editors/space_sequencer/sequencer_proxy.c b/source/blender/editors/space_sequencer/sequencer_proxy.c index b208f320591..b9698492aa5 100644 --- a/source/blender/editors/space_sequencer/sequencer_proxy.c +++ b/source/blender/editors/space_sequencer/sequencer_proxy.c @@ -168,13 +168,13 @@ static void seq_proxy_build_job(const bContext *C, ReportList *reports) } SEQ_CURRENT_END; + BLI_gset_free(file_list, MEM_freeN); + if (!selected) { BKE_reportf(reports, RPT_WARNING, "Select movie or image strips"); return; } - BLI_gset_free(file_list, MEM_freeN); - if (selected && !WM_jobs_is_running(wm_job)) { G.is_break = false; WM_jobs_start(CTX_wm_manager(C), wm_job); From 41979fc03b93ba8d55002311569536bf8c9ee983 Mon Sep 17 00:00:00 2001 From: Richard Antalik Date: Tue, 26 Jan 2021 17:40:35 +0100 Subject: [PATCH 44/55] Fix T84160: Wrong DOF when camera is overriden Workbench engine used active camera to setup DOF effect even when camera was overridden. Store camera override in `WORKBENCH_PrivateData` and use it in `workbench_dof_engine_init()` Reviewed By: brecht Differential Revision: https://developer.blender.org/D9952 --- source/blender/draw/engines/workbench/workbench_data.c | 9 +++++++++ .../draw/engines/workbench/workbench_effect_dof.c | 4 ++-- source/blender/draw/engines/workbench/workbench_engine.c | 7 +------ .../blender/draw/engines/workbench/workbench_private.h | 5 +++++ source/blender/draw/engines/workbench/workbench_render.c | 2 ++ 5 files changed, 19 insertions(+), 8 deletions(-) diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c index c566b35cd34..4f689fd55a5 100644 --- a/source/blender/draw/engines/workbench/workbench_data.c +++ b/source/blender/draw/engines/workbench/workbench_data.c @@ -137,6 +137,15 @@ static void workbench_studiolight_data_update(WORKBENCH_PrivateData *wpd, WORKBE wd->use_specular = workbench_is_specular_highlight_enabled(wpd); } +void workbench_private_data_alloc(WORKBENCH_StorageList *stl) +{ + if (!stl->wpd) { + stl->wpd = MEM_callocN(sizeof(*stl->wpd), __func__); + stl->wpd->taa_sample_len_previous = -1; + stl->wpd->view_updated = true; + } +} + void workbench_private_data_init(WORKBENCH_PrivateData *wpd) { const DRWContextState *draw_ctx = DRW_context_state_get(); diff --git a/source/blender/draw/engines/workbench/workbench_effect_dof.c b/source/blender/draw/engines/workbench/workbench_effect_dof.c index fcee8c270dd..73cd501190f 100644 --- a/source/blender/draw/engines/workbench/workbench_effect_dof.c +++ b/source/blender/draw/engines/workbench/workbench_effect_dof.c @@ -133,14 +133,14 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata) const DRWContextState *draw_ctx = DRW_context_state_get(); RegionView3D *rv3d = draw_ctx->rv3d; View3D *v3d = draw_ctx->v3d; - Scene *scene = draw_ctx->scene; + Object *camera; if (v3d && rv3d) { camera = (rv3d->persp == RV3D_CAMOB) ? v3d->camera : NULL; } else { - camera = scene->camera; + camera = wpd->cam_original_ob; } Camera *cam = camera != NULL ? camera->data : NULL; diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c index 37dbfe4d2a6..bd5b61b26e9 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.c +++ b/source/blender/draw/engines/workbench/workbench_engine.c @@ -53,12 +53,7 @@ void workbench_engine_init(void *ved) workbench_shader_library_ensure(); - if (!stl->wpd) { - stl->wpd = MEM_callocN(sizeof(*stl->wpd), __func__); - stl->wpd->taa_sample_len_previous = -1; - stl->wpd->view_updated = true; - } - + workbench_private_data_alloc(stl); WORKBENCH_PrivateData *wpd = stl->wpd; workbench_private_data_init(wpd); workbench_update_world_ubo(wpd); diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h index f3ff0616668..d157c260fbd 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -70,6 +70,7 @@ extern struct DrawEngineType draw_engine_workbench; #define OBJECT_ID_PASS_ENABLED(wpd) (OBJECT_OUTLINE_ENABLED(wpd) || CURVATURE_ENABLED(wpd)) #define NORMAL_ENCODING_ENABLED() (true) +struct Object; struct RenderEngine; struct RenderLayer; struct rcti; @@ -351,6 +352,9 @@ typedef struct WORKBENCH_PrivateData { float dof_rotation; float dof_ratio; + /* Camera override for rendering. */ + struct Object *cam_original_ob; + /** True if any volume needs to be rendered. */ bool volumes_do; /** Convenience boolean. */ @@ -504,6 +508,7 @@ DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd, workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, interp, WORKBENCH_DATATYPE_HAIR) /* workbench_data.c */ +void workbench_private_data_alloc(WORKBENCH_StorageList *stl); void workbench_private_data_init(WORKBENCH_PrivateData *wpd); void workbench_update_world_ubo(WORKBENCH_PrivateData *wpd); void workbench_update_material_ubos(WORKBENCH_PrivateData *wpd); diff --git a/source/blender/draw/engines/workbench/workbench_render.c b/source/blender/draw/engines/workbench/workbench_render.c index 2c3b5a5f935..cec372ba732 100644 --- a/source/blender/draw/engines/workbench/workbench_render.c +++ b/source/blender/draw/engines/workbench/workbench_render.c @@ -175,6 +175,8 @@ void workbench_render(void *ved, RenderEngine *engine, RenderLayer *render_layer return; } + workbench_private_data_alloc(data->stl); + data->stl->wpd->cam_original_ob = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re)); workbench_engine_init(data); workbench_cache_init(data); From c9672084601e1563763ccc5b89d3c0c6bfd1c630 Mon Sep 17 00:00:00 2001 From: Richard Antalik Date: Tue, 26 Jan 2021 17:41:49 +0100 Subject: [PATCH 45/55] Fix T79922: Cache of meta strip not invalidated Meta strip cache is not invalidated if strip inside of meta strip is invalidated. Find all metastrips that contain invalidated strip and invalidate them recursively. Reviewed By: sergey Differential Revision: https://developer.blender.org/D10192 --- .../sequencer/intern/strip_relations.c | 35 +++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/source/blender/sequencer/intern/strip_relations.c b/source/blender/sequencer/intern/strip_relations.c index 18ae21e3a65..1a2ff08bd08 100644 --- a/source/blender/sequencer/intern/strip_relations.c +++ b/source/blender/sequencer/intern/strip_relations.c @@ -127,17 +127,49 @@ static void sequence_invalidate_cache(Scene *scene, SEQ_prefetch_stop(scene); } +/* Find metastrips that contain invalidated_seq and invalidate them. */ +static bool seq_relations_find_and_invalidate_metas(Scene *scene, + Sequence *invalidated_seq, + Sequence *meta_seq) +{ + ListBase *seqbase; + + if (meta_seq == NULL) { + Editing *ed = SEQ_editing_get(scene, false); + seqbase = &ed->seqbase; + } + else { + seqbase = &meta_seq->seqbase; + } + + LISTBASE_FOREACH (Sequence *, seq, seqbase) { + if (seq->type == SEQ_TYPE_META) { + if (seq_relations_find_and_invalidate_metas(scene, invalidated_seq, seq)) { + sequence_invalidate_cache(scene, seq, true, SEQ_CACHE_ALL_TYPES); + return true; + } + } + if (seq == invalidated_seq && meta_seq != NULL) { + sequence_invalidate_cache(scene, meta_seq, true, SEQ_CACHE_ALL_TYPES); + return true; + } + } + return false; +} + void SEQ_relations_invalidate_cache_in_range(Scene *scene, Sequence *seq, Sequence *range_mask, int invalidate_types) { seq_cache_cleanup_sequence(scene, seq, range_mask, invalidate_types, true); + seq_relations_find_and_invalidate_metas(scene, seq, NULL); } void SEQ_relations_invalidate_cache_raw(Scene *scene, Sequence *seq) { sequence_invalidate_cache(scene, seq, true, SEQ_CACHE_ALL_TYPES); + seq_relations_find_and_invalidate_metas(scene, seq, NULL); } void SEQ_relations_invalidate_cache_preprocessed(Scene *scene, Sequence *seq) @@ -147,6 +179,7 @@ void SEQ_relations_invalidate_cache_preprocessed(Scene *scene, Sequence *seq) true, SEQ_CACHE_STORE_PREPROCESSED | SEQ_CACHE_STORE_COMPOSITE | SEQ_CACHE_STORE_FINAL_OUT); + seq_relations_find_and_invalidate_metas(scene, seq, NULL); } void SEQ_relations_invalidate_cache_composite(Scene *scene, Sequence *seq) @@ -157,6 +190,7 @@ void SEQ_relations_invalidate_cache_composite(Scene *scene, Sequence *seq) sequence_invalidate_cache( scene, seq, true, SEQ_CACHE_STORE_COMPOSITE | SEQ_CACHE_STORE_FINAL_OUT); + seq_relations_find_and_invalidate_metas(scene, seq, NULL); } void SEQ_relations_invalidate_dependent(Scene *scene, Sequence *seq) @@ -167,6 +201,7 @@ void SEQ_relations_invalidate_dependent(Scene *scene, Sequence *seq) sequence_invalidate_cache( scene, seq, false, SEQ_CACHE_STORE_COMPOSITE | SEQ_CACHE_STORE_FINAL_OUT); + seq_relations_find_and_invalidate_metas(scene, seq, NULL); } static void invalidate_scene_strips(Scene *scene, Scene *scene_target, ListBase *seqbase) From 6d40d7218971b558074eb418afd244ab13ab8fbf Mon Sep 17 00:00:00 2001 From: Richard Antalik Date: Tue, 26 Jan 2021 17:46:34 +0100 Subject: [PATCH 46/55] Fix T84847: Crash after splitting effect strip `seq->tmp` was left in invalid state after `SEQ_sequence_base_dupli_recursive()` which is run by `scene_copy_data()` Ensure all strips have `seq->tmp` set to `NULL` before splitting strips. --- source/blender/editors/space_sequencer/sequencer_edit.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index f470d1913dc..7474f8034de 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -1395,6 +1395,10 @@ static int sequencer_split_exec(bContext *C, wmOperator *op) SEQ_prefetch_stop(scene); + LISTBASE_FOREACH (Sequence *, seq, ed->seqbasep) { + seq->tmp = NULL; + } + LISTBASE_FOREACH_BACKWARD (Sequence *, seq, ed->seqbasep) { if (use_cursor_position && seq->machine != split_channel) { continue; From abd6b1d7b281c85fce748e0535f1f769916cd9b3 Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Tue, 26 Jan 2021 18:21:12 +0100 Subject: [PATCH 47/55] Fix T85049: Geometry Nodes: How to handle instances with shear? Use transform matrices instead of loc, rot, scale variables to store instance transforms. Reviewed By: JacquesLucke Differential Revision: http://developer.blender.org/D10211 --- source/blender/blenkernel/BKE_geometry_set.h | 4 +- source/blender/blenkernel/BKE_geometry_set.hh | 31 ++------ .../blender/blenkernel/intern/geometry_set.cc | 77 ++++--------------- .../blender/blenkernel/intern/object_dupli.c | 26 ++----- source/blender/blenlib/BLI_float4x4.hh | 11 +++ .../geometry/nodes/node_geo_join_geometry.cc | 6 +- .../geometry/nodes/node_geo_point_instance.cc | 4 +- .../geometry/nodes/node_geo_transform.cc | 17 ++-- 8 files changed, 52 insertions(+), 124 deletions(-) diff --git a/source/blender/blenkernel/BKE_geometry_set.h b/source/blender/blenkernel/BKE_geometry_set.h index 5b8273def66..27ac6d98688 100644 --- a/source/blender/blenkernel/BKE_geometry_set.h +++ b/source/blender/blenkernel/BKE_geometry_set.h @@ -46,9 +46,7 @@ typedef struct InstancedData { } InstancedData; int BKE_geometry_set_instances(const struct GeometrySet *geometry_set, - float (**r_positions)[3], - float (**r_rotations)[3], - float (**r_scales)[3], + float (**r_transforms)[4][4], int **r_ids, struct InstancedData **r_instanced_data); diff --git a/source/blender/blenkernel/BKE_geometry_set.hh b/source/blender/blenkernel/BKE_geometry_set.hh index ad5a5d57045..3b093ae730a 100644 --- a/source/blender/blenkernel/BKE_geometry_set.hh +++ b/source/blender/blenkernel/BKE_geometry_set.hh @@ -24,6 +24,7 @@ #include #include "BLI_float3.hh" +#include "BLI_float4x4.hh" #include "BLI_hash.hh" #include "BLI_map.hh" #include "BLI_set.hh" @@ -422,9 +423,7 @@ class PointCloudComponent : public GeometryComponent { /** A geometry component that stores instances. */ class InstancesComponent : public GeometryComponent { private: - blender::Vector positions_; - blender::Vector rotations_; - blender::Vector scales_; + blender::Vector transforms_; blender::Vector ids_; blender::Vector instanced_data_; @@ -434,30 +433,14 @@ class InstancesComponent : public GeometryComponent { GeometryComponent *copy() const override; void clear(); - void add_instance(Object *object, - blender::float3 position, - blender::float3 rotation = {0, 0, 0}, - blender::float3 scale = {1, 1, 1}, - const int id = -1); - void add_instance(Collection *collection, - blender::float3 position, - blender::float3 rotation = {0, 0, 0}, - blender::float3 scale = {1, 1, 1}, - const int id = -1); - void add_instance(InstancedData data, - blender::float3 position, - blender::float3 rotation, - blender::float3 scale, - const int id = -1); + void add_instance(Object *object, blender::float4x4 transform, const int id = -1); + void add_instance(Collection *collection, blender::float4x4 transform, const int id = -1); + void add_instance(InstancedData data, blender::float4x4 transform, const int id = -1); blender::Span instanced_data() const; - blender::Span positions() const; - blender::Span rotations() const; - blender::Span scales() const; + blender::Span transforms() const; blender::Span ids() const; - blender::MutableSpan positions(); - blender::MutableSpan rotations(); - blender::MutableSpan scales(); + blender::MutableSpan transforms(); int instances_amount() const; bool is_empty() const final; diff --git a/source/blender/blenkernel/intern/geometry_set.cc b/source/blender/blenkernel/intern/geometry_set.cc index 81958b81213..bb315bc0289 100644 --- a/source/blender/blenkernel/intern/geometry_set.cc +++ b/source/blender/blenkernel/intern/geometry_set.cc @@ -25,6 +25,7 @@ #include "MEM_guardedalloc.h" using blender::float3; +using blender::float4x4; using blender::MutableSpan; using blender::Span; using blender::StringRef; @@ -458,9 +459,7 @@ InstancesComponent::InstancesComponent() : GeometryComponent(GeometryComponentTy GeometryComponent *InstancesComponent::copy() const { InstancesComponent *new_component = new InstancesComponent(); - new_component->positions_ = positions_; - new_component->rotations_ = rotations_; - new_component->scales_ = scales_; + new_component->transforms_ = transforms_; new_component->instanced_data_ = instanced_data_; return new_component; } @@ -468,45 +467,29 @@ GeometryComponent *InstancesComponent::copy() const void InstancesComponent::clear() { instanced_data_.clear(); - positions_.clear(); - rotations_.clear(); - scales_.clear(); + transforms_.clear(); } -void InstancesComponent::add_instance(Object *object, - blender::float3 position, - blender::float3 rotation, - blender::float3 scale, - const int id) +void InstancesComponent::add_instance(Object *object, float4x4 transform, const int id) { InstancedData data; data.type = INSTANCE_DATA_TYPE_OBJECT; data.data.object = object; - this->add_instance(data, position, rotation, scale, id); + this->add_instance(data, transform, id); } -void InstancesComponent::add_instance(Collection *collection, - blender::float3 position, - blender::float3 rotation, - blender::float3 scale, - const int id) +void InstancesComponent::add_instance(Collection *collection, float4x4 transform, const int id) { InstancedData data; data.type = INSTANCE_DATA_TYPE_COLLECTION; data.data.collection = collection; - this->add_instance(data, position, rotation, scale, id); + this->add_instance(data, transform, id); } -void InstancesComponent::add_instance(InstancedData data, - blender::float3 position, - blender::float3 rotation, - blender::float3 scale, - const int id) +void InstancesComponent::add_instance(InstancedData data, float4x4 transform, const int id) { instanced_data_.append(data); - positions_.append(position); - rotations_.append(rotation); - scales_.append(scale); + transforms_.append(transform); ids_.append(id); } @@ -515,19 +498,9 @@ Span InstancesComponent::instanced_data() const return instanced_data_; } -Span InstancesComponent::positions() const +Span InstancesComponent::transforms() const { - return positions_; -} - -Span InstancesComponent::rotations() const -{ - return rotations_; -} - -Span InstancesComponent::scales() const -{ - return scales_; + return transforms_; } Span InstancesComponent::ids() const @@ -535,33 +508,21 @@ Span InstancesComponent::ids() const return ids_; } -MutableSpan InstancesComponent::positions() +MutableSpan InstancesComponent::transforms() { - return positions_; -} - -MutableSpan InstancesComponent::rotations() -{ - return rotations_; -} - -MutableSpan InstancesComponent::scales() -{ - return scales_; + return transforms_; } int InstancesComponent::instances_amount() const { const int size = instanced_data_.size(); - BLI_assert(positions_.size() == size); - BLI_assert(rotations_.size() == size); - BLI_assert(scales_.size() == size); + BLI_assert(transforms_.size() == size); return size; } bool InstancesComponent::is_empty() const { - return positions_.size() == 0; + return transforms_.size() == 0; } /** \} */ @@ -581,9 +542,7 @@ bool BKE_geometry_set_has_instances(const GeometrySet *geometry_set) } int BKE_geometry_set_instances(const GeometrySet *geometry_set, - float (**r_positions)[3], - float (**r_rotations)[3], - float (**r_scales)[3], + float (**r_transforms)[4][4], int **r_ids, InstancedData **r_instanced_data) { @@ -591,9 +550,7 @@ int BKE_geometry_set_instances(const GeometrySet *geometry_set, if (component == nullptr) { return 0; } - *r_positions = (float(*)[3])component->positions().data(); - *r_rotations = (float(*)[3])component->rotations().data(); - *r_scales = (float(*)[3])component->scales().data(); + *r_transforms = (float(*)[4][4])component->transforms().data(); *r_ids = (int *)component->ids().data(); *r_instanced_data = (InstancedData *)component->instanced_data().data(); *r_instanced_data = (InstancedData *)component->instanced_data().data(); diff --git a/source/blender/blenkernel/intern/object_dupli.c b/source/blender/blenkernel/intern/object_dupli.c index d5317864480..6c8a57f8599 100644 --- a/source/blender/blenkernel/intern/object_dupli.c +++ b/source/blender/blenkernel/intern/object_dupli.c @@ -813,40 +813,26 @@ static const DupliGenerator gen_dupli_verts_pointcloud = { static void make_duplis_instances_component(const DupliContext *ctx) { - float(*positions)[3]; - float(*rotations)[3]; - float(*scales)[3]; + float(*instance_offset_matrices)[4][4]; int *ids; InstancedData *instanced_data; - const int amount = BKE_geometry_set_instances(ctx->object->runtime.geometry_set_eval, - &positions, - &rotations, - &scales, - &ids, - &instanced_data); + const int amount = BKE_geometry_set_instances( + ctx->object->runtime.geometry_set_eval, &instance_offset_matrices, &ids, &instanced_data); for (int i = 0; i < amount; i++) { InstancedData *data = &instanced_data[i]; - float scale_matrix[4][4]; - size_to_mat4(scale_matrix, scales[i]); - float rotation_matrix[4][4]; - eul_to_mat4(rotation_matrix, rotations[i]); - float instance_offset_matrix[4][4]; - mul_m4_m4m4(instance_offset_matrix, rotation_matrix, scale_matrix); - copy_v3_v3(instance_offset_matrix[3], positions[i]); - const int id = ids[i] != -1 ? ids[i] : i; if (data->type == INSTANCE_DATA_TYPE_OBJECT) { Object *object = data->data.object; if (object != NULL) { float matrix[4][4]; - mul_m4_m4m4(matrix, ctx->object->obmat, instance_offset_matrix); + mul_m4_m4m4(matrix, ctx->object->obmat, instance_offset_matrices[i]); make_dupli(ctx, object, matrix, id); float space_matrix[4][4]; - mul_m4_m4m4(space_matrix, instance_offset_matrix, object->imat); + mul_m4_m4m4(space_matrix, instance_offset_matrices[i], object->imat); mul_m4_m4_pre(space_matrix, ctx->object->obmat); make_recursive_duplis(ctx, object, space_matrix, id); } @@ -857,7 +843,7 @@ static void make_duplis_instances_component(const DupliContext *ctx) float collection_matrix[4][4]; unit_m4(collection_matrix); sub_v3_v3(collection_matrix[3], collection->instance_offset); - mul_m4_m4_pre(collection_matrix, instance_offset_matrix); + mul_m4_m4_pre(collection_matrix, instance_offset_matrices[i]); mul_m4_m4_pre(collection_matrix, ctx->object->obmat); eEvaluationMode mode = DEG_get_mode(ctx->depsgraph); diff --git a/source/blender/blenlib/BLI_float4x4.hh b/source/blender/blenlib/BLI_float4x4.hh index 0433197b22a..d6d759ccfe4 100644 --- a/source/blender/blenlib/BLI_float4x4.hh +++ b/source/blender/blenlib/BLI_float4x4.hh @@ -45,6 +45,17 @@ struct float4x4 { return &values[0][0]; } + using c_style_float4x4 = float[4][4]; + c_style_float4x4 &ptr() + { + return values; + } + + const c_style_float4x4 &ptr() const + { + return values; + } + friend float4x4 operator*(const float4x4 &a, const float4x4 &b) { float4x4 result; diff --git a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc index e00ee9b01d8..67bc095fa31 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_join_geometry.cc @@ -233,11 +233,9 @@ static void join_components(Span src_components, Geo for (const InstancesComponent *component : src_components) { const int size = component->instances_amount(); Span instanced_data = component->instanced_data(); - Span positions = component->positions(); - Span rotations = component->rotations(); - Span scales = component->scales(); + Span transforms = component->transforms(); for (const int i : IndexRange(size)) { - dst_component.add_instance(instanced_data[i], positions[i], rotations[i], scales[i]); + dst_component.add_instance(instanced_data[i], transforms[i]); } } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc index d9e69adb860..a96dc710427 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_point_instance.cc @@ -165,7 +165,9 @@ static void add_instances_from_geometry_component(InstancesComponent &instances, for (const int i : IndexRange(domain_size)) { if (instances_data[i].has_value()) { - instances.add_instance(*instances_data[i], positions[i], rotations[i], scales[i], ids[i]); + float transform[4][4]; + loc_eul_size_to_mat4(transform, positions[i], rotations[i], scales[i]); + instances.add_instance(*instances_data[i], transform, ids[i]); } } } diff --git a/source/blender/nodes/geometry/nodes/node_geo_transform.cc b/source/blender/nodes/geometry/nodes/node_geo_transform.cc index 84540c283ef..1fcd1063993 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_transform.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_transform.cc @@ -91,27 +91,20 @@ static void transform_instances(InstancesComponent &instances, const float3 rotation, const float3 scale) { - MutableSpan positions = instances.positions(); - MutableSpan rotations = instances.rotations(); - MutableSpan scales = instances.scales(); + MutableSpan transforms = instances.transforms(); /* Use only translation if rotation and scale don't apply. */ if (use_translate(rotation, scale)) { - for (float3 &position : positions) { - add_v3_v3(position, translation); + for (float4x4 &transform : transforms) { + add_v3_v3(transform.ptr()[3], translation); } } else { float mat[4][4]; - float instance_mat[4][4]; - float quaternion[4]; loc_eul_size_to_mat4(mat, translation, rotation, scale); - for (int i = 0; i < positions.size(); i++) { - loc_eul_size_to_mat4(instance_mat, positions[i], rotations[i], scales[i]); - mul_m4_m4_pre(instance_mat, mat); - mat4_decompose(positions[i], quaternion, scales[i], instance_mat); - quat_to_eul(rotations[i], quaternion); + for (float4x4 &transform : transforms) { + mul_m4_m4_pre(transform.ptr(), mat); } } } From 6157c45445dceb0bceabb5b9ea80cd6eb60e04fc Mon Sep 17 00:00:00 2001 From: Sebastian Parborg Date: Tue, 26 Jan 2021 18:25:16 +0100 Subject: [PATCH 48/55] Fix T85049: Geometry Nodes: How to handle instances with shear? (part2) Update to changes in master. Reviewed By: JacquesLucke Differential Revision: http://developer.blender.org/D10211 --- source/blender/nodes/geometry/nodes/node_geo_object_info.cc | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc index fe0303a5f1c..d713c191d5d 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_object_info.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_object_info.cc @@ -91,10 +91,12 @@ static void geo_node_object_info_exec(GeoNodeExecParams params) InstancesComponent &instances = geometry_set.get_component_for_write(); if (transform_space_relative) { - instances.add_instance(object, location, rotation, scale); + instances.add_instance(object, transform); } else { - instances.add_instance(object, {0, 0, 0}); + float unit_transform[4][4]; + unit_m4(unit_transform); + instances.add_instance(object, unit_transform); } } } From ef28da262342447bd3a666f5069d6012d71e1781 Mon Sep 17 00:00:00 2001 From: Falk David Date: Tue, 26 Jan 2021 18:04:52 +0100 Subject: [PATCH 49/55] Fix T85082: Perspective distortion while drawing When the drawing plane was set to view and the user would pan their camera sideways, the drawing would be more and more distorted and projected further back. The fix projects the strokes to view when the user is looking through the camera or has the drawing plane set to view. Reviewed By: antoniov Maniphest Tasks: T85082 Differential Revision: https://developer.blender.org/D10213 --- source/blender/editors/gpencil/gpencil_fill.c | 4 ++-- source/blender/editors/gpencil/gpencil_paint.c | 8 ++++---- source/blender/editors/gpencil/gpencil_primitive.c | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index 84447059884..b8af8552a0d 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -1284,8 +1284,8 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) gpencil_apply_parent_point(tgpf->depsgraph, tgpf->ob, tgpf->gpl, pt); } - /* if camera view, reproject flat to view to avoid perspective effect */ - if (is_camera) { + /* If camera view or view projection, reproject flat to view to avoid perspective effect. */ + if ((*p->align_flag & GP_PROJECT_VIEWSPACE) || is_camera) { ED_gpencil_project_stroke_to_view(tgpf->C, tgpf->gpl, gps); } diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 7571f7cded8..b55e47d74f3 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -1086,8 +1086,8 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p) gpencil_apply_parent_point(depsgraph, obact, gpl, pt); } - /* if camera view, reproject flat to view to avoid perspective effect */ - if (is_camera) { + /* If camera view or view projection, reproject flat to view to avoid perspective effect. */ + if ((*p->align_flag & GP_PROJECT_VIEWSPACE) || is_camera) { ED_gpencil_project_stroke_to_view(p->C, p->gpl, gps); } } @@ -1235,8 +1235,8 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p) gpencil_reproject_toplane(p, gps); /* change position relative to parent object */ gpencil_apply_parent(depsgraph, obact, gpl, gps); - /* if camera view, reproject flat to view to avoid perspective effect */ - if (is_camera) { + /* If camera view or view projection, reproject flat to view to avoid perspective effect. */ + if ((*p->align_flag & GP_PROJECT_VIEWSPACE) || is_camera) { ED_gpencil_project_stroke_to_view(p->C, p->gpl, gps); } diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index ef86b19cc66..363d5d7ec17 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -1081,8 +1081,8 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) gpencil_apply_parent_point(tgpi->depsgraph, tgpi->ob, tgpi->gpl, pt); } - /* if camera view, reproject flat to view to avoid perspective effect */ - if (is_camera) { + /* If camera view or view projection, reproject flat to view to avoid perspective effect. */ + if ((*p->align_flag & GP_PROJECT_VIEWSPACE) || is_camera) { ED_gpencil_project_stroke_to_view(C, tgpi->gpl, gps); } From 23e108c5b608e58ae46f11a0f2badde6710b7495 Mon Sep 17 00:00:00 2001 From: Falk David Date: Tue, 26 Jan 2021 18:04:52 +0100 Subject: [PATCH 50/55] Fix T85082: Perspective distortion while drawing When the drawing plane was set to view and the user would pan their camera sideways, the drawing would be more and more distorted and projected further back. The fix projects the strokes to view when the user is looking through the camera or has the drawing plane set to view. Reviewed By: antoniov Maniphest Tasks: T85082 Differential Revision: https://developer.blender.org/D10213 --- source/blender/editors/gpencil/gpencil_fill.c | 4 ++-- source/blender/editors/gpencil/gpencil_paint.c | 8 ++++---- source/blender/editors/gpencil/gpencil_primitive.c | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index 622556943c9..d3616909415 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -1283,8 +1283,8 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) gpencil_apply_parent_point(tgpf->depsgraph, tgpf->ob, tgpf->gpl, pt); } - /* if camera view, reproject flat to view to avoid perspective effect */ - if (is_camera) { + /* If camera view or view projection, reproject flat to view to avoid perspective effect. */ + if ((*p->align_flag & GP_PROJECT_VIEWSPACE) || is_camera) { ED_gpencil_project_stroke_to_view(tgpf->C, tgpf->gpl, gps); } diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 14313a50118..fcdada1e673 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -1084,8 +1084,8 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p) gpencil_apply_parent_point(depsgraph, obact, gpl, pt); } - /* if camera view, reproject flat to view to avoid perspective effect */ - if (is_camera) { + /* If camera view or view projection, reproject flat to view to avoid perspective effect. */ + if ((*p->align_flag & GP_PROJECT_VIEWSPACE) || is_camera) { ED_gpencil_project_stroke_to_view(p->C, p->gpl, gps); } } @@ -1233,8 +1233,8 @@ static void gpencil_stroke_newfrombuffer(tGPsdata *p) gpencil_reproject_toplane(p, gps); /* change position relative to parent object */ gpencil_apply_parent(depsgraph, obact, gpl, gps); - /* if camera view, reproject flat to view to avoid perspective effect */ - if (is_camera) { + /* If camera view or view projection, reproject flat to view to avoid perspective effect. */ + if ((*p->align_flag & GP_PROJECT_VIEWSPACE) || is_camera) { ED_gpencil_project_stroke_to_view(p->C, p->gpl, gps); } diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index 33497429331..cf2f8d51d74 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -1077,8 +1077,8 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) gpencil_apply_parent_point(tgpi->depsgraph, tgpi->ob, tgpi->gpl, pt); } - /* if camera view, reproject flat to view to avoid perspective effect */ - if (is_camera) { + /* If camera view or view projection, reproject flat to view to avoid perspective effect. */ + if ((*p->align_flag & GP_PROJECT_VIEWSPACE) || is_camera) { ED_gpencil_project_stroke_to_view(C, tgpi->gpl, gps); } From a6016bf5af95ab9f7a7b75a0d129555be12d3f8b Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 26 Jan 2021 11:55:36 -0600 Subject: [PATCH 51/55] UI: Fix ugly alignment of timeline popover buttons Apparently things have changed since {rB98d205508977a6f72bf55}, and putting the buttons in two separate rows is no longer enough to keep the right-most popover button in the timeline header from aligning with the menu buttons. This just adds a separator large enough to avoid the alignment. --- release/scripts/startup/bl_ui/space_time.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/release/scripts/startup/bl_ui/space_time.py b/release/scripts/startup/bl_ui/space_time.py index 3b9ce5311f3..774e2938deb 100644 --- a/release/scripts/startup/bl_ui/space_time.py +++ b/release/scripts/startup/bl_ui/space_time.py @@ -107,6 +107,9 @@ class TIME_MT_editor_menus(Menu): text="Keying", ) + # Add a separator to keep the popover button from aligning with the menu button. + sub.separator(factor=0.4) + if horizontal: sub = row.row(align=True) From d9a63d40e2dad80cea134d0cdfeda264c94ddb9e Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 26 Jan 2021 12:13:28 -0600 Subject: [PATCH 52/55] Fix build error An extra `p->` was added for some reason in a recent commit. Additionally, there's no reason for the flag to be kept as a pointer, so just dereference it at the start of both functions. --- source/blender/editors/gpencil/gpencil_fill.c | 6 +++--- source/blender/editors/gpencil/gpencil_primitive.c | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/source/blender/editors/gpencil/gpencil_fill.c b/source/blender/editors/gpencil/gpencil_fill.c index d3616909415..3c16a6fb028 100644 --- a/source/blender/editors/gpencil/gpencil_fill.c +++ b/source/blender/editors/gpencil/gpencil_fill.c @@ -1153,8 +1153,8 @@ static int gpencil_points_from_stack(tGPDfill *tgpf) static void gpencil_stroke_from_buffer(tGPDfill *tgpf) { ToolSettings *ts = tgpf->scene->toolsettings; - const char *align_flag = &ts->gpencil_v3d_align; - const bool is_depth = (bool)(*align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)); + const char align_flag = ts->gpencil_v3d_align; + const bool is_depth = (bool)(align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)); const bool is_camera = (bool)(ts->gp_sculpt.lock_axis == 0) && (tgpf->rv3d->persp == RV3D_CAMOB) && (!is_depth); Brush *brush = BKE_paint_brush(&ts->gp_paint->paint); @@ -1284,7 +1284,7 @@ static void gpencil_stroke_from_buffer(tGPDfill *tgpf) } /* If camera view or view projection, reproject flat to view to avoid perspective effect. */ - if ((*p->align_flag & GP_PROJECT_VIEWSPACE) || is_camera) { + if ((align_flag & GP_PROJECT_VIEWSPACE) || is_camera) { ED_gpencil_project_stroke_to_view(tgpf->C, tgpf->gpl, gps); } diff --git a/source/blender/editors/gpencil/gpencil_primitive.c b/source/blender/editors/gpencil/gpencil_primitive.c index cf2f8d51d74..a742d149fce 100644 --- a/source/blender/editors/gpencil/gpencil_primitive.c +++ b/source/blender/editors/gpencil/gpencil_primitive.c @@ -711,8 +711,8 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) bGPDstroke *gps = tgpi->gpf->strokes.first; GP_Sculpt_Settings *gset = &ts->gp_sculpt; int depth_margin = (ts->gpencil_v3d_align & GP_PROJECT_DEPTH_STROKE) ? 4 : 0; - const char *align_flag = &ts->gpencil_v3d_align; - bool is_depth = (bool)(*align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)); + const char align_flag = ts->gpencil_v3d_align; + bool is_depth = (bool)(align_flag & (GP_PROJECT_DEPTH_VIEW | GP_PROJECT_DEPTH_STROKE)); const bool is_camera = (bool)(ts->gp_sculpt.lock_axis == 0) && (tgpi->rv3d->persp == RV3D_CAMOB) && (!is_depth); @@ -1078,7 +1078,7 @@ static void gpencil_primitive_update_strokes(bContext *C, tGPDprimitive *tgpi) } /* If camera view or view projection, reproject flat to view to avoid perspective effect. */ - if ((*p->align_flag & GP_PROJECT_VIEWSPACE) || is_camera) { + if ((align_flag & GP_PROJECT_VIEWSPACE) || is_camera) { ED_gpencil_project_stroke_to_view(C, tgpi->gpl, gps); } From de3f369b30e5d08415b8cff14e462ec6d18689ea Mon Sep 17 00:00:00 2001 From: Harley Acheson Date: Tue, 26 Jan 2021 10:17:37 -0800 Subject: [PATCH 53/55] UI: Use Ellipsis for Short Truncated Text Allow use of ellipsis to indicate truncated text down to a single character. Differential Revision: https://developer.blender.org/D9483 Reviewed by Hans Goudey --- .../editors/interface/interface_widgets.c | 29 +++++++++---------- 1 file changed, 13 insertions(+), 16 deletions(-) diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 3c720a39003..89720cbf17e 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1533,27 +1533,24 @@ static void ui_text_clip_right_ex(const uiFontStyle *fstyle, { BLI_assert(str[0]); - /* If the trailing ellipsis takes more than 20% of all available width, just cut the string - * (as using the ellipsis would remove even more useful chars, and we cannot show much - * already!). - */ - if (sep_strwidth / okwidth > 0.2f) { - float tmp; - const int l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, okwidth, &tmp); - str[l_end] = '\0'; - if (r_final_len) { - *r_final_len = (size_t)l_end; - } - } - else { - float tmp; - const int l_end = BLF_width_to_strlen( - fstyle->uifont_id, str, max_len, okwidth - sep_strwidth, &tmp); + /* How many BYTES (not characters) of this utf-8 string can fit, along with appended ellipsis. */ + int l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, okwidth - sep_strwidth, NULL); + + if (l_end > 0) { + /* At least one character, so clip and add the ellipsis. */ memcpy(str + l_end, sep, sep_len + 1); /* +1 for trailing '\0'. */ if (r_final_len) { *r_final_len = (size_t)(l_end) + sep_len; } } + else { + /* Otherwise fit as much as we can without adding an ellipsis. */ + l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, okwidth, NULL); + str[l_end] = '\0'; + if (r_final_len) { + *r_final_len = (size_t)l_end; + } + } } /** From 1c4b0c47dd476c424b750edd4dadf977937fee85 Mon Sep 17 00:00:00 2001 From: Hans Goudey Date: Tue, 26 Jan 2021 12:57:31 -0600 Subject: [PATCH 54/55] Geometry Nodes: Support all operations in the "Attribute Math" node This adds the ability to use all the math operations in the regular utility "Math" node. The code is quite similar to the attribute vector math node, with the simplification that the result is always a float. Differential Revision: https://developer.blender.org/D10199 --- .../blender/blenkernel/BKE_blender_version.h | 2 +- .../blenloader/intern/versioning_290.c | 15 ++ source/blender/editors/space_node/drawnode.c | 69 ++++++- source/blender/makesdna/DNA_node_types.h | 9 +- source/blender/makesrna/intern/rna_nodetree.c | 25 +-- .../geometry/nodes/node_geo_attribute_math.cc | 174 +++++++++++++++--- 6 files changed, 242 insertions(+), 52 deletions(-) diff --git a/source/blender/blenkernel/BKE_blender_version.h b/source/blender/blenkernel/BKE_blender_version.h index 8854949fa11..7c77c6a8f86 100644 --- a/source/blender/blenkernel/BKE_blender_version.h +++ b/source/blender/blenkernel/BKE_blender_version.h @@ -39,7 +39,7 @@ extern "C" { /* Blender file format version. */ #define BLENDER_FILE_VERSION BLENDER_VERSION -#define BLENDER_FILE_SUBVERSION 3 +#define BLENDER_FILE_SUBVERSION 4 /* Minimum Blender version that supports reading file written with the current * version. Older Blender versions will test this and show a warning if the file diff --git a/source/blender/blenloader/intern/versioning_290.c b/source/blender/blenloader/intern/versioning_290.c index d1cbf05c0ba..b389c5ed210 100644 --- a/source/blender/blenloader/intern/versioning_290.c +++ b/source/blender/blenloader/intern/versioning_290.c @@ -1630,6 +1630,21 @@ void blo_do_versions_290(FileData *fd, Library *UNUSED(lib), Main *bmain) FOREACH_NODETREE_END; } + if (!MAIN_VERSION_ATLEAST(bmain, 293, 4)) { + /* Add support for all operations to the "Attribute Math" node. */ + FOREACH_NODETREE_BEGIN (bmain, ntree, id) { + if (ntree->type == NTREE_GEOMETRY) { + LISTBASE_FOREACH (bNode *, node, &ntree->nodes) { + if (node->type == GEO_NODE_ATTRIBUTE_MATH) { + NodeAttributeMath *data = (NodeAttributeMath *)node->storage; + data->input_type_c = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE; + } + } + } + } + FOREACH_NODETREE_END; + } + /** * Versioning code until next subversion bump goes here. * diff --git a/source/blender/editors/space_node/drawnode.c b/source/blender/editors/space_node/drawnode.c index 8f3602c8d50..7905483fac9 100644 --- a/source/blender/editors/space_node/drawnode.c +++ b/source/blender/editors/space_node/drawnode.c @@ -3166,13 +3166,80 @@ static void node_geometry_buts_random_attribute(uiLayout *layout, uiItemR(layout, ptr, "data_type", DEFAULT_FLAGS, "", ICON_NONE); } +static bool node_attribute_math_operation_use_input_b(const NodeMathOperation operation) +{ + switch (operation) { + case NODE_MATH_ADD: + case NODE_MATH_SUBTRACT: + case NODE_MATH_MULTIPLY: + case NODE_MATH_DIVIDE: + case NODE_MATH_POWER: + case NODE_MATH_LOGARITHM: + case NODE_MATH_MINIMUM: + case NODE_MATH_MAXIMUM: + case NODE_MATH_LESS_THAN: + case NODE_MATH_GREATER_THAN: + case NODE_MATH_MODULO: + case NODE_MATH_ARCTAN2: + case NODE_MATH_SNAP: + case NODE_MATH_WRAP: + case NODE_MATH_COMPARE: + case NODE_MATH_MULTIPLY_ADD: + case NODE_MATH_PINGPONG: + case NODE_MATH_SMOOTH_MIN: + case NODE_MATH_SMOOTH_MAX: + return true; + case NODE_MATH_SINE: + case NODE_MATH_COSINE: + case NODE_MATH_TANGENT: + case NODE_MATH_ARCSINE: + case NODE_MATH_ARCCOSINE: + case NODE_MATH_ARCTANGENT: + case NODE_MATH_ROUND: + case NODE_MATH_ABSOLUTE: + case NODE_MATH_FLOOR: + case NODE_MATH_CEIL: + case NODE_MATH_FRACTION: + case NODE_MATH_SQRT: + case NODE_MATH_INV_SQRT: + case NODE_MATH_SIGN: + case NODE_MATH_EXPONENT: + case NODE_MATH_RADIANS: + case NODE_MATH_DEGREES: + case NODE_MATH_SINH: + case NODE_MATH_COSH: + case NODE_MATH_TANH: + case NODE_MATH_TRUNC: + return false; + } + BLI_assert(false); + return false; +} + static void node_geometry_buts_attribute_math(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr) { + bNode *node = (bNode *)ptr->data; + NodeAttributeMath *node_storage = (NodeAttributeMath *)node->storage; + NodeMathOperation operation = (NodeMathOperation)node_storage->operation; + uiItemR(layout, ptr, "operation", DEFAULT_FLAGS, "", ICON_NONE); uiItemR(layout, ptr, "input_type_a", DEFAULT_FLAGS, IFACE_("Type A"), ICON_NONE); - uiItemR(layout, ptr, "input_type_b", DEFAULT_FLAGS, IFACE_("Type B"), ICON_NONE); + + /* These "use input b / c" checks are copied from the node's code. + * They could be de-duplicated if the drawing code was moved to the node's file. */ + if (node_attribute_math_operation_use_input_b(operation)) { + uiItemR(layout, ptr, "input_type_b", DEFAULT_FLAGS, IFACE_("Type B"), ICON_NONE); + } + if (ELEM(operation, + NODE_MATH_MULTIPLY_ADD, + NODE_MATH_SMOOTH_MIN, + NODE_MATH_SMOOTH_MAX, + NODE_MATH_WRAP, + NODE_MATH_COMPARE)) { + uiItemR(layout, ptr, "input_type_c", DEFAULT_FLAGS, IFACE_("Type C"), ICON_NONE); + } } static void node_geometry_buts_attribute_vector_math(uiLayout *layout, diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index e26a2861f04..0c92099e23b 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1089,14 +1089,15 @@ typedef struct NodeAttributeCompare { } NodeAttributeCompare; typedef struct NodeAttributeMath { - /* e.g. NODE_MATH_ADD. */ + /* NodeMathOperation. */ uint8_t operation; /* GeometryNodeAttributeInputMode */ uint8_t input_type_a; uint8_t input_type_b; + uint8_t input_type_c; - char _pad[5]; + char _pad[4]; } NodeAttributeMath; typedef struct NodeAttributeMix { @@ -1387,7 +1388,7 @@ enum { #define SHD_MATH_CLAMP 1 /* Math node operations. */ -enum { +typedef enum NodeMathOperation { NODE_MATH_ADD = 0, NODE_MATH_SUBTRACT = 1, NODE_MATH_MULTIPLY = 2, @@ -1428,7 +1429,7 @@ enum { NODE_MATH_PINGPONG = 37, NODE_MATH_SMOOTH_MIN = 38, NODE_MATH_SMOOTH_MAX = 39, -}; +} NodeMathOperation; /* Vector Math node operations. */ typedef enum NodeVectorMathOperation { diff --git a/source/blender/makesrna/intern/rna_nodetree.c b/source/blender/makesrna/intern/rna_nodetree.c index db9c774bf9b..90badae2e8e 100644 --- a/source/blender/makesrna/intern/rna_nodetree.c +++ b/source/blender/makesrna/intern/rna_nodetree.c @@ -1980,22 +1980,6 @@ static const EnumPropertyItem *rna_GeometryNodeAttributeFill_domain_itemf( return itemf_function_check(rna_enum_attribute_domain_items, attribute_fill_domain_supported); } -static bool attribute_math_operation_supported(const EnumPropertyItem *item) -{ - return ELEM(item->value, - NODE_MATH_ADD, - NODE_MATH_SUBTRACT, - NODE_MATH_MULTIPLY, - NODE_MATH_DIVIDE) && - (item->identifier[0] != '\0'); -} -static const EnumPropertyItem *rna_GeometryNodeAttributeMath_operation_itemf( - bContext *UNUSED(C), PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) -{ - *r_free = true; - return itemf_function_check(rna_enum_node_math_items, attribute_math_operation_supported); -} - /** * This bit of ugly code makes sure the float / attribute option shows up instead of * vector / attribute if the node uses an operation that uses a float for input B. @@ -8579,10 +8563,9 @@ static void def_geo_attribute_math(StructRNA *srna) prop = RNA_def_property(srna, "operation", PROP_ENUM, PROP_NONE); RNA_def_property_enum_sdna(prop, NULL, "operation"); RNA_def_property_enum_items(prop, rna_enum_node_math_items); - RNA_def_property_enum_funcs(prop, NULL, NULL, "rna_GeometryNodeAttributeMath_operation_itemf"); RNA_def_property_enum_default(prop, NODE_MATH_ADD); RNA_def_property_ui_text(prop, "Operation", ""); - RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); prop = RNA_def_property(srna, "input_type_a", PROP_ENUM, PROP_NONE); RNA_def_property_enum_bitflag_sdna(prop, NULL, "input_type_a"); @@ -8595,6 +8578,12 @@ static void def_geo_attribute_math(StructRNA *srna) RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float); RNA_def_property_ui_text(prop, "Input Type B", ""); RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); + + prop = RNA_def_property(srna, "input_type_c", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_bitflag_sdna(prop, NULL, "input_type_c"); + RNA_def_property_enum_items(prop, rna_node_geometry_attribute_input_type_items_float); + RNA_def_property_ui_text(prop, "Input Type C", ""); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_socket_update"); } static void def_geo_attribute_vector_math(StructRNA *srna) diff --git a/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc b/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc index f8ec9124db3..f3fc45fc1be 100644 --- a/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc +++ b/source/blender/nodes/geometry/nodes/node_geo_attribute_math.cc @@ -34,6 +34,8 @@ static bNodeSocketTemplate geo_node_attribute_math_in[] = { {SOCK_FLOAT, N_("A"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, {SOCK_STRING, N_("B")}, {SOCK_FLOAT, N_("B"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, + {SOCK_STRING, N_("C")}, + {SOCK_FLOAT, N_("C"), 0.0f, 0.0f, 0.0f, 0.0f, -FLT_MAX, FLT_MAX}, {SOCK_STRING, N_("Result")}, {-1, ""}, }; @@ -51,45 +53,132 @@ static void geo_node_attribute_math_init(bNodeTree *UNUSED(tree), bNode *node) data->operation = NODE_MATH_ADD; data->input_type_a = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE; data->input_type_b = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE; + data->input_type_c = GEO_NODE_ATTRIBUTE_INPUT_ATTRIBUTE; node->storage = data; } +static bool operation_use_input_c(const NodeMathOperation operation) +{ + return ELEM(operation, + NODE_MATH_MULTIPLY_ADD, + NODE_MATH_SMOOTH_MIN, + NODE_MATH_SMOOTH_MAX, + NODE_MATH_WRAP, + NODE_MATH_COMPARE); +} + +static bool operation_use_input_b(const NodeMathOperation operation) +{ + switch (operation) { + case NODE_MATH_ADD: + case NODE_MATH_SUBTRACT: + case NODE_MATH_MULTIPLY: + case NODE_MATH_DIVIDE: + case NODE_MATH_POWER: + case NODE_MATH_LOGARITHM: + case NODE_MATH_MINIMUM: + case NODE_MATH_MAXIMUM: + case NODE_MATH_LESS_THAN: + case NODE_MATH_GREATER_THAN: + case NODE_MATH_MODULO: + case NODE_MATH_ARCTAN2: + case NODE_MATH_SNAP: + case NODE_MATH_WRAP: + case NODE_MATH_COMPARE: + case NODE_MATH_MULTIPLY_ADD: + case NODE_MATH_PINGPONG: + case NODE_MATH_SMOOTH_MIN: + case NODE_MATH_SMOOTH_MAX: + return true; + case NODE_MATH_SINE: + case NODE_MATH_COSINE: + case NODE_MATH_TANGENT: + case NODE_MATH_ARCSINE: + case NODE_MATH_ARCCOSINE: + case NODE_MATH_ARCTANGENT: + case NODE_MATH_ROUND: + case NODE_MATH_ABSOLUTE: + case NODE_MATH_FLOOR: + case NODE_MATH_CEIL: + case NODE_MATH_FRACTION: + case NODE_MATH_SQRT: + case NODE_MATH_INV_SQRT: + case NODE_MATH_SIGN: + case NODE_MATH_EXPONENT: + case NODE_MATH_RADIANS: + case NODE_MATH_DEGREES: + case NODE_MATH_SINH: + case NODE_MATH_COSH: + case NODE_MATH_TANH: + case NODE_MATH_TRUNC: + return false; + } + BLI_assert(false); + return false; +} + namespace blender::nodes { static void geo_node_attribute_math_update(bNodeTree *UNUSED(ntree), bNode *node) { - NodeAttributeMath *node_storage = (NodeAttributeMath *)node->storage; + NodeAttributeMath &node_storage = *(NodeAttributeMath *)node->storage; + NodeMathOperation operation = static_cast(node_storage.operation); update_attribute_input_socket_availabilities( - *node, "A", (GeometryNodeAttributeInputMode)node_storage->input_type_a); + *node, "A", (GeometryNodeAttributeInputMode)node_storage.input_type_a); update_attribute_input_socket_availabilities( - *node, "B", (GeometryNodeAttributeInputMode)node_storage->input_type_b); + *node, + "B", + (GeometryNodeAttributeInputMode)node_storage.input_type_b, + operation_use_input_b(operation)); + update_attribute_input_socket_availabilities( + *node, + "C", + (GeometryNodeAttributeInputMode)node_storage.input_type_c, + operation_use_input_c(operation)); } -static void do_math_operation(const FloatReadAttribute &input_a, - const FloatReadAttribute &input_b, - FloatWriteAttribute result, - const int operation) +static void do_math_operation(Span span_a, + Span span_b, + Span span_c, + MutableSpan span_result, + const NodeMathOperation operation) { - const int size = input_a.size(); - - Span span_a = input_a.get_span(); - Span span_b = input_b.get_span(); - MutableSpan span_result = result.get_span_for_write_only(); - - bool success = try_dispatch_float_math_fl_fl_to_fl( + bool success = try_dispatch_float_math_fl_fl_fl_to_fl( operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) { - for (const int i : IndexRange(size)) { - const float in1 = span_a[i]; - const float in2 = span_b[i]; - const float out = math_function(in1, in2); - span_result[i] = out; + for (const int i : IndexRange(span_result.size())) { + span_result[i] = math_function(span_a[i], span_b[i], span_c[i]); } }); + BLI_assert(success); + UNUSED_VARS_NDEBUG(success); +} - result.apply_span(); +static void do_math_operation(Span span_a, + Span span_b, + MutableSpan span_result, + const NodeMathOperation operation) +{ + bool success = try_dispatch_float_math_fl_fl_to_fl( + operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) { + for (const int i : IndexRange(span_result.size())) { + span_result[i] = math_function(span_a[i], span_b[i]); + } + }); + BLI_assert(success); + UNUSED_VARS_NDEBUG(success); +} - /* The operation is not supported by this node currently. */ +static void do_math_operation(Span span_input, + MutableSpan span_result, + const NodeMathOperation operation) +{ + bool success = try_dispatch_float_math_fl_to_fl( + operation, [&](auto math_function, const FloatMathOperationInfo &UNUSED(info)) { + for (const int i : IndexRange(span_result.size())) { + span_result[i] = math_function(span_input[i]); + } + }); BLI_assert(success); UNUSED_VARS_NDEBUG(success); } @@ -98,7 +187,7 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP { const bNode &node = params.node(); const NodeAttributeMath *node_storage = (const NodeAttributeMath *)node.storage; - const int operation = node_storage->operation; + const NodeMathOperation operation = static_cast(node_storage->operation); /* The result type of this node is always float. */ const CustomDataType result_type = CD_PROP_FLOAT; @@ -115,15 +204,44 @@ static void attribute_math_calc(GeometryComponent &component, const GeoNodeExecP ReadAttributePtr attribute_a = params.get_input_attribute( "A", component, result_domain, result_type, nullptr); - ReadAttributePtr attribute_b = params.get_input_attribute( - "B", component, result_domain, result_type, nullptr); - if (!attribute_a || !attribute_b) { - /* Attribute wasn't found. */ + if (!attribute_a) { return; } - do_math_operation(*attribute_a, *attribute_b, *attribute_result, operation); - attribute_result.save(); + /* Note that passing the data with `get_span()` works + * because the attributes were accessed with #CD_PROP_FLOAT. */ + if (operation_use_input_b(operation)) { + ReadAttributePtr attribute_b = params.get_input_attribute( + "B", component, result_domain, result_type, nullptr); + if (!attribute_b) { + return; + } + if (operation_use_input_c(operation)) { + ReadAttributePtr attribute_c = params.get_input_attribute( + "C", component, result_domain, result_type, nullptr); + if (!attribute_c) { + return; + } + do_math_operation(attribute_a->get_span(), + attribute_b->get_span(), + attribute_c->get_span(), + attribute_result->get_span_for_write_only(), + operation); + } + else { + do_math_operation(attribute_a->get_span(), + attribute_b->get_span(), + attribute_result->get_span_for_write_only(), + operation); + } + } + else { + do_math_operation(attribute_a->get_span(), + attribute_result->get_span_for_write_only(), + operation); + } + + attribute_result.apply_span_and_save(); } static void geo_node_attribute_math_exec(GeoNodeExecParams params) From c32c6a5f857675ad4cf3538f1b8a44419272af10 Mon Sep 17 00:00:00 2001 From: Harley Acheson Date: Tue, 26 Jan 2021 11:14:54 -0800 Subject: [PATCH 55/55] UI: Current Frame Marker Cleanup Draw current frame marker in a single pass. Differential Revision: https://developer.blender.org/D10217 Reviewed by Hans Goudey --- .../blender/editors/animation/time_scrub_ui.c | 25 +++++++------------ 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/source/blender/editors/animation/time_scrub_ui.c b/source/blender/editors/animation/time_scrub_ui.c index f5240d67cca..034378399b9 100644 --- a/source/blender/editors/animation/time_scrub_ui.c +++ b/source/blender/editors/animation/time_scrub_ui.c @@ -124,29 +124,22 @@ static void draw_current_frame(const Scene *scene, UI_draw_roundbox_corner_set(UI_CNR_ALL); - UI_draw_roundbox_3fv_alpha( - &(const rctf){ - .xmin = frame_x - box_width / 2 + U.pixelsize / 2, - .xmax = frame_x + box_width / 2 + U.pixelsize / 2, - .ymin = scrub_region_rect->ymin + box_padding, - .ymax = scrub_region_rect->ymax - box_padding, - }, - true, - 4 * UI_DPI_FAC, - bg_color, - 1.0f); + float outline_color[4]; + UI_GetThemeColorShade4fv(TH_CFRAME, 5, outline_color); - UI_GetThemeColorShade4fv(TH_CFRAME, 5, bg_color); - UI_draw_roundbox_aa( + UI_draw_roundbox_4fv_ex( &(const rctf){ .xmin = frame_x - box_width / 2 + U.pixelsize / 2, .xmax = frame_x + box_width / 2 + U.pixelsize / 2, .ymin = scrub_region_rect->ymin + box_padding, .ymax = scrub_region_rect->ymax - box_padding, }, - true, - 4 * UI_DPI_FAC, - bg_color); + bg_color, + NULL, + 1.0f, + outline_color, + U.pixelsize, + 4 * UI_DPI_FAC); uchar text_color[4]; UI_GetThemeColor4ubv(TH_HEADER_TEXT_HI, text_color);