diff options
author | Julian Eisel <eiseljulian@gmail.com> | 2017-12-06 19:42:39 +0300 |
---|---|---|
committer | Julian Eisel <eiseljulian@gmail.com> | 2017-12-06 19:42:39 +0300 |
commit | 9d956c65a64ea6f8b1dec1a1fe11f7c67d7a0709 (patch) | |
tree | a17fa5fff8f22ea969fca67166f3842adf78f205 /source/blender/editors | |
parent | 8f46733e77752edbd958628efd432b38dc1457f2 (diff) | |
parent | 46f518e92790a04885f4e047bb59b11019d73aa3 (diff) |
Merge branch 'blender2.8' into topbar
Diffstat (limited to 'source/blender/editors')
72 files changed, 1429 insertions, 435 deletions
diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index e32324d25f9..b87942fed84 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -807,6 +807,7 @@ enum { SIMEDBONE_PREFIX, SIMEDBONE_SUFFIX, SIMEDBONE_LAYER, + SIMEDBONE_GROUP, SIMEDBONE_SHAPE, }; @@ -819,6 +820,7 @@ static const EnumPropertyItem prop_similar_types[] = { {SIMEDBONE_PREFIX, "PREFIX", 0, "Prefix", ""}, {SIMEDBONE_SUFFIX, "SUFFIX", 0, "Suffix", ""}, {SIMEDBONE_LAYER, "LAYER", 0, "Layer", ""}, + {SIMEDBONE_GROUP, "GROUP", 0, "Group", ""}, {SIMEDBONE_SHAPE, "SHAPE", 0, "Shape", ""}, {0, NULL, 0, NULL, NULL} }; @@ -1009,6 +1011,9 @@ static int armature_select_similar_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } +#define STRUCT_SIZE_AND_OFFSET(_struct, _member) \ + sizeof(((_struct *)NULL)->_member), offsetof(_struct, _member) + switch (type) { case SIMEDBONE_CHILDREN: select_similar_children(arm, ebone_act); @@ -1034,13 +1039,20 @@ static int armature_select_similar_exec(bContext *C, wmOperator *op) case SIMEDBONE_LAYER: select_similar_layer(arm, ebone_act); break; + case SIMEDBONE_GROUP: + select_similar_data_pchan( + arm, obedit, ebone_act, + STRUCT_SIZE_AND_OFFSET(bPoseChannel, agrp_index)); + break; case SIMEDBONE_SHAPE: select_similar_data_pchan( arm, obedit, ebone_act, - sizeof(void *), offsetof(bPoseChannel, custom)); + STRUCT_SIZE_AND_OFFSET(bPoseChannel, custom)); break; } +#undef STRUCT_SIZE_AND_OFFSET + WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, obedit); return OPERATOR_FINISHED; diff --git a/source/blender/editors/armature/editarmature_sketch.c b/source/blender/editors/armature/editarmature_sketch.c index a240d6b190f..4dd8e4bd6fa 100644 --- a/source/blender/editors/armature/editarmature_sketch.c +++ b/source/blender/editors/armature/editarmature_sketch.c @@ -998,7 +998,7 @@ static int sk_getStrokeSnapPoint(bContext *C, SK_Point *pt, SK_Sketch *sketch, S * the ideal would be to call this function only at the beginning of the snap operation, * or at the beginning of the operator itself */ struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d( - CTX_data_main(C), CTX_data_scene(C), CTX_data_view_layer(C), CTX_data_engine(C), 0, + CTX_data_main(C), CTX_data_scene(C), CTX_data_view_layer(C), CTX_data_engine_type(C), 0, CTX_wm_region(C), CTX_wm_view3d(C)); float mvalf[2] = {UNPACK2(dd->mval)}; diff --git a/source/blender/editors/curve/editcurve.c b/source/blender/editors/curve/editcurve.c index e8c784f15d5..79b63f36b76 100644 --- a/source/blender/editors/curve/editcurve.c +++ b/source/blender/editors/curve/editcurve.c @@ -5020,7 +5020,7 @@ static int add_vertex_invoke(bContext *C, wmOperator *op, const wmEvent *event) const float mval[2] = {UNPACK2(event->mval)}; struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d( - CTX_data_main(C), vc.scene, vc.view_layer, vc.engine, 0, + CTX_data_main(C), vc.scene, vc.view_layer, vc.engine_type, 0, vc.ar, vc.v3d); ED_transform_snap_object_project_view3d_mixed( diff --git a/source/blender/editors/gpencil/gpencil_convert.c b/source/blender/editors/gpencil/gpencil_convert.c index 92daa802601..f3b12b9bc85 100644 --- a/source/blender/editors/gpencil/gpencil_convert.c +++ b/source/blender/editors/gpencil/gpencil_convert.c @@ -1156,7 +1156,7 @@ static void gp_layer_to_curve(bContext *C, ReportList *reports, bGPdata *gpd, bG */ ob = BKE_object_add_only_object(bmain, OB_CURVE, gpl->info); cu = ob->data = BKE_curve_add(bmain, gpl->info, OB_CURVE); - BKE_collection_object_add(scene, sc, ob); + BKE_collection_object_add(&scene->id, sc, ob); base_new = BKE_view_layer_base_find(view_layer, ob); cu->flag |= CU_3D; diff --git a/source/blender/editors/include/ED_mesh.h b/source/blender/editors/include/ED_mesh.h index 1c8cf0665b3..1fd7756df77 100644 --- a/source/blender/editors/include/ED_mesh.h +++ b/source/blender/editors/include/ED_mesh.h @@ -76,7 +76,6 @@ struct BMFace *EDBM_verts_mirror_get_face(struct BMEditMesh *em, struct BMFace * void EDBM_verts_mirror_cache_clear(struct BMEditMesh *em, struct BMVert *v); void EDBM_verts_mirror_cache_end(struct BMEditMesh *em); -void EDBM_mesh_ensure_valid_dm_hack(struct Scene *scene, struct BMEditMesh *em); void EDBM_mesh_normals_update(struct BMEditMesh *em); void EDBM_mesh_clear(struct BMEditMesh *em); diff --git a/source/blender/editors/include/ED_object.h b/source/blender/editors/include/ED_object.h index 066c4e5a692..8d2ff327c51 100644 --- a/source/blender/editors/include/ED_object.h +++ b/source/blender/editors/include/ED_object.h @@ -82,7 +82,7 @@ typedef enum eParentType { PAR_VERTEX_TRI, } eParentType; -typedef enum eObjectSelect_Mode{ +typedef enum eObjectSelect_Mode { BA_DESELECT = 0, BA_SELECT = 1, BA_INVERT = 2, diff --git a/source/blender/editors/include/ED_render.h b/source/blender/editors/include/ED_render.h index 707d7c6c693..b7317d75cd4 100644 --- a/source/blender/editors/include/ED_render.h +++ b/source/blender/editors/include/ED_render.h @@ -31,6 +31,7 @@ #include "DNA_vec_types.h" struct bContext; +struct DEGEditorUpdateContext; struct ID; struct Main; struct MTex; @@ -43,13 +44,15 @@ struct wmWindowManager; void ED_operatortypes_render(void); -/* render_shading.c */ +/* render_update.c */ -void ED_render_id_flush_update(struct Main *bmain, struct ID *id); void ED_render_engine_changed(struct Main *bmain); void ED_render_engine_area_exit(struct Main *bmain, struct ScrArea *sa); -void ED_render_scene_update(struct Main *bmain, struct Scene *scene, int updated); -void ED_render_scene_update_pre(struct Main *bmain, struct Scene *scene, bool time); + +/* Callbacks handling data update events coming from depsgraph. */ + +void ED_render_id_flush_update(const struct DEGEditorUpdateContext *update_ctx, struct ID *id); +void ED_render_scene_update(const struct DEGEditorUpdateContext *update_ctx, int updated); void ED_viewport_render_kill_jobs(struct wmWindowManager *wm, struct Main *bmain, bool free_database); struct Scene *ED_render_job_get_scene(const struct bContext *C); diff --git a/source/blender/editors/include/ED_screen.h b/source/blender/editors/include/ED_screen.h index 6cb20c818fd..d931109b941 100644 --- a/source/blender/editors/include/ED_screen.h +++ b/source/blender/editors/include/ED_screen.h @@ -55,6 +55,9 @@ struct ARegion; struct uiBlock; struct rcti; struct Main; +struct wmMsgBus; +struct wmMsgSubscribeKey; +struct wmMsgSubscribeValue; /* regions */ void ED_region_do_listen( @@ -86,6 +89,18 @@ void ED_region_grid_draw(struct ARegion *ar, float zoomx, float zoomy); float ED_region_blend_factor(struct ARegion *ar); void ED_region_visible_rect(struct ARegion *ar, struct rcti *rect); +/* message_bus callbacks */ +void ED_region_do_msg_notify_tag_redraw( + struct bContext *C, struct wmMsgSubscribeKey *msg_key, struct wmMsgSubscribeValue *msg_val); +void ED_area_do_msg_notify_tag_refresh( + struct bContext *C, struct wmMsgSubscribeKey *msg_key, struct wmMsgSubscribeValue *msg_val); + +/* message bus */ +void ED_region_message_subscribe( + struct bContext *C, + struct WorkSpace *workspace, struct Scene *scene, + struct bScreen *screen, struct ScrArea *sa, struct ARegion *ar, + struct wmMsgBus *mbus); /* spaces */ void ED_spacetypes_keymap(struct wmKeyConfig *keyconf); @@ -153,6 +168,7 @@ void ED_screen_preview_render(const struct bScreen *screen, int size_x, int s struct WorkSpace *ED_workspace_add( struct Main *bmain, const char *name, + Scene *scene, ViewLayer *act_render_layer, struct ViewRender *view_render) ATTR_NONNULL(); bool ED_workspace_change( @@ -169,7 +185,8 @@ bool ED_workspace_delete( void ED_workspace_scene_data_sync( struct WorkSpaceInstanceHook *hook, Scene *scene) ATTR_NONNULL(); void ED_workspace_view_layer_unset( - const struct Main *bmain, const ViewLayer *layer_unset, ViewLayer *layer_new) ATTR_NONNULL(1, 2); + const struct Main *bmain, struct Scene *scene, + const ViewLayer *layer_unset, ViewLayer *layer_new) ATTR_NONNULL(1, 2); struct WorkSpaceLayout *ED_workspace_layout_add( struct WorkSpace *workspace, struct wmWindow *win, diff --git a/source/blender/editors/include/ED_transform_snap_object_context.h b/source/blender/editors/include/ED_transform_snap_object_context.h index 49e85600819..8761f2c5361 100644 --- a/source/blender/editors/include/ED_transform_snap_object_context.h +++ b/source/blender/editors/include/ED_transform_snap_object_context.h @@ -76,9 +76,9 @@ struct SnapObjectParams { typedef struct SnapObjectContext SnapObjectContext; SnapObjectContext *ED_transform_snap_object_context_create( - struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, struct RenderEngineType *engine, int flag); + struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, struct RenderEngineType *engine_type, int flag); SnapObjectContext *ED_transform_snap_object_context_create_view3d( - struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, struct RenderEngineType *engine, int flag, + struct Main *bmain, struct Scene *scene, struct ViewLayer *view_layer, struct RenderEngineType *engine_type, int flag, /* extra args for view3d */ const struct ARegion *ar, const struct View3D *v3d); void ED_transform_snap_object_context_destroy(SnapObjectContext *sctx); diff --git a/source/blender/editors/include/ED_view3d.h b/source/blender/editors/include/ED_view3d.h index feb3686db9f..69061bdcd26 100644 --- a/source/blender/editors/include/ED_view3d.h +++ b/source/blender/editors/include/ED_view3d.h @@ -78,7 +78,7 @@ typedef struct ViewContext { struct Depsgraph *depsgraph; struct Scene *scene; struct ViewLayer *view_layer; - struct RenderEngineType *engine; + struct RenderEngineType *engine_type; struct Object *obact; struct Object *obedit; struct ARegion *ar; diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 51a98c47718..9a816f21fb8 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -73,6 +73,7 @@ struct bNodeSocket; struct wmDropBox; struct wmDrag; struct wmEvent; +struct wmMsgBus; typedef struct uiBut uiBut; typedef struct uiBlock uiBlock; @@ -183,6 +184,8 @@ enum { UI_BUT_UPDATE_DELAY = (1 << 28), /* don't run updates while dragging (needed in rare cases). */ UI_BUT_TEXTEDIT_UPDATE = (1 << 29), /* when widget is in textedit mode, update value on each char stroke */ UI_BUT_VALUE_CLEAR = (1 << 30), /* show 'x' icon to clear/unlink value of text or search button */ + + UI_BUT_OVERRIDEN = (1 << 31), /* RNA property of the button is overriden from linked reference data. */ }; #define UI_PANEL_WIDTH 340 @@ -901,6 +904,8 @@ uiLayout *UI_block_layout(uiBlock *block, int dir, int type, int x, int y, int s void UI_block_layout_set_current(uiBlock *block, uiLayout *layout); void UI_block_layout_resolve(uiBlock *block, int *x, int *y); +void UI_region_message_subscribe(struct ARegion *ar, struct wmMsgBus *mbus); + uiBlock *uiLayoutGetBlock(uiLayout *layout); void uiLayoutSetFunc(uiLayout *layout, uiMenuHandleFunc handlefunc, void *argv); diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 09007681455..a5ef2943387 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -41,6 +41,7 @@ #include "DNA_scene_types.h" #include "DNA_screen_types.h" #include "DNA_userdef_types.h" +#include "DNA_workspace_types.h" #include "BLI_math.h" #include "BLI_listbase.h" @@ -69,11 +70,14 @@ #include "WM_api.h" #include "WM_types.h" #include "wm_subwindow.h" +#include "WM_message.h" #include "RNA_access.h" #include "BPY_extern.h" +#include "ED_screen.h" + #include "IMB_colormanagement.h" #include "interface_intern.h" @@ -1216,6 +1220,20 @@ static void ui_menu_block_set_keymaps(const bContext *C, uiBlock *block) } } +void ui_but_override_flag(uiBut *but) +{ + bool is_overridden; + + RNA_property_override_status(&but->rnapoin, but->rnaprop, but->rnaindex, NULL, &is_overridden, NULL, NULL); + + if (is_overridden) { + but->flag |= UI_BUT_OVERRIDEN; + } + else { + but->flag &= ~UI_BUT_OVERRIDEN; + } +} + void UI_block_update_from_old(const bContext *C, uiBlock *block) { uiBut *but_old; @@ -1280,6 +1298,7 @@ void UI_block_end_ex(const bContext *C, uiBlock *block, const int xy[2], int r_x } ui_but_anim_flag(but, (scene) ? scene->r.cfra : 0.0f); + ui_but_override_flag(but); } @@ -1438,6 +1457,40 @@ void UI_block_draw(const bContext *C, uiBlock *block) ui_draw_links(block); } +static void ui_block_message_subscribe(ARegion *ar, struct wmMsgBus *mbus, uiBlock *block) +{ + uiBut *but_prev = NULL; + /* possibly we should keep the region this block is contained in? */ + for (uiBut *but = block->buttons.first; but; but = but->next) { + if (but->rnapoin.type && but->rnaprop) { + /* quick check to avoid adding buttons representing a vector, multiple times. */ + if ((but_prev && + (but_prev->rnaprop == but->rnaprop) && + (but_prev->rnapoin.type == but->rnapoin.type) && + (but_prev->rnapoin.data == but->rnapoin.data) && + (but_prev->rnapoin.id.data == but->rnapoin.id.data)) == false) + { + /* TODO: could make this into utility function. */ + WM_msg_subscribe_rna( + mbus, &but->rnapoin, but->rnaprop, + &(const wmMsgSubscribeValue){ + .owner = ar, + .user_data = ar, + .notify = ED_region_do_msg_notify_tag_redraw, + }, __func__); + but_prev = but; + } + } + } +} + +void UI_region_message_subscribe(ARegion *ar, struct wmMsgBus *mbus) +{ + for (uiBlock *block = ar->uiblocks.first; block; block = block->next) { + ui_block_message_subscribe(ar, mbus, block); + } +} + /* ************* EVENTS ************* */ /** diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 908fa19e3b1..53505fc39a4 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -6800,6 +6800,8 @@ static bool ui_but_menu(bContext *C, uiBut *but) MenuType *mt = WM_menutype_find("WM_MT_button_context", true); bool is_array, is_array_component; uiStringInfo label = {BUT_GET_LABEL, NULL}; + wmOperatorType *ot; + PointerRNA op_ptr; /* if ((but->rnapoin.data && but->rnaprop) == 0 && but->optype == NULL)*/ /* return 0;*/ @@ -6826,11 +6828,11 @@ static bool ui_but_menu(bContext *C, uiBut *but) const PropertySubType subtype = RNA_property_subtype(prop); bool is_anim = RNA_property_animateable(ptr, prop); bool is_editable = RNA_property_editable(ptr, prop); + bool is_overridable; /*bool is_idprop = RNA_property_is_idprop(prop);*/ /* XXX does not work as expected, not strictly needed */ bool is_set = RNA_property_is_set(ptr, prop); - /* Set the (button_pointer, button_prop) and pointer data for Python access to the hovered ui element. */ - uiLayoutSetContextFromBut(layout, but); + RNA_property_override_status(ptr, prop, -1, &is_overridable, NULL, NULL, NULL); /* second slower test, saved people finding keyframe items in menus when its not possible */ if (is_anim) @@ -6959,11 +6961,57 @@ static bool ui_but_menu(bContext *C, uiBut *but) ICON_NONE, "ANIM_OT_keyingset_button_remove"); } } - + + if (is_overridable) { + /* Override Operators */ + uiItemS(layout); + + if (but->flag & UI_BUT_OVERRIDEN) { + if (is_array_component) { + ot = WM_operatortype_find("UI_OT_override_type_set_button", false); + uiItemFullO_ptr(layout, ot, "Overrides Type", ICON_NONE, + NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr); + RNA_boolean_set(&op_ptr, "all", true); + uiItemFullO_ptr(layout, ot, "Single Override Type", ICON_NONE, + NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr); + RNA_boolean_set(&op_ptr, "all", false); + + uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Overrides"), + ICON_X, "UI_OT_override_remove_button", "all", true); + uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Single Override"), + ICON_X, "UI_OT_override_remove_button", "all", false); + } + else { + uiItemFullO(layout, "UI_OT_override_type_set_button", "Override Type", ICON_NONE, + NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr); + RNA_boolean_set(&op_ptr, "all", false); + + uiItemBooleanO(layout, CTX_IFACE_(BLT_I18NCONTEXT_OPERATOR_DEFAULT, "Remove Override"), + ICON_X, "UI_OT_override_remove_button", "all", true); + } + } + else { + if (is_array_component) { + ot = WM_operatortype_find("UI_OT_override_type_set_button", false); + uiItemFullO_ptr(layout, ot, "Define Overrides", ICON_NONE, + NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr); + RNA_boolean_set(&op_ptr, "all", true); + uiItemFullO_ptr(layout, ot, "Define Single Override", ICON_NONE, + NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr); + RNA_boolean_set(&op_ptr, "all", false); + } + else { + uiItemFullO(layout, "UI_OT_override_type_set_button", "Define Override", ICON_NONE, + NULL, WM_OP_INVOKE_DEFAULT, 0, &op_ptr); + RNA_boolean_set(&op_ptr, "all", false); + } + } + } + uiItemS(layout); - + /* Property Operators */ - + /* Copy Property Value * Paste Property Value */ @@ -8241,6 +8289,7 @@ void UI_context_update_anim_flag(const bContext *C) for (block = ar->uiblocks.first; block; block = block->next) { for (but = block->buttons.first; but; but = but->next) { ui_but_anim_flag(but, (scene) ? scene->r.cfra : 0.0f); + ui_but_override_flag(but); ED_region_tag_redraw(ar); if (but->active) { diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 424063953a7..6f450093d30 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -514,6 +514,7 @@ extern bool ui_but_supports_cycling(const uiBut *but) ATTR_WARN_UNUSED_RESULT; extern int ui_but_is_pushed_ex(uiBut *but, double *value) ATTR_WARN_UNUSED_RESULT; extern int ui_but_is_pushed(uiBut *but) ATTR_WARN_UNUSED_RESULT; +void ui_but_override_flag(uiBut *but); extern void ui_block_bounds_calc(uiBlock *block); extern void ui_block_translate(uiBlock *block, int x, int y); diff --git a/source/blender/editors/interface/interface_ops.c b/source/blender/editors/interface/interface_ops.c index 5913f1c48f5..bbcd10270d5 100644 --- a/source/blender/editors/interface/interface_ops.c +++ b/source/blender/editors/interface/interface_ops.c @@ -46,6 +46,7 @@ #include "BKE_layer.h" #include "BKE_screen.h" #include "BKE_global.h" +#include "BKE_library_override.h" #include "BKE_node.h" #include "BKE_text.h" /* for UI_OT_reports_to_text */ #include "BKE_report.h" @@ -452,6 +453,215 @@ static void UI_OT_unuse_property_button(wmOperatorType *ot) ot->flag = OPTYPE_UNDO; } + + + + +/* Note that we use different values for UI/UX than 'real' override operations, user does not care + * whether it's added or removed for the differential operation e.g. */ +enum { + UIOverride_Type_NOOP = 0, + UIOverride_Type_Replace = 1, + UIOverride_Type_Difference = 2, /* Add/subtract */ + UIOverride_Type_Factor = 3, /* Multiply */ + /* TODO: should/can we expose insert/remove ones for collections? Doubt it... */ +}; + +static EnumPropertyItem override_type_items[] = { + {UIOverride_Type_NOOP, "NOOP", 0, "NoOp", + "'No-Operation', place holder preventing automatic override to ever affect the property"}, + {UIOverride_Type_Replace, "REPLACE", 0, "Replace", "Completely replace value from linked data by local one"}, + {UIOverride_Type_Difference, "DIFFERENCE", 0, "Difference", "Store difference to linked data value"}, + {UIOverride_Type_Factor, "FACTOR", 0, "Factor", "Store factor to linked data value (useful e.g. for scale)"}, + {0, NULL, 0, NULL, NULL} +}; + + +static int override_type_set_button_poll(bContext *C) +{ + PointerRNA ptr; + PropertyRNA *prop; + int index; + bool is_overridable; + + UI_context_active_but_prop_get(C, &ptr, &prop, &index); + + RNA_property_override_status(&ptr, prop, index, &is_overridable, NULL, NULL, NULL); + + return (ptr.data && prop && is_overridable); +} + +static int override_type_set_button_exec(bContext *C, wmOperator *op) +{ + PointerRNA ptr; + PropertyRNA *prop; + int index; + bool created; + const bool all = RNA_boolean_get(op->ptr, "all"); + const int op_type = RNA_enum_get(op->ptr, "type"); + + short operation; + + switch (op_type) { + case UIOverride_Type_NOOP: + operation = IDOVERRIDESTATIC_OP_NOOP; + break; + case UIOverride_Type_Replace: + operation = IDOVERRIDESTATIC_OP_REPLACE; + break; + case UIOverride_Type_Difference: + operation = IDOVERRIDESTATIC_OP_ADD; /* override code will automatically switch to subtract if needed. */ + break; + case UIOverride_Type_Factor: + operation = IDOVERRIDESTATIC_OP_MULTIPLY; + break; + default: + operation = IDOVERRIDESTATIC_OP_REPLACE; + BLI_assert(0); + break; + } + + /* try to reset the nominated setting to its default value */ + UI_context_active_but_prop_get(C, &ptr, &prop, &index); + + BLI_assert(ptr.id.data != NULL); + + if (all) { + index = -1; + } + + IDOverrideStaticPropertyOperation *opop = RNA_property_override_property_operation_get( + &ptr, prop, operation, index, true, NULL, &created); + if (!created) { + opop->operation = operation; + } + + return operator_button_property_finish(C, &ptr, prop); +} + +static int override_type_set_button_invoke(bContext *C, wmOperator *op, const wmEvent *UNUSED(event)) +{ + return WM_menu_invoke_ex(C, op, WM_OP_INVOKE_DEFAULT); +} + +static void UI_OT_override_type_set_button(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Define Override Type"; + ot->idname = "UI_OT_override_type_set_button"; + ot->description = "Create an override operation, or set the type of an existing one"; + + /* callbacks */ + ot->poll = override_type_set_button_poll; + ot->exec = override_type_set_button_exec; + ot->invoke = override_type_set_button_invoke; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array"); + ot->prop = RNA_def_enum(ot->srna, "type", override_type_items, UIOverride_Type_Replace, + "Type", "Type of override operation"); + /* TODO: add itemf callback, not all aoptions are available for all data types... */ +} + + +static int override_remove_button_poll(bContext *C) +{ + PointerRNA ptr; + PropertyRNA *prop; + int index; + bool is_overridden; + + UI_context_active_but_prop_get(C, &ptr, &prop, &index); + + RNA_property_override_status(&ptr, prop, index, NULL, &is_overridden, NULL, NULL); + + return (ptr.data && ptr.id.data && prop && is_overridden); +} + +static int override_remove_button_exec(bContext *C, wmOperator *op) +{ + PointerRNA ptr, id_refptr, src; + PropertyRNA *prop; + int index; + const bool all = RNA_boolean_get(op->ptr, "all"); + + /* try to reset the nominated setting to its default value */ + UI_context_active_but_prop_get(C, &ptr, &prop, &index); + + ID *id = ptr.id.data; + IDOverrideStaticProperty *oprop = RNA_property_override_property_find(&ptr, prop); + BLI_assert(oprop != NULL); + BLI_assert(id != NULL && id->override_static != NULL); + + const bool is_template = (id->override_static->reference == NULL); + + /* We need source (i.e. linked data) to restore values of deleted overrides... + * If this is an override template, we obviously do not need to restore anything. */ + if (!is_template) { + RNA_id_pointer_create(id->override_static->reference, &id_refptr); + if (!RNA_path_resolve(&id_refptr, oprop->rna_path, &src, NULL)) { + BLI_assert(0 && "Failed to create matching source (linked data) RNA pointer"); + } + } + + if (!all && index != -1) { + bool is_strict_find; + /* Remove override operation for given item, add singular operations for the other items as needed. */ + IDOverrideStaticPropertyOperation *opop = BKE_override_static_property_operation_find( + oprop, NULL, NULL, index, index, false, &is_strict_find); + BLI_assert(opop != NULL); + if (!is_strict_find) { + /* No specific override operation, we have to get generic one, + * and create item-specific override operations for all but given index, before removing generic one. */ + for (int idx = RNA_property_array_length(&ptr, prop); idx--; ) { + if (idx != index) { + BKE_override_static_property_operation_get(oprop, opop->operation, NULL, NULL, idx, idx, true, NULL, NULL); + } + } + } + BKE_override_static_property_operation_delete(oprop, opop); + if (!is_template) { + RNA_property_copy(&ptr, &src, prop, index); + } + if (BLI_listbase_is_empty(&oprop->operations)) { + BKE_override_static_property_delete(id->override_static, oprop); + } + } + else { + /* Just remove whole generic override operation of this property. */ + BKE_override_static_property_delete(id->override_static, oprop); + if (!is_template) { + RNA_property_copy(&ptr, &src, prop, -1); + } + } + + return operator_button_property_finish(C, &ptr, prop); +} + +static void UI_OT_override_remove_button(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Remove Override"; + ot->idname = "UI_OT_override_remove_button"; + ot->description = "Remove an override operation"; + + /* callbacks */ + ot->poll = override_remove_button_poll; + ot->exec = override_remove_button_exec; + + /* flags */ + ot->flag = OPTYPE_UNDO; + + /* properties */ + RNA_def_boolean(ot->srna, "all", 1, "All", "Reset to default values all elements of the array"); +} + + + + /* Copy To Selected Operator ------------------------ */ bool UI_context_copy_to_selected_list( @@ -1243,6 +1453,8 @@ void ED_operatortypes_ui(void) WM_operatortype_append(UI_OT_unset_property_button); WM_operatortype_append(UI_OT_use_property_button); WM_operatortype_append(UI_OT_unuse_property_button); + WM_operatortype_append(UI_OT_override_type_set_button); + WM_operatortype_append(UI_OT_override_remove_button); WM_operatortype_append(UI_OT_copy_to_selected_button); WM_operatortype_append(UI_OT_reports_to_textblock); /* XXX: temp? */ WM_operatortype_append(UI_OT_drop_color); diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index c7e1a60b05c..78874076b92 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -1075,8 +1075,10 @@ void uiTemplateSearch( const char *newop, const char *unlinkop) { TemplateSearch *template_search = template_search_setup(ptr, propname, searchptr, searchpropname); - template_search_buttons(C, layout, template_search, newop, unlinkop); - MEM_freeN(template_search); + if (template_search != NULL) { + template_search_buttons(C, layout, template_search, newop, unlinkop); + MEM_freeN(template_search); + } } void uiTemplateSearchPreview( @@ -1088,13 +1090,15 @@ void uiTemplateSearchPreview( { TemplateSearch *template_search = template_search_setup(ptr, propname, searchptr, searchpropname); - template_search->use_previews = true; - template_search->preview_rows = rows; - template_search->preview_cols = cols; + if (template_search != NULL) { + template_search->use_previews = true; + template_search->preview_rows = rows; + template_search->preview_cols = cols; - template_search_buttons(C, layout, template_search, newop, unlinkop); + template_search_buttons(C, layout, template_search, newop, unlinkop); - MEM_freeN(template_search); + MEM_freeN(template_search); + } } /********************* RNA Path Builder Template ********************/ diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 375f4f95697..8c894c7852e 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1710,6 +1710,8 @@ static struct uiWidgetStateColors wcol_state_colors = { {215, 211, 75, 255}, {180, 0, 255, 255}, {153, 0, 230, 255}, + {74, 137, 137, 255}, + {49, 112, 112, 255}, 0.5f, 0.0f }; @@ -2062,6 +2064,8 @@ static void widget_state(uiWidgetType *wt, int state) widget_state_blend(wt->wcol.inner, wcol_state->inner_anim_sel, wcol_state->blend); else if (state & UI_BUT_DRIVEN) widget_state_blend(wt->wcol.inner, wcol_state->inner_driven_sel, wcol_state->blend); + else if (state & UI_BUT_OVERRIDEN) + widget_state_blend(wt->wcol.inner, wcol_state->inner_overridden_sel, wcol_state->blend); copy_v3_v3_char(wt->wcol.text, wt->wcol.text_sel); @@ -2075,6 +2079,8 @@ static void widget_state(uiWidgetType *wt, int state) widget_state_blend(wt->wcol.inner, wcol_state->inner_anim, wcol_state->blend); else if (state & UI_BUT_DRIVEN) widget_state_blend(wt->wcol.inner, wcol_state->inner_driven, wcol_state->blend); + else if (state & UI_BUT_OVERRIDEN) + widget_state_blend(wt->wcol.inner, wcol_state->inner_overridden, wcol_state->blend); if (state & UI_ACTIVE) { /* mouse over? */ wt->wcol.inner[0] = wt->wcol.inner[0] >= 240 ? 255 : wt->wcol.inner[0] + 15; @@ -2120,7 +2126,9 @@ static void widget_state_numslider(uiWidgetType *wt, int state) widget_state_blend(wt->wcol.item, wcol_state->inner_anim_sel, blend); else if (state & UI_BUT_DRIVEN) widget_state_blend(wt->wcol.item, wcol_state->inner_driven_sel, blend); - + else if (state & UI_BUT_OVERRIDEN) + widget_state_blend(wt->wcol.item, wcol_state->inner_overridden_sel, blend); + if (state & UI_SELECT) SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown); } @@ -2131,6 +2139,8 @@ static void widget_state_numslider(uiWidgetType *wt, int state) widget_state_blend(wt->wcol.item, wcol_state->inner_anim, blend); else if (state & UI_BUT_DRIVEN) widget_state_blend(wt->wcol.item, wcol_state->inner_driven, blend); + else if (state & UI_BUT_OVERRIDEN) + widget_state_blend(wt->wcol.item, wcol_state->inner_overridden, blend); } } @@ -3157,7 +3167,7 @@ static void widget_swatch(uiBut *but, uiWidgetColors *wcol, rcti *rect, int stat ui_but_v3_get(but, col); - if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT)) { + if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_OVERRIDEN | UI_BUT_REDALERT)) { /* draw based on state - color for keyed etc */ widgetbase_draw(&wtb, wcol); diff --git a/source/blender/editors/mesh/editmesh_bevel.c b/source/blender/editors/mesh/editmesh_bevel.c index e541df8ffa3..d4d7d92d5ad 100644 --- a/source/blender/editors/mesh/editmesh_bevel.c +++ b/source/blender/editors/mesh/editmesh_bevel.c @@ -58,8 +58,7 @@ #define MVAL_PIXEL_MARGIN 5.0f -/* until implement profile = 0 case, need to clamp somewhat above zero */ -#define PROFILE_HARD_MIN 0.15f +#define PROFILE_HARD_MIN 0.0f #define SEGMENTS_HARD_MAX 1000 @@ -623,6 +622,7 @@ void MESH_OT_bevel(wmOperatorType *ot) RNA_def_enum(ot->srna, "offset_type", offset_type_items, 0, "Amount Type", "What distance Amount measures"); prop = RNA_def_float(ot->srna, "offset", 0.0f, -1e6f, 1e6f, "Amount", "", 0.0f, 1.0f); RNA_def_property_float_array_funcs_runtime(prop, NULL, NULL, mesh_ot_bevel_offset_range_func); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); RNA_def_int(ot->srna, "segments", 1, 1, SEGMENTS_HARD_MAX, "Segments", "Segments for curved edge", 1, 8); RNA_def_float(ot->srna, "profile", 0.5f, PROFILE_HARD_MIN, 1.0f, "Profile", "Controls profile shape (0.5 = round)", PROFILE_HARD_MIN, 1.0f); diff --git a/source/blender/editors/mesh/editmesh_inset.c b/source/blender/editors/mesh/editmesh_inset.c index 3e0747f055f..afe52ec69f4 100644 --- a/source/blender/editors/mesh/editmesh_inset.c +++ b/source/blender/editors/mesh/editmesh_inset.c @@ -80,8 +80,10 @@ static void edbm_inset_update_header(wmOperator *op, bContext *C) { InsetData *opdata = op->customdata; - const char *str = IFACE_("Confirm: Enter/LClick, Cancel: (Esc/RClick), Thickness: %s, " - "Depth (Ctrl to tweak): %s (%s), Outset (O): (%s), Boundary (B): (%s), Individual (I): (%s)"); + const char *str = IFACE_( + "Confirm: Enter/LClick, Cancel: (Esc/RClick), Thickness: %s, " + "Depth (Ctrl to tweak): %s (%s), Outset (O): (%s), Boundary (B): (%s), Individual (I): (%s)" + ); char msg[UI_MAX_DRAW_STR]; ScrArea *sa = CTX_wm_area(C); @@ -141,7 +143,8 @@ static bool edbm_inset_init(bContext *C, wmOperator *op, const bool is_modal) ARegion *ar = CTX_wm_region(C); opdata->mesh_backup = EDBM_redo_state_store(em); - opdata->draw_handle_pixel = ED_region_draw_cb_activate(ar->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL); + opdata->draw_handle_pixel = ED_region_draw_cb_activate( + ar->type, ED_region_draw_mouse_line_cb, opdata->mcenter, REGION_DRAW_POST_PIXEL); G.moving = G_TRANSFORM_EDIT; if (v3d) { opdata->twtype = v3d->twtype; @@ -506,16 +509,27 @@ void MESH_OT_inset(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO | OPTYPE_GRAB_CURSOR | OPTYPE_BLOCKING; /* properties */ - RNA_def_boolean(ot->srna, "use_boundary", true, "Boundary", "Inset face boundaries"); - RNA_def_boolean(ot->srna, "use_even_offset", true, "Offset Even", "Scale the offset to give more even thickness"); - RNA_def_boolean(ot->srna, "use_relative_offset", false, "Offset Relative", "Scale the offset by surrounding geometry"); - RNA_def_boolean(ot->srna, "use_edge_rail", false, "Edge Rail", "Inset the region along existing edges"); + RNA_def_boolean( + ot->srna, "use_boundary", + true, "Boundary", "Inset face boundaries"); + RNA_def_boolean( + ot->srna, "use_even_offset", + true, "Offset Even", "Scale the offset to give more even thickness"); + RNA_def_boolean( + ot->srna, "use_relative_offset", + false, "Offset Relative", "Scale the offset by surrounding geometry"); + RNA_def_boolean( + ot->srna, "use_edge_rail", + false, "Edge Rail", "Inset the region along existing edges"); prop = RNA_def_float_distance(ot->srna, "thickness", 0.01f, 0.0f, 1e12f, "Thickness", "", 0.0f, 10.0f); /* use 1 rather then 10 for max else dragging the button moves too far */ RNA_def_property_ui_range(prop, 0.0, 1.0, 0.01, 4); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); + prop = RNA_def_float_distance(ot->srna, "depth", 0.0f, -1e12f, 1e12f, "Depth", "", -10.0f, 10.0f); RNA_def_property_ui_range(prop, -10.0f, 10.0f, 0.01, 4); + RNA_def_property_flag(prop, PROP_SKIP_SAVE); RNA_def_boolean(ot->srna, "use_outset", false, "Outset", "Outset rather than inset"); RNA_def_boolean(ot->srna, "use_select_inset", false, "Select Outer", "Select the new inset faces"); diff --git a/source/blender/editors/mesh/editmesh_loopcut.c b/source/blender/editors/mesh/editmesh_loopcut.c index 876d63ef64a..3ab56f2ebcb 100644 --- a/source/blender/editors/mesh/editmesh_loopcut.c +++ b/source/blender/editors/mesh/editmesh_loopcut.c @@ -534,9 +534,6 @@ static int ringsel_init(bContext *C, wmOperator *op, bool do_cut) lcd->num.unit_type[0] = B_UNIT_NONE; lcd->num.unit_type[1] = B_UNIT_NONE; - /* XXX, temp, workaround for [# ] */ - EDBM_mesh_ensure_valid_dm_hack(scene, lcd->em); - em_setup_viewcontext(C, &lcd->vc); ED_region_tag_redraw(lcd->ar); diff --git a/source/blender/editors/mesh/editmesh_polybuild.c b/source/blender/editors/mesh/editmesh_polybuild.c index bfabd64396f..f398f087da9 100644 --- a/source/blender/editors/mesh/editmesh_polybuild.c +++ b/source/blender/editors/mesh/editmesh_polybuild.c @@ -132,7 +132,7 @@ static int edbm_polybuild_face_at_cursor_invoke( BMEdge *e_iter = v_act->e; do { if ((BM_elem_flag_test(e_iter, BM_ELEM_HIDDEN) == false) && - (allow_wire ? BM_edge_is_wire(e_iter) : BM_edge_is_boundary(e_iter))) + (allow_wire ? BM_edge_is_wire(e_iter) : BM_edge_is_boundary(e_iter))) { if (i == 2) { e_pair[0] = e_pair[1] = NULL; @@ -489,9 +489,9 @@ static int edbm_polybuild_hover_invoke( /* pass */ } else if (vc.win->tweak || - (vc.win->eventstate->check_click && - vc.win->eventstate->prevval == KM_PRESS && - ISMOUSE(vc.win->eventstate->prevtype))) + (vc.win->eventstate->check_click && + vc.win->eventstate->prevval == KM_PRESS && + ISMOUSE(vc.win->eventstate->prevtype))) { return OPERATOR_PASS_THROUGH; } diff --git a/source/blender/editors/mesh/editmesh_select.c b/source/blender/editors/mesh/editmesh_select.c index 0a0a8ff2de3..3e0afd3095e 100644 --- a/source/blender/editors/mesh/editmesh_select.c +++ b/source/blender/editors/mesh/editmesh_select.c @@ -640,9 +640,17 @@ BMEdge *EDBM_edge_find_nearest_ex( unsigned int index; BMEdge *eed; + /* Make sure that the edges also are considered to find nearest. + * TODO: cleanup: add `selectmode` as a parameter */ + const short ts_selectmode = vc->scene->toolsettings->selectmode; + vc->scene->toolsettings->selectmode |= SCE_SELECT_EDGE; + /* No afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad. */ ED_view3d_backbuf_validate(eval_ctx, vc); + /* restore `selectmode` */ + vc->scene->toolsettings->selectmode = ts_selectmode; + index = ED_view3d_backbuf_sample_rect(eval_ctx, vc, vc->mval, dist_px, bm_solidoffs, bm_wireoffs, &dist_test); eed = index ? BM_edge_at_index_find_or_table(bm, index - 1) : NULL; @@ -1583,9 +1591,17 @@ static bool mouse_mesh_loop(bContext *C, const int mval[2], bool extend, bool de mvalf[1] = (float)(vc.mval[1] = mval[1]); em = vc.em; + /* Make sure that the edges are also considered for selection. + * TODO: cleanup: add `selectmode` as a parameter */ + const short ts_selectmode = vc.scene->toolsettings->selectmode; + vc.scene->toolsettings->selectmode |= SCE_SELECT_EDGE; + /* no afterqueue (yet), so we check it now, otherwise the bm_xxxofs indices are bad */ ED_view3d_backbuf_validate(&eval_ctx, &vc); + /* restore `selectmode` */ + vc.scene->toolsettings->selectmode = ts_selectmode; + eed = EDBM_edge_find_nearest_ex(&eval_ctx, &vc, &dist, NULL, true, true, NULL); if (eed == NULL) { return false; diff --git a/source/blender/editors/mesh/editmesh_tools.c b/source/blender/editors/mesh/editmesh_tools.c index 74bd4e978e7..75a13a916e6 100644 --- a/source/blender/editors/mesh/editmesh_tools.c +++ b/source/blender/editors/mesh/editmesh_tools.c @@ -311,7 +311,7 @@ void EMBM_project_snap_verts(bContext *C, ARegion *ar, BMEditMesh *em) ED_view3d_init_mats_rv3d(obedit, ar->regiondata); struct SnapObjectContext *snap_context = ED_transform_snap_object_context_create_view3d( - CTX_data_main(C), CTX_data_scene(C), CTX_data_view_layer(C), CTX_data_engine(C), 0, + CTX_data_main(C), CTX_data_scene(C), CTX_data_view_layer(C), CTX_data_engine_type(C), 0, ar, CTX_wm_view3d(C)); BM_ITER_MESH (eve, &iter, em->bm, BM_VERTS_OF_MESH) { diff --git a/source/blender/editors/mesh/editmesh_utils.c b/source/blender/editors/mesh/editmesh_utils.c index 230f46abad1..27fe93b049a 100644 --- a/source/blender/editors/mesh/editmesh_utils.c +++ b/source/blender/editors/mesh/editmesh_utils.c @@ -53,7 +53,7 @@ #include "DEG_depsgraph.h" -#include "BKE_object.h" /* XXX. only for EDBM_mesh_ensure_valid_dm_hack() which will be removed */ +#include "BKE_object.h" /* XXX. only for EDBM_mesh_load(). */ #include "WM_api.h" #include "WM_types.h" @@ -108,21 +108,6 @@ void EDBM_redo_state_free(BMBackup *backup, BMEditMesh *em, int recalctess) BKE_editmesh_tessface_calc(em); } -/* hack to workaround multiple operators being called within the same event loop without an update - * see: [#31811] */ -void EDBM_mesh_ensure_valid_dm_hack(Scene *scene, BMEditMesh *em) -{ - if ((((ID *)em->ob->data)->tag & LIB_TAG_ID_RECALC) || - (em->ob->recalc & OB_RECALC_DATA)) - { - /* since we may not have done selection flushing */ - if ((em->ob->recalc & OB_RECALC_DATA) == 0) { - DEG_id_tag_update(&em->ob->id, OB_RECALC_DATA); - } - BKE_object_handle_update(G.main->eval_ctx, scene, em->ob); - } -} - void EDBM_mesh_normals_update(BMEditMesh *em) { BM_mesh_normals_update(em->bm); @@ -413,6 +398,7 @@ void EDBM_mesh_load(Object *ob) * of freed data on scene update, especially in cases when there are dependency * cycles. */ + /* for (Object *other_object = G.main->object.first; other_object != NULL; other_object = other_object->id.next) @@ -421,6 +407,7 @@ void EDBM_mesh_load(Object *ob) BKE_object_free_derived_caches(other_object); } } + */ } /** diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 77b30951dee..e8807432328 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -449,10 +449,13 @@ Object *ED_object_add_type( ob->gameflag &= ~(OB_SENSOR | OB_RIGID_BODY | OB_SOFT_BODY | OB_COLLISION | OB_CHARACTER | OB_OCCLUDER | OB_DYNAMIC | OB_NAVMESH); /* copied from rna_object.c */ } + /* TODO(sergey): This is weird to manually tag objects for update, better to + * use DEG_id_tag_update here perhaps. + */ DEG_id_type_tag(bmain, ID_OB); DEG_relations_tag_update(bmain); - if (ob->data) { - ED_render_id_flush_update(bmain, ob->data); + if (ob->data != NULL) { + DEG_id_tag_update_ex(bmain, (ID *)ob->data, DEG_TAG_EDITORS_UPDATE); } if (enter_editmode) @@ -1218,7 +1221,7 @@ void ED_object_base_free_and_unlink(Main *bmain, Scene *scene, Object *ob) DEG_id_tag_update_ex(bmain, &ob->id, DEG_TAG_BASE_FLAGS_UPDATE); object_delete_check_glsl_update(ob); - BKE_collections_object_remove(bmain, scene, ob, true); + BKE_collections_object_remove(bmain, &scene->id, ob, true); } static int object_delete_exec(bContext *C, wmOperator *op) @@ -2340,8 +2343,8 @@ Base *ED_object_add_duplicate(Main *bmain, Scene *scene, ViewLayer *view_layer, /* DAG_relations_tag_update(bmain); */ /* caller must do */ - if (ob->data) { - ED_render_id_flush_update(bmain, ob->data); + if (ob->data != NULL) { + DEG_id_tag_update_ex(bmain, (ID *)ob->data, DEG_TAG_EDITORS_UPDATE); } BKE_main_id_clear_newpoins(bmain); diff --git a/source/blender/editors/object/object_edit.c b/source/blender/editors/object/object_edit.c index 804d0ed1f0d..5697c48d381 100644 --- a/source/blender/editors/object/object_edit.c +++ b/source/blender/editors/object/object_edit.c @@ -1516,15 +1516,13 @@ bool ED_object_mode_compat_set(bContext *C, Object *ob, int mode, ReportList *re { bool ok; if (!ELEM(ob->mode, mode, OB_MODE_OBJECT)) { - WorkSpace *workspace = CTX_wm_workspace(C); const char *opstring = object_mode_op_string(ob->mode); WM_operator_name_call(C, opstring, WM_OP_EXEC_REGION_WIN, NULL); #ifdef USE_WORKSPACE_MODE - BKE_workspace_object_mode_set(workspace, ob->mode); -#else - UNUSED_VARS(workspace); + BKE_workspace_object_mode_set(CTX_wm_workspace(C), CTX_data_scene(C), ob->mode); #endif + ok = ELEM(ob->mode, mode, OB_MODE_OBJECT); if (!ok) { wmOperatorType *ot = WM_operatortype_find(opstring, false); @@ -1648,7 +1646,7 @@ void ED_object_toggle_modes(bContext *C, int mode) #ifdef USE_WORKSPACE_MODE Object *ob = CTX_data_active_object(C); if (ob) { - BKE_workspace_object_mode_set(workspace, ob->mode); + BKE_workspace_object_mode_set(workspace, CTX_data_scene(C), ob->mode); } #endif } diff --git a/source/blender/editors/object/object_intern.h b/source/blender/editors/object/object_intern.h index 3e655fa04a4..c38a7d58904 100644 --- a/source/blender/editors/object/object_intern.h +++ b/source/blender/editors/object/object_intern.h @@ -68,6 +68,7 @@ void OBJECT_OT_track_clear(struct wmOperatorType *ot); void OBJECT_OT_slow_parent_set(struct wmOperatorType *ot); void OBJECT_OT_slow_parent_clear(struct wmOperatorType *ot); void OBJECT_OT_make_local(struct wmOperatorType *ot); +void OBJECT_OT_make_override(struct wmOperatorType *ot); void OBJECT_OT_make_single_user(struct wmOperatorType *ot); void OBJECT_OT_make_links_scene(struct wmOperatorType *ot); void OBJECT_OT_make_links_data(struct wmOperatorType *ot); diff --git a/source/blender/editors/object/object_ops.c b/source/blender/editors/object/object_ops.c index c87df877d5c..ceea3b9c0ac 100644 --- a/source/blender/editors/object/object_ops.c +++ b/source/blender/editors/object/object_ops.c @@ -84,6 +84,7 @@ void ED_operatortypes_object(void) WM_operatortype_append(OBJECT_OT_slow_parent_set); WM_operatortype_append(OBJECT_OT_slow_parent_clear); WM_operatortype_append(OBJECT_OT_make_local); + WM_operatortype_append(OBJECT_OT_make_override); WM_operatortype_append(OBJECT_OT_make_single_user); WM_operatortype_append(OBJECT_OT_make_links_scene); WM_operatortype_append(OBJECT_OT_make_links_data); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index 9854b61813b..436364ec6c3 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -77,8 +77,10 @@ #include "BKE_lattice.h" #include "BKE_layer.h" #include "BKE_library.h" +#include "BKE_library_override.h" #include "BKE_library_query.h" #include "BKE_library_remap.h" +#include "BKE_lightprobe.h" #include "BKE_main.h" #include "BKE_material.h" #include "BKE_mball.h" @@ -340,17 +342,15 @@ static int make_proxy_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); Object *ob, *gob = ED_object_active_context(C); - GroupObject *go; Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); if (gob->dup_group != NULL) { - go = BLI_findlink(&gob->dup_group->gobject, RNA_enum_get(op->ptr, "object")); - ob = go->ob; + Base *base = BLI_findlink(&gob->dup_group->view_layer->object_bases, RNA_enum_get(op->ptr, "object")); + ob = base->object; } else { ob = gob; - gob = NULL; } if (ob) { @@ -395,17 +395,18 @@ static const EnumPropertyItem *proxy_group_object_itemf(bContext *C, PointerRNA int totitem = 0; int i = 0; Object *ob = ED_object_active_context(C); - GroupObject *go; if (!ob || !ob->dup_group) return DummyRNA_DEFAULT_items; /* find the object to affect */ - for (go = ob->dup_group->gobject.first; go; go = go->next) { - item_tmp.identifier = item_tmp.name = go->ob->id.name + 2; + FOREACH_GROUP_OBJECT(ob->dup_group, object) + { + item_tmp.identifier = item_tmp.name = object->id.name + 2; item_tmp.value = i++; RNA_enum_item_add(&item, &totitem, &item_tmp); } + FOREACH_GROUP_OBJECT_END RNA_enum_item_end(&item, &totitem); *r_free = true; @@ -1366,10 +1367,10 @@ static int make_links_scene_exec(bContext *C, wmOperator *op) return OPERATOR_CANCELLED; } - SceneCollection *sc_to = BKE_collection_master(scene_to); + SceneCollection *sc_to = BKE_collection_master(&scene_to->id); CTX_DATA_BEGIN (C, Base *, base, selected_bases) { - BKE_collection_object_add(scene_to, sc_to, base->object); + BKE_collection_object_add(&scene_to->id, sc_to, base->object); } CTX_DATA_END; @@ -1689,12 +1690,11 @@ static void single_object_users_scene_collection(Main *bmain, Scene *scene, Scen static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const int flag, const bool copy_groups) { Group *group, *groupn; - GroupObject *go; clear_sca_new_poins(); /* BGE logic */ /* duplicate all the objects of the scene */ - SceneCollection *msc = BKE_collection_master(scene); + SceneCollection *msc = BKE_collection_master(&scene->id); single_object_users_scene_collection(bmain, scene, msc, flag, copy_groups); /* loop over ViewLayers and assign the pointers accordingly */ @@ -1706,22 +1706,26 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in /* duplicate groups that consist entirely of duplicated objects */ for (group = bmain->group.first; group; group = group->id.next) { - if (copy_groups && group->gobject.first) { + if (copy_groups && group->view_layer->object_bases.first) { bool all_duplicated = true; - for (go = group->gobject.first; go; go = go->next) { - if (!(go->ob && (go->ob->id.newid))) { + FOREACH_GROUP_OBJECT(group, object) + { + if (object->id.newid == NULL) { all_duplicated = false; break; } } + FOREACH_GROUP_OBJECT_END if (all_duplicated) { groupn = ID_NEW_SET(group, BKE_group_copy(bmain, group)); - for (go = groupn->gobject.first; go; go = go->next) { - go->ob = (Object *)go->ob->id.newid; + FOREACH_GROUP_BASE(groupn, base) + { + base->object = (Object *)base->object->id.newid; } + FOREACH_GROUP_BASE_END } } } @@ -1840,9 +1844,15 @@ static void single_obdata_users(Main *bmain, Scene *scene, ViewLayer *view_layer case OB_SPEAKER: ob->data = ID_NEW_SET(ob->data, BKE_speaker_copy(bmain, ob->data)); break; + case OB_LIGHTPROBE: + ob->data = ID_NEW_SET(ob->data, BKE_lightprobe_copy(bmain, ob->data)); + break; default: - if (G.debug & G_DEBUG) - printf("ERROR %s: can't copy %s\n", __func__, id->name); + printf("ERROR %s: can't copy %s\n", __func__, id->name); + BLI_assert(!"This should never happen."); + + /* We need to end the FOREACH_OBJECT_FLAG iterator to prevent memory leak. */ + BKE_scene_objects_iterator_end(&iter_macro); return; } @@ -2143,7 +2153,7 @@ static bool make_local_all__instance_indirect_unused(Main *bmain, Scene *scene, id_us_plus(&ob->id); - BKE_collection_object_add(scene, sc, ob); + BKE_collection_object_add(&scene->id, sc, ob); base = BKE_view_layer_base_find(view_layer, ob); base->flag |= BASE_SELECTED; BKE_scene_object_base_flag_sync_from_base(base); @@ -2325,6 +2335,44 @@ void OBJECT_OT_make_local(wmOperatorType *ot) ot->prop = RNA_def_enum(ot->srna, "type", type_items, 0, "Type", ""); } +static int make_override_exec(bContext *C, wmOperator *UNUSED(op)) +{ + Main *bmain = CTX_data_main(C); + Object *locobj, *refobj = CTX_data_active_object(C); + + locobj = (Object *)BKE_override_static_create_from(bmain, &refobj->id); + UNUSED_VARS(locobj); + + WM_event_add_notifier(C, NC_WINDOW, NULL); + + return OPERATOR_FINISHED; +} + +static int make_override_poll(bContext *C) +{ + Object *obact = CTX_data_active_object(C); + + /* Object must be directly linked to be overridable. */ + return (ED_operator_objectmode(C) && obact && obact->id.lib != NULL && obact->id.tag & LIB_TAG_EXTERN); +} + +void OBJECT_OT_make_override(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Make Override"; + ot->description = "Make local override of this library linked data-block"; + ot->idname = "OBJECT_OT_make_override"; + + /* api callbacks */ + ot->exec = make_override_exec; + ot->poll = make_override_poll; + + /* flags */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; + + /* properties */ +} + enum { MAKE_SINGLE_USER_ALL = 1, MAKE_SINGLE_USER_SELECTED = 2, diff --git a/source/blender/editors/object/object_select.c b/source/blender/editors/object/object_select.c index 47e63cb43e5..552380cebdb 100644 --- a/source/blender/editors/object/object_select.c +++ b/source/blender/editors/object/object_select.c @@ -123,8 +123,7 @@ void ED_object_base_activate(bContext *C, Base *base) if (base) { #ifdef USE_WORKSPACE_MODE - WorkSpace *workspace = CTX_wm_workspace(C); - BKE_workspace_object_mode_set(workspace, base->object->mode); + BKE_workspace_object_mode_set(CTX_wm_workspace(C), CTX_data_scene(C), base->object->mode); #endif WM_event_add_notifier(C, NC_SCENE | ND_OB_ACTIVE, view_layer); } diff --git a/source/blender/editors/render/render_internal.c b/source/blender/editors/render/render_internal.c index 2c659d2b985..4e75ca3e6f1 100644 --- a/source/blender/editors/render/render_internal.c +++ b/source/blender/editors/render/render_internal.c @@ -832,7 +832,7 @@ static void clean_viewport_memory(Main *bmain, Scene *scene) } } - for (SETLOOPER_SET_ONLY(scene, sce_iter, base)) { + for (SETLOOPER_SET_ONLY(scene, sce_iter, base)) { clean_viewport_memory_base(base); } } diff --git a/source/blender/editors/render/render_update.c b/source/blender/editors/render/render_update.c index 8956ef79958..a391b13a000 100644 --- a/source/blender/editors/render/render_update.c +++ b/source/blender/editors/render/render_update.c @@ -70,6 +70,8 @@ #include "ED_render.h" #include "ED_view3d.h" +#include "DEG_depsgraph.h" + #include "WM_api.h" #include "render_intern.h" // own include @@ -78,10 +80,13 @@ extern Material defmaterial; /***************************** Render Engines ********************************/ -void ED_render_scene_update(Main *bmain, Scene *scene, int updated) +void ED_render_scene_update(const DEGEditorUpdateContext *update_ctx, int updated) { /* viewport rendering update on data changes, happens after depsgraph * updates if there was any change. context is set to the 3d view */ + Main *bmain = update_ctx->bmain; + Scene *scene = update_ctx->scene; + ViewLayer *view_layer = update_ctx->view_layer; bContext *C; wmWindowManager *wm; wmWindow *win; @@ -123,15 +128,11 @@ void ED_render_scene_update(Main *bmain, Scene *scene, int updated) continue; for (ar = sa->regionbase.first; ar; ar = ar->next) { - RegionView3D *rv3d; - RenderEngine *engine; - - if (ar->regiontype != RGN_TYPE_WINDOW) + if (ar->regiontype != RGN_TYPE_WINDOW) { continue; - - rv3d = ar->regiondata; - engine = rv3d->render_engine; - + } + RegionView3D *rv3d = ar->regiondata; + RenderEngine *engine = rv3d->render_engine; /* call update if the scene changed, or if the render engine * tagged itself for update (e.g. because it was busy at the * time of the last update) */ @@ -145,13 +146,20 @@ void ED_render_scene_update(Main *bmain, Scene *scene, int updated) engine->type->view_update(engine, C); } - else if ((RE_engines_find(view_render->engine_id)->flag & RE_USE_LEGACY_PIPELINE) == 0) { - if (updated) { - CTX_wm_screen_set(C, sc); - CTX_wm_area_set(C, sa); - CTX_wm_region_set(C, ar); - - DRW_notify_view_update(C); + else { + RenderEngineType *engine_type = RE_engines_find(view_render->engine_id); + if ((engine_type->flag & RE_USE_LEGACY_PIPELINE) == 0) { + if (updated) { + DRW_notify_view_update( + (&(DRWUpdateContext){ + .bmain = bmain, + .scene = scene, + .view_layer = view_layer, + .ar = ar, + .v3d = (View3D *)sa->spacedata.first, + .engine_type = engine_type + })); + } } } } @@ -163,23 +171,6 @@ void ED_render_scene_update(Main *bmain, Scene *scene, int updated) recursive_check = false; } -void ED_render_scene_update_pre(Main *bmain, Scene *scene, bool time) -{ - /* Blender internal might access to the data which is gonna to be freed - * by the scene update functions. This applies for example to simulation - * data like smoke and fire. - */ - if (time && !BKE_scene_use_new_shading_nodes(scene)) { - bScreen *sc; - ScrArea *sa; - for (sc = bmain->screen.first; sc; sc = sc->id.next) { - for (sa = sc->areabase.first; sa; sa = sa->next) { - ED_render_engine_area_exit(bmain, sa); - } - } - } -} - void ED_render_engine_area_exit(Main *bmain, ScrArea *sa) { /* clear all render engines in this area */ @@ -199,18 +190,21 @@ void ED_render_engine_area_exit(Main *bmain, ScrArea *sa) void ED_render_engine_changed(Main *bmain) { /* on changing the render engine type, clear all running render engines */ - bScreen *sc; - ScrArea *sa; - Scene *scene; - - for (sc = bmain->screen.first; sc; sc = sc->id.next) - for (sa = sc->areabase.first; sa; sa = sa->next) + for (bScreen *sc = bmain->screen.first; sc; sc = sc->id.next) { + for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) { ED_render_engine_area_exit(bmain, sa); - + } + } RE_FreePersistentData(); - - for (scene = bmain->scene.first; scene; scene = scene->id.next) { - ED_render_id_flush_update(bmain, &scene->id); + /* Inform all render engines and draw managers. */ + DEGEditorUpdateContext update_ctx = {NULL}; + update_ctx.bmain = bmain; + for (Scene *scene = bmain->scene.first; scene; scene = scene->id.next) { + update_ctx.scene = scene; + LINKLIST_FOREACH(ViewLayer *, view_layer, &scene->view_layers) { + update_ctx.view_layer = view_layer; + ED_render_id_flush_update(&update_ctx, &scene->id); + } if (scene->nodetree) { ntreeCompositUpdateRLayers(scene->nodetree); } @@ -536,14 +530,18 @@ static void scene_changed(Main *bmain, Scene *scene) } } -void ED_render_id_flush_update(Main *bmain, ID *id) +void ED_render_id_flush_update(const DEGEditorUpdateContext *update_ctx, ID *id) { /* this can be called from render or baking thread when a python script makes * changes, in that case we don't want to do any editor updates, and making * GPU changes is not possible because OpenGL only works in the main thread */ - if (!BLI_thread_is_main()) + if (!BLI_thread_is_main()) { return; - + } + Main *bmain = update_ctx->bmain; + Scene *scene = update_ctx->scene; + ViewLayer *view_layer = update_ctx->view_layer; + /* Internal ID update handlers. */ switch (GS(id->name)) { case ID_MA: material_changed(bmain, (Material *)id); @@ -569,7 +567,42 @@ void ED_render_id_flush_update(Main *bmain, ID *id) render_engine_flag_changed(bmain, RE_ENGINE_UPDATE_OTHER); break; } - + /* Inform all draw managers about changes. + * + * TODO(sergey): This code is run for every updated ID, via flushing + * mechanism. How can we avoid iterating over the whole interface for + * every of those IDs? One of the ideas would be to call draw manager's + * ID update which is not bound to any of contexts. + */ + { + wmWindowManager *wm = bmain->wm.first; + for (wmWindow *win = wm->windows.first; win; win = win->next) { + bScreen *sc = WM_window_get_active_screen(win); + WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook); + ViewRender *view_render = BKE_viewrender_get(win->scene, workspace); + for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) { + if (sa->spacetype != SPACE_VIEW3D) { + continue; + } + for (ARegion *ar = sa->regionbase.first; ar; ar = ar->next) { + if (ar->regiontype != RGN_TYPE_WINDOW) { + continue; + } + RenderEngineType *engine_type = RE_engines_find(view_render->engine_id); + DRW_notify_id_update( + (&(DRWUpdateContext){ + .bmain = bmain, + .scene = scene, + .view_layer = view_layer, + .ar = ar, + .v3d = (View3D *)sa->spacedata.first, + .engine_type = engine_type + }), + id); + } + } + } + } } diff --git a/source/blender/editors/scene/scene_edit.c b/source/blender/editors/scene/scene_edit.c index c7f04a0e2f9..812f9a736bf 100644 --- a/source/blender/editors/scene/scene_edit.c +++ b/source/blender/editors/scene/scene_edit.c @@ -118,16 +118,20 @@ void ED_scene_exit(bContext *C) ED_object_editmode_exit(C, EM_FREEDATA | EM_DO_UNDO); } +static ViewLayer *scene_change_get_new_view_layer(const WorkSpace *workspace, const Scene *scene_new) +{ + ViewLayer *layer_new = BKE_workspace_view_layer_get(workspace, scene_new); + return layer_new ? layer_new : BKE_view_layer_from_scene_get(scene_new); +} + void ED_scene_changed_update(Main *bmain, bContext *C, Scene *scene_new, const bScreen *active_screen) { - /* XXX Just using active scene render-layer for workspace when switching, - * but workspace should remember the last one set. Could store render-layer - * per window-workspace combination (using WorkSpaceDataRelation) */ - ViewLayer *layer_new = BLI_findlink(&scene_new->view_layers, scene_new->active_view_layer); + WorkSpace *workspace = CTX_wm_workspace(C); + ViewLayer *layer_new = scene_change_get_new_view_layer(workspace, scene_new); Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene_new, layer_new, true); CTX_data_scene_set(C, scene_new); - BKE_workspace_view_layer_set(CTX_wm_workspace(C), layer_new); + BKE_workspace_view_layer_set(workspace, layer_new, scene_new); BKE_scene_set_background(bmain, scene_new); DEG_graph_relations_update(depsgraph, bmain, scene_new, layer_new); DEG_on_visible_update(bmain, false); @@ -186,7 +190,8 @@ bool ED_scene_view_layer_delete( BLI_assert(BLI_listbase_is_empty(&scene->view_layers) == false); scene->active_view_layer = 0; - ED_workspace_view_layer_unset(bmain, layer, scene->view_layers.first); + ED_workspace_view_layer_unset(bmain, scene, layer, scene->view_layers.first); + BKE_workspace_view_layer_remove_references(bmain, layer); view_layer_remove_unset_nodetrees(bmain, scene, layer); BKE_view_layer_free(layer); diff --git a/source/blender/editors/screen/area.c b/source/blender/editors/screen/area.c index e5ed2ff1d67..dbeac782e10 100644 --- a/source/blender/editors/screen/area.c +++ b/source/blender/editors/screen/area.c @@ -51,6 +51,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "WM_message.h" #include "wm_subwindow.h" #include "ED_screen.h" @@ -511,6 +512,33 @@ void ED_region_set(const bContext *C, ARegion *ar) ED_region_pixelspace(ar); } +/* Follow wmMsgNotifyFn spec */ +void ED_region_do_msg_notify_tag_redraw( + bContext *UNUSED(C), wmMsgSubscribeKey *UNUSED(msg_key), wmMsgSubscribeValue *msg_val) +{ + ARegion *ar = msg_val->owner; + ED_region_tag_redraw(ar); + + /* This avoids _many_ situations where header/properties control display settings. + * the common case is space properties in the header */ + if (ELEM(ar->regiontype, RGN_TYPE_HEADER, RGN_TYPE_UI)) { + while (ar && ar->prev) { + ar = ar->prev; + } + for (; ar; ar = ar->next) { + if (ELEM(ar->regiontype, RGN_TYPE_WINDOW, RGN_TYPE_CHANNELS)) { + ED_region_tag_redraw(ar); + } + } + } +} +/* Follow wmMsgNotifyFn spec */ +void ED_area_do_msg_notify_tag_refresh( + bContext *UNUSED(C), wmMsgSubscribeKey *UNUSED(msg_key), wmMsgSubscribeValue *msg_val) +{ + ScrArea *sa = msg_val->user_data; + ED_area_tag_refresh(sa); +} /* only exported for WM */ void ED_region_do_draw(bContext *C, ARegion *ar) @@ -589,6 +617,37 @@ void ED_region_do_draw(bContext *C, ARegion *ar) region_draw_emboss(ar, &ar->winrct); } } + + /* We may want to detach message-subscriptions from drawing. */ + { + WorkSpace *workspace = CTX_wm_workspace(C); + wmWindowManager *wm = CTX_wm_manager(C); + bScreen *screen = WM_window_get_active_screen(win); + Scene *scene = CTX_data_scene(C); + struct wmMsgBus *mbus = wm->message_bus; + WM_msgbus_clear_by_owner(mbus, ar); + + /* Cheat, always subscribe to this space type properties. + * + * This covers most cases and avoids copy-paste similar code for each space type. + */ + if (ELEM(ar->regiontype, RGN_TYPE_WINDOW, RGN_TYPE_CHANNELS, RGN_TYPE_UI, RGN_TYPE_TOOLS)) { + SpaceLink *sl = sa->spacedata.first; + + PointerRNA ptr; + RNA_pointer_create(&screen->id, &RNA_Space, sl, &ptr); + + wmMsgSubscribeValue msg_sub_value_region_tag_redraw = { + .owner = ar, + .user_data = ar, + .notify = ED_region_do_msg_notify_tag_redraw, + }; + /* All properties for this space type. */ + WM_msg_subscribe_rna(mbus, &ptr, NULL, &msg_sub_value_region_tag_redraw, __func__); + } + + ED_region_message_subscribe(C, workspace, scene, screen, sa, ar, mbus); + } } /* ********************************** @@ -2695,3 +2754,25 @@ void ED_region_cache_draw_cached_segments(const ARegion *ar, const int num_segme immUnbindProgram(); } } + +/** + * Generate subscriptions for this region. + */ +void ED_region_message_subscribe( + bContext *C, + struct WorkSpace *workspace, struct Scene *scene, + struct bScreen *screen, struct ScrArea *sa, struct ARegion *ar, + struct wmMsgBus *mbus) +{ + if (ar->manipulator_map != NULL) { + WM_manipulatormap_message_subscribe(C, ar->manipulator_map, ar, mbus); + } + + if (BLI_listbase_is_empty(&ar->uiblocks)) { + UI_region_message_subscribe(ar, mbus); + } + + if (ar->type->message_subscribe != NULL) { + ar->type->message_subscribe(C, workspace, scene, screen, sa, ar, mbus); + } +} diff --git a/source/blender/editors/screen/screen_context.c b/source/blender/editors/screen/screen_context.c index d84f256bc32..4c62253bef6 100644 --- a/source/blender/editors/screen/screen_context.c +++ b/source/blender/editors/screen/screen_context.c @@ -91,7 +91,7 @@ int ed_screen_context(const bContext *C, const char *member, bContextDataResult WorkSpace *workspace = BKE_workspace_active_get(win->workspace_hook); ViewLayer *view_layer = BKE_view_layer_from_workspace_get(scene, workspace); Object *obedit = scene->obedit; - Object *obact = view_layer->basact ? view_layer->basact->object : NULL; + Object *obact = (view_layer && view_layer->basact) ? view_layer->basact->object : NULL; if (CTX_data_dir(member)) { CTX_data_dir_set(result, screen_context_dir); diff --git a/source/blender/editors/screen/screen_edit.c b/source/blender/editors/screen/screen_edit.c index c1ea219ad04..4b5ce2f4b81 100644 --- a/source/blender/editors/screen/screen_edit.c +++ b/source/blender/editors/screen/screen_edit.c @@ -66,6 +66,8 @@ #include "UI_interface.h" +#include "WM_message.h" + /* XXX actually should be not here... solve later */ #include "wm_subwindow.h" @@ -897,6 +899,8 @@ void ED_region_exit(bContext *C, ARegion *ar) ar->regiontimer = NULL; } + WM_msgbus_clear_by_owner(wm->message_bus, ar); + CTX_wm_region_set(C, prevar); } diff --git a/source/blender/editors/screen/workspace_edit.c b/source/blender/editors/screen/workspace_edit.c index fb113816144..da9cb69b528 100644 --- a/source/blender/editors/screen/workspace_edit.c +++ b/source/blender/editors/screen/workspace_edit.c @@ -71,15 +71,16 @@ * \{ */ WorkSpace *ED_workspace_add( - Main *bmain, const char *name, ViewLayer *act_view_layer, ViewRender *view_render) + Main *bmain, const char *name, Scene *scene, + ViewLayer *act_view_layer, ViewRender *view_render) { WorkSpace *workspace = BKE_workspace_add(bmain, name); - BKE_workspace_view_layer_set(workspace, act_view_layer); + BKE_workspace_view_layer_set(workspace, act_view_layer, scene); BKE_viewrender_copy(&workspace->view_render, view_render); #ifdef USE_WORKSPACE_MODE - BKE_workspace_object_mode_set(workspace, OB_MODE_OBJECT); + BKE_workspace_object_mode_set(workspace, scene, OB_MODE_OBJECT); #endif return workspace; @@ -94,8 +95,9 @@ static void workspace_change_update_mode( const WorkSpace *workspace_old, const WorkSpace *workspace_new, bContext *C, Object *ob_act, ReportList *reports) { - eObjectMode mode_old = BKE_workspace_object_mode_get(workspace_old); - eObjectMode mode_new = BKE_workspace_object_mode_get(workspace_new); + const Scene *scene = CTX_data_scene(C); + eObjectMode mode_old = BKE_workspace_object_mode_get(workspace_old, scene); + eObjectMode mode_new = BKE_workspace_object_mode_get(workspace_new, scene); if (mode_old != mode_new) { ED_object_mode_compat_set(C, ob_act, mode_new, reports); @@ -105,10 +107,11 @@ static void workspace_change_update_mode( #endif static void workspace_change_update_view_layer( - WorkSpace *workspace_new, const WorkSpace *workspace_old) + WorkSpace *workspace_new, const WorkSpace *workspace_old, + Scene *scene) { - if (!BKE_workspace_view_layer_get(workspace_new)) { - BKE_workspace_view_layer_set(workspace_new, BKE_workspace_view_layer_get(workspace_old)); + if (!BKE_workspace_view_layer_get(workspace_new, scene)) { + BKE_workspace_view_layer_set(workspace_new, BKE_workspace_view_layer_get(workspace_old, scene), scene); } } @@ -117,7 +120,7 @@ static void workspace_change_update( bContext *C, wmWindowManager *wm) { /* needs to be done before changing mode! (to ensure right context) */ - workspace_change_update_view_layer(workspace_new, workspace_old); + workspace_change_update_view_layer(workspace_new, workspace_old, CTX_data_scene(C)); #ifdef USE_WORKSPACE_MODE workspace_change_update_mode(workspace_old, workspace_new, C, CTX_data_active_object(C), &wm->reports); #else @@ -199,7 +202,7 @@ bool ED_workspace_change( screen_changed_update(C, win, screen_new); workspace_change_update(workspace_new, workspace_old, C, wm); - BLI_assert(BKE_workspace_view_layer_get(workspace_new) != NULL); + BLI_assert(BKE_workspace_view_layer_get(workspace_new, CTX_data_scene(C)) != NULL); BLI_assert(CTX_wm_workspace(C) == workspace_new); WM_toolsystem_unlink(C, workspace_old); @@ -220,15 +223,16 @@ WorkSpace *ED_workspace_duplicate( { WorkSpaceLayout *layout_active_old = BKE_workspace_active_layout_get(win->workspace_hook); ListBase *layouts_old = BKE_workspace_layouts_get(workspace_old); + Scene *scene = WM_window_get_active_scene(win); WorkSpace *workspace_new = ED_workspace_add( - bmain, workspace_old->id.name + 2, - BKE_workspace_view_layer_get(workspace_old), + bmain, workspace_old->id.name + 2, scene, + BKE_workspace_view_layer_get(workspace_old, scene), &workspace_old->view_render); ListBase *transform_orientations_old = BKE_workspace_transform_orientations_get(workspace_old); ListBase *transform_orientations_new = BKE_workspace_transform_orientations_get(workspace_new); #ifdef USE_WORKSPACE_MODE - BKE_workspace_object_mode_set(workspace_new, BKE_workspace_object_mode_get(workspace_old)); + BKE_workspace_object_mode_set(workspace_new, scene, BKE_workspace_object_mode_get(workspace_old, scene)); #endif BLI_duplicatelist(transform_orientations_new, transform_orientations_old); @@ -279,11 +283,12 @@ void ED_workspace_scene_data_sync( } void ED_workspace_view_layer_unset( - const Main *bmain, const ViewLayer *layer_unset, ViewLayer *layer_new) + const Main *bmain, Scene *scene, + const ViewLayer *layer_unset, ViewLayer *layer_new) { for (WorkSpace *workspace = bmain->workspaces.first; workspace; workspace = workspace->id.next) { - if (BKE_workspace_view_layer_get(workspace) == layer_unset) { - BKE_workspace_view_layer_set(workspace, layer_new); + if (BKE_workspace_view_layer_get(workspace, scene) == layer_unset) { + BKE_workspace_view_layer_set(workspace, layer_new, scene); } } } diff --git a/source/blender/editors/space_buttons/buttons_context.c b/source/blender/editors/space_buttons/buttons_context.c index 183d715a93e..8866c6b6c40 100644 --- a/source/blender/editors/space_buttons/buttons_context.c +++ b/source/blender/editors/space_buttons/buttons_context.c @@ -39,6 +39,7 @@ #include "BLT_translation.h" #include "DNA_armature_types.h" +#include "DNA_group_types.h" #include "DNA_lamp_types.h" #include "DNA_material_types.h" #include "DNA_node_types.h" @@ -177,7 +178,7 @@ static int buttons_context_path_workspace(ButsContextPath *path) return RNA_struct_is_a(ptr->type, &RNA_WorkSpace); } -static int buttons_context_path_collection(ButsContextPath *path) +static int buttons_context_path_collection(ButsContextPath *path, eSpaceButtons_Collection_Context collection_context) { PointerRNA *ptr = &path->ptr[path->len - 1]; @@ -187,10 +188,21 @@ static int buttons_context_path_collection(ButsContextPath *path) } ViewLayer *view_layer = ptr->data; - LayerCollection *sc = BKE_layer_collection_get_active(view_layer); - if (sc) { - RNA_pointer_create(NULL, &RNA_LayerCollection, sc, &path->ptr[path->len]); + if (collection_context == SB_COLLECTION_CTX_GROUP) { + Object *ob = OBACT(view_layer); + if (ob && ob->dup_group) { + view_layer = ob->dup_group->view_layer; + + /* Replace the view layer by the group in the context path. */ + RNA_pointer_create(NULL, &RNA_Group, ob->dup_group, &path->ptr[path->len - 1]); + } + } + + LayerCollection *layer_collection = BKE_layer_collection_get_active(view_layer); + + if (layer_collection) { + RNA_pointer_create(NULL, &RNA_LayerCollection, layer_collection, &path->ptr[path->len]); path->len++; return 1; } @@ -650,7 +662,7 @@ static int buttons_context_path(const bContext *C, ButsContextPath *path, int ma found = buttons_context_path_workspace(path); break; case BCONTEXT_COLLECTION: - found = buttons_context_path_collection(path); + found = buttons_context_path_collection(path, sbuts->collection_context); break; case BCONTEXT_OBJECT: case BCONTEXT_PHYSICS: diff --git a/source/blender/editors/space_buttons/buttons_intern.h b/source/blender/editors/space_buttons/buttons_intern.h index 7fc35a6b1e7..e6d19caad47 100644 --- a/source/blender/editors/space_buttons/buttons_intern.h +++ b/source/blender/editors/space_buttons/buttons_intern.h @@ -65,6 +65,7 @@ typedef struct ButsContextPath { int len; int flag; int tex_ctx; + int collection_ctx; } ButsContextPath; typedef struct ButsTextureUser { diff --git a/source/blender/editors/space_buttons/space_buttons.c b/source/blender/editors/space_buttons/space_buttons.c index 74b20360a53..d2f407bfa8c 100644 --- a/source/blender/editors/space_buttons/space_buttons.c +++ b/source/blender/editors/space_buttons/space_buttons.c @@ -44,6 +44,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "WM_message.h" #include "RNA_access.h" diff --git a/source/blender/editors/space_file/file_ops.c b/source/blender/editors/space_file/file_ops.c index cca33cdd1a7..217ce8f1d9a 100644 --- a/source/blender/editors/space_file/file_ops.c +++ b/source/blender/editors/space_file/file_ops.c @@ -151,15 +151,25 @@ static FileSelection file_selection_get(bContext *C, const rcti *rect, bool fill /* if desired, fill the selection up from the last selected file to the current one */ if (fill && (sel.last >= 0) && (sel.last < numfiles) ) { - int f = sel.last; - while (f >= 0) { + int f; + /* Try to find a smaller-index selected item. */ + for (f = sel.last; f >= 0; f--) { if (filelist_entry_select_index_get(sfile->files, f, CHECK_ALL) ) break; - f--; } if (f >= 0) { sel.first = f + 1; } + /* If none found, try to find a higher-index selected item. */ + else { + for (f = sel.first; f < numfiles; f++) { + if (filelist_entry_select_index_get(sfile->files, f, CHECK_ALL) ) + break; + } + if (f < numfiles) { + sel.last = f - 1; + } + } } return sel; } diff --git a/source/blender/editors/space_file/space_file.c b/source/blender/editors/space_file/space_file.c index 780c2ec5a47..3f26604c23a 100644 --- a/source/blender/editors/space_file/space_file.c +++ b/source/blender/editors/space_file/space_file.c @@ -49,6 +49,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "WM_message.h" #include "ED_space_api.h" #include "ED_screen.h" @@ -354,6 +355,33 @@ static void file_main_region_listener( } } +static void file_main_region_message_subscribe( + const struct bContext *UNUSED(C), + struct WorkSpace *UNUSED(workspace), struct Scene *UNUSED(scene), + struct bScreen *screen, struct ScrArea *sa, struct ARegion *ar, + struct wmMsgBus *mbus) +{ + SpaceFile *sfile = sa->spacedata.first; + FileSelectParams *params = ED_fileselect_get_params(sfile); + /* This is a bit odd that a region owns the subscriber for an area, + * keep for now since all subscribers for WM are regions. + * May be worth re-visiting later. */ + wmMsgSubscribeValue msg_sub_value_area_tag_refresh = { + .owner = ar, + .user_data = sa, + .notify = ED_area_do_msg_notify_tag_refresh, + }; + + /* FileSelectParams */ + { + PointerRNA ptr; + RNA_pointer_create(&screen->id, &RNA_FileSelectParams, params, &ptr); + + /* All properties for this space type. */ + WM_msg_subscribe_rna(mbus, &ptr, NULL, &msg_sub_value_area_tag_refresh, __func__); + } +} + static void file_main_region_draw(const bContext *C, ARegion *ar) { /* draw entirely, view changes should be handled here */ @@ -731,6 +759,7 @@ void ED_spacetype_file(void) art->init = file_main_region_init; art->draw = file_main_region_draw; art->listener = file_main_region_listener; + art->message_subscribe = file_main_region_message_subscribe; art->keymapflag = ED_KEYMAP_UI | ED_KEYMAP_VIEW2D; BLI_addhead(&st->regiontypes, art); diff --git a/source/blender/editors/space_info/info_stats.c b/source/blender/editors/space_info/info_stats.c index 53709e4cea7..3cf833756ef 100644 --- a/source/blender/editors/space_info/info_stats.c +++ b/source/blender/editors/space_info/info_stats.c @@ -270,6 +270,39 @@ static void stats_object_sculpt_dynamic_topology(Object *ob, SceneStats *stats) stats->tottri = ob->sculpt->bm->totface; } +static void stats_dupli_object_group_count(SceneCollection *scene_collection, int *count) +{ + for (LinkData *link = scene_collection->objects.first; link; link = link->next) { + (*count)++; + } + + SceneCollection *scene_collection_nested; + for (scene_collection_nested = scene_collection->scene_collections.first; + scene_collection_nested; + scene_collection_nested = scene_collection_nested->next) + { + stats_dupli_object_group_count(scene_collection_nested, count); + } +} + +static void stats_dupli_object_group_doit(SceneCollection *scene_collection, SceneStats *stats, ParticleSystem *psys, + const int totgroup, int *cur) +{ + for (LinkData *link = scene_collection->objects.first; link; link = link->next) { + int tot = count_particles_mod(psys, totgroup, *cur); + stats_object(link->data, 0, tot, stats); + (*cur)++; + } + + SceneCollection *scene_collection_nested; + for (scene_collection_nested = scene_collection->scene_collections.first; + scene_collection_nested; + scene_collection_nested = scene_collection_nested->next) + { + stats_dupli_object_group_doit(scene_collection_nested, stats, psys, totgroup, cur); + } +} + static void stats_dupli_object(Base *base, Object *ob, SceneStats *stats) { if (base->flag & BASE_SELECTED) stats->totobjsel++; @@ -287,17 +320,11 @@ static void stats_dupli_object(Base *base, Object *ob, SceneStats *stats) stats_object(part->dup_ob, 0, tot, stats); } else if (part->draw_as == PART_DRAW_GR && part->dup_group) { - GroupObject *go; - int tot, totgroup = 0, cur = 0; - - for (go = part->dup_group->gobject.first; go; go = go->next) - totgroup++; - - for (go = part->dup_group->gobject.first; go; go = go->next) { - tot = count_particles_mod(psys, totgroup, cur); - stats_object(go->ob, 0, tot, stats); - cur++; - } + int totgroup = 0, cur = 0; + + SceneCollection *scene_collection = part->dup_group->collection; + stats_dupli_object_group_count(scene_collection, &totgroup); + stats_dupli_object_group_doit(scene_collection, stats, psys, totgroup, &cur); } } diff --git a/source/blender/editors/space_outliner/outliner_collections.c b/source/blender/editors/space_outliner/outliner_collections.c index adf7e1dc5d3..d5c833a7b5f 100644 --- a/source/blender/editors/space_outliner/outliner_collections.c +++ b/source/blender/editors/space_outliner/outliner_collections.c @@ -36,6 +36,8 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" +#include "DNA_group_types.h" + #include "ED_screen.h" #include "WM_api.h" @@ -110,7 +112,7 @@ static int collection_link_exec(bContext *C, wmOperator *op) { Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); - SceneCollection *sc_master = BKE_collection_master(scene); + SceneCollection *sc_master = BKE_collection_master(&scene->id); SceneCollection *sc; int scene_collection_index = RNA_enum_get(op->ptr, "scene_collection"); @@ -136,7 +138,9 @@ static int collection_link_exec(bContext *C, wmOperator *op) static int collection_link_invoke(bContext *C, wmOperator *op, const wmEvent *event) { - if (BKE_collection_master(CTX_data_scene(C))->scene_collections.first == NULL) { + Scene *scene = CTX_data_scene(C); + SceneCollection *master_collection = BKE_collection_master(&scene->id); + if (master_collection->scene_collections.first == NULL) { RNA_enum_set(op->ptr, "scene_collection", 0); return collection_link_exec(C, op); } @@ -169,7 +173,7 @@ static const EnumPropertyItem *collection_scene_collection_itemf( int value = 0, totitem = 0; Scene *scene = CTX_data_scene(C); - SceneCollection *sc = BKE_collection_master(scene); + SceneCollection *sc = BKE_collection_master(&scene->id); collection_scene_collection_itemf_recursive(&tmp, &item, &totitem, &value, sc); RNA_enum_item_end(&item, &totitem); @@ -257,15 +261,18 @@ void OUTLINER_OT_collection_unlink(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/**********************************************************************************/ +/* Add new collection. */ + static int collection_new_exec(bContext *C, wmOperator *UNUSED(op)) { + Main *bmain = CTX_data_main(C); Scene *scene = CTX_data_scene(C); ViewLayer *view_layer = CTX_data_view_layer(C); + SceneCollection *scene_collection = BKE_collection_add(&scene->id, NULL, COLLECTION_TYPE_NONE, NULL); + BKE_collection_link(view_layer, scene_collection); - SceneCollection *sc = BKE_collection_add(scene, NULL, NULL); - BKE_collection_link(view_layer, sc); - - DEG_relations_tag_update(CTX_data_main(C)); + DEG_relations_tag_update(bmain); WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); return OPERATOR_FINISHED; } @@ -275,7 +282,7 @@ void OUTLINER_OT_collection_new(wmOperatorType *ot) /* identifiers */ ot->name = "New Collection"; ot->idname = "OUTLINER_OT_collection_new"; - ot->description = "Add a new collection to the scene, and link it to the active layer"; + ot->description = "Add a new collection to the scene"; /* api callbacks */ ot->exec = collection_new_exec; @@ -284,6 +291,8 @@ void OUTLINER_OT_collection_new(wmOperatorType *ot) ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; } +/**********************************************************************************/ + /** * Returns true is selected element is a collection */ @@ -325,9 +334,10 @@ void OUTLINER_OT_collection_override_new(wmOperatorType *ot) struct CollectionDeleteData { Scene *scene; SpaceOops *soops; + GSet *collections_to_delete; }; -static TreeTraversalAction collection_delete_cb(TreeElement *te, void *customdata) +static TreeTraversalAction collection_find_data_to_delete(TreeElement *te, void *customdata) { struct CollectionDeleteData *data = customdata; SceneCollection *scene_collection = outliner_scene_collection_from_tree_element(te); @@ -336,12 +346,12 @@ static TreeTraversalAction collection_delete_cb(TreeElement *te, void *customdat return TRAVERSE_SKIP_CHILDS; } - if (scene_collection == BKE_collection_master(data->scene)) { + if (scene_collection == BKE_collection_master(&data->scene->id)) { /* skip - showing warning/error message might be missleading * when deleting multiple collections, so just do nothing */ } else { - BKE_collection_remove(data->scene, scene_collection); + BLI_gset_add(data->collections_to_delete, scene_collection); } return TRAVERSE_CONTINUE; @@ -353,8 +363,22 @@ static int collection_delete_exec(bContext *C, wmOperator *UNUSED(op)) SpaceOops *soops = CTX_wm_space_outliner(C); struct CollectionDeleteData data = {.scene = scene, .soops = soops}; + data.collections_to_delete = BLI_gset_ptr_new(__func__); + TODO_LAYER_OVERRIDE; /* handle overrides */ - outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_delete_cb, &data); + + /* We first walk over and find the SceneCollections we actually want to delete (ignoring duplicates). */ + outliner_tree_traverse(soops, &soops->tree, 0, TSE_SELECTED, collection_find_data_to_delete, &data); + + /* Effectively delete the collections. */ + GSetIterator collections_to_delete_iter; + GSET_ITER(collections_to_delete_iter, data.collections_to_delete) { + + SceneCollection *sc = BLI_gsetIterator_getKey(&collections_to_delete_iter); + BKE_collection_remove(&data.scene->id, sc); + } + + BLI_gset_free(data.collections_to_delete, NULL); DEG_relations_tag_update(CTX_data_main(C)); diff --git a/source/blender/editors/space_outliner/outliner_draw.c b/source/blender/editors/space_outliner/outliner_draw.c index 8b4ed61f148..670fc4e6627 100644 --- a/source/blender/editors/space_outliner/outliner_draw.c +++ b/source/blender/editors/space_outliner/outliner_draw.c @@ -250,9 +250,16 @@ static void restrictbutton_gp_layer_flag_cb(bContext *C, void *UNUSED(poin), voi static void enablebutton_collection_flag_cb(bContext *C, void *poin, void *poin2) { Main *bmain = CTX_data_main(C); - Scene *scene = poin; + Scene *scene = CTX_data_scene(C); + ID *id = poin; LayerCollection *layer_collection = poin2; - ViewLayer *view_layer = BKE_view_layer_find_from_collection(scene, layer_collection); + ViewLayer *view_layer = BKE_view_layer_find_from_collection(id, layer_collection); + + /* TODO: This breaks when you see the collections of a group. (dfelinto) */ + if (view_layer == NULL) { + WM_reportf(RPT_INFO, "Enable/disable of group collections disabled for now"); + return; + } /* We need to toggle the flag since this is called after the flag is already set. */ layer_collection->flag ^= COLLECTION_DISABLED; @@ -273,11 +280,16 @@ static void enablebutton_collection_flag_cb(bContext *C, void *poin, void *poin2 static void restrictbutton_collection_flag_cb(bContext *C, void *poin, void *UNUSED(poin2)) { - Scene *scene = poin; + ID *id = (ID *)poin; + /* hide and deselect bases that are directly influenced by this LayerCollection */ /* TODO(sergey): Use proper flag for tagging here. */ - DEG_id_tag_update(&scene->id, 0); - WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); + DEG_id_tag_update(id, 0); + + if (GS(id->name) == ID_SCE) { + WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, id); + } + WM_event_add_notifier(C, NC_SCENE | ND_LAYER_CONTENT, NULL); } @@ -595,22 +607,24 @@ static void outliner_draw_restrictbuts(uiBlock *block, Scene *scene, ARegion *ar (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_ENABLEX), te->ys, UI_UNIT_X, UI_UNIT_Y, &collection->flag, 0, 0, 0, 0, TIP_("Enable/Disable collection from depsgraph")); - UI_but_func_set(bt, enablebutton_collection_flag_cb, scene, collection); + UI_but_func_set(bt, enablebutton_collection_flag_cb, tselem->id, collection); UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_VISIBLE, 0, ICON_RESTRICT_VIEW_OFF, (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_VIEWX), te->ys, UI_UNIT_X, UI_UNIT_Y, &collection->flag, 0, 0, 0, 0, TIP_("Restrict/Allow 3D View visibility of objects in the collection")); - UI_but_func_set(bt, restrictbutton_collection_flag_cb, scene, collection); + UI_but_func_set(bt, restrictbutton_collection_flag_cb, tselem->id, collection); UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); - bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_SELECTABLE, 0, ICON_RESTRICT_SELECT_OFF, - (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X, - UI_UNIT_Y, &collection->flag, 0, 0, 0, 0, - TIP_("Restrict/Allow 3D View selection of objects in the collection")); - UI_but_func_set(bt, restrictbutton_collection_flag_cb, scene, collection); - UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + if (collection->scene_collection->type == COLLECTION_TYPE_NONE) { + bt = uiDefIconButBitS(block, UI_BTYPE_ICON_TOGGLE_N, COLLECTION_SELECTABLE, 0, ICON_RESTRICT_SELECT_OFF, + (int)(ar->v2d.cur.xmax - OL_TOG_RESTRICT_SELECTX), te->ys, UI_UNIT_X, + UI_UNIT_Y, &collection->flag, 0, 0, 0, 0, + TIP_("Restrict/Allow 3D View selection of objects in the collection")); + UI_but_func_set(bt, restrictbutton_collection_flag_cb, scene, collection); + UI_but_flag_enable(bt, UI_BUT_DRAG_LOCK); + } UI_block_emboss_set(block, UI_EMBOSS); } diff --git a/source/blender/editors/space_outliner/outliner_edit.c b/source/blender/editors/space_outliner/outliner_edit.c index 4858b6cb120..8cd76179f23 100644 --- a/source/blender/editors/space_outliner/outliner_edit.c +++ b/source/blender/editors/space_outliner/outliner_edit.c @@ -274,7 +274,7 @@ static void do_item_rename(const Scene *scene, ARegion *ar, TreeElement *te, Tre BKE_report(reports, RPT_WARNING, "Cannot edit sequence name"); } else if (ELEM(tselem->type, TSE_LAYER_COLLECTION, TSE_SCENE_COLLECTION)) { - SceneCollection *master = BKE_collection_master(scene); + SceneCollection *master = BKE_collection_master(&scene->id); if ((tselem->type == TSE_SCENE_COLLECTION && te->directdata == master) || (((LayerCollection *)te->directdata)->scene_collection == master)) @@ -1940,7 +1940,7 @@ static int parent_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) BLI_assert(scene); RNA_string_get(op->ptr, "child", childname); ob = (Object *)BKE_libblock_find_name(ID_OB, childname); - BKE_collection_object_add(scene, sc, ob); + BKE_collection_object_add(&scene->id, sc, ob); DEG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); @@ -2166,13 +2166,13 @@ static int scene_drop_invoke(bContext *C, wmOperator *op, const wmEvent *event) SceneCollection *sc; if (scene != CTX_data_scene(C)) { /* when linking to an inactive scene link to the master collection */ - sc = BKE_collection_master(scene); + sc = BKE_collection_master(&scene->id); } else { sc = CTX_data_scene_collection(C); } - BKE_collection_object_add(scene, sc, ob); + BKE_collection_object_add(&scene->id, sc, ob); for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) { Base *base = BKE_view_layer_base_find(view_layer, ob); diff --git a/source/blender/editors/space_outliner/outliner_intern.h b/source/blender/editors/space_outliner/outliner_intern.h index 23e1b766891..f69eb9af1bf 100644 --- a/source/blender/editors/space_outliner/outliner_intern.h +++ b/source/blender/editors/space_outliner/outliner_intern.h @@ -67,9 +67,8 @@ typedef enum TreeTraversalAction { /** * Callback type for reinserting elements at a different position, used to allow user customizable element order. - * Passing scene right now, may be better to allow some custom data. */ -typedef void (*TreeElementReinsertFunc)(struct Main *bmain, const struct Scene *scene, +typedef void (*TreeElementReinsertFunc)(struct Main *bmain, struct TreeElement *insert_element, struct TreeElement *insert_handle, TreeElementInsertType action); /** @@ -77,7 +76,7 @@ typedef void (*TreeElementReinsertFunc)(struct Main *bmain, const struct Scene * * if reinserting insert_element before/after/into insert_handle would be allowed. * It's allowed to change the reinsert info here for non const pointers. */ -typedef bool (*TreeElementReinsertPollFunc)(const struct Scene *scene, const struct TreeElement *insert_element, +typedef bool (*TreeElementReinsertPollFunc)(const struct TreeElement *insert_element, struct TreeElement **io_insert_handle, TreeElementInsertType *io_action); typedef TreeTraversalAction (*TreeTraversalFunc)(struct TreeElement *te, void *customdata); diff --git a/source/blender/editors/space_outliner/outliner_ops.c b/source/blender/editors/space_outliner/outliner_ops.c index aa6a5dba6a7..856dd022c14 100644 --- a/source/blender/editors/space_outliner/outliner_ops.c +++ b/source/blender/editors/space_outliner/outliner_ops.c @@ -58,7 +58,7 @@ static int outliner_item_drag_drop_poll(bContext *C) SpaceOops *soops = CTX_wm_space_outliner(C); return ED_operator_outliner_active(C) && /* Only collection display modes supported for now. Others need more design work */ - ELEM(soops->outlinevis, SO_ACT_LAYER, SO_COLLECTIONS); + ELEM(soops->outlinevis, SO_ACT_LAYER, SO_COLLECTIONS, SO_GROUPS); } static TreeElement *outliner_item_drag_element_find(SpaceOops *soops, ARegion *ar, const wmEvent *event) @@ -138,7 +138,7 @@ static void outliner_item_drag_get_insert_data( } static void outliner_item_drag_handle( - const Scene *scene, SpaceOops *soops, ARegion *ar, const wmEvent *event, TreeElement *te_dragged) + SpaceOops *soops, ARegion *ar, const wmEvent *event, TreeElement *te_dragged) { TreeElement *te_insert_handle; TreeElementInsertType insert_type; @@ -156,7 +156,7 @@ static void outliner_item_drag_handle( /* nothing will happen anyway, no need to do poll check */ } else if (!te_dragged->reinsert_poll || - !te_dragged->reinsert_poll(scene, te_dragged, &te_insert_handle, &insert_type)) + !te_dragged->reinsert_poll(te_dragged, &te_insert_handle, &insert_type)) { te_insert_handle = NULL; } @@ -164,7 +164,7 @@ static void outliner_item_drag_handle( te_dragged->drag_data->insert_handle = te_insert_handle; } -static bool outliner_item_drag_drop_apply(Main *bmain, const Scene *scene, TreeElement *dragged_te) +static bool outliner_item_drag_drop_apply(Main *bmain, TreeElement *dragged_te) { TreeElement *insert_handle = dragged_te->drag_data->insert_handle; TreeElementInsertType insert_type = dragged_te->drag_data->insert_type; @@ -173,12 +173,12 @@ static bool outliner_item_drag_drop_apply(Main *bmain, const Scene *scene, TreeE /* No need to do anything */ } else if (dragged_te->reinsert) { - BLI_assert(!dragged_te->reinsert_poll || dragged_te->reinsert_poll(scene, dragged_te, &insert_handle, + BLI_assert(!dragged_te->reinsert_poll || dragged_te->reinsert_poll(dragged_te, &insert_handle, &insert_type)); /* call of assert above should not have changed insert_handle and insert_type at this point */ BLI_assert(dragged_te->drag_data->insert_handle == insert_handle && dragged_te->drag_data->insert_type == insert_type); - dragged_te->reinsert(bmain, scene, dragged_te, insert_handle, insert_type); + dragged_te->reinsert(bmain, dragged_te, insert_handle, insert_type); return true; } @@ -188,7 +188,6 @@ static bool outliner_item_drag_drop_apply(Main *bmain, const Scene *scene, TreeE static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEvent *event) { Main *bmain = CTX_data_main(C); - Scene *scene = CTX_data_scene(C); ARegion *ar = CTX_wm_region(C); SpaceOops *soops = CTX_wm_space_outliner(C); TreeElement *te_dragged = op->customdata; @@ -199,7 +198,7 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv switch (event->type) { case EVT_MODAL_MAP: if (event->val == OUTLINER_ITEM_DRAG_CONFIRM) { - if (outliner_item_drag_drop_apply(bmain, scene, te_dragged)) { + if (outliner_item_drag_drop_apply(bmain, te_dragged)) { skip_rebuild = false; } retval = OPERATOR_FINISHED; @@ -215,7 +214,7 @@ static int outliner_item_drag_drop_modal(bContext *C, wmOperator *op, const wmEv redraw = true; break; case MOUSEMOVE: - outliner_item_drag_handle(scene, soops, ar, event, te_dragged); + outliner_item_drag_handle(soops, ar, event, te_dragged); redraw = true; break; } diff --git a/source/blender/editors/space_outliner/outliner_select.c b/source/blender/editors/space_outliner/outliner_select.c index 5215efaa05c..08b5f337936 100644 --- a/source/blender/editors/space_outliner/outliner_select.c +++ b/source/blender/editors/space_outliner/outliner_select.c @@ -44,6 +44,7 @@ #include "BLI_listbase.h" #include "BKE_context.h" +#include "BKE_group.h" #include "BKE_object.h" #include "BKE_layer.h" #include "BKE_scene.h" @@ -780,12 +781,23 @@ static eOLDrawState tree_element_active_collection( /* don't allow selecting a scene collection, it can have multiple layer collection * instances (which one would the user want to be selected then?) */ else if (tselem->type == TSE_LAYER_COLLECTION) { - ViewLayer *view_layer = CTX_data_view_layer(C); - LayerCollection *lc = te->directdata; - const int collection_index = BKE_layer_collection_findindex(view_layer, lc); + LayerCollection *layer_collection = te->directdata; + + switch (layer_collection->scene_collection->type) { + case COLLECTION_TYPE_NONE: + case COLLECTION_TYPE_GROUP_INTERNAL: + { + ViewLayer *view_layer = BKE_view_layer_find_from_collection(tselem->id, layer_collection); + const int collection_index = BKE_layer_collection_findindex(view_layer, layer_collection); - BLI_assert(collection_index >= 0); - view_layer->active_collection = collection_index; + if (collection_index > -1) { + view_layer->active_collection = collection_index; + } + break; + } + default: + BLI_assert(!"Collection type not fully implemented"); + } WM_main_add_notifier(NC_SCENE | ND_LAYER, NULL); } @@ -906,26 +918,30 @@ static void do_outliner_item_activate_tree_element( } else if (te->idcode == ID_GR) { Group *gr = (Group *)tselem->id; - GroupObject *gob; if (extend) { int sel = BA_SELECT; - for (gob = gr->gobject.first; gob; gob = gob->next) { - if (gob->ob->flag & SELECT) { + FOREACH_GROUP_BASE(gr, base) + { + if (base->flag & BASE_SELECTED) { sel = BA_DESELECT; break; } } + FOREACH_GROUP_BASE_END - for (gob = gr->gobject.first; gob; gob = gob->next) { - ED_object_base_select(BKE_view_layer_base_find(view_layer, gob->ob), sel); + FOREACH_GROUP_OBJECT(gr, object) + { + ED_object_base_select(BKE_view_layer_base_find(view_layer, object), sel); } + FOREACH_GROUP_OBJECT_END } else { BKE_view_layer_base_deselect_all(view_layer); - for (gob = gr->gobject.first; gob; gob = gob->next) { - Base *base = BKE_view_layer_base_find(view_layer, gob->ob); + FOREACH_GROUP_OBJECT(gr, object) + { + Base *base = BKE_view_layer_base_find(view_layer, object); /* Object may not be in this scene */ if (base != NULL) { if ((base->flag & BASE_SELECTED) == 0) { @@ -933,6 +949,7 @@ static void do_outliner_item_activate_tree_element( } } } + FOREACH_GROUP_OBJECT_END } WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 63e1a527138..99fd539293f 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -525,20 +525,21 @@ static void group_linkobs2scene_cb( ViewLayer *view_layer = CTX_data_view_layer(C); SceneCollection *sc = CTX_data_scene_collection(C); Group *group = (Group *)tselem->id; - GroupObject *gob; Base *base; - for (gob = group->gobject.first; gob; gob = gob->next) { - base = BKE_view_layer_base_find(view_layer, gob->ob); + FOREACH_GROUP_OBJECT(group, object) + { + base = BKE_view_layer_base_find(view_layer, object); if (!base) { /* link to scene */ - BKE_collection_object_add(scene, sc, gob->ob); - base = BKE_view_layer_base_find(view_layer, gob->ob); - id_us_plus(&gob->ob->id); + BKE_collection_object_add(&scene->id, sc, object); + base = BKE_view_layer_base_find(view_layer, object); + id_us_plus(&object->id); } base->flag |= BASE_SELECTED; } + FOREACH_GROUP_OBJECT_END } static void group_instance_cb( @@ -663,6 +664,7 @@ typedef enum eOutliner_PropCollectionOps { OL_COLLECTION_OP_COLLECTION_NEW, OL_COLLECTION_OP_COLLECTION_DEL, OL_COLLECTION_OP_COLLECTION_UNLINK, + OL_COLLECTION_OP_GROUP_CREATE, } eOutliner_PropCollectionOps; static void pchan_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tselem), void *UNUSED(arg)) @@ -820,12 +822,13 @@ static void collection_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tsel bContext *C = (bContext *)Carg; Scene *scene = CTX_data_scene(C); LayerCollection *lc = te->directdata; + ID *id = te->store_elem->id; SceneCollection *sc = lc->scene_collection; if (event == OL_COLLECTION_OP_OBJECTS_ADD) { CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { - BKE_collection_object_add(scene, sc, ob); + BKE_collection_object_add(id, sc, ob); } CTX_DATA_END; @@ -836,7 +839,7 @@ static void collection_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tsel CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { - BKE_collection_object_remove(bmain, scene, sc, ob, true); + BKE_collection_object_remove(bmain, id, sc, ob, true); } CTX_DATA_END; @@ -844,7 +847,13 @@ static void collection_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tsel te->store_elem->flag &= ~TSE_SELECTED; } else if (event == OL_COLLECTION_OP_COLLECTION_NEW) { - BKE_collection_add(scene, sc, NULL); + if (GS(id->name) == ID_GR) { + BKE_collection_add(id, sc, COLLECTION_TYPE_GROUP_INTERNAL, NULL); + } + else { + BLI_assert(GS(id->name) == ID_SCE); + BKE_collection_add(id, sc, COLLECTION_TYPE_NONE, NULL); + } WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); } else if (event == OL_COLLECTION_OP_COLLECTION_UNLINK) { @@ -861,7 +870,7 @@ static void collection_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tsel } } else if (event == OL_COLLECTION_OP_COLLECTION_DEL) { - if (BKE_collection_remove(scene, sc)) { + if (BKE_collection_remove(id, sc)) { DEG_relations_tag_update(CTX_data_main(C)); WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); } @@ -870,6 +879,17 @@ static void collection_cb(int event, TreeElement *te, TreeStoreElem *UNUSED(tsel TODO_LAYER_OPERATORS; /* this shouldn't be in the menu in those cases */ } } + else if (event == OL_COLLECTION_OP_GROUP_CREATE) { + Main *bmain = CTX_data_main(C); + BKE_collection_group_create(bmain, scene, lc); + DEG_relations_tag_update(bmain); + /* TODO(sergey): Use proper flag for tagging here. */ + DEG_id_tag_update(&scene->id, 0); + WM_event_add_notifier(C, NC_SCENE | ND_LAYER, scene); + } + else { + BLI_assert(!"Collection operation not fully implemented!"); + } } static void outliner_do_data_operation(SpaceOops *soops, int type, int event, ListBase *lb, @@ -1794,15 +1814,39 @@ void OUTLINER_OT_modifier_operation(wmOperatorType *ot) /* ******************** */ -static EnumPropertyItem prop_collection_op_types[] = { - {OL_COLLECTION_OP_OBJECTS_ADD, "OBJECTS_ADD", ICON_ZOOMIN, "Add Selected", "Add selected objects to collection"}, - {OL_COLLECTION_OP_OBJECTS_REMOVE, "OBJECTS_REMOVE", ICON_X, "Remove Selected", "Remove selected objects from collection"}, - {OL_COLLECTION_OP_COLLECTION_NEW, "COLLECTION_NEW", ICON_NEW, "New Collection", "Add a new nested collection"}, - {OL_COLLECTION_OP_COLLECTION_UNLINK, "COLLECTION_UNLINK", ICON_UNLINKED, "Unlink", "Unlink collection"}, - {OL_COLLECTION_OP_COLLECTION_DEL, "COLLECTION_DEL", ICON_X, "Delete Collection", "Delete the collection"}, - {0, NULL, 0, NULL, NULL} +static EnumPropertyItem prop_collection_op_none_types[] = { + {OL_COLLECTION_OP_OBJECTS_ADD, "OBJECTS_ADD", ICON_ZOOMIN, "Add Selected", "Add selected objects to collection"}, + {OL_COLLECTION_OP_OBJECTS_REMOVE, "OBJECTS_REMOVE", ICON_X, "Remove Selected", "Remove selected objects from collection"}, + {OL_COLLECTION_OP_COLLECTION_NEW, "COLLECTION_NEW", ICON_NEW, "New Collection", "Add a new nested collection"}, + {OL_COLLECTION_OP_COLLECTION_UNLINK, "COLLECTION_UNLINK", ICON_UNLINKED, "Unlink", "Unlink collection"}, + {OL_COLLECTION_OP_COLLECTION_DEL, "COLLECTION_DEL", ICON_X, "Delete Collection", "Delete the collection"}, + {OL_COLLECTION_OP_GROUP_CREATE, "GROUP_CREATE", ICON_GROUP, "Create Group", "Turn the collection into a group collection"}, + {0, NULL, 0, NULL, NULL} +}; + +static EnumPropertyItem prop_collection_op_group_internal_types[] = { + {OL_COLLECTION_OP_OBJECTS_ADD, "OBJECTS_ADD", ICON_ZOOMIN, "Add Selected", "Add selected objects to collection"}, + {OL_COLLECTION_OP_OBJECTS_REMOVE, "OBJECTS_REMOVE", ICON_X, "Remove Selected", "Remove selected objects from collection"}, + {OL_COLLECTION_OP_COLLECTION_NEW, "COLLECTION_NEW", ICON_NEW, "New Collection", "Add a new nested collection"}, + {OL_COLLECTION_OP_COLLECTION_DEL, "COLLECTION_DEL", ICON_X, "Delete Collection", "Delete the collection"}, + {0, NULL, 0, NULL, NULL} }; +static const EnumPropertyItem *outliner_collection_operation_type_itemf( + bContext *C, PointerRNA *UNUSED(ptr), PropertyRNA *UNUSED(prop), bool *r_free) +{ + *r_free = false; + SpaceOops *soops = CTX_wm_space_outliner(C); + + switch (soops->outlinevis) { + case SO_GROUPS: + return prop_collection_op_group_internal_types; + case SO_ACT_LAYER: + return prop_collection_op_none_types; + } + return NULL; +} + static int outliner_collection_operation_exec(bContext *C, wmOperator *op) { SpaceOops *soops = CTX_wm_space_outliner(C); @@ -1823,6 +1867,8 @@ static int outliner_collection_operation_exec(bContext *C, wmOperator *op) void OUTLINER_OT_collection_operation(wmOperatorType *ot) { + PropertyRNA *prop; + /* identifiers */ ot->name = "Outliner Collection Operation"; ot->idname = "OUTLINER_OT_collection_operation"; @@ -1835,7 +1881,10 @@ void OUTLINER_OT_collection_operation(wmOperatorType *ot) ot->flag = 0; - ot->prop = RNA_def_enum(ot->srna, "type", prop_collection_op_types, 0, "Collection Operation", ""); + prop = RNA_def_enum(ot->srna, "type", DummyRNA_NULL_items, 0, "Collection Operation", ""); + RNA_def_enum_funcs(prop, outliner_collection_operation_type_itemf); + RNA_def_property_flag(prop, PROP_ENUM_NO_TRANSLATE); + ot->prop = prop; } /* ******************** */ diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 1ab715d0246..a9c9ab74970 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -88,6 +88,8 @@ #endif /* prototypes */ +static void outliner_add_layer_collections_recursive( + SpaceOops *soops, ListBase *tree, ID *id, ListBase *layer_collections, TreeElement *parent_ten); static void outliner_make_hierarchy(ListBase *lb); /* ********************************************************* */ @@ -386,13 +388,14 @@ static void outliner_add_scene_contents(SpaceOops *soops, ListBase *lb, Scene *s } static void outliner_object_reorder( - Main *UNUSED(bmain), const Scene *scene, + Main *UNUSED(bmain), TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action) { TreeStoreElem *tselem_insert = TREESTORE(insert_element); Object *ob = (Object *)tselem_insert->id; SceneCollection *sc = outliner_scene_collection_from_tree_element(insert_handle); SceneCollection *sc_ob_parent = NULL; + ID *id = insert_handle->store_elem->id; BLI_assert(action == TE_INSERT_INTO); UNUSED_VARS_NDEBUG(action); @@ -407,13 +410,13 @@ static void outliner_object_reorder( } } else { - sc_ob_parent = BKE_collection_master(scene); + sc_ob_parent = BKE_collection_master(id); } - BKE_collection_object_move(scene, sc, sc_ob_parent, ob); + BKE_collection_object_move(id, sc, sc_ob_parent, ob); } static bool outliner_object_reorder_poll( - const Scene *UNUSED(scene), const TreeElement *insert_element, + const TreeElement *insert_element, TreeElement **io_insert_handle, TreeElementInsertType *io_action) { TreeStoreElem *tselem_handle = TREESTORE(*io_insert_handle); @@ -861,7 +864,7 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i } /* exceptions */ - if (ELEM(type, TSE_ID_BASE, TSE_LAYER_COLLECTION)) { + if (type == TSE_ID_BASE) { /* pass */ } else if (id == NULL) { @@ -1199,6 +1202,11 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i te->flag |= TE_LAZY_CLOSED; } + if ((type != TSE_LAYER_COLLECTION) && GS(id->name) == ID_GR) { + Group *group = (Group *)id; + outliner_add_layer_collections_recursive(soops, &te->subtree, id, &group->view_layer->layer_collections, NULL); + } + return te; } @@ -1349,20 +1357,21 @@ static void outliner_add_orphaned_datablocks(Main *mainvar, SpaceOops *soops) } static void outliner_layer_collections_reorder( - Main *bmain, const Scene *scene, + Main *bmain, TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action) { LayerCollection *lc_insert = insert_element->directdata; LayerCollection *lc_handle = insert_handle->directdata; + ID *id = insert_element->store_elem->id; if (action == TE_INSERT_BEFORE) { - BKE_layer_collection_move_above(scene, lc_handle, lc_insert); + BKE_layer_collection_move_above(id, lc_handle, lc_insert); } else if (action == TE_INSERT_AFTER) { - BKE_layer_collection_move_below(scene, lc_handle, lc_insert); + BKE_layer_collection_move_below(id, lc_handle, lc_insert); } else if (action == TE_INSERT_INTO) { - BKE_layer_collection_move_into(scene, lc_handle, lc_insert); + BKE_layer_collection_move_into(id, lc_handle, lc_insert); } else { BLI_assert(0); @@ -1371,25 +1380,30 @@ static void outliner_layer_collections_reorder( DEG_relations_tag_update(bmain); } static bool outliner_layer_collections_reorder_poll( - const Scene *UNUSED(scene), const TreeElement *UNUSED(insert_element), + const TreeElement *insert_element, TreeElement **io_insert_handle, TreeElementInsertType *UNUSED(io_action)) { const TreeStoreElem *tselem_handle = TREESTORE(*io_insert_handle); + + if (tselem_handle->id != insert_element->store_elem->id) { + return false; + } + return ELEM(tselem_handle->type, TSE_LAYER_COLLECTION); } static void outliner_add_layer_collections_recursive( - SpaceOops *soops, ListBase *tree, ListBase *layer_collections, TreeElement *parent_ten) + SpaceOops *soops, ListBase *tree, ID *id, ListBase *layer_collections, TreeElement *parent_ten) { for (LayerCollection *collection = layer_collections->first; collection; collection = collection->next) { - TreeElement *ten = outliner_add_element(soops, tree, collection, parent_ten, TSE_LAYER_COLLECTION, 0); + TreeElement *ten = outliner_add_element(soops, tree, id, parent_ten, TSE_LAYER_COLLECTION, 0); ten->name = collection->scene_collection->name; ten->directdata = collection; ten->reinsert = outliner_layer_collections_reorder; ten->reinsert_poll = outliner_layer_collections_reorder_poll; - outliner_add_layer_collections_recursive(soops, &ten->subtree, &collection->layer_collections, ten); + outliner_add_layer_collections_recursive(soops, &ten->subtree, id, &collection->layer_collections, ten); for (LinkData *link = collection->object_bases.first; link; link = link->next) { Base *base = (Base *)link->data; TreeElement *te_object = outliner_add_element(soops, &ten->subtree, base->object, ten, 0, 0); @@ -1398,27 +1412,29 @@ static void outliner_add_layer_collections_recursive( outliner_make_hierarchy(&ten->subtree); } } -static void outliner_add_collections_act_layer(SpaceOops *soops, ViewLayer *layer) +static void outliner_add_collections_act_layer(SpaceOops *soops, Scene *scene, ViewLayer *layer) { - outliner_add_layer_collections_recursive(soops, &soops->tree, &layer->layer_collections, NULL); + outliner_add_layer_collections_recursive(soops, &soops->tree, &scene->id, &layer->layer_collections, NULL); } static void outliner_scene_collections_reorder( - Main *bmain, const Scene *scene, + Main *bmain, TreeElement *insert_element, TreeElement *insert_handle, TreeElementInsertType action) { SceneCollection *sc_insert = insert_element->directdata; SceneCollection *sc_handle = insert_handle->directdata; + ID *id = insert_handle->store_elem->id; + BLI_assert(id == insert_element->store_elem->id); - BLI_assert((action == TE_INSERT_INTO) || (sc_handle != BKE_collection_master(scene))); + BLI_assert((action == TE_INSERT_INTO) || (sc_handle != BKE_collection_master(id))); if (action == TE_INSERT_BEFORE) { - BKE_collection_move_above(scene, sc_handle, sc_insert); + BKE_collection_move_above(id, sc_handle, sc_insert); } else if (action == TE_INSERT_AFTER) { - BKE_collection_move_below(scene, sc_handle, sc_insert); + BKE_collection_move_below(id, sc_handle, sc_insert); } else if (action == TE_INSERT_INTO) { - BKE_collection_move_into(scene, sc_handle, sc_insert); + BKE_collection_move_into(id, sc_handle, sc_insert); } else { BLI_assert(0); @@ -1427,17 +1443,23 @@ static void outliner_scene_collections_reorder( DEG_relations_tag_update(bmain); } static bool outliner_scene_collections_reorder_poll( - const Scene *scene, const TreeElement *UNUSED(insert_element), + const TreeElement *insert_element, TreeElement **io_insert_handle, TreeElementInsertType *io_action) { const TreeStoreElem *tselem_handle = TREESTORE(*io_insert_handle); - SceneCollection *sc_master = BKE_collection_master(scene); - SceneCollection *sc_handle = (*io_insert_handle)->directdata; + ID *id = tselem_handle->id; + + if (id != insert_element->store_elem->id) { + return false; + } if (!ELEM(tselem_handle->type, TSE_SCENE_COLLECTION)) { return false; } + SceneCollection *sc_master = BKE_collection_master(id); + SceneCollection *sc_handle = (*io_insert_handle)->directdata; + if (sc_handle == sc_master) { /* exception: Can't insert before/after master selection, has to be one of its childs */ TreeElement *te_master = *io_insert_handle; @@ -1478,7 +1500,7 @@ static void outliner_add_scene_collections_recursive( } static void outliner_add_collections_master(SpaceOops *soops, Scene *scene) { - SceneCollection *master = BKE_collection_master(scene); + SceneCollection *master = BKE_collection_master(&scene->id); outliner_add_scene_collections_recursive(soops, &soops->tree, &master->scene_collections, NULL); outliner_add_scene_collection_objects(soops, &soops->tree, master, NULL); } @@ -1851,19 +1873,9 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa } else if (soops->outlinevis == SO_GROUPS) { Group *group; - GroupObject *go; - for (group = mainvar->group.first; group; group = group->id.next) { - if (group->gobject.first) { - te = outliner_add_element(soops, &soops->tree, group, NULL, 0, 0); - - for (go = group->gobject.first; go; go = go->next) { - outliner_add_element(soops, &te->subtree, go->ob, te, 0, 0); - } - outliner_make_hierarchy(&te->subtree); - /* clear id.newid, to prevent objects be inserted in wrong scenes (parent in other scene) */ - for (go = group->gobject.first; go; go = go->next) go->ob->id.newid = NULL; - } + te = outliner_add_element(soops, &soops->tree, group, NULL, 0, 0); + outliner_make_hierarchy(&te->subtree); } } else if (soops->outlinevis == SO_SAME_TYPE) { @@ -1940,7 +1952,7 @@ void outliner_build_tree(Main *mainvar, Scene *scene, ViewLayer *view_layer, Spa outliner_add_orphaned_datablocks(mainvar, soops); } else if (soops->outlinevis == SO_ACT_LAYER) { - outliner_add_collections_act_layer(soops, view_layer); + outliner_add_collections_act_layer(soops, scene, view_layer); } else if (soops->outlinevis == SO_COLLECTIONS) { outliner_add_collections_master(soops, scene); diff --git a/source/blender/editors/space_outliner/space_outliner.c b/source/blender/editors/space_outliner/space_outliner.c index ffaa259ab6f..1bc1a227a03 100644 --- a/source/blender/editors/space_outliner/space_outliner.c +++ b/source/blender/editors/space_outliner/space_outliner.c @@ -125,7 +125,8 @@ static int outliner_parent_drop_poll(bContext *C, wmDrag *drag, const wmEvent *e */ if (!scene) { return 1; - } else { + } + else { for (ViewLayer *view_layer = scene->view_layers.first; view_layer; view_layer = view_layer->next) diff --git a/source/blender/editors/space_sequencer/sequencer_draw.c b/source/blender/editors/space_sequencer/sequencer_draw.c index 399e76e71b8..04dbab0b853 100644 --- a/source/blender/editors/space_sequencer/sequencer_draw.c +++ b/source/blender/editors/space_sequencer/sequencer_draw.c @@ -157,6 +157,7 @@ void color3ubv_from_seq(Scene *curscene, Sequence *seq, unsigned char col[3]) case SEQ_TYPE_MULTICAM: case SEQ_TYPE_ADJUSTMENT: case SEQ_TYPE_GAUSSIAN_BLUR: + case SEQ_TYPE_COLORMIX: UI_GetThemeColor3ubv(TH_SEQ_EFFECT, col); /* slightly offset hue to distinguish different effects */ @@ -171,6 +172,7 @@ void color3ubv_from_seq(Scene *curscene, Sequence *seq, unsigned char col[3]) else if (seq->type == SEQ_TYPE_MULTICAM) rgb_byte_set_hue_float_offset(col, 0.32); else if (seq->type == SEQ_TYPE_ADJUSTMENT) rgb_byte_set_hue_float_offset(col, 0.40); else if (seq->type == SEQ_TYPE_GAUSSIAN_BLUR) rgb_byte_set_hue_float_offset(col, 0.42); + else if (seq->type == SEQ_TYPE_COLORMIX) rgb_byte_set_hue_float_offset(col, 0.46); break; case SEQ_TYPE_COLOR: diff --git a/source/blender/editors/space_sequencer/sequencer_edit.c b/source/blender/editors/space_sequencer/sequencer_edit.c index a8a5bc6e96b..8f6eb064b0d 100644 --- a/source/blender/editors/space_sequencer/sequencer_edit.c +++ b/source/blender/editors/space_sequencer/sequencer_edit.c @@ -95,6 +95,7 @@ EnumPropertyItem sequencer_prop_effect_types[] = { {SEQ_TYPE_ADJUSTMENT, "ADJUSTMENT", 0, "Adjustment Layer", ""}, {SEQ_TYPE_GAUSSIAN_BLUR, "GAUSSIAN_BLUR", 0, "Gaussian Blur", ""}, {SEQ_TYPE_TEXT, "TEXT", 0, "Text", ""}, + {SEQ_TYPE_COLORMIX, "COLORMIX", 0, "Color Mix", ""}, {0, NULL, 0, NULL, NULL} }; @@ -694,7 +695,7 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe) BKE_sequence_calc(scene, seq); } - if ((seq->startstill) && (cutframe < seq->start)) { + if ((seq->startstill) && (cutframe <= seq->start)) { /* don't do funny things with METAs ... */ if (seq->type == SEQ_TYPE_META) { skip_dup = true; @@ -708,13 +709,15 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe) } } /* normal strip */ - else if ((cutframe >= seq->start) && (cutframe <= (seq->start + seq->len))) { + else if ((cutframe >= seq->start) && (cutframe < (seq->start + seq->len))) { seq->endofs = 0; seq->endstill = 0; seq->anim_endofs += (seq->start + seq->len) - cutframe; } /* strips with extended stillframes after */ - else if (((seq->start + seq->len) < cutframe) && (seq->endstill)) { + else if (((seq->start + seq->len) == cutframe) || + (((seq->start + seq->len) < cutframe) && (seq->endstill))) + { seq->endstill -= seq->enddisp - cutframe; /* don't do funny things with METAs ... */ if (seq->type == SEQ_TYPE_META) { @@ -743,7 +746,7 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe) } /* normal strip */ - else if ((cutframe >= seqn->start) && (cutframe <= (seqn->start + seqn->len))) { + else if ((cutframe >= seqn->start) && (cutframe < (seqn->start + seqn->len))) { seqn->start = cutframe; seqn->startstill = 0; seqn->startofs = 0; @@ -754,7 +757,9 @@ static Sequence *cut_seq_hard(Scene *scene, Sequence *seq, int cutframe) } /* strips with extended stillframes after */ - else if (((seqn->start + seqn->len) < cutframe) && (seqn->endstill)) { + else if (((seqn->start + seqn->len) == cutframe) || + (((seqn->start + seqn->len) < cutframe) && (seqn->endstill))) + { seqn->start = cutframe; seqn->startofs = 0; seqn->anim_startofs += ts.len - 1; @@ -790,7 +795,7 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe) /* First Strip! */ /* strips with extended stillfames before */ - if ((seq->startstill) && (cutframe < seq->start)) { + if ((seq->startstill) && (cutframe <= seq->start)) { /* don't do funny things with METAs ... */ if (seq->type == SEQ_TYPE_META) { skip_dup = true; @@ -804,11 +809,13 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe) } } /* normal strip */ - else if ((cutframe >= seq->start) && (cutframe <= (seq->start + seq->len))) { + else if ((cutframe >= seq->start) && (cutframe < (seq->start + seq->len))) { seq->endofs = (seq->start + seq->len) - cutframe; } /* strips with extended stillframes after */ - else if (((seq->start + seq->len) < cutframe) && (seq->endstill)) { + else if (((seq->start + seq->len) == cutframe) || + (((seq->start + seq->len) < cutframe) && (seq->endstill))) + { seq->endstill -= seq->enddisp - cutframe; /* don't do funny things with METAs ... */ if (seq->type == SEQ_TYPE_META) { @@ -834,9 +841,9 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe) seqn->endofs = ts.endofs; seqn->endstill = ts.endstill; } - + /* normal strip */ - else if ((cutframe >= seqn->start) && (cutframe <= (seqn->start + seqn->len))) { + if ((cutframe >= seqn->start) && (cutframe < (seqn->start + seqn->len))) { seqn->startstill = 0; seqn->startofs = cutframe - ts.start; seqn->endofs = ts.endofs; @@ -844,7 +851,9 @@ static Sequence *cut_seq_soft(Scene *scene, Sequence *seq, int cutframe) } /* strips with extended stillframes after */ - else if (((seqn->start + seqn->len) < cutframe) && (seqn->endstill)) { + else if (((seqn->start + seqn->len) == cutframe) || + (((seqn->start + seqn->len) < cutframe) && (seqn->endstill))) + { seqn->start = cutframe - ts.len + 1; seqn->startofs = ts.len - 1; seqn->endstill = ts.enddisp - cutframe - 1; diff --git a/source/blender/editors/space_time/space_time.c b/source/blender/editors/space_time/space_time.c index 99ac0d9024c..283dbf3b4e2 100644 --- a/source/blender/editors/space_time/space_time.c +++ b/source/blender/editors/space_time/space_time.c @@ -58,6 +58,9 @@ #include "WM_api.h" #include "WM_types.h" +#include "WM_message.h" + +#include "RNA_access.h" #include "BIF_gl.h" @@ -649,6 +652,47 @@ static void time_main_region_listener( } } +static void time_main_region_message_subscribe( + const struct bContext *UNUSED(C), + struct WorkSpace *UNUSED(workspace), struct Scene *scene, + struct bScreen *screen, struct ScrArea *sa, struct ARegion *ar, + struct wmMsgBus *mbus) +{ + PointerRNA ptr; + RNA_pointer_create(&screen->id, &RNA_SpaceTimeline, sa->spacedata.first, &ptr); + + wmMsgSubscribeValue msg_sub_value_region_tag_redraw = { + .owner = ar, + .user_data = ar, + .notify = ED_region_do_msg_notify_tag_redraw, + }; + + /* Timeline depends on scene properties. */ + { + bool use_preview = (scene->r.flag & SCER_PRV_RANGE); + extern PropertyRNA rna_Scene_frame_start; + extern PropertyRNA rna_Scene_frame_end; + extern PropertyRNA rna_Scene_frame_preview_start; + extern PropertyRNA rna_Scene_frame_preview_end; + extern PropertyRNA rna_Scene_use_preview_range; + extern PropertyRNA rna_Scene_frame_current; + const PropertyRNA *props[] = { + use_preview ? &rna_Scene_frame_preview_start : &rna_Scene_frame_start, + use_preview ? &rna_Scene_frame_preview_end : &rna_Scene_frame_end, + &rna_Scene_use_preview_range, + &rna_Scene_frame_current, + }; + + PointerRNA idptr; + RNA_id_pointer_create(&scene->id, &idptr); + + for (int i = 0; i < ARRAY_SIZE(props); i++) { + WM_msg_subscribe_rna(mbus, &idptr, props[i], &msg_sub_value_region_tag_redraw, __func__); + } + } +} + + /* ************************ header time area region *********************** */ /* add handlers, stuff you only do once or on area/region changes */ @@ -797,6 +841,7 @@ void ED_spacetype_time(void) art->init = time_main_region_init; art->draw = time_main_region_draw; art->listener = time_main_region_listener; + art->message_subscribe = time_main_region_message_subscribe; art->keymap = time_keymap; art->lock = 1; /* Due to pointcache, see T4960. */ BLI_addhead(&st->regiontypes, art); diff --git a/source/blender/editors/space_view3d/drawobject.c b/source/blender/editors/space_view3d/drawobject.c index 3e7e617bd0e..08ef9cc21cb 100644 --- a/source/blender/editors/space_view3d/drawobject.c +++ b/source/blender/editors/space_view3d/drawobject.c @@ -9458,6 +9458,8 @@ static void bbs_mesh_verts(BMEditMesh *em, DerivedMesh *dm, int offset) #else static void bbs_mesh_verts(BMEditMesh *em, DerivedMesh *UNUSED(dm), int offset) { + glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); + Mesh *me = em->ob->data; Gwn_Batch *batch = DRW_mesh_batch_cache_get_verts_with_select_id(me, offset); GWN_batch_program_set_builtin(batch, GPU_SHADER_3D_FLAT_COLOR_U32); @@ -9497,7 +9499,7 @@ static void bbs_mesh_wire(BMEditMesh *em, DerivedMesh *dm, int offset) immBindBuiltinProgram(GPU_SHADER_3D_FLAT_COLOR_U32); - glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); + glLineWidth(1.0f); immBeginAtMost(GWN_PRIM_LINES, imm_len); dm->foreachMappedEdge(dm, bbs_mesh_wire__mapFunc, &data); @@ -9508,7 +9510,7 @@ static void bbs_mesh_wire(BMEditMesh *em, DerivedMesh *dm, int offset) #else static void bbs_mesh_wire(BMEditMesh *em, DerivedMesh *UNUSED(dm), int offset) { - glPointSize(UI_GetThemeValuef(TH_VERTEX_SIZE)); + glLineWidth(1.0f); Mesh *me = em->ob->data; Gwn_Batch *batch = DRW_mesh_batch_cache_get_edges_with_select_id(me, offset); @@ -9772,9 +9774,11 @@ void draw_object_backbufsel( ED_view3d_polygon_offset(rv3d, 1.0); - /* we draw edges always, for loop (select) tools */ - bbs_mesh_wire(em, dm, bm_solidoffs); - bm_wireoffs = bm_solidoffs + em->bm->totedge; + /* we draw edges if edge select mode */ + if (ts->selectmode & SCE_SELECT_EDGE) { + bbs_mesh_wire(em, dm, bm_solidoffs); + bm_wireoffs = bm_solidoffs + em->bm->totedge; + } /* we draw verts if vert select mode. */ if (ts->selectmode & SCE_SELECT_VERTEX) { diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index f138b014d03..7cf1573de43 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -67,6 +67,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "WM_message.h" #include "RE_engine.h" #include "RE_pipeline.h" @@ -1038,6 +1039,75 @@ static void view3d_main_region_listener( } } +static void view3d_main_region_message_subscribe( + const struct bContext *UNUSED(C), + struct WorkSpace *workspace, struct Scene *scene, + struct bScreen *UNUSED(screen), struct ScrArea *UNUSED(sa), struct ARegion *ar, + struct wmMsgBus *mbus) +{ + /* Developer note: there are many properties that impact 3D view drawing, + * so instead of subscribing to individual properties, just subscribe to types + * accepting some redundant redraws. + * + * For other space types we might try avoid this, keep the 3D view as an exceptional case! */ + ViewRender *view_render = BKE_viewrender_get(scene, workspace); + wmMsgParams_RNA msg_key_params = {0}; + + /* Only subscribe to types. */ + StructRNA *type_array[] = { + /* These object have properties that impact drawing. */ + &RNA_AreaLamp, + &RNA_Camera, + &RNA_Lamp, + &RNA_Speaker, + &RNA_SunLamp, + + /* General types the 3D view depends on. */ + &RNA_Object, + &RNA_UnitSettings, /* grid-floor */ + + &RNA_ViewRenderSettings, + &RNA_World, + }; + + wmMsgSubscribeValue msg_sub_value_region_tag_redraw = { + .owner = ar, + .user_data = ar, + .notify = ED_region_do_msg_notify_tag_redraw, + }; + + for (int i = 0; i < ARRAY_SIZE(type_array); i++) { + msg_key_params.ptr.type = type_array[i]; + WM_msg_subscribe_rna_params( + mbus, + &msg_key_params, + &msg_sub_value_region_tag_redraw, + __func__); + } + + /* Subscribe to a handful of other properties. */ + RegionView3D *rv3d = ar->regiondata; + + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, resolution_x, &msg_sub_value_region_tag_redraw); + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, resolution_y, &msg_sub_value_region_tag_redraw); + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, pixel_aspect_x, &msg_sub_value_region_tag_redraw); + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, pixel_aspect_y, &msg_sub_value_region_tag_redraw); + if (rv3d->persp == RV3D_CAMOB) { + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, use_border, &msg_sub_value_region_tag_redraw); + } + + /* Each engine could be responsible for its own engine data types. + * For now this is simplest. */ + if (STREQ(view_render->engine_id, RE_engine_id_BLENDER_EEVEE)) { + extern StructRNA RNA_ViewLayerEngineSettingsEevee; + WM_msg_subscribe_rna_anon_type(mbus, ViewLayerEngineSettingsEevee, &msg_sub_value_region_tag_redraw); + } + else if (STREQ(view_render->engine_id, RE_engine_id_BLENDER_CLAY)) { + extern StructRNA RNA_ViewLayerEngineSettingsClay; + WM_msg_subscribe_rna_anon_type(mbus, ViewLayerEngineSettingsClay, &msg_sub_value_region_tag_redraw); + } +} + /* concept is to retrieve cursor type context-less */ static void view3d_main_region_cursor(wmWindow *win, ScrArea *UNUSED(sa), ARegion *UNUSED(ar)) { @@ -1379,6 +1449,7 @@ void ED_spacetype_view3d(void) art->free = view3d_main_region_free; art->duplicate = view3d_main_region_duplicate; art->listener = view3d_main_region_listener; + art->message_subscribe = view3d_main_region_message_subscribe; art->cursor = view3d_main_region_cursor; art->lock = 1; /* can become flag, see BKE_spacedata_draw_locks */ BLI_addhead(&st->regiontypes, art); diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 8024a733f40..6ea2ff10af2 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -90,6 +90,8 @@ #include "WM_api.h" #include "WM_types.h" +#include "RNA_access.h" + #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" @@ -1931,8 +1933,8 @@ static void view3d_stereo3d_setup_offscreen( void ED_view3d_draw_offscreen_init(const EvaluationContext *eval_ctx, Scene *scene, ViewLayer *view_layer, View3D *v3d) { - RenderEngineType *type = eval_ctx->engine; - if (type->flag & RE_USE_LEGACY_PIPELINE) { + RenderEngineType *engine_type = eval_ctx->engine_type; + if (engine_type->flag & RE_USE_LEGACY_PIPELINE) { /* shadow buffers, before we setup matrices */ if (draw_glsl_material(scene, view_layer, NULL, v3d, v3d->drawtype)) { VP_deprecated_gpu_update_lamps_shadows_world(eval_ctx, scene, v3d); @@ -2014,8 +2016,8 @@ void ED_view3d_draw_offscreen( view3d_main_region_setup_view(eval_ctx, scene, v3d, ar, viewmat, winmat, NULL); /* main drawing call */ - RenderEngineType *type = eval_ctx->engine; - if (type->flag & RE_USE_LEGACY_PIPELINE) { + RenderEngineType *engine_type = eval_ctx->engine_type; + if (engine_type->flag & RE_USE_LEGACY_PIPELINE) { /* framebuffer fx needed, we need to draw offscreen first */ if (v3d->fx_settings.fx_flag && fx) { @@ -2058,7 +2060,7 @@ void ED_view3d_draw_offscreen( /* XXX, should take depsgraph as arg */ Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, false); BLI_assert(depsgraph != NULL); - DRW_draw_render_loop_offscreen(depsgraph, eval_ctx->engine, ar, v3d, ofs); + DRW_draw_render_loop_offscreen(depsgraph, eval_ctx->engine_type, ar, v3d, ofs); } /* restore size */ diff --git a/source/blender/editors/space_view3d/view3d_manipulator_camera.c b/source/blender/editors/space_view3d/view3d_manipulator_camera.c index a4d408eedc6..d020571930a 100644 --- a/source/blender/editors/space_view3d/view3d_manipulator_camera.c +++ b/source/blender/editors/space_view3d/view3d_manipulator_camera.c @@ -45,6 +45,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "WM_message.h" #include "view3d_intern.h" /* own include */ @@ -217,6 +218,55 @@ static void WIDGETGROUP_camera_refresh(const bContext *C, wmManipulatorGroup *mg } +static void WIDGETGROUP_camera_message_subscribe( + const bContext *C, wmManipulatorGroup *mgroup, struct wmMsgBus *mbus) +{ + ARegion *ar = CTX_wm_region(C); + Object *ob = CTX_data_active_object(C); + Camera *ca = ob->data; + + wmMsgSubscribeValue msg_sub_value_mpr_tag_refresh = { + .owner = ar, + .user_data = mgroup->parent_mmap, + .notify = WM_manipulator_do_msg_notify_tag_refresh, + }; + + { + extern PropertyRNA rna_Camera_dof_distance; + extern PropertyRNA rna_Camera_draw_size; + extern PropertyRNA rna_Camera_ortho_scale; + extern PropertyRNA rna_Camera_sensor_fit; + extern PropertyRNA rna_Camera_sensor_width; + extern PropertyRNA rna_Camera_shift_x; + extern PropertyRNA rna_Camera_shift_y; + extern PropertyRNA rna_Camera_type; + const PropertyRNA *props[] = { + &rna_Camera_dof_distance, + &rna_Camera_draw_size, + &rna_Camera_ortho_scale, + &rna_Camera_sensor_fit, + &rna_Camera_sensor_width, + &rna_Camera_shift_x, + &rna_Camera_shift_y, + &rna_Camera_type, + }; + + PointerRNA idptr; + RNA_id_pointer_create(&ca->id, &idptr); + + for (int i = 0; i < ARRAY_SIZE(props); i++) { + WM_msg_subscribe_rna(mbus, &idptr, props[i], &msg_sub_value_mpr_tag_refresh, __func__); + } + } + + /* Subscribe to render settings */ + { + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, resolution_x, &msg_sub_value_mpr_tag_refresh); + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, resolution_y, &msg_sub_value_mpr_tag_refresh); + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, pixel_aspect_x, &msg_sub_value_mpr_tag_refresh); + WM_msg_subscribe_rna_anon_prop(mbus, RenderSettings, pixel_aspect_y, &msg_sub_value_mpr_tag_refresh); + } +} void VIEW3D_WGT_camera(wmManipulatorGroupType *wgt) { @@ -230,6 +280,7 @@ void VIEW3D_WGT_camera(wmManipulatorGroupType *wgt) wgt->poll = WIDGETGROUP_camera_poll; wgt->setup = WIDGETGROUP_camera_setup; wgt->refresh = WIDGETGROUP_camera_refresh; + wgt->message_subscribe = WIDGETGROUP_camera_message_subscribe; } /** \} */ diff --git a/source/blender/editors/space_view3d/view3d_manipulator_ruler.c b/source/blender/editors/space_view3d/view3d_manipulator_ruler.c index 0495d1d696c..230b4f44c16 100644 --- a/source/blender/editors/space_view3d/view3d_manipulator_ruler.c +++ b/source/blender/editors/space_view3d/view3d_manipulator_ruler.c @@ -272,7 +272,7 @@ static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state) } else if (state == RULER_STATE_DRAG) { ruler_info->snap_context = ED_transform_snap_object_context_create_view3d( - CTX_data_main(C), CTX_data_scene(C), CTX_data_view_layer(C), CTX_data_engine(C), 0, + CTX_data_main(C), CTX_data_scene(C), CTX_data_view_layer(C), CTX_data_engine_type(C), 0, ruler_info->ar, CTX_wm_view3d(C)); } else { diff --git a/source/blender/editors/space_view3d/view3d_ops.c b/source/blender/editors/space_view3d/view3d_ops.c index 568343f8ec8..79fa9e14dc1 100644 --- a/source/blender/editors/space_view3d/view3d_ops.c +++ b/source/blender/editors/space_view3d/view3d_ops.c @@ -46,6 +46,7 @@ #include "BKE_appdir.h" #include "BKE_blender_copybuffer.h" #include "BKE_context.h" +#include "BKE_group.h" #include "BKE_main.h" #include "BKE_report.h" @@ -81,14 +82,16 @@ static int view3d_copybuffer_exec(bContext *C, wmOperator *op) CTX_DATA_END; for (Group *group = bmain->group.first; group; group = group->id.next) { - for (GroupObject *go = group->gobject.first; go; go = go->next) { - if (go->ob && (go->ob->id.tag & LIB_TAG_DOIT)) { + FOREACH_GROUP_OBJECT(group, object) + { + if (object && (object->id.tag & LIB_TAG_DOIT)) { BKE_copybuffer_tag_ID(&group->id); /* don't expand out to all other objects */ group->id.tag &= ~LIB_TAG_NEED_EXPAND; break; } } + FOREACH_GROUP_OBJECT_END } BLI_make_file_string("/", str, BKE_tempdir_base(), "copybuffer.blend"); diff --git a/source/blender/editors/space_view3d/view3d_ruler.c b/source/blender/editors/space_view3d/view3d_ruler.c index 5d213962ae9..093425fc3bc 100644 --- a/source/blender/editors/space_view3d/view3d_ruler.c +++ b/source/blender/editors/space_view3d/view3d_ruler.c @@ -282,7 +282,7 @@ static void ruler_state_set(bContext *C, RulerInfo *ruler_info, int state) } else if (state == RULER_STATE_DRAG) { ruler_info->snap_context = ED_transform_snap_object_context_create_view3d( - CTX_data_main(C), CTX_data_scene(C), CTX_data_view_layer(C), CTX_data_engine(C), 0, + CTX_data_main(C), CTX_data_scene(C), CTX_data_view_layer(C), CTX_data_engine_type(C), 0, ruler_info->ar, CTX_wm_view3d(C)); } else { diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index 4658ca566d2..28e15b3bfee 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -113,7 +113,7 @@ void view3d_set_viewcontext(bContext *C, ViewContext *vc) vc->depsgraph = CTX_data_depsgraph(C); vc->scene = CTX_data_scene(C); vc->view_layer = CTX_data_view_layer(C); - vc->engine = CTX_data_engine(C); + vc->engine_type = CTX_data_engine_type(C); vc->v3d = CTX_wm_view3d(C); vc->win = CTX_wm_window(C); vc->rv3d = CTX_wm_region_view3d(C); diff --git a/source/blender/editors/space_view3d/view3d_walk.c b/source/blender/editors/space_view3d/view3d_walk.c index 2901588b040..76da1faf530 100644 --- a/source/blender/editors/space_view3d/view3d_walk.c +++ b/source/blender/editors/space_view3d/view3d_walk.c @@ -251,7 +251,7 @@ typedef struct WalkInfo { ARegion *ar; Scene *scene; ViewLayer *view_layer; - RenderEngineType *engine; + RenderEngineType *engine_type; wmTimer *timer; /* needed for redraws */ @@ -515,7 +515,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) walk->ar = CTX_wm_region(C); walk->scene = CTX_data_scene(C); walk->view_layer = CTX_data_view_layer(C); - walk->engine = CTX_data_engine(C); + walk->engine_type = CTX_data_engine_type(C); #ifdef NDOF_WALK_DEBUG puts("\n-- walk begin --"); @@ -604,7 +604,7 @@ static bool initWalkInfo(bContext *C, WalkInfo *walk, wmOperator *op) walk->rv3d->rflag |= RV3D_NAVIGATING; walk->snap_context = ED_transform_snap_object_context_create_view3d( - CTX_data_main(C), walk->scene, walk->view_layer, walk->engine, 0, + CTX_data_main(C), walk->scene, walk->view_layer, walk->engine_type, 0, walk->ar, walk->v3d); walk->v3d_camera_control = ED_view3d_cameracontrol_acquire( diff --git a/source/blender/editors/transform/transform.h b/source/blender/editors/transform/transform.h index b6a9ba1079a..d9bfcd0c289 100644 --- a/source/blender/editors/transform/transform.h +++ b/source/blender/editors/transform/transform.h @@ -470,7 +470,7 @@ typedef struct TransInfo { struct ARegion *ar; struct Scene *scene; struct ViewLayer *view_layer; - struct RenderEngineType *engine; + struct RenderEngineType *engine_type; struct ToolSettings *settings; struct wmTimer *animtimer; struct wmKeyMap *keymap; /* so we can do lookups for header text */ diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c index 89c43187bd4..730ca70547b 100644 --- a/source/blender/editors/transform/transform_conversions.c +++ b/source/blender/editors/transform/transform_conversions.c @@ -119,6 +119,7 @@ #include "DEG_depsgraph.h" #include "DEG_depsgraph_build.h" +#include "DEG_depsgraph_query.h" #include "transform.h" #include "bmesh.h" @@ -1890,7 +1891,6 @@ static void createTransParticleVerts(bContext *C, TransInfo *t) { TransData *td = NULL; TransDataExtension *tx; - Base *base = CTX_data_active_base(C); Object *ob = CTX_data_active_object(C); ParticleEditSettings *pset = PE_settings(t->scene); PTCacheEdit *edit = PE_get_current(t->scene, t->view_layer, ob); @@ -1910,8 +1910,6 @@ static void createTransParticleVerts(bContext *C, TransInfo *t) if (psys) psmd = psys_get_modifier(ob, psys); - base->flag |= BA_HAS_RECALC_DATA; - for (i = 0, point = edit->points; i < edit->totpoint; i++, point++) { point->flag &= ~PEP_TRANSFORM; transformparticle = 0; @@ -2485,7 +2483,7 @@ static void createTransEditVerts(TransInfo *t) int *island_vert_map = NULL; DEG_evaluation_context_init_from_scene(&eval_ctx, - t->scene, t->view_layer, t->engine, + t->scene, t->view_layer, t->engine_type, DAG_EVAL_VIEWPORT); /* Even for translation this is needed because of island-orientation, see: T51651. */ @@ -5531,6 +5529,37 @@ static void ObjectToTransData(TransInfo *t, TransData *td, Object *ob) } } +static void trans_object_base_deps_flag_prepare(ViewLayer *view_layer) +{ + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + base->object->id.tag &= ~LIB_TAG_DOIT; + } +} + +static void set_trans_object_base_deps_flag_cb(ID *id, void *UNUSED(user_data)) +{ + /* Here we only handle object IDs. */ + if (GS(id->name) != ID_OB) { + return; + } + id->tag |= LIB_TAG_DOIT; +} + +static void flush_trans_object_base_deps_flag(Depsgraph *depsgraph, Object *object) +{ + object->id.tag |= LIB_TAG_DOIT; + DEG_foreach_dependent_ID(depsgraph, &object->id, + set_trans_object_base_deps_flag_cb, NULL); +} + +static void trans_object_base_deps_flag_finish(ViewLayer *view_layer) +{ + for (Base *base = view_layer->object_bases.first; base; base = base->next) { + if (base->object->id.tag & LIB_TAG_DOIT) { + base->flag_legacy |= BA_SNAP_FIX_DEPS_FIASCO; + } + } +} /* sets flags in Bases to define whether they take part in transform */ /* it deselects Bases, so we have to call the clear function always after */ @@ -5541,47 +5570,30 @@ static void set_trans_object_base_flags(TransInfo *t) ViewLayer *view_layer = t->view_layer; Scene *scene = t->scene; Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true); - - /* - * if Base selected and has parent selected: - * base->flag_legacy = BA_WAS_SEL + /* NOTE: if Base selected and has parent selected: + * base->flag_legacy = BA_WAS_SEL */ - Base *base; - - /* don't do it if we're not actually going to recalculate anything */ - if (t->mode == TFM_DUMMY) + /* Don't do it if we're not actually going to recalculate anything. */ + if (t->mode == TFM_DUMMY) { return; - - /* makes sure base flags and object flags are identical */ + } + /* Makes sure base flags and object flags are identical. */ BKE_scene_base_flag_to_objects(t->view_layer); - /* Make sure depsgraph is here. */ DEG_graph_relations_update(depsgraph, bmain, scene, view_layer); - - /* handle pending update events, otherwise they got copied below */ - EvaluationContext eval_ctx; - DEG_evaluation_context_init_from_scene(&eval_ctx, - t->scene, t->view_layer, t->engine, - DAG_EVAL_VIEWPORT); - for (base = view_layer->object_bases.first; base; base = base->next) { - if (base->object->recalc & OB_RECALC_ALL) { - /* TODO(sergey): Ideally, it's not needed. */ - BKE_object_handle_update(&eval_ctx, t->scene, base->object); - } - } - - for (base = view_layer->object_bases.first; base; base = base->next) { + /* Clear all flags we need. It will be used to detect dependencies. */ + trans_object_base_deps_flag_prepare(view_layer); + /* Traverse all bases and set all possible flags. */ + for (Base *base = view_layer->object_bases.first; base; base = base->next) { base->flag_legacy &= ~BA_WAS_SEL; - if (TESTBASELIB_BGMODE(base)) { Object *ob = base->object; Object *parsel = ob->parent; - - /* if parent selected, deselect */ - while (parsel) { + /* If parent selected, deselect. */ + while (parsel != NULL) { if (parsel->base_flag & BASE_SELECTED) { Base *parbase = BKE_view_layer_base_find(view_layer, parsel); - if (parbase) { /* in rare cases this can fail */ + if (parbase != NULL) { /* in rare cases this can fail */ if (TESTBASELIB_BGMODE(parbase)) { break; } @@ -5589,9 +5601,8 @@ static void set_trans_object_base_flags(TransInfo *t) } parsel = parsel->parent; } - - if (parsel) { - /* rotation around local centers are allowed to propagate */ + if (parsel != NULL) { + /* Rotation around local centers are allowed to propagate. */ if ((t->around == V3D_AROUND_LOCAL_ORIGINS) && (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL)) { @@ -5602,21 +5613,13 @@ static void set_trans_object_base_flags(TransInfo *t) base->flag_legacy |= BA_WAS_SEL; } } - DEG_id_tag_update(&ob->id, OB_RECALC_OB); + flush_trans_object_base_deps_flag(depsgraph, ob); } } - - /* all recalc flags get flushed to all layers, so a layer flip later on works fine */ - DEG_graph_flush_update(bmain, depsgraph); - - /* and we store them temporal in base (only used for transform code) */ - /* this because after doing updates, the object->recalc is cleared */ - for (base = view_layer->object_bases.first; base; base = base->next) { - if (base->object->recalc & OB_RECALC_OB) - base->flag_legacy |= BA_HAS_RECALC_OB; - if (base->object->recalc & OB_RECALC_DATA) - base->flag_legacy |= BA_HAS_RECALC_DATA; - } + /* Store temporary bits in base indicating that base is being modified + * (directly or indirectly) by transforming objects. + */ + trans_object_base_deps_flag_finish(view_layer); } static bool mark_children(Object *ob) @@ -5637,32 +5640,28 @@ static bool mark_children(Object *ob) static int count_proportional_objects(TransInfo *t) { int total = 0; - /* TODO(sergey): Get rid of global, use explicit main. */ - Main *bmain = G.main; ViewLayer *view_layer = t->view_layer; Scene *scene = t->scene; Depsgraph *depsgraph = BKE_scene_get_depsgraph(scene, view_layer, true); - Base *base; - - /* rotations around local centers are allowed to propagate, so we take all objects */ + /* Clear all flags we need. It will be used to detect dependencies. */ + trans_object_base_deps_flag_prepare(view_layer); + /* Rotations around local centers are allowed to propagate, so we take all objects. */ if (!((t->around == V3D_AROUND_LOCAL_ORIGINS) && (t->mode == TFM_ROTATION || t->mode == TFM_TRACKBALL))) { - /* mark all parents */ - for (base = view_layer->object_bases.first; base; base = base->next) { + /* Mark all parents. */ + for (Base *base = view_layer->object_bases.first; base; base = base->next) { if (TESTBASELIB_BGMODE(base)) { Object *parent = base->object->parent; - /* flag all parents */ - while (parent) { + while (parent != NULL) { parent->flag |= BA_TRANSFORM_PARENT; parent = parent->parent; } } } - - /* mark all children */ - for (base = view_layer->object_bases.first; base; base = base->next) { + /* Mark all children. */ + for (Base *base = view_layer->object_bases.first; base; base = base->next) { /* all base not already selected or marked that is editable */ if ((base->object->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 && (base->flag & BASE_SELECTED) == 0 && @@ -5672,36 +5671,24 @@ static int count_proportional_objects(TransInfo *t) } } } - - for (base = view_layer->object_bases.first; base; base = base->next) { + /* Flush changed flags to all dependencies. */ + for (Base *base = view_layer->object_bases.first; base; base = base->next) { Object *ob = base->object; - - /* if base is not selected, not a parent of selection or not a child of selection and it is editable */ + /* If base is not selected, not a parent of selection or not a child of + * selection and it is editable. + */ if ((ob->flag & (BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT)) == 0 && (base->flag & BASE_SELECTED) == 0 && (BASE_EDITABLE_BGMODE(base))) { - - DEG_id_tag_update(&ob->id, OB_RECALC_OB); - + flush_trans_object_base_deps_flag(depsgraph, ob); total += 1; } } - - - /* all recalc flags get flushed to all layers, so a layer flip later on works fine */ - DEG_graph_relations_update(depsgraph, bmain, scene, view_layer); - DEG_graph_flush_update(bmain, depsgraph); - - /* and we store them temporal in base (only used for transform code) */ - /* this because after doing updates, the object->recalc is cleared */ - for (base = view_layer->object_bases.first; base; base = base->next) { - if (base->object->recalc & OB_RECALC_OB) - base->flag_legacy |= BA_HAS_RECALC_OB; - if (base->object->recalc & OB_RECALC_DATA) - base->flag_legacy |= BA_HAS_RECALC_DATA; - } - + /* Store temporary bits in base indicating that base is being modified + * (directly or indirectly) by transforming objects. + */ + trans_object_base_deps_flag_finish(view_layer); return total; } @@ -5715,7 +5702,7 @@ static void clear_trans_object_base_flags(TransInfo *t) base->flag |= BASE_SELECTED; } - base->flag_legacy &= ~(BA_WAS_SEL | BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA | BA_TEMP_TAG | BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT); + base->flag_legacy &= ~(BA_WAS_SEL | BA_SNAP_FIX_DEPS_FIASCO | BA_TEMP_TAG | BA_TRANSFORM_CHILD | BA_TRANSFORM_PARENT); } } @@ -6489,12 +6476,16 @@ void special_aftertrans_update(bContext *C, TransInfo *t) DEG_id_tag_update(&ob->id, OB_RECALC_DATA); } else if (arm->flag & ARM_DELAYDEFORM) { - /* old optimize trick... this enforces to bypass the depgraph */ + /* TODO(sergey): Armature is already updated by recalcData(), so we + * might save some time by skipping re-evaluating it. But this isn't + * possible yet within new dependency graph, and also other contexts + * might need to update their CoW copies. + */ DEG_id_tag_update(&ob->id, OB_RECALC_DATA); - ob->recalc = 0; // is set on OK position already by recalcData() } - else + else { DEG_id_tag_update(&ob->id, OB_RECALC_DATA); + } } else if (t->options & CTX_PAINT_CURVE) { @@ -8291,7 +8282,7 @@ void createTransData(bContext *C, TransInfo *t) RegionView3D *rv3d = t->ar->regiondata; if ((rv3d->persp == RV3D_CAMOB) && v3d->camera) { /* we could have a flag to easily check an object is being transformed */ - if (v3d->camera->recalc) { + if (v3d->camera->id.tag & LIB_TAG_DOIT) { t->flag |= T_CAMERA; } } diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index f6ec93d8ff9..10a7677f42b 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1123,12 +1123,12 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve Object *obedit = CTX_data_edit_object(C); Object *ob = CTX_data_active_object(C); bGPdata *gpd = CTX_data_gpencil_data(C); - RenderEngineType *engine = CTX_data_engine(C); + RenderEngineType *engine_type = CTX_data_engine_type(C); PropertyRNA *prop; t->scene = sce; t->view_layer = view_layer; - t->engine = engine; + t->engine_type = engine_type; t->sa = sa; t->ar = ar; t->obedit = obedit; diff --git a/source/blender/editors/transform/transform_manipulator.c b/source/blender/editors/transform/transform_manipulator.c index ee722397f91..0e0c2f3ae25 100644 --- a/source/blender/editors/transform/transform_manipulator.c +++ b/source/blender/editors/transform/transform_manipulator.c @@ -65,6 +65,7 @@ #include "WM_api.h" #include "WM_types.h" +#include "WM_message.h" #include "ED_armature.h" #include "ED_curve.h" @@ -1115,6 +1116,47 @@ static void manipulator_line_range(const View3D *v3d, const short axis_type, flo *r_len -= *r_start; } +static void manipulator_xform_message_subscribe( + wmManipulatorGroup *mgroup, struct wmMsgBus *mbus, + bScreen *screen, ScrArea *sa, ARegion *ar, const void *type_fn) +{ + /* Subscribe to view properties */ + wmMsgSubscribeValue msg_sub_value_mpr_tag_refresh = { + .owner = ar, + .user_data = mgroup->parent_mmap, + .notify = WM_manipulator_do_msg_notify_tag_refresh, + }; + + PointerRNA space_ptr; + RNA_pointer_create(&screen->id, &RNA_SpaceView3D, sa->spacedata.first, &space_ptr); + + { + extern PropertyRNA rna_SpaceView3D_transform_orientation; + const PropertyRNA *props[] = { + &rna_SpaceView3D_transform_orientation, + }; + for (int i = 0; i < ARRAY_SIZE(props); i++) { + WM_msg_subscribe_rna(mbus, &space_ptr, props[i], &msg_sub_value_mpr_tag_refresh, __func__); + } + } + + if (type_fn == TRANSFORM_WGT_manipulator) { + extern PropertyRNA rna_SpaceView3D_pivot_point; + const PropertyRNA *props[] = { + &rna_SpaceView3D_pivot_point + }; + for (int i = 0; i < ARRAY_SIZE(props); i++) { + WM_msg_subscribe_rna(mbus, &space_ptr, props[i], &msg_sub_value_mpr_tag_refresh, __func__); + } + } + else if (type_fn == VIEW3D_WGT_xform_cage) { + /* pass */ + } + else { + BLI_assert(0); + } +} + /** \} */ @@ -1383,6 +1425,15 @@ static void WIDGETGROUP_manipulator_refresh(const bContext *C, wmManipulatorGrou MAN_ITER_AXES_END; } +static void WIDGETGROUP_manipulator_message_subscribe( + const bContext *C, wmManipulatorGroup *mgroup, struct wmMsgBus *mbus) +{ + bScreen *screen = CTX_wm_screen(C); + ScrArea *sa = CTX_wm_area(C); + ARegion *ar = CTX_wm_region(C); + manipulator_xform_message_subscribe(mgroup, mbus, screen, sa, ar, TRANSFORM_WGT_manipulator); +} + static void WIDGETGROUP_manipulator_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) { ManipulatorGroup *man = mgroup->customdata; @@ -1464,6 +1515,7 @@ void TRANSFORM_WGT_manipulator(wmManipulatorGroupType *wgt) wgt->poll = WIDGETGROUP_manipulator_poll; wgt->setup = WIDGETGROUP_manipulator_setup; wgt->refresh = WIDGETGROUP_manipulator_refresh; + wgt->message_subscribe = WIDGETGROUP_manipulator_message_subscribe; wgt->draw_prepare = WIDGETGROUP_manipulator_draw_prepare; } @@ -1500,7 +1552,7 @@ static void WIDGETGROUP_xform_cage_setup(const bContext *UNUSED(C), wmManipulato ED_MANIPULATOR_CAGE2D_XFORM_FLAG_TRANSLATE); mpr->color[0] = 1; - mpr->color_hi[0]=1; + mpr->color_hi[0] =1; mgroup->customdata = xmgroup; @@ -1585,6 +1637,15 @@ static void WIDGETGROUP_xform_cage_refresh(const bContext *C, wmManipulatorGroup } } +static void WIDGETGROUP_xform_cage_message_subscribe( + const bContext *C, wmManipulatorGroup *mgroup, struct wmMsgBus *mbus) +{ + bScreen *screen = CTX_wm_screen(C); + ScrArea *sa = CTX_wm_area(C); + ARegion *ar = CTX_wm_region(C); + manipulator_xform_message_subscribe(mgroup, mbus, screen, sa, ar, VIEW3D_WGT_xform_cage); +} + static void WIDGETGROUP_xform_cage_draw_prepare(const bContext *C, wmManipulatorGroup *mgroup) { struct XFormCageWidgetGroup *xmgroup = mgroup->customdata; @@ -1613,6 +1674,7 @@ void VIEW3D_WGT_xform_cage(wmManipulatorGroupType *wgt) wgt->poll = WIDGETGROUP_xform_cage_poll; wgt->setup = WIDGETGROUP_xform_cage_setup; wgt->refresh = WIDGETGROUP_xform_cage_refresh; + wgt->message_subscribe = WIDGETGROUP_xform_cage_message_subscribe; wgt->draw_prepare = WIDGETGROUP_xform_cage_draw_prepare; } diff --git a/source/blender/editors/transform/transform_snap.c b/source/blender/editors/transform/transform_snap.c index 6b3167a0392..30aad46843d 100644 --- a/source/blender/editors/transform/transform_snap.c +++ b/source/blender/editors/transform/transform_snap.c @@ -300,9 +300,7 @@ void applyProject(TransInfo *t) mul_m4_v3(ob->obmat, iloc); } else if (t->flag & T_OBJECT) { - /* TODO(sergey): Ideally force update is not needed here. */ - td->ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME; - BKE_object_handle_update(G.main->eval_ctx, t->scene, td->ob); + BKE_object_eval_transform_all(G.main->eval_ctx, t->scene, td->ob); copy_v3_v3(iloc, td->ob->obmat[3]); } @@ -391,8 +389,7 @@ void applyGridAbsolute(TransInfo *t) mul_m4_v3(obmat, iloc); } else if (t->flag & T_OBJECT) { - td->ob->recalc |= OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME; - BKE_object_handle_update(G.main->eval_ctx, t->scene, td->ob); + BKE_object_eval_transform_all(G.main->eval_ctx, t->scene, td->ob); copy_v3_v3(iloc, td->ob->obmat[3]); } @@ -585,7 +582,7 @@ static void initSnappingMode(TransInfo *t) if (t->spacetype == SPACE_VIEW3D) { if (t->tsnap.object_context == NULL) { t->tsnap.object_context = ED_transform_snap_object_context_create_view3d( - G.main, t->scene, t->view_layer, t->engine, 0, + G.main, t->scene, t->view_layer, t->engine_type, 0, t->ar, t->view); ED_transform_snap_object_context_set_editmesh_callbacks( diff --git a/source/blender/editors/transform/transform_snap_object.c b/source/blender/editors/transform/transform_snap_object.c index 61705ba2868..ce8de2ef4d3 100644 --- a/source/blender/editors/transform/transform_snap_object.c +++ b/source/blender/editors/transform/transform_snap_object.c @@ -161,17 +161,8 @@ static void iter_snap_objects( void *data) { Base *base_act = sctx->eval_ctx.view_layer->basact; - /* Need an exception for particle edit because the base is flagged with BA_HAS_RECALC_DATA - * which makes the loop skip it, even the derived mesh will never change - * - * To solve that problem, we do it first as an exception. - * */ - if (base_act && base_act->object && base_act->object->mode & OB_MODE_PARTICLE_EDIT) { - sob_callback(sctx, false, base_act->object, base_act->object->obmat, data); - } - for (Base *base = sctx->eval_ctx.view_layer->object_bases.first; base != NULL; base = base->next) { - if ((BASE_VISIBLE(base)) && (base->flag_legacy & (BA_HAS_RECALC_OB | BA_HAS_RECALC_DATA)) == 0 && + if ((BASE_VISIBLE(base)) && (base->flag_legacy & BA_SNAP_FIX_DEPS_FIASCO) == 0 && !((snap_select == SNAP_NOT_SELECTED && ((base->flag & BASE_SELECTED) || (base->flag_legacy & BA_WAS_SEL))) || (snap_select == SNAP_NOT_ACTIVE && base == base_act))) { @@ -2096,7 +2087,7 @@ static bool snapObjectsRay( * \{ */ SnapObjectContext *ED_transform_snap_object_context_create( - Main *bmain, Scene *scene, ViewLayer *view_layer, RenderEngineType *engine, int flag) + Main *bmain, Scene *scene, ViewLayer *view_layer, RenderEngineType *engine_type, int flag) { SnapObjectContext *sctx = MEM_callocN(sizeof(*sctx), __func__); @@ -2105,7 +2096,7 @@ SnapObjectContext *ED_transform_snap_object_context_create( sctx->bmain = bmain; sctx->scene = scene; - DEG_evaluation_context_init_from_scene(&sctx->eval_ctx, scene, view_layer, engine, DAG_EVAL_VIEWPORT); + DEG_evaluation_context_init_from_scene(&sctx->eval_ctx, scene, view_layer, engine_type, DAG_EVAL_VIEWPORT); sctx->cache.object_map = BLI_ghash_ptr_new(__func__); sctx->cache.mem_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__); @@ -2114,11 +2105,11 @@ SnapObjectContext *ED_transform_snap_object_context_create( } SnapObjectContext *ED_transform_snap_object_context_create_view3d( - Main *bmain, Scene *scene, ViewLayer *view_layer, RenderEngineType *engine, int flag, + Main *bmain, Scene *scene, ViewLayer *view_layer, RenderEngineType *engine_type, int flag, /* extra args for view3d */ const ARegion *ar, const View3D *v3d) { - SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, view_layer, engine, flag); + SnapObjectContext *sctx = ED_transform_snap_object_context_create(bmain, scene, view_layer, engine_type, flag); sctx->use_v3d = true; sctx->v3d_data.ar = ar; diff --git a/source/blender/editors/util/numinput.c b/source/blender/editors/util/numinput.c index 61142fdc887..0f3240946fd 100644 --- a/source/blender/editors/util/numinput.c +++ b/source/blender/editors/util/numinput.c @@ -488,8 +488,9 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event) const float fac = (float)BKE_scene_unit_scale(&sce->unit, n->unit_type[idx], 1.0); /* Make radian default unit when needed. */ - if (n->unit_use_radians && n->unit_type[idx] == B_UNIT_ROTATION) + if (n->unit_use_radians && n->unit_type[idx] == B_UNIT_ROTATION) { default_unit = "r"; + } BLI_strncpy(str_unit_convert, n->str, sizeof(str_unit_convert)); @@ -513,7 +514,16 @@ bool handleNumInput(bContext *C, NumInput *n, const wmEvent *event) n->val[idx] = -n->val[idx]; } if (n->val_flag[idx] & NUM_INVERSE) { - n->val[idx] = 1.0f / n->val[idx]; + val = n->val[idx]; + /* If we invert on radians when user is in degrees, you get unexpected results... See T53463. */ + if (!n->unit_use_radians && n->unit_type[idx] == B_UNIT_ROTATION) { + val = RAD2DEG(val); + } + val = 1.0 / val; + if (!n->unit_use_radians && n->unit_type[idx] == B_UNIT_ROTATION) { + val = DEG2RAD(val); + } + n->val[idx] = (float)val; } if (UNLIKELY(!isfinite(n->val[idx]))) { diff --git a/source/blender/editors/util/undo.c b/source/blender/editors/util/undo.c index c24e4994f7f..dbf1cf46c61 100644 --- a/source/blender/editors/util/undo.c +++ b/source/blender/editors/util/undo.c @@ -45,6 +45,7 @@ #include "BKE_blender_undo.h" #include "BKE_context.h" #include "BKE_global.h" +#include "BKE_library_override.h" #include "BKE_main.h" #include "BKE_screen.h" @@ -82,6 +83,9 @@ void ED_undo_push(bContext *C, const char *str) if (G.debug & G_DEBUG) printf("%s: %s\n", __func__, str); + /* Always do it for now, this might need to be refined... */ + BKE_main_override_static_operations_create(CTX_data_main(C)); + if (obedit) { if (U.undosteps == 0) return; |