diff options
author | Lukas Tönne <lukas.toenne@gmail.com> | 2016-12-01 12:29:46 +0300 |
---|---|---|
committer | Lukas Tönne <lukas.toenne@gmail.com> | 2016-12-01 12:29:46 +0300 |
commit | ff2a74906a7b70625a4e941c6a805f7734491204 (patch) | |
tree | 562f5ccdd9f4e377d20fe22eadca48201924b4b3 /source/blender/editors | |
parent | 73c1c92c0e86ce1b5a8abeaa16be2bf2c259412b (diff) | |
parent | 58877d6d082d82185ca611b704364168e5984bd7 (diff) |
Merge branch 'master' into blender2.8
Diffstat (limited to 'source/blender/editors')
24 files changed, 330 insertions, 196 deletions
diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index 12d837dfb29..15f65b394a9 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -96,7 +96,11 @@ static int gpencil_editmode_toggle_exec(bContext *C, wmOperator *UNUSED(op)) /* Just toggle editmode flag... */ gpd->flag ^= GP_DATA_STROKE_EDITMODE; - + /* recalculate parent matrix */ + if (gpd->flag & GP_DATA_STROKE_EDITMODE) { + ED_gpencil_reset_layers_parent(gpd); + } + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, NULL); WM_event_add_notifier(C, NC_SCENE | ND_MODE, NULL); diff --git a/source/blender/editors/gpencil/gpencil_utils.c b/source/blender/editors/gpencil/gpencil_utils.c index 564ba639983..76e85f20c36 100644 --- a/source/blender/editors/gpencil/gpencil_utils.c +++ b/source/blender/editors/gpencil/gpencil_utils.c @@ -915,7 +915,7 @@ void gp_subdivide_stroke(bGPDstroke *gps, const int new_totpoints) /** * Add randomness to stroke * \param gps Stroke data - * \param brsuh Brush data + * \param brush Brush data */ void gp_randomize_stroke(bGPDstroke *gps, bGPDbrush *brush) { @@ -997,6 +997,46 @@ void ED_gpencil_parent_location(bGPDlayer *gpl, float diff_mat[4][4]) } } +/* reset parent matrix for all layers */ +void ED_gpencil_reset_layers_parent(bGPdata *gpd) +{ + bGPDspoint *pt; + int i; + float diff_mat[4][4]; + float cur_mat[4][4]; + + for (bGPDlayer *gpl = gpd->layers.first; gpl; gpl = gpl->next) { + if (gpl->parent != NULL) { + /* calculate new matrix */ + if ((gpl->partype == PAROBJECT) || (gpl->partype == PARSKEL)) { + invert_m4_m4(cur_mat, gpl->parent->obmat); + } + else if (gpl->partype == PARBONE) { + bPoseChannel *pchan = BKE_pose_channel_find_name(gpl->parent->pose, gpl->parsubstr); + if (pchan) { + float tmp_mat[4][4]; + mul_m4_m4m4(tmp_mat, gpl->parent->obmat, pchan->pose_mat); + invert_m4_m4(cur_mat, tmp_mat); + } + } + + /* only redo if any change */ + if (!equals_m4m4(gpl->inverse, cur_mat)) { + /* first apply current transformation to all strokes */ + ED_gpencil_parent_location(gpl, diff_mat); + for (bGPDframe *gpf = gpl->frames.first; gpf; gpf = gpf->next) { + for (bGPDstroke *gps = gpf->strokes.first; gps; gps = gps->next) { + for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) { + mul_m4_v3(diff_mat, &pt->x); + } + } + } + /* set new parent matrix */ + copy_m4_m4(gpl->inverse, cur_mat); + } + } + } +} /* ******************************************************** */ bool ED_gpencil_stroke_minmax( const bGPDstroke *gps, const bool use_select, diff --git a/source/blender/editors/include/ED_gpencil.h b/source/blender/editors/include/ED_gpencil.h index bc93b5622cb..74d9ad0886d 100644 --- a/source/blender/editors/include/ED_gpencil.h +++ b/source/blender/editors/include/ED_gpencil.h @@ -185,6 +185,8 @@ int ED_undo_gpencil_step(struct bContext *C, int step, const char *name); /* get difference matrix using parent */ void ED_gpencil_parent_location(struct bGPDlayer *gpl, float diff_mat[4][4]); +/* reset parent matrix for all layers */ +void ED_gpencil_reset_layers_parent(struct bGPdata *gpd); #endif /* __ED_GPENCIL_H__ */ diff --git a/source/blender/editors/include/UI_icons.h b/source/blender/editors/include/UI_icons.h index e016e014a1a..8579778ff79 100644 --- a/source/blender/editors/include/UI_icons.h +++ b/source/blender/editors/include/UI_icons.h @@ -1005,15 +1005,6 @@ DEF_ICON(MATCAP_23) DEF_ICON(MATCAP_24) /* vector icons, VICO_ prefix added */ -DEF_VICO(VIEW3D_VEC) -DEF_VICO(EDIT_VEC) -DEF_VICO(EDITMODE_VEC_DEHLT) -DEF_VICO(EDITMODE_VEC_HLT) -DEF_VICO(DISCLOSURE_TRI_RIGHT_VEC) -DEF_VICO(DISCLOSURE_TRI_DOWN_VEC) -DEF_VICO(MOVE_UP_VEC) -DEF_VICO(MOVE_DOWN_VEC) -DEF_VICO(X_VEC) DEF_VICO(SMALL_TRI_RIGHT_VEC) DEF_VICO(KEYTYPE_KEYFRAME_VEC) diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index d1f14bf5c1a..d48cfbee413 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -181,7 +181,7 @@ enum { UI_BUT_HAS_SEP_CHAR = (1 << 27), /* but->str contains UI_SEP_CHAR, used for key shortcuts */ 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_SEARCH_UNLINK = (1 << 30), /* show unlink for search button */ + UI_BUT_VALUE_CLEAR = (1 << 30), /* show 'x' icon to clear/unlink value of text or search button */ }; #define UI_PANEL_WIDTH 340 diff --git a/source/blender/editors/interface/interface.c b/source/blender/editors/interface/interface.c index 6bba35e821f..a913421d12c 100644 --- a/source/blender/editors/interface/interface.c +++ b/source/blender/editors/interface/interface.c @@ -1987,22 +1987,29 @@ uiBut *ui_but_drag_multi_edit_get(uiBut *but) /** \name Check to show extra icons * * Extra icons are shown on the right hand side of buttons. + * This could (should!) definitely become more generic, but for now this is good enough. * \{ */ +static bool ui_but_icon_extra_is_visible_text_clear(const uiBut *but) +{ + BLI_assert(but->type == UI_BTYPE_TEXT); + return ((but->flag & UI_BUT_VALUE_CLEAR) && but->drawstr && but->drawstr[0]); +} + static bool ui_but_icon_extra_is_visible_search_unlink(const uiBut *but) { BLI_assert(but->type == UI_BTYPE_SEARCH_MENU); return ((but->editstr == NULL) && (but->drawstr[0] != '\0') && - (but->flag & UI_BUT_SEARCH_UNLINK)); + (but->flag & UI_BUT_VALUE_CLEAR)); } -static bool ui_but_icon_extra_is_visible_eyedropper(uiBut *but) +static bool ui_but_icon_extra_is_visible_search_eyedropper(uiBut *but) { StructRNA *type; short idcode; - BLI_assert(but->type == UI_BTYPE_SEARCH_MENU && (but->flag & UI_BUT_SEARCH_UNLINK)); + BLI_assert(but->type == UI_BTYPE_SEARCH_MENU && (but->flag & UI_BUT_VALUE_CLEAR)); if (but->rnaprop == NULL) { return false; @@ -2011,21 +2018,31 @@ static bool ui_but_icon_extra_is_visible_eyedropper(uiBut *but) type = RNA_property_pointer_type(&but->rnapoin, but->rnaprop); idcode = RNA_type_to_ID_code(type); - return ((but->editstr == NULL) && (idcode == ID_OB || OB_DATA_SUPPORT_ID(idcode))); } uiButExtraIconType ui_but_icon_extra_get(uiBut *but) { - if ((but->flag & UI_BUT_SEARCH_UNLINK) == 0) { - /* pass */ - } - else if (ui_but_icon_extra_is_visible_search_unlink(but)) { - return UI_BUT_ICONEXTRA_UNLINK; - } - else if (ui_but_icon_extra_is_visible_eyedropper(but)) { - return UI_BUT_ICONEXTRA_EYEDROPPER; + switch (but->type) { + case UI_BTYPE_TEXT: + if (ui_but_icon_extra_is_visible_text_clear(but)) { + return UI_BUT_ICONEXTRA_CLEAR; + } + break; + case UI_BTYPE_SEARCH_MENU: + if ((but->flag & UI_BUT_VALUE_CLEAR) == 0) { + /* pass */ + } + else if (ui_but_icon_extra_is_visible_search_unlink(but)) { + return UI_BUT_ICONEXTRA_CLEAR; + } + else if (ui_but_icon_extra_is_visible_search_eyedropper(but)) { + return UI_BUT_ICONEXTRA_EYEDROPPER; + } + break; + default: + break; } return UI_BUT_ICONEXTRA_NONE; diff --git a/source/blender/editors/interface/interface_eyedropper.c b/source/blender/editors/interface/interface_eyedropper.c index 9c808589d26..6efa711a53f 100644 --- a/source/blender/editors/interface/interface_eyedropper.c +++ b/source/blender/editors/interface/interface_eyedropper.c @@ -748,7 +748,7 @@ static int datadropper_poll(bContext *C) if ((CTX_wm_window(C) != NULL) && (but = UI_context_active_but_prop_get(C, &ptr, &prop, &index_dummy)) && (but->type == UI_BTYPE_SEARCH_MENU) && - (but->flag & UI_BUT_SEARCH_UNLINK)) + (but->flag & UI_BUT_VALUE_CLEAR)) { if (prop && RNA_property_type(prop) == PROP_POINTER) { StructRNA *type = RNA_property_pointer_type(&ptr, prop); diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 09ba666773b..ce67c24f096 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -2554,6 +2554,18 @@ void ui_but_text_password_hide(char password_str[UI_MAX_PASSWORD_STR], uiBut *bu } } +static void ui_but_text_clear(bContext *C, uiBut *but, uiHandleButtonData *data) +{ + /* most likely NULL, but let's check, and give it temp zero string */ + if (!data->str) { + data->str = MEM_callocN(1, "temp str"); + } + data->str[0] = 0; + + ui_apply_but_TEX(C, but, data); + button_activate_state(C, but, BUTTON_STATE_EXIT); +} + /* ************* in-button text selection/editing ************* */ @@ -3820,6 +3832,21 @@ static int ui_do_but_KEYEVT( return WM_UI_HANDLER_CONTINUE; } +static bool ui_but_is_mouse_over_icon_extra(const ARegion *region, uiBut *but, const int mouse_xy[2]) +{ + int x = mouse_xy[0], y = mouse_xy[1]; + rcti icon_rect; + + BLI_assert(ui_but_icon_extra_get(but) != UI_BUT_ICONEXTRA_NONE); + + ui_window_to_block(region, but->block, &x, &y); + + BLI_rcti_rctf_copy(&icon_rect, &but->rect); + icon_rect.xmin = icon_rect.xmax - (BLI_rcti_size_y(&icon_rect)); + + return BLI_rcti_isect_pt(&icon_rect, x, y); +} + static int ui_do_but_TEX( bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) @@ -3833,7 +3860,14 @@ static int ui_do_but_TEX( /* pass */ } else { - button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); + const bool has_icon_extra = ui_but_icon_extra_get(but) == UI_BUT_ICONEXTRA_CLEAR; + + if (has_icon_extra && ui_but_is_mouse_over_icon_extra(data->region, but, &event->x)) { + ui_but_text_clear(C, but, data); + } + else { + button_activate_state(C, but, BUTTON_STATE_TEXT_EDITING); + } return WM_UI_HANDLER_BREAK; } } @@ -3854,47 +3888,29 @@ static int ui_do_but_SEARCH_UNLINK( bContext *C, uiBlock *block, uiBut *but, uiHandleButtonData *data, const wmEvent *event) { - uiButExtraIconType extra_icon_type; + const uiButExtraIconType extra_icon_type = ui_but_icon_extra_get(but); + const bool has_icon_extra = (extra_icon_type != UI_BUT_ICONEXTRA_NONE); /* unlink icon is on right */ if ((ELEM(event->type, LEFTMOUSE, EVT_BUT_OPEN, PADENTER, RETKEY)) && - ((extra_icon_type = ui_but_icon_extra_get(but)) != UI_BUT_ICONEXTRA_NONE)) + (has_icon_extra == true) && + (ui_but_is_mouse_over_icon_extra(data->region, but, &event->x) == true)) { - ARegion *ar = data->region; - rcti rect; - int x = event->x, y = event->y; - - ui_window_to_block(ar, but->block, &x, &y); - - BLI_rcti_rctf_copy(&rect, &but->rect); - - rect.xmin = rect.xmax - (BLI_rcti_size_y(&rect)); - /* handle click on unlink/eyedropper icon */ - if (BLI_rcti_isect_pt(&rect, x, y)) { - /* doing this on KM_PRESS calls eyedropper after clicking unlink icon */ - if (event->val == KM_RELEASE) { - /* unlink */ - if (extra_icon_type == UI_BUT_ICONEXTRA_UNLINK) { - /* most likely NULL, but let's check, and give it temp zero string */ - if (data->str == NULL) { - data->str = MEM_callocN(1, "temp str"); - } - data->str[0] = 0; - - ui_apply_but_TEX(C, but, data); - button_activate_state(C, but, BUTTON_STATE_EXIT); - } - /* eyedropper */ - else if (extra_icon_type == UI_BUT_ICONEXTRA_EYEDROPPER) { - WM_operator_name_call(C, "UI_OT_eyedropper_id", WM_OP_INVOKE_DEFAULT, NULL); - } - else { - BLI_assert(0); - } + /* doing this on KM_PRESS calls eyedropper after clicking unlink icon */ + if (event->val == KM_RELEASE) { + /* unlink */ + if (extra_icon_type == UI_BUT_ICONEXTRA_CLEAR) { + ui_but_text_clear(C, but, data); + } + /* eyedropper */ + else if (extra_icon_type == UI_BUT_ICONEXTRA_EYEDROPPER) { + WM_operator_name_call(C, "UI_OT_eyedropper_id", WM_OP_INVOKE_DEFAULT, NULL); + } + else { + BLI_assert(0); } - - return WM_UI_HANDLER_BREAK; } + return WM_UI_HANDLER_BREAK; } return ui_do_but_TEX(C, block, but, data, event); } @@ -7069,7 +7085,7 @@ static int ui_do_button(bContext *C, uiBlock *block, uiBut *but, const wmEvent * case UI_BTYPE_TEXT: case UI_BTYPE_SEARCH_MENU: if ((but->type == UI_BTYPE_SEARCH_MENU) && - (but->flag & UI_BUT_SEARCH_UNLINK)) + (but->flag & UI_BUT_VALUE_CLEAR)) { retval = ui_do_but_SEARCH_UNLINK(C, block, but, data, event); if (retval & WM_UI_HANDLER_BREAK) { diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 0f9db6fd9b6..7529f60c6f0 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -127,7 +127,7 @@ enum { * (e.g. 'x' icon in search menu) - used with ui_but_icon_extra_get */ typedef enum uiButExtraIconType { UI_BUT_ICONEXTRA_NONE = 1, - UI_BUT_ICONEXTRA_UNLINK, + UI_BUT_ICONEXTRA_CLEAR, UI_BUT_ICONEXTRA_EYEDROPPER, } uiButExtraIconType; diff --git a/source/blender/editors/interface/interface_layout.c b/source/blender/editors/interface/interface_layout.c index 875522e01c6..b128bf47b5f 100644 --- a/source/blender/editors/interface/interface_layout.c +++ b/source/blender/editors/interface/interface_layout.c @@ -1659,7 +1659,7 @@ void ui_but_add_search(uiBut *but, PointerRNA *ptr, PropertyRNA *prop, PointerRN but->rnasearchprop = searchprop; but->drawflag |= UI_BUT_ICON_LEFT | UI_BUT_TEXT_LEFT; if (RNA_property_is_unlink(prop)) { - but->flag |= UI_BUT_SEARCH_UNLINK; + but->flag |= UI_BUT_VALUE_CLEAR; } if (RNA_property_type(prop) == PROP_ENUM) { diff --git a/source/blender/editors/interface/interface_regions.c b/source/blender/editors/interface/interface_regions.c index cdf34642a8d..466978272bc 100644 --- a/source/blender/editors/interface/interface_regions.c +++ b/source/blender/editors/interface/interface_regions.c @@ -851,7 +851,7 @@ static void ui_searchbox_select(bContext *C, ARegion *ar, uiBut *but, int step) } else { /* only let users step into an 'unset' state for unlink buttons */ - data->active = (but->flag & UI_BUT_SEARCH_UNLINK) ? -1 : 0; + data->active = (but->flag & UI_BUT_VALUE_CLEAR) ? -1 : 0; } } @@ -922,8 +922,8 @@ bool ui_searchbox_apply(uiBut *but, ARegion *ar) return true; } - else if (but->flag & UI_BUT_SEARCH_UNLINK) { - /* It is valid for _UNLINK flavor to have no active element (it's a valid way to unlink). */ + else if (but->flag & UI_BUT_VALUE_CLEAR) { + /* It is valid for _VALUE_CLEAR flavor to have no active element (it's a valid way to unlink). */ but->editstr[0] = '\0'; return true; diff --git a/source/blender/editors/interface/interface_templates.c b/source/blender/editors/interface/interface_templates.c index 09c5854fb26..80784e86b1e 100644 --- a/source/blender/editors/interface/interface_templates.c +++ b/source/blender/editors/interface/interface_templates.c @@ -302,7 +302,10 @@ static void template_id_cb(bContext *C, void *arg_litem, void *arg_event) break; case UI_ID_LOCAL: if (id) { - if (id_make_local(CTX_data_main(C), id, false, false)) { + Main *bmain = CTX_data_main(C); + if (id_make_local(bmain, id, false, false)) { + BKE_main_id_clear_newpoins(bmain); + /* reassign to get get proper updates/notifiers */ idptr = RNA_property_pointer_get(&template->ptr, template->prop); RNA_property_pointer_set(&template->ptr, template->prop, idptr); diff --git a/source/blender/editors/interface/interface_utils.c b/source/blender/editors/interface/interface_utils.c index 1d51c0588b6..8dfbbdd02eb 100644 --- a/source/blender/editors/interface/interface_utils.c +++ b/source/blender/editors/interface/interface_utils.c @@ -119,6 +119,10 @@ uiBut *uiDefAutoButR(uiBlock *block, PointerRNA *ptr, PropertyRNA *prop, int ind else but = uiDefButR_prop(block, UI_BTYPE_TEXT, 0, name, x1, y1, x2, y2, ptr, prop, index, 0, 0, -1, -1, NULL); + PropertySubType subtype = RNA_property_subtype(prop); + if (!(ELEM(subtype, PROP_FILEPATH, PROP_DIRPATH, PROP_FILENAME) || (block->flag & UI_BLOCK_LIST_ITEM))) { + UI_but_flag_enable(but, UI_BUT_VALUE_CLEAR); + } if (RNA_property_flag(prop) & PROP_TEXTEDIT_UPDATE) { UI_but_flag_enable(but, UI_BUT_TEXTEDIT_UPDATE); } diff --git a/source/blender/editors/interface/interface_widgets.c b/source/blender/editors/interface/interface_widgets.c index 6cb3aa19db3..b75ecf68136 100644 --- a/source/blender/editors/interface/interface_widgets.c +++ b/source/blender/editors/interface/interface_widgets.c @@ -1513,10 +1513,10 @@ static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *b /* draws text and icons for buttons */ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but, rcti *rect) { + const uiButExtraIconType extra_icon_type = ui_but_icon_extra_get(but); const bool show_menu_icon = ui_but_draw_menu_icon(but); float alpha = (float)wcol->text[3] / 255.0f; char password_str[UI_MAX_DRAW_STR]; - uiButExtraIconType extra_icon_type; ui_but_text_password_hide(password_str, but, false); @@ -1582,15 +1582,13 @@ static void widget_draw_text_icon(uiFontStyle *fstyle, uiWidgetColors *wcol, uiB rect->xmax -= (UI_TEXT_MARGIN_X * U.widget_unit) / but->block->aspect; } - /* unlink icon for this button type */ - if ((but->type == UI_BTYPE_SEARCH_MENU) && - ((extra_icon_type = ui_but_icon_extra_get(but)) != UI_BUT_ICONEXTRA_NONE)) - { + /* extra icons, e.g. 'x' icon to clear text or icon for eyedropper */ + if (extra_icon_type != UI_BUT_ICONEXTRA_NONE) { rcti temp = *rect; temp.xmin = temp.xmax - (BLI_rcti_size_y(rect) * 1.08f); - if (extra_icon_type == UI_BUT_ICONEXTRA_UNLINK) { + if (extra_icon_type == UI_BUT_ICONEXTRA_CLEAR) { widget_draw_icon(but, ICON_X, alpha, &temp, false); } else if (extra_icon_type == UI_BUT_ICONEXTRA_EYEDROPPER) { diff --git a/source/blender/editors/mesh/editmesh_knife.c b/source/blender/editors/mesh/editmesh_knife.c index a84b8d9dcc8..44453d03ade 100644 --- a/source/blender/editors/mesh/editmesh_knife.c +++ b/source/blender/editors/mesh/editmesh_knife.c @@ -2140,7 +2140,7 @@ static float snap_v2_angle(float r[2], const float v[2], const float v_ref[2], f normalize_v2_v2(v_unit, v); angle = angle_signed_v2v2(v_unit, v_ref); angle_delta = (roundf(angle / angle_snap) * angle_snap) - angle; - rotate_m2(m2, angle_delta); + angle_to_mat2(m2, angle_delta); mul_v2_m2v2(r, m2, v); return angle + angle_delta; diff --git a/source/blender/editors/object/object_add.c b/source/blender/editors/object/object_add.c index 6e973740f7c..a6f7388cb49 100644 --- a/source/blender/editors/object/object_add.c +++ b/source/blender/editors/object/object_add.c @@ -1252,10 +1252,10 @@ static void copy_object_set_idnew(bContext *C) /********************* Make Duplicates Real ************************/ /** - * \note regarding hashing dupli-objects, skip the first member of #DupliObject.persistent_id + * \note regarding hashing dupli-objects when using OB_DUPLIGROUP, skip the first member of #DupliObject.persistent_id * since its a unique index and we only want to know if the group objects are from the same dupli-group instance. */ -static unsigned int dupliobject_hash(const void *ptr) +static unsigned int dupliobject_group_hash(const void *ptr) { const DupliObject *dob = ptr; unsigned int hash = BLI_ghashutil_ptrhash(dob->ob); @@ -1266,7 +1266,20 @@ static unsigned int dupliobject_hash(const void *ptr) return hash; } -static bool dupliobject_cmp(const void *a_, const void *b_) +/** + * \note regarding hashing dupli-objects when NOT using OB_DUPLIGROUP, include the first member of #DupliObject.persistent_id + * since its the index of the vertex/face the object is instantiated on and we want to identify objects on the same vertex/face. + */ +static unsigned int dupliobject_hash(const void *ptr) +{ + const DupliObject *dob = ptr; + unsigned int hash = BLI_ghashutil_ptrhash(dob->ob); + hash ^= (dob->persistent_id[0] ^ 0); + return hash; +} + +/* Compare function that matches dupliobject_group_hash */ +static bool dupliobject_group_cmp(const void *a_, const void *b_) { const DupliObject *a = a_; const DupliObject *b = b_; @@ -1289,6 +1302,24 @@ static bool dupliobject_cmp(const void *a_, const void *b_) return false; } +/* Compare function that matches dupliobject_hash */ +static bool dupliobject_cmp(const void *a_, const void *b_) +{ + const DupliObject *a = a_; + const DupliObject *b = b_; + + if (a->ob != b->ob) { + return true; + } + + if (a->persistent_id[0] != b->persistent_id[0]) { + return true; + } + + /* matching */ + return false; +} + static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, const bool use_base_parent, const bool use_hierarchy) @@ -1307,13 +1338,18 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, if (use_hierarchy || use_base_parent) { dupli_gh = BLI_ghash_ptr_new(__func__); if (use_hierarchy) { - parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__); + if (base->object->transflag & OB_DUPLIGROUP) { + parent_gh = BLI_ghash_new(dupliobject_group_hash, dupliobject_group_cmp, __func__); + } + else { + parent_gh = BLI_ghash_new(dupliobject_hash, dupliobject_cmp, __func__); + } } } for (dob = lb->first; dob; dob = dob->next) { Base *basen; - Object *ob = BKE_object_copy(bmain, dob->ob); + Object *ob = ID_NEW_SET(dob->ob, BKE_object_copy(bmain, dob->ob)); /* font duplis can have a totcol without material, we get them from parent * should be implemented better... @@ -1357,6 +1393,11 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, } } + /* Remap new object to itself, and clear again newid pointer of orig object. */ + BKE_libblock_relink(&ob->id); + set_sca_new_poins_ob(ob); + BKE_id_clear_newpoin(&dob->ob->id); + DAG_id_tag_update(&ob->id, OB_RECALC_DATA); } @@ -1375,9 +1416,14 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, * they won't be read, this is simply for a hash lookup. */ DupliObject dob_key; dob_key.ob = ob_src_par; - memcpy(&dob_key.persistent_id[1], - &dob->persistent_id[1], - sizeof(dob->persistent_id[1]) * (MAX_DUPLI_RECUR - 1)); + if (base->object->transflag & OB_DUPLIGROUP) { + memcpy(&dob_key.persistent_id[1], + &dob->persistent_id[1], + sizeof(dob->persistent_id[1]) * (MAX_DUPLI_RECUR - 1)); + } + else { + dob_key.persistent_id[0] = dob->persistent_id[0]; + } ob_dst_par = BLI_ghash_lookup(parent_gh, &dob_key); } @@ -1442,8 +1488,6 @@ static void make_object_duplilist_real(bContext *C, Scene *scene, Base *base, if (parent_gh) BLI_ghash_free(parent_gh, NULL, NULL); - copy_object_set_idnew(C); - free_object_duplilist(lb); base->object->transflag &= ~OB_DUPLI; @@ -1918,8 +1962,12 @@ void OBJECT_OT_convert(wmOperatorType *ot) /* used below, assumes id.new is correct */ /* leaves selection of base/object unaltered */ +/* Does set ID->newid pointers. */ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base, int dupflag) { +#define ID_NEW_REMAP_US(a) if ( (a)->id.newid) { (a) = (void *)(a)->id.newid; (a)->id.us++; } +#define ID_NEW_REMAP_US2(a) if (((ID *)a)->newid) { (a) = ((ID *)a)->newid; ((ID *)a)->us++; } + Base *basen = NULL; Material ***matarar; Object *ob, *obn; @@ -1931,7 +1979,7 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base ; /* nothing? */ } else { - obn = BKE_object_copy(bmain, ob); + obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob)); DAG_id_tag_update(&obn->id, OB_RECALC_OB | OB_RECALC_DATA | OB_RECALC_TIME); basen = MEM_mallocN(sizeof(Base), "duplibase"); @@ -1953,20 +2001,21 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base /* duplicates using userflags */ if (dupflag & USER_DUP_ACT) { - BKE_animdata_copy_id_action(&obn->id); + BKE_animdata_copy_id_action(&obn->id, true); } if (dupflag & USER_DUP_MAT) { for (a = 0; a < obn->totcol; a++) { id = (ID *)obn->mat[a]; if (id) { - ID_NEW_US(obn->mat[a]) - else - obn->mat[a] = BKE_material_copy(bmain, obn->mat[a]); + ID_NEW_REMAP_US(obn->mat[a]) + else { + obn->mat[a] = ID_NEW_SET(obn->mat[a], BKE_material_copy(bmain, obn->mat[a])); + } id_us_min(id); if (dupflag & USER_DUP_ACT) { - BKE_animdata_copy_id_action(&obn->mat[a]->id); + BKE_animdata_copy_id_action(&obn->mat[a]->id, true); } } } @@ -1978,9 +2027,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base switch (obn->type) { case OB_MESH: if (dupflag & USER_DUP_MESH) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_mesh_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_mesh_copy(bmain, obn->data)); didit = 1; } id_us_min(id); @@ -1988,9 +2037,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base break; case OB_CURVE: if (dupflag & USER_DUP_CURVE) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_curve_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data)); didit = 1; } id_us_min(id); @@ -1998,9 +2047,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base break; case OB_SURF: if (dupflag & USER_DUP_SURF) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_curve_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data)); didit = 1; } id_us_min(id); @@ -2008,9 +2057,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base break; case OB_FONT: if (dupflag & USER_DUP_FONT) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_curve_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_curve_copy(bmain, obn->data)); didit = 1; } id_us_min(id); @@ -2018,9 +2067,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base break; case OB_MBALL: if (dupflag & USER_DUP_MBALL) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_mball_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_mball_copy(bmain, obn->data)); didit = 1; } id_us_min(id); @@ -2028,9 +2077,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base break; case OB_LAMP: if (dupflag & USER_DUP_LAMP) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_lamp_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_lamp_copy(bmain, obn->data)); didit = 1; } id_us_min(id); @@ -2041,9 +2090,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base if (obn->pose) BKE_pose_tag_recalc(bmain, obn->pose); if (dupflag & USER_DUP_ARM) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_armature_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_armature_copy(bmain, obn->data)); BKE_pose_rebuild(obn, obn->data); didit = 1; } @@ -2052,9 +2101,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base break; case OB_LATTICE: if (dupflag != 0) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_lattice_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_lattice_copy(bmain, obn->data)); didit = 1; } id_us_min(id); @@ -2062,9 +2111,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base break; case OB_CAMERA: if (dupflag != 0) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_camera_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_camera_copy(bmain, obn->data)); didit = 1; } id_us_min(id); @@ -2072,9 +2121,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base break; case OB_SPEAKER: if (dupflag != 0) { - ID_NEW_US2(obn->data) + ID_NEW_REMAP_US2(obn->data) else { - obn->data = BKE_speaker_copy(bmain, obn->data); + obn->data = ID_NEW_SET(obn->data, BKE_speaker_copy(bmain, obn->data)); didit = 1; } id_us_min(id); @@ -2089,12 +2138,15 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base if (dupflag & USER_DUP_ACT) { bActuator *act; - BKE_animdata_copy_id_action((ID *)obn->data); + BKE_animdata_copy_id_action((ID *)obn->data, true); if (key) { - BKE_animdata_copy_id_action((ID *)key); + BKE_animdata_copy_id_action((ID *)key, true); } /* Update the duplicated action in the action actuators */ + /* XXX TODO this code is all wrong! actact->act is user-refcounted (see readfile.c), + * and what about other ID pointers of other BGE logic bricks, + * and since this is object-level, why is it only ran if obdata was duplicated??? -mont29 */ for (act = obn->actuators.first; act; act = act->next) { if (act->type == ACT_ACTION) { bActionActuator *actact = (bActionActuator *) act->data; @@ -2111,9 +2163,10 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base for (a = 0; a < obn->totcol; a++) { id = (ID *)(*matarar)[a]; if (id) { - ID_NEW_US((*matarar)[a]) - else - (*matarar)[a] = BKE_material_copy(bmain, (*matarar)[a]); + ID_NEW_REMAP_US((*matarar)[a]) + else { + (*matarar)[a] = ID_NEW_SET((*matarar)[a], BKE_material_copy(bmain, (*matarar)[a])); + } id_us_min(id); } } @@ -2122,6 +2175,9 @@ static Base *object_add_duplicate_internal(Main *bmain, Scene *scene, Base *base } } return basen; + +#undef ID_NEW_REMAP_US +#undef ID_NEW_REMAP_US2 } /* single object duplicate, if dupflag==0, fully linked, else it uses the flags given */ @@ -2134,8 +2190,7 @@ Base *ED_object_add_duplicate(Main *bmain, Scene *scene, Base *base, int dupflag Base *basen; Object *ob; - BKE_main_id_clear_newpoins(bmain); - clear_sca_new_poins(); /* sensor/contr/act */ + clear_sca_new_poins(); /* BGE logic */ basen = object_add_duplicate_internal(bmain, scene, base, dupflag); if (basen == NULL) { @@ -2154,6 +2209,8 @@ Base *ED_object_add_duplicate(Main *bmain, Scene *scene, Base *base, int dupflag ED_render_id_flush_update(bmain, ob->data); } + BKE_main_id_clear_newpoins(bmain); + return basen; } @@ -2165,8 +2222,7 @@ static int duplicate_exec(bContext *C, wmOperator *op) const bool linked = RNA_boolean_get(op->ptr, "linked"); int dupflag = (linked) ? 0 : U.dupflag; - BKE_main_id_clear_newpoins(bmain); - clear_sca_new_poins(); /* sensor/contr/act */ + clear_sca_new_poins(); /* BGE logic */ CTX_DATA_BEGIN (C, Base *, base, selected_bases) { @@ -2192,6 +2248,8 @@ static int duplicate_exec(bContext *C, wmOperator *op) copy_object_set_idnew(C); + BKE_main_id_clear_newpoins(bmain); + DAG_relations_tag_update(bmain); WM_event_add_notifier(C, NC_SCENE | ND_OB_SELECT, scene); @@ -2250,8 +2308,7 @@ static int add_named_exec(bContext *C, wmOperator *op) base->flag = ob->flag; /* prepare dupli */ - BKE_main_id_clear_newpoins(bmain); - clear_sca_new_poins(); /* sensor/contr/act */ + clear_sca_new_poins(); /* BGE logic */ basen = object_add_duplicate_internal(bmain, scene, base, dupflag); @@ -2277,6 +2334,8 @@ static int add_named_exec(bContext *C, wmOperator *op) copy_object_set_idnew(C); + BKE_main_id_clear_newpoins(bmain); + DAG_relations_tag_update(bmain); MEM_freeN(base); diff --git a/source/blender/editors/object/object_relations.c b/source/blender/editors/object/object_relations.c index a3ff8dcb676..0bfd4b054eb 100644 --- a/source/blender/editors/object/object_relations.c +++ b/source/blender/editors/object/object_relations.c @@ -1730,6 +1730,7 @@ void OBJECT_OT_make_links_data(wmOperatorType *ot) /**************************** Make Single User ********************************/ +/* Warning, sets ID->newid pointers of objects and groups, but does not clear them. */ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const int flag, const bool copy_groups) { Base *base; @@ -1737,18 +1738,7 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in Group *group, *groupn; GroupObject *go; - clear_sca_new_poins(); /* sensor/contr/act */ - - /* newid may still have some trash from Outliner tree building, so clear that first to avoid errors, see T26002. - * We have to clear whole datablocks, not only Object one may be accessed here, see T49905. */ - ListBase *lbarray[MAX_LIBARRAY]; - int a = set_listbasepointers(bmain, lbarray); - while (a--) { - ListBase *lb = lbarray[a]; - for (ID *id = lb->first; id; id = id->next) { - id->newid = NULL; - } - } + clear_sca_new_poins(); /* BGE logic */ /* duplicate (must set newid) */ for (base = FIRSTBASE; base; base = base->next) { @@ -1757,8 +1747,7 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in if ((base->flag & flag) == flag) { if (!ID_IS_LINKED_DATABLOCK(ob) && ob->id.us > 1) { /* base gets copy of object */ - obn = BKE_object_copy(bmain, ob); - base->object = obn; + base->object = obn = ID_NEW_SET(ob, BKE_object_copy(bmain, ob)); if (copy_groups) { if (ob->flag & OB_FROMGROUP) { @@ -1788,8 +1777,6 @@ 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) { - group->id.newid = NULL; - if (copy_groups && group->gobject.first) { bool all_duplicated = true; @@ -1801,10 +1788,11 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in } if (all_duplicated) { - groupn = BKE_group_copy(bmain, group); + groupn = ID_NEW_SET(group, BKE_group_copy(bmain, group)); - for (go = groupn->gobject.first; go; go = go->next) + for (go = groupn->gobject.first; go; go = go->next) { go->ob = (Object *)go->ob->id.newid; + } } } } @@ -1812,8 +1800,8 @@ static void single_object_users(Main *bmain, Scene *scene, View3D *v3d, const in /* group pointers in scene */ BKE_scene_groups_relink(scene); - ID_NEW(scene->camera); - if (v3d) ID_NEW(v3d->camera); + ID_NEW_REMAP(scene->camera); + if (v3d) ID_NEW_REMAP(v3d->camera); /* object and group pointers */ for (base = FIRSTBASE; base; base = base->next) { @@ -1836,6 +1824,8 @@ void ED_object_single_user(Main *bmain, Scene *scene, Object *ob) } single_object_users(bmain, scene, NULL, OB_DONE, copy_groups); + + BKE_main_id_clear_newpoins(bmain); } static void new_id_matar(Main *bmain, Material **matar, const int totcol) @@ -1852,9 +1842,8 @@ static void new_id_matar(Main *bmain, Material **matar, const int totcol) id_us_min(id); } else if (id->us > 1) { - matar[a] = BKE_material_copy(bmain, matar[a]); + matar[a] = ID_NEW_SET(id, BKE_material_copy(bmain, matar[a])); id_us_min(id); - id->newid = (ID *)matar[a]; } } } @@ -1882,45 +1871,46 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag) switch (ob->type) { case OB_LAMP: - ob->data = la = BKE_lamp_copy(bmain, ob->data); + ob->data = la = ID_NEW_SET(ob->data, BKE_lamp_copy(bmain, ob->data)); for (a = 0; a < MAX_MTEX; a++) { if (la->mtex[a]) { - ID_NEW(la->mtex[a]->object); + ID_NEW_REMAP(la->mtex[a]->object); } } break; case OB_CAMERA: - ob->data = BKE_camera_copy(bmain, ob->data); + ob->data = ID_NEW_SET(ob->data, BKE_camera_copy(bmain, ob->data)); break; case OB_MESH: - ob->data = me = BKE_mesh_copy(bmain, ob->data); - if (me->key) - BKE_animdata_copy_id_action((ID *)me->key); + /* Needed to remap texcomesh below. */ + me = ob->data = ID_NEW_SET(ob->data, BKE_mesh_copy(bmain, ob->data)); + if (me->key) /* We do not need to set me->key->id.newid here... */ + BKE_animdata_copy_id_action((ID *)me->key, false); break; case OB_MBALL: - ob->data = BKE_mball_copy(bmain, ob->data); + ob->data = ID_NEW_SET(ob->data, BKE_mball_copy(bmain, ob->data)); break; case OB_CURVE: case OB_SURF: case OB_FONT: - ob->data = cu = BKE_curve_copy(bmain, ob->data); - ID_NEW(cu->bevobj); - ID_NEW(cu->taperobj); - if (cu->key) - BKE_animdata_copy_id_action((ID *)cu->key); + ob->data = cu = ID_NEW_SET(ob->data, BKE_curve_copy(bmain, ob->data)); + ID_NEW_REMAP(cu->bevobj); + ID_NEW_REMAP(cu->taperobj); + if (cu->key) /* We do not need to set cu->key->id.newid here... */ + BKE_animdata_copy_id_action((ID *)cu->key, false); break; case OB_LATTICE: - ob->data = lat = BKE_lattice_copy(bmain, ob->data); - if (lat->key) - BKE_animdata_copy_id_action((ID *)lat->key); + ob->data = lat = ID_NEW_SET(ob->data, BKE_lattice_copy(bmain, ob->data)); + if (lat->key) /* We do not need to set lat->key->id.newid here... */ + BKE_animdata_copy_id_action((ID *)lat->key, false); break; case OB_ARMATURE: DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - ob->data = BKE_armature_copy(bmain, ob->data); + ob->data = ID_NEW_SET(ob->data, BKE_armature_copy(bmain, ob->data)); BKE_pose_rebuild(ob, ob->data); break; case OB_SPEAKER: - ob->data = BKE_speaker_copy(bmain, ob->data); + ob->data = ID_NEW_SET(ob->data, BKE_speaker_copy(bmain, ob->data)); break; default: if (G.debug & G_DEBUG) @@ -1933,17 +1923,16 @@ static void single_obdata_users(Main *bmain, Scene *scene, const int flag) * AnimData structure, which is not what we want. * (sergey) */ - BKE_animdata_copy_id_action((ID *)ob->data); + BKE_animdata_copy_id_action((ID *)ob->data, false); id_us_min(id); - id->newid = ob->data; } } } me = bmain->mesh.first; while (me) { - ID_NEW(me->texcomesh); + ID_NEW_REMAP(me->texcomesh); me = me->id.next; } } @@ -1957,7 +1946,7 @@ static void single_object_action_users(Scene *scene, const int flag) ob = base->object; if (!ID_IS_LINKED_DATABLOCK(ob) && (flag == 0 || (base->flag & SELECT)) ) { DAG_id_tag_update(&ob->id, OB_RECALC_DATA); - BKE_animdata_copy_id_action(&ob->id); + BKE_animdata_copy_id_action(&ob->id, false); } } } @@ -1976,11 +1965,11 @@ static void single_mat_users(Main *bmain, Scene *scene, const int flag, const bo for (a = 1; a <= ob->totcol; a++) { ma = give_current_material(ob, a); if (ma) { - /* do not test for LIB_TAG_NEW: this functions guaranteed delivers single_users! */ + /* do not test for LIB_TAG_NEW or use newid: this functions guaranteed delivers single_users! */ if (ma->id.us > 1) { man = BKE_material_copy(bmain, ma); - BKE_animdata_copy_id_action(&man->id); + BKE_animdata_copy_id_action(&man->id, false); man->id.us = 0; assign_material(ob, man, a, BKE_MAT_ASSIGN_USERPREF); @@ -1991,7 +1980,7 @@ static void single_mat_users(Main *bmain, Scene *scene, const int flag, const bo if (tex->id.us > 1) { id_us_min(&tex->id); tex = BKE_texture_copy(bmain, tex); - BKE_animdata_copy_id_action(&tex->id); + BKE_animdata_copy_id_action(&tex->id, false); man->mtex[b]->tex = tex; } } @@ -2017,8 +2006,8 @@ static void do_single_tex_user(Main *bmain, Tex **from) id_us_min(&tex->id); } else if (tex->id.us > 1) { - texn = BKE_texture_copy(bmain, tex); - BKE_animdata_copy_id_action(&texn->id); + texn = ID_NEW_SET(tex, BKE_texture_copy(bmain, tex)); + BKE_animdata_copy_id_action(&texn->id, false); tex->id.newid = (ID *)texn; id_us_min(&tex->id); *from = texn; @@ -2095,7 +2084,7 @@ static void single_mat_users_expand(Main *bmain) if (ma->id.tag & LIB_TAG_NEW) for (a = 0; a < MAX_MTEX; a++) if (ma->mtex[a]) - ID_NEW(ma->mtex[a]->object); + ID_NEW_REMAP(ma->mtex[a]->object); } /* used for copying scenes */ @@ -2245,7 +2234,6 @@ static int make_local_exec(bContext *C, wmOperator *op) } tag_localizable_objects(C, mode); - BKE_main_id_clear_newpoins(bmain); CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { @@ -2262,7 +2250,7 @@ static int make_local_exec(bContext *C, wmOperator *op) CTX_DATA_BEGIN (C, Object *, ob, selected_objects) { if (ob->id.lib == NULL) { - ID_NEW(ob->parent); + ID_NEW_REMAP(ob->parent); } } CTX_DATA_END; @@ -2330,6 +2318,7 @@ static int make_local_exec(bContext *C, wmOperator *op) CTX_DATA_END; } + BKE_main_id_clear_newpoins(bmain); WM_event_add_notifier(C, NC_WINDOW, NULL); return OPERATOR_FINISHED; @@ -2376,8 +2365,6 @@ static int make_single_user_exec(bContext *C, wmOperator *op) const bool copy_groups = false; bool update_deps = false; - BKE_main_id_clear_newpoins(bmain); - if (RNA_boolean_get(op->ptr, "object")) { single_object_users(bmain, scene, v3d, flag, copy_groups); @@ -2401,11 +2388,6 @@ static int make_single_user_exec(bContext *C, wmOperator *op) single_object_action_users(scene, flag); } - /* TODO(sergey): This should not be needed, however some tool still could rely - * on the fact, that id->newid is kept NULL by default. - * Need to make sure all the guys are learing newid before they're - * using it, not after. - */ BKE_main_id_clear_newpoins(bmain); WM_event_add_notifier(C, NC_WINDOW, NULL); diff --git a/source/blender/editors/object/object_warp.c b/source/blender/editors/object/object_warp.c index 9f4da87903d..92b82e2a31b 100644 --- a/source/blender/editors/object/object_warp.c +++ b/source/blender/editors/object/object_warp.c @@ -53,8 +53,7 @@ static void object_warp_calc_view_matrix(float r_mat_view[4][4], float r_center_ float viewmat_roll[4][4]; /* apply the rotation offset by rolling the view */ - unit_m4(mat_offset); - rotate_m4(mat_offset, 'Z', offset_angle); + axis_angle_to_mat4_single(mat_offset, 'Z', offset_angle); mul_m4_m4m4(viewmat_roll, mat_offset, viewmat); /* apply the view and the object matrix */ diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index 53434b18d06..ef2f2d36ab7 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -821,10 +821,9 @@ static float calc_overlap(StrokeCache *cache, const char symm, const char axis, flip_v3_v3(mirror, cache->true_location, symm); if (axis != 0) { - float mat[4][4]; - unit_m4(mat); - rotate_m4(mat, axis, angle); - mul_m4_v3(mat, mirror); + float mat[3][3]; + axis_angle_to_mat3_single(mat, axis, angle); + mul_m3_v3(mat, mirror); } /* distsq = len_squared_v3v3(mirror, cache->traced_location); */ diff --git a/source/blender/editors/space_outliner/outliner_tools.c b/source/blender/editors/space_outliner/outliner_tools.c index 2c678457025..d6300b74aea 100644 --- a/source/blender/editors/space_outliner/outliner_tools.c +++ b/source/blender/editors/space_outliner/outliner_tools.c @@ -442,6 +442,9 @@ static void id_local_cb( if (id_make_local(bmain, tselem->id, false, false) == false) { id_clear_lib_data(bmain, tselem->id); } + else { + BKE_main_id_clear_newpoins(bmain); + } } } diff --git a/source/blender/editors/space_outliner/outliner_tree.c b/source/blender/editors/space_outliner/outliner_tree.c index 3b499a81831..d1c75b01157 100644 --- a/source/blender/editors/space_outliner/outliner_tree.c +++ b/source/blender/editors/space_outliner/outliner_tree.c @@ -1099,8 +1099,12 @@ static TreeElement *outliner_add_element(SpaceOops *soops, ListBase *lb, void *i tselem->flag &= ~TSE_CLOSED; if (TSELEM_OPEN(tselem, soops)) { - for (a = 0; a < tot; a++) - outliner_add_element(soops, &te->subtree, (void *)ptr, te, TSE_RNA_PROPERTY, a); + for (a = 0; a < tot; a++) { + RNA_property_collection_lookup_int(ptr, iterprop, a, &propptr); + if (!(RNA_property_flag(propptr.data) & PROP_HIDDEN)) { + outliner_add_element(soops, &te->subtree, (void *)ptr, te, TSE_RNA_PROPERTY, a); + } + } } else if (tot) te->flag |= TE_LAZY_CLOSED; @@ -1632,11 +1636,6 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops) outliner_free_tree(&soops->tree); outliner_storage_cleanup(soops); - /* clear ob id.new flags */ - for (Object *ob = mainvar->object.first; ob; ob = ob->id.next) { - ob->id.newid = NULL; - } - /* options */ if (soops->outlinevis == SO_LIBRARIES) { Library *lib; @@ -1822,6 +1821,8 @@ void outliner_build_tree(Main *mainvar, Scene *scene, SpaceOops *soops) outliner_sort(&soops->tree); } outliner_filter_tree(soops, &soops->tree); + + BKE_main_id_clear_newpoins(mainvar); } diff --git a/source/blender/editors/space_view3d/drawarmature.c b/source/blender/editors/space_view3d/drawarmature.c index b37a6740891..7ac176f82b1 100644 --- a/source/blender/editors/space_view3d/drawarmature.c +++ b/source/blender/editors/space_view3d/drawarmature.c @@ -2719,6 +2719,11 @@ bool draw_armature(Scene *scene, View3D *v3d, ARegion *ar, Base *base, else { /* Draw Pose */ if (ob->pose && ob->pose->chanbase.first) { + /* We can't safely draw non-updated pose, might contain NULL bone pointers... */ + if (ob->pose->flag & POSE_RECALC) { + BKE_pose_rebuild(ob, arm); + } + /* drawing posemode selection indices or colors only in these cases */ if (!(base->flag & OB_FROMDUPLI)) { if (G.f & G_PICKSEL) { diff --git a/source/blender/editors/space_view3d/view3d_draw.c b/source/blender/editors/space_view3d/view3d_draw.c index 9184e4723a8..201209789a2 100644 --- a/source/blender/editors/space_view3d/view3d_draw.c +++ b/source/blender/editors/space_view3d/view3d_draw.c @@ -125,7 +125,7 @@ static bool use_depth(const bContext *C) void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float viewmat[4][4], float winmat[4][4]) { RegionView3D *rv3d = ar->regiondata; - rctf cameraborder; + /* setup window matrices */ if (winmat) @@ -139,7 +139,7 @@ void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float view else view3d_viewmatrix_set(scene, v3d, rv3d); /* note: calls BKE_object_where_is_calc for camera... */ - /* update utilitity matrices */ + /* update utility matrices */ mul_m4_m4m4(rv3d->persmat, rv3d->winmat, rv3d->viewmat); invert_m4_m4(rv3d->persinv, rv3d->persmat); invert_m4_m4(rv3d->viewinv, rv3d->viewmat); @@ -148,6 +148,7 @@ void ED_view3d_update_viewmat(Scene *scene, View3D *v3d, ARegion *ar, float view /* store window coordinates scaling/offset */ if (rv3d->persp == RV3D_CAMOB && v3d->camera) { + rctf cameraborder; ED_view3d_calc_camera_border(scene, ar, v3d, rv3d, &cameraborder, false); rv3d->viewcamtexcofac[0] = (float)ar->winx / BLI_rctf_size_x(&cameraborder); rv3d->viewcamtexcofac[1] = (float)ar->winy / BLI_rctf_size_y(&cameraborder); @@ -1447,6 +1448,16 @@ static void view3d_draw_grid(const bContext *C, ARegion *ar) * Also for now always assume depth is there, so we * draw on top of it. */ + /** + * Calculate pixel-size factor once, is used for lamps and object centers. + * Used by #ED_view3d_pixel_size and typically not accessed directly. + * + * \note #BKE_camera_params_compute_viewplane' also calculates a pixel-size value, + * passed to #RE_SetPixelSize, in ortho mode this is compatible with this value, + * but in perspective mode its offset by the near-clip. + * + * 'RegionView3D.pixsize' is used for viewport drawing, not rendering. + */ Scene *scene = CTX_data_scene(C); View3D *v3d = CTX_wm_view3d(C); RegionView3D *rv3d = ar->regiondata; diff --git a/source/blender/editors/uvedit/uvedit_smart_stitch.c b/source/blender/editors/uvedit/uvedit_smart_stitch.c index 59442e89787..50aec737c8e 100644 --- a/source/blender/editors/uvedit/uvedit_smart_stitch.c +++ b/source/blender/editors/uvedit/uvedit_smart_stitch.c @@ -459,7 +459,7 @@ static void stitch_calculate_island_snapping( island_stitch_data[i].num_rot_elements_neg) / totelem; } - rotate_m2(rotation_mat, rotation); + angle_to_mat2(rotation_mat, rotation); numOfIslandUVs = getNumOfIslandUvs(state->element_map, i); element = &state->element_map->buf[state->element_map->islandIndices[i]]; for (j = 0; j < numOfIslandUVs; j++, element++) { |